[英]Impossible to close a file after reading it - C programming
我編寫了一個函數,該函數讀取一個充滿文本的文件,然后將所有行連接到一個字符串中。 它可以工作,但是fclose()指令在使用時會引發錯誤:
“ * ./main”中的錯誤:兩次釋放或損壞(輸出):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;
}
最有可能發生的情況是您對scanf()和/或strcat()的調用超出了分配的緩沖區(內容或鏈)的末尾,並破壞了堆。 當試圖釋放“鏈”時,free()會注意到該損壞,從而導致錯誤消息和崩潰。
為了避免越過緩沖區的末尾,您需要確切知道每個調用將要寫入緩沖區的字節數。 除非您對文件中的內容有保證(通常沒有),否則很難用fscanf()知道,因此您可能想使用fread(),以便可以指定最大字節數讀書。 同樣,在調用strcat()時,您需要確保第一個參數所指向的緩沖區具有足夠的空間容納其現有內容以及要添加到其現有內容末尾的字符串內容。 如果您要確保避免覆蓋,請考慮調用strncat(),因為strcat()無法知道緩沖區的大小,它將很高興地寫到緩沖區太短的末尾-至少是strncat ()將在您在第三個參數中指定的字節數之后停止寫入)
除了其他注釋外,還應避免在循環中使用strcat()。 每次循環時,strcat都必須在字符串中搜索nul字符,並且這種搜索越來越長。
一種更有效的方法是保留指向nul字符的指針,然后僅使用strcpy對其進行添加,然后將指針增加所添加的字符數。
正如其他人所述,您的內容指針指向未初始化的內存,當您嘗試對其進行strcat()時,它可能包含垃圾。 嘗試使用calloc()代替,這會將所有字符設置為'\\ 0'並允許您執行所需的操作。
考慮遵循Jeremy的建議,並創建一個更有效的功能來執行您想要的操作。 現在,您正在分配文件大小的兩個緩沖區,並尋找標記來填充這些巨大的緩沖區之一,並將它們串聯到另一個緩沖區中。 因為要刪除定界符,所以肯定會有足夠的空間,但這是很多浪費的空間。
如問題注釋中所述,發布的代碼存在很多問題。
以下發布的代碼糾正了這些問題,干凈地編譯並執行了所需的功能。
#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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.