C语言文件IO异常:重复读取时内容叠加问题
问题
用户实现了重复读取指定文件的功能:输入1时触发读取操作,但出现异常——首次读取输出正常,再次读取时内容会和之前的结果叠加输出。
代码
#include <stdio.h> #include <string.h> char* read_file(char* file_name){ FILE *fp = fopen(file_name, "r"); if (fp == NULL) { printf("Error: could not open file %s", file_name); return ""; } // reading line by line, max 256 bytes const unsigned MAX_LENGTH = 30000; char buffer[30000]; char data[MAX_LENGTH]; memset(buffer, '\0', MAX_LENGTH); while (fgets(buffer, MAX_LENGTH, fp)){ strcat(data, buffer); // strcat(data, "\n"); } // close the file fclose(fp); char* return_data = &data[0]; return return_data; } void send_data(char* file_name){ printf("\n\n %s\n", read_file(file_name)); } int main() { int cont = 1; while(cont){ send_data("try/try.txt"); scanf("%d", &cont); } }
输出日志
tusharsing@techie-Latitude-3520:~/Desktop/Project/project/temp$ ./filetry HTTP/1.1 200 OK Content-Type: text/plain Content-Length: 12 <!DOCTYPE html> <html> <head> <title>Page Title</title> </head> <body> <h1>My First Heading</h1> <p>My first paragraph.</p> </body> </html> 1 HTTP/1.1 200 OK Content-Type: text/plain Content-Length: 12 <!DOCTYPE html> <html> <head> <title>Page Title</title> </head> <body> <h1>My First Heading</h1> <p>My first paragraph.</p> </body> </html> HTTP/1.1 200 OK Content-Type: text/plain Content-Length: 12 <!DOCTYPE html> <html> <head> <title>Page Title</title> </head> <body> <h1>My First Heading</h1> <p>My first paragraph.</p> </body> </html> ^C
解决方案
问题根源
- 局部数组未初始化:
read_file中的data是局部栈数组,未初始化时内存值随机。第一次调用时可能碰巧开头是\0,strcat能正常追加;但后续调用时,栈内存残留了上次的内容,strcat会从上次的字符串结尾继续追加,导致内容叠加。 - 返回局部变量指针的未定义行为:函数执行完毕后,局部变量的栈内存会被释放,返回的
data指针指向的内存已不属于当前函数,后续访问该指针会引发不可预测的程序行为。
修正方案1:调用者提供缓冲区(推荐,无内存泄漏风险)
修改read_file函数,由调用者传入缓冲区,避免返回局部变量指针,同时确保每次读取前缓冲区被清空:
#include <stdio.h> #include <string.h> // 读取文件内容到调用者提供的缓冲区,返回读取的字节数,失败返回-1 int read_file(char* file_name, char* buffer, size_t buffer_size) { FILE *fp = fopen(file_name, "r"); if (fp == NULL) { printf("Error: could not open file %s\n", file_name); return -1; } // 清空缓冲区,确保从空字符串开始追加 memset(buffer, '\0', buffer_size); char line[30000]; while (fgets(line, sizeof(line), fp)) { // 检查缓冲区是否足够容纳新内容,避免溢出 if (strlen(buffer) + strlen(line) >= buffer_size) { printf("Error: buffer too small to hold file content\n"); fclose(fp); return -1; } strcat(buffer, line); } fclose(fp); return strlen(buffer); } void send_data(char* file_name) { const unsigned MAX_LENGTH = 30000; char data[MAX_LENGTH] = {0}; // 初始化缓冲区为空 if (read_file(file_name, data, MAX_LENGTH) != -1) { printf("\n\n %s\n", data); } } int main() { int cont = 1; while (cont) { send_data("try/try.txt"); scanf("%d", &cont); } return 0; }
修正方案2:动态分配内存
如果需要函数直接返回字符串,可以使用malloc动态分配内存,注意使用后必须释放内存避免泄漏:
#include <stdio.h> #include <string.h> #include <stdlib.h> char* read_file(char* file_name) { FILE *fp = fopen(file_name, "r"); if (fp == NULL) { printf("Error: could not open file %s\n", file_name); return NULL; } const unsigned MAX_LENGTH = 30000; char* data = malloc(MAX_LENGTH); if (data == NULL) { printf("Error: failed to allocate memory\n"); fclose(fp); return NULL; } memset(data, '\0', MAX_LENGTH); // 初始化空字符串 char buffer[30000]; while (fgets(buffer, sizeof(buffer), fp)) { if (strlen(data) + strlen(buffer) >= MAX_LENGTH) { printf("Error: file content exceeds maximum length\n"); free(data); fclose(fp); return NULL; } strcat(data, buffer); } fclose(fp); return data; } void send_data(char* file_name) { char* content = read_file(file_name); if (content != NULL) { printf("\n\n %s\n", content); free(content); // 必须释放动态分配的内存 } } int main() { int cont = 1; while (cont) { send_data("try/try.txt"); scanf("%d", &cont); } return 0; }
关键修改点说明
- 初始化缓冲区:确保每次读取前目标字符串以
\0结尾,strcat能从开头正确追加内容。 - 避免返回局部变量指针:改用调用者缓冲区或动态内存,消除未定义行为。
- 增加缓冲区溢出检查:防止内存越界导致的程序异常。
内容的提问来源于stack exchange,提问作者Dying Falcon
相关产品推荐
相关产品推荐

