You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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
解决方案

问题根源

  1. 局部数组未初始化:read_file中的data是局部栈数组,未初始化时内存值随机。第一次调用时可能碰巧开头是\0,strcat能正常追加;但后续调用时,栈内存残留了上次的内容,strcat会从上次的字符串结尾继续追加,导致内容叠加。
  2. 返回局部变量指针的未定义行为:函数执行完毕后,局部变量的栈内存会被释放,返回的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 15:40:18