fclose()导致分段错误
我有一个制表符分隔的文本文件,我正在解析。 其第一列包含格式为chrX
字符串,其中X
表示一组字符串,例如“1”,“2”,……,“X”,“Y”。
当解析文件时,这些都存储在称为chromosome
的char*
。
文本文件按字典顺序排在第一列,即,我将有一些以“chr1”开头的行,然后是“chr2”等。
在每个“chrX”条目中,我需要打开与此条目关联的另一个文件:
FILE *merbaseIn; // loop through rows... if (chromosome == NULL) openSourceFile(&chromosome, fieldArray[i], &merbaseIn, GENPATHIN); else { if (strcmp(chromosome, fieldArray[i]) != 0) { // new chromosome fclose(merbaseIn); // close old chromosome FILE ptr free(chromosome); // free old chromosome ptr openSourceFile(&chromosome, fieldArray[i], &merbaseIn, GENPATHIN); // set up new chromosome FILE ptr } } // parse row
我有openSourceFile
函数,定义如下:
void openSourceFile (char** chrome, const char* field, FILE** filePtr, const char *path) { char filename[100]; *chrome = (char *) malloc ((size_t) strlen(field)); if (*chrome == NULL) { fprintf(stderr, "ERROR: Cannot allocate memory for chromosome name!"); exit(EXIT_FAILURE); } strcpy(*chrome, field); sprintf(filename,"%s%s.fa", path, field); *filePtr = fopen(filename, "r"); if (*filePtr == NULL) { fprintf(stderr, "ERROR: Could not open fasta source file %s\n", filename); exit(EXIT_FAILURE); } }
问题是我的应用程序在下一行从第一个染色体到第二个染色体(从chr1
到chr2
)退出分段错误,在那里我关闭了我打开的第一个染色体文件:
fclose(merbaseIn);
我知道我没有传递fclose
一个NULL指针,因为直到Segmentation Fault,我正在从这个文件中读取数据。 我甚至可以在条件中包装它,我仍然得到错误:
if (merbaseIn != NULL) { fclose(merbaseIn); }
此外,我知道openSourceFile
工作(至少对于chr1
,在设置FILE*
的第一个文件句柄时),因为我的应用程序解析chr1
行并正确地从FILE*
源文件中读取数据。
这个fclose
调用导致分段错误发生的原因是什么?
valgrind --db-attach=yes --leak-check=yes --tool=memcheck --num-callers=16 --leak-resolution=high ./yourprogram args
segfault很可能是由堆上的内存损坏引起的,而不是任何影响本地的内存。 Valgrind会立即向您显示您所犯的第一个错误访问权限。
编辑:自2014年版本3.10.0以来,不推荐使用valgrind
的--db-attach
选项。发行说明指出:
The built-in GDB server capabilities are superior and should be used instead. Learn more here:
http://valgrind.org/docs/manual/manual-core-adv.html#manual-core-adv.gdbserver
我注意到的一个错误是这一行:
*chrome = (char *) malloc ((size_t) strlen(field));
应该是:
*chrome = (char *) malloc ((size_t) strlen(field)+1);
这是因为一个字符串在结尾处有一个结束0,你还必须腾出空间
除了由reinier发现的错误之外 ,我怀疑:
free(chromosome);
应该遵循:
chromosome = NULL;
以防止潜在使用不再有效的值。
最好的猜测是,代码的其他部分是通过缓冲区溢出或类似错误来破坏内存。
虽然不太可能是原因,但是当完整文件名超过100个字符时,您的文件名数组中可能存在溢出条件。
我建议使用调试器来监视merbaseIn变量使用的内存位置的变化。
通用指针问题
C语言很棒,但它确实要求你不要破坏自己的记忆。 除了前面提到的malloc短1字节的问题,你可能还有其他指针问题。
我建议使用内存调试器 。 在过去, 电围栏相当受欢迎,但这些天我听到更多关于valgrind 。 还有很多其他选择。
为什么这个FILE ** filePtr如果只有这个FILE * filePtr就足够了? 只是一个想法…
具有memcheck
valgrind
绝对是发现分段错误原因的正确工具。 要将调试器与valgrind
,请注意,自2014年Valgrind 3.10.0发布以来, valgrind
的--db-attach
选项已被弃用。发行说明指出:
The built-in GDB server capabilities are superior and should be used instead. Learn more here:
http://valgrind.org/docs/manual/manual-core-adv.html#manual-core-adv.gdbserver