Невозможно закрыть файл после прочтения - C программирование

Я написал функцию, которая читает файл, полный текста, и приступает к объединению всех строк в одну строку. Это работает, но инструкция fclose(), когда она используется, запускает ошибку:

"* Ошибка в`./main': двойное освобождение или повреждение (out): 0x00000000020fc330 *", за которым следуют обратная трассировка и карта памяти.

Это также плохо работает для файлов с одной строкой.

Что я могу сделать?

Код:

char* readFile(char* fileName){
FILE* myFile = fopen(fileName, "r");
if (myFile != NULL) {
    fseek(myFile, 0, SEEK_END);
    long l = ftell(myFile);
    fseek(myFile, 0, SEEK_SET);
    char* content = (char*)malloc((size_t)l * sizeof(char));
    if (content == NULL) return NULL;
    char * chain = (char*)malloc((size_t)l * sizeof(char));     
    while(fscanf(myFile, "%s\n", chain) != EOF || fscanf(myFile, "%s\t", chain) != EOF || fscanf(myFile, "%s ", chain) != EOF){
        strcat(content, chain);
    }
    free(chain);
    fclose(myFile);         
    return content;
} else return NULL;

}

4 ответа

Скорее всего, здесь происходит то, что ваши вызовы scanf () и / или strcat () пишут после окончания ваших выделенных буферов (контента или цепочки) и повреждают кучу. Это повреждение замечено free (), когда он пытается освободить 'цепочку', вызывая сообщение об ошибке и сбой.

Чтобы избежать записи после окончания буферов, вам нужно точно знать, сколько байтов каждый из этих вызовов записывает в буфер. Это трудно понять с помощью fscanf (), если у вас нет гарантии того, что будет в файле (а обычно нет), поэтому вы можете использовать вместо него fread (), чтобы вы могли указать максимальное количество байтов читать. Также при вызове strcat () необходимо убедиться, что в буфере, на который указывает первый аргумент, достаточно места как для его существующего содержимого, так и для содержимого строки, которую вы хотите добавить в конец существующего содержимого. Попробуйте вместо этого вызвать strncat (), если хотите избежать перезаписи (поскольку strcat () не может узнать, насколько велики буферы, он с радостью запишет за конец слишком короткого буфера - по крайней мере, strncat () прекратит запись после того количества байтов, которое вы указали в третьем аргументе)

В дополнение к другим комментариям, вы должны избегать использования strcat() в цикле. Каждый раз в цикле strcat должен искать в строке нулевой символ, и этот поиск становится все длиннее и длиннее.

Более эффективным способом было бы сохранить указатель на символ nul и просто использовать strcpy для добавления к нему, а затем увеличить указатель на количество добавленных символов.

Как уже говорили другие, ваш указатель содержимого указывает на память, которая не инициализирована, он может содержать нежелательную информацию, когда вы пытаетесь выполнить для нее strcat(). Попробуйте вместо этого использовать calloc(), это установит все символы в '\0' и позволит вам делать то, что вы хотите.

Подумайте о том, чтобы следовать совету Джереми и создать более эффективную функцию, чтобы делать то, что вы хотите. Прямо сейчас вы выделяете два буфера размером с файл и ищете токены для заполнения одного из этих огромных буферов и объединяете их в другой. У вас определенно будет много места, так как вы отбрасываете разделители, но это много потерянного места.

Размещенный код, как указано в комментариях к вопросу, имеет много проблем.

Следующий опубликованный код исправляет эти проблемы, аккуратно компилирует и выполняет нужную функцию.

#include <stdio.h>   // fopen(), fclose(), fseek(), NULL, perror()
#include <stdlib.h>  // malloc(), free()
#include <string.h>  // strcat()

char* readFile( char* );

char* readFile( char* fileName )
{
    FILE* myFile = fopen(fileName, "r");

    if ( !myFile )
    {
        perror( "fopen for reading file failed" );
        return NULL;
    }

    // implied else, fopen successful

    if( 0 != fseek(myFile, 0, SEEK_END) )
    {
        perror( "fseek to end of file failed:" );
        return NULL;
    }

    // implied else, fseek successful

    long fileLength = ftell(myFile);
    if( -1 == fileLength )
    {
        perror( "ftell failed" );
        return NULL;
    }

    // implied else, ftell successful

    if( 0 != fseek(myFile, 0, SEEK_SET) )
    {
        perror( "fseek to start of file failed" );
        return NULL;
    }

    // implied else, fseek successful

    char* content = malloc((size_t)fileLength+1 );
    if (content == NULL)
        return NULL;

    // initialize the concatenated string to be empty
    content[0] = '\0';

    char * chain = malloc((size_t)fileLength+1);
    if ( chain == NULL)
        return NULL;

    while( fgets( chain, (int)fileLength, myFile ) )
    {
        strcat(content, chain);
    }

    free(chain);
    fclose(myFile);
    return content;
} // end function: readfile
Другие вопросы по тегам