C printf如何避免分段错误?
--重要编辑-- 感谢您提供了使用C printf如何避免分段错误?,c,C,--重要编辑-- 感谢您提供了使用-fsanize=address-g进行编译的技巧,它使我能够跟踪问题。我几乎完成了,我已经隔离了这个问题(发生在清理函数顶部附近)。为了简化事情,为什么下面的代码(使用上述标志编译时)会失败 将30000更改为1000,将29999更改为999 我已经阅读了关于malloc、realloc和calloc的文档,并浏览了其他答案,但我仍然无法回答这个问题。据我所知,我没有内存泄漏(即使我realloc一个struct pair*,每个struct中指针处的内存
-fsanize=address-g
进行编译的技巧,它使我能够跟踪问题。我几乎完成了,我已经隔离了这个问题(发生在清理函数顶部附近)。为了简化事情,为什么下面的代码(使用上述标志编译时)会失败
将30000更改为1000,将29999更改为999
我已经阅读了关于malloc、realloc和calloc的文档,并浏览了其他答案,但我仍然无法回答这个问题。据我所知,我没有内存泄漏(即使我realloc一个struct pair*,每个struct中指针处的内存也没有泄漏,因为它在char*程序块中)或其他问题。这就是为什么我会提供最低限度的答案来重现这个问题,但我开始怀疑删除源代码中看似不相关的部分不会对它产生任何影响(尽管我仍然对代码进行了大量精简)
我使用MacOSX10.14,bash“gcc-oBrainfc brainfc.c”或“clang-oBrainfc brainfc.c”来编译,“brainfc mandelbrot.b”来运行程序。
mandelbrot.b文件可在以下位置找到:
#包括
#包括
#包括
char*program=NULL;
结构对{
字符*左;
char*对;
};
//从文件读入全局变量程序
无效文件输入(字符*文件名){
文件*fp;
fp=fopen(文件名,“rb”);
if(fp){
输入大小=0;
fseek(fp,0,SEEK_END);
int filesize=ftell(fp);
倒带(fp);
程序=malloc(文件大小+1);
fread(程序,文件大小,1,fp);
*(程序+文件大小)=0;
fclose(fp);
}
}
//从程序中删除不需要的字符,并编译成对的查找表
//为了提高效率,这只需对程序进行一次扫描,
//不过,如果我对可读性进行了优化,这个问题可能不会出现
结构对*cleanup(){
int pairsize=200;
结构对*pairs=calloc(pairsize,sizeof(*pairs));
字符*src,*dest;
结构对*buildptr=对;
内括号级别=0;
for(src=dest=program;*src;dest+=(strchr(“+-[],”,*src++)!=NULL)){
*dest=*src;
如果(*dest=='['){
bracketlevel++;
同时(buildptr->left){
if(buildptr==pairs+(pairsize-1)*sizeof(*pairs)){
pairsize+=100;
pairs=realloc(pairs,pairsize*sizeof(*pairs));
对于(int x=0;x<100;x++){
buildptr+=sizeof(*对);
buildptr->left=buildptr->right=NULL;
}
buildptr-=sizeof(*对)*100;
}
buildptr+=sizeof(*对);
}
buildptr->left=dest;
}如果(*dest==']',则为else{
括号级别--;
如果(括号级别<0){
返回NULL;
}
同时(buildptr->right){
buildptr-=sizeof(*对);
}
buildptr->right=dest;
}
}
如果(括号级别!=0){
返回NULL;
}
*dest=0;
程序=realloc(程序,strlen(程序)+1);
返回对;
}
//执行程序
int执行(结构对*对){
无符号字符*指针=(无符号字符*)calloc(30000,1);
无符号字符*leftbound=指针,*righbound=指针;
右边界+=29999;
用于(char*pc=program;*pc;pc++){
开关(*pc){
案例“”:
如果(指针==右边界)返回1;
指针++;
打破
格“+”:
(*指针)++;
打破
案例'-':
(*指针)--;
打破
案例“[”:
而(pairs->left!=pc)pairs+=sizeof(*pairs);
如果(!(*指针))pc=pairs->right;
打破
案例']':
而(pairs->right!=pc)pairs-=sizeof(*pairs);
如果(*指针)pc=pairs->left;
打破
案例“”:
printf(“%c”,*指针);
打破
案例',':
printf(“输入10(暂时)\n”);
*指针=10;
打破
}
}
返回0;
}
//解析命令行参数,按顺序调用每个函数
int main(int argc,char*argv[]){
如果(argc>0){
char*filepath=argv[1];
fileinput(filepath);
}
if(程序==NULL){
printf(“错误:找不到文件\n”);
返回3;
}
结构对*pairs=cleanup();
if(pairs==NULL){
printf(“错误:无效程序\n”);
返回4;
}
int execstatus=执行(成对);
开关(执行状态){
案例1:
printf(“\n错误:指针超出范围\n”);
返回1;
案例2:
printf(“\n错误:字节溢出\n”);
返回2;
违约:
返回0;
}
}
任何帮助都将不胜感激
pairs += sizeof(*pairs);
C中的指针算法总是以指向的类型为单位——这里,它以struct pair
s为单位。因此,如果希望对
指向数组中的下一个结构对
,请添加1。(编译器将在内部将其转换为添加适当数量的字节,或者不管指针如何在系统上工作。)此行应为pairs+=1代码>或成对++代码>或++对代码>根据您的喜好
目前,如果系统上的sizeof(*pairs)
恰好是16个,那么每次迭代时都会跳过15个以上的struct pairs
。您将访问第0、第16、第32。。。数组中的第1584个结构对。因为它只包含100个,很明显,其中的大多数都是不允许的。因此你
unsigned char *pointer = (unsigned char*) calloc(30000, 1);
unsigned char *leftbound = pointer, *rightbound = pointer;
rightbound += 29999;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *program = NULL;
struct pair {
char *left;
char *right;
};
//Reads into global variable program from file
void fileinput(char *filename) {
FILE *fp;
fp = fopen(filename, "rb");
if (fp) {
size_t inputlen = 0;
fseek(fp, 0, SEEK_END);
int filesize = ftell(fp);
rewind(fp);
program = malloc(filesize + 1);
fread(program, filesize, 1, fp);
*(program + filesize) = 0;
fclose(fp);
}
}
//Removes unwanted characters from program, as well as compiling lookup table of pairs
//This happens in a single sweep through the program for efficiency,
//though again this problem might not occur if I optimized for readability
struct pair* cleanup() {
int pairsize = 200;
struct pair *pairs = calloc(pairsize, sizeof(*pairs));
char *src, *dest;
struct pair *buildptr = pairs;
int bracketlevel = 0;
for (src = dest = program; *src; dest += (strchr("<>+-[].,", *src++) != NULL)) {
*dest = *src;
if (*dest == '[') {
bracketlevel++;
while (buildptr->left) {
if (buildptr == pairs + (pairsize - 1) * sizeof(*pairs)) {
pairsize += 100;
pairs = realloc(pairs, pairsize * sizeof(*pairs));
for (int x = 0; x < 100; x++) {
buildptr += sizeof(*pairs);
buildptr->left = buildptr->right = NULL;
}
buildptr -= sizeof(*pairs) * 100;
}
buildptr += sizeof(*pairs);
}
buildptr->left = dest;
} else if (*dest == ']') {
bracketlevel--;
if (bracketlevel < 0) {
return NULL;
}
while (buildptr->right) {
buildptr -= sizeof(*pairs);
}
buildptr->right = dest;
}
}
if (bracketlevel != 0) {
return NULL;
}
*dest = 0;
program = realloc(program, strlen(program) + 1);
return pairs;
}
//Executes program
int execute(struct pair *pairs) {
unsigned char *pointer = (unsigned char*) calloc(30000, 1);
unsigned char *leftbound = pointer, *rightbound = pointer;
rightbound += 29999;
for (char *pc = program; *pc; pc++) {
switch (*pc) {
case '<':
if (pointer == leftbound) return 1;
pointer--;
break;
case '>':
if (pointer == rightbound) return 1;
pointer++;
break;
case '+':
(*pointer)++;
break;
case '-':
(*pointer)--;
break;
case '[':
while (pairs->left != pc) pairs += sizeof(*pairs);
if (!(*pointer)) pc = pairs->right;
break;
case ']':
while (pairs->right != pc) pairs -= sizeof(*pairs);
if (*pointer) pc = pairs->left;
break;
case '.':
printf("%c", *pointer);
break;
case ',':
printf("Inputting 10 (for now)\n");
*pointer = 10;
break;
}
}
return 0;
}
//Parses command line arguments, calls each function in order
int main(int argc, char *argv[]) {
if (argc > 0) {
char *filepath = argv[1];
fileinput(filepath);
}
if (program == NULL) {
printf("Error: File not found\n");
return 3;
}
struct pair *pairs = cleanup();
if (pairs == NULL) {
printf("Error: Invalid program\n");
return 4;
}
int execstatus = execute(pairs);
switch (execstatus) {
case 1:
printf("\nError: Pointer out-of-bounds\n");
return 1;
case 2:
printf("\nError: Byte overflow\n");
return 2;
default:
return 0;
}
}
pairs += sizeof(*pairs);
pairs->left = pairs->right = NULL;
pairs += sizeof(*pairs);
pairs[x].left = pairs[x].right = NULL;