fclose()导致分段错误
我正在解析一个以制表符分隔的文本文件。其第一列包含格式为fclose()导致分段错误,c,segmentation-fault,fopen,fclose,C,Segmentation Fault,Fopen,Fclose,我正在解析一个以制表符分隔的文本文件。其第一列包含格式为chrX的字符串,其中X表示一组字符串,例如,“1”、“2”、…、“X”、“Y” 当解析文件时,它们都存储在名为染色体的char*中 文本文件按字典顺序排列在第一列,即,我将有许多行,从“chr1”开始,然后是“chr2”,等等 在每个“chrX”条目中,我需要打开与此条目关联的另一个文件: FILE *merbaseIn; // loop through rows... if (chromosome == NULL)
chrX
的字符串,其中X
表示一组字符串,例如,“1”、“2”、…、“X”、“Y”
当解析文件时,它们都存储在名为染色体
的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
空指针,因为在出现分段错误之前,我一直在从该文件读取数据。我甚至可以把它包装成一个条件,但我仍然会犯错误:
if (merbaseIn != NULL) {
fclose(merbaseIn);
}
此外,我知道openSourceFile
是有效的(至少对于chr1
,在设置file*
的第一个文件句柄时是有效的),因为我的应用程序解析chr1
行并正确读取file*
源文件中的数据
这个
fclose
调用导致出现分段错误的原因是什么?我注意到的一个错误是这一行:
*chrome = (char *) malloc ((size_t) strlen(field));
应该是:
*chrome = (char *) malloc ((size_t) strlen(field)+1);
这是因为字符串末尾有一个结束符0,您还必须为它腾出空间
valgrind --db-attach=yes --leak-check=yes --tool=memcheck --num-callers=16 --leak-resolution=high ./yourprogram args
segfault很可能是由堆上的内存损坏引起的,而不是影响本地的任何东西。将立即显示您的第一次错误访问
编辑:自2014年3.10.0版以来,--db attach
选项已被弃用到valgrind
。发行说明指出:
The built-in GDB server capabilities are superior and should be used
instead. Learn more here:
The built-in GDB server capabilities are superior and should be used
instead. Learn more here:
最好的猜测是,代码的其他部分通过缓冲区溢出或类似的错误而损坏内存 虽然不太可能是原因,但当完整文件名超过100个字符时,文件名数组中可能存在溢出情况 我建议使用调试器来监视merbaseIn变量使用的内存位置的更改。通用指针问题 C语言是一门伟大的语言,但它确实要求你不要破坏自己的记忆。除了前面提到的malloc短1字节的问题外,您可能还有其他指针问题
我建议。在过去,它很受欢迎,但现在我。还有很多其他选择。除了发现的错误,我怀疑:
free(chromosome);
随后应:
chromosome = NULL;
为了防止使用不再有效的值。如果只有这个文件*文件ptr就足够了,为什么要使用这个文件**filePtr?
只是一个想法…
valgrind
和memcheck
绝对是发现分段故障原因的正确工具。要将调试器与valgrind
一起使用,请注意,--db attach
选项到valgrind
自2014年发布valgrind 3.10.0以来已被弃用。发行说明指出:
The built-in GDB server capabilities are superior and should be used
instead. Learn more here:
The built-in GDB server capabilities are superior and should be used
instead. Learn more here:
查看您使用的每个地方“malloc”,看看您是否犯了错误 例如,我将从文件中读取的行放入一个char**,但我没有正确地输入 将其命名为:
my_list = malloc(sizeof(char) * num_lines_found_in_file);
当它应该是:
my_list = malloc(sizeof(char*)* num_lines_found_in_file);
是,但是strlen()返回size\u t,所以请删除该类型。malloc()返回void*,它可以转换为C中的任何其他(数据)指针类型,因此也可以删除该转换。在这种情况下,可以使用strdup()替换malloc()+strcpy()。我不同意(char*)转换,该转换清楚地说明了意图。我没有在双指针中的指针上运行
free
。我也没有在其他地方释放指针。我废弃了这个应用程序,从头开始编写,一边运行valgrind
,以确保正确管理内存。谢谢你给我指点这个工具!是的,valgrind教会了我:1)每个人都是对的,我应该只使用smart(自动/参考计数等)指针或垃圾收集;2)valgrind实际上不需要垃圾收集。唯一的警告是测试覆盖率。我认为使用valgrind查找内存泄漏比使用我熟悉的任何GC语言工具(如JVM或.NET语言)都要容易。关闭时使用双文件指针是一种很好的做法。通过这种方式,您可以在关闭原始文件指针后将其设置为NULL
,因为它不是函数参数。