fclose() вызывает ошибку сегментации
У меня есть текстовый файл с разделителями табуляции, который я анализирую. Его первый столбец содержит строки формата chrX
, где X
обозначает набор строк, например, "1", "2", ..., "X", "Y".
Каждый из них хранится в char*
называется chromosome
, как файл анализируется.
Текстовый файл отсортирован по первому столбцу лексикографически, т.е. у меня будет ряд строк, начинающихся с "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
вызов, вызывающий ошибку сегментации?
7 ответов
valgrind --db-attach=yes --leak-check=yes --tool=memcheck --num-callers=16 --leak-resolution=high ./yourprogram args
Весьма вероятно, что ошибка вызвана повреждением памяти в куче, а не чем-то, что влияет на локальных пользователей. Valgrind немедленно покажет вам первый неверный доступ.
Изменить: --db-attach
возможность valgrind
устарела с версии 3.10.0 в 2014 году. Примечания к выпуску:
The built-in GDB server capabilities are superior and should be used
instead. Learn more here:
Я заметил одну ошибку:
*chrome = (char *) malloc ((size_t) strlen(field));
который должен быть:
*chrome = (char *) malloc ((size_t) strlen(field)+1);
Это потому, что строка имеет закрывающий 0 в конце, который вы также должны освободить место для
В дополнение к ошибке, обнаруженной Reinier, я подозреваю, что:
free(chromosome);
должно сопровождаться:
chromosome = NULL;
для того, чтобы предотвратить потенциальное использование более не действительного значения.
Общая проблема указателя
С - отличный язык, но он требует, чтобы вы не забивали свою собственную память. Помимо ранее отмеченной проблемы, когда malloc имеет длину 1 байт, у вас могут быть и другие проблемы с указателями.
Я бы предложил использовать отладчик памяти. В прошлом Electric Fence был довольно популярен, но сейчас я слышу больше о valgrind. Есть много других вариантов.
Лучше всего предположить, что какая-то другая часть вашего кода повреждает память из-за переполнения буфера или подобной ошибки.
Хотя это вряд ли является причиной, у вас есть потенциальное переполнение в массиве имен файлов, когда полное имя файла превышает 100 символов.
Я бы предложил использовать отладчик для отслеживания изменений в ячейке памяти, используемой переменной merbaseIn.
Просмотрите каждое место, где вы использовали "malloc", и посмотрите, не ошиблись ли вы.
Например, я помещал строки, прочитанные из файла, в символ **, но я неправильно назвал его следующим образом:
my_list = malloc(sizeof(char) * num_lines_found_in_file);
Когда это должно было быть:
my_list = malloc(sizeof(char*)* num_lines_found_in_file);
valgrind
с memcheck
это определенно правильный инструмент для обнаружения причины ошибки сегментации. Использовать отладчик с valgrind
обратите внимание, что --db-attach
возможность valgrind
устарела с момента выпуска Valgrind 3.10.0 в 2014 году. Примечания к выпуску:
The built-in GDB server capabilities are superior and should be used
instead. Learn more here:
Почему этот FILE** filePtr, если только этого FILE* filePtr будет достаточно? просто мысль...