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

C语言动态内存读取文件时strcat函数失效问题修复

问题根因

代码存在4个核心错误,直接导致strcat工作异常、输出乱码甚至程序崩溃:

  • 目标字符数组内存分配错误:main中定义的char firstS []="";和char secondS []="";本质是长度为1的栈数组,仅能容纳空终止符\0,strcat向其中追加内容时会直接越界写入栈内存,属于未定义行为,这是异常的核心诱因。
  • 头文件缺失:代码使用strcat等字符串处理函数,但未引入<string.h>头文件,会导致函数隐式声明,运行时行为不可预期。
  • 文件读取逻辑错误:用while(!feof(fp))作为循环判断条件会多读取一次无效内容——feof只有在读取操作触发文件结束标记后才会返回真,会导致最后一次fgets读取失败时仍然执行strcat,追加内存中的垃圾值。
  • 缓冲区逻辑混乱:函数内malloc了1000字节的临时缓冲区,但fgets每次最多仅读取99字节到缓冲区,内存分配大小和实际读取长度不匹配,且未对缓冲区做初始化,存在读取脏值的风险。
修复方案

修复思路如下:

  • 弃用固定长度的栈数组存储文件内容,改用动态分配的堆内存,根据读取到的内容长度自动扩容,从根源避免内存越界
  • 修正feof的错误用法,直接以fgets的返回值作为循环终止判断条件
  • 简化缓冲区逻辑,用固定长度的栈空间做单次读取的临时缓冲区,避免无意义的堆分配
  • 所有动态分配的内存在使用完成后及时释放,避免内存泄漏

修复后可正常运行的代码:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

// 读取文件内容返回堆上分配的字符串,调用方需手动释放内存
char* fileTest (char* filename){
    size_t cap = 1024; // 初始分配1024字节存储内容
    char* content = (char*)malloc(cap * sizeof(char));
    if (content == NULL) {
        perror("malloc failed");
        exit(-1);
    }
    content[0] = '\0'; // 初始化为合法空字符串,保证strcat正常工作

    char buf[100]; // 单次读取的临时栈缓冲区,每次最多读99字节
    FILE *fp = fopen(filename, "r");
    if (fp == NULL){
        perror("open file failed");
        free(content);
        exit(-1);
    }

    // 以fgets返回值判断是否读到文件末尾,规避feof的经典误用问题
    while(fgets(buf, sizeof(buf), fp) != NULL) {
        size_t curLen = strlen(content);
        size_t readLen = strlen(buf);
        // 剩余空间不足时自动扩容为原容量的2倍
        if (curLen + readLen + 1 > cap) {
            while (curLen + readLen + 1 > cap) {
                cap *= 2;
            }
            char* tmp = (char*)realloc(content, cap * sizeof(char));
            if (tmp == NULL) {
                perror("realloc failed");
                free(content);
                fclose(fp);
                exit(-1);
            }
            content = tmp;
        }
        strcat(content, buf);
    }

    fclose(fp);
    return content;
}

int main() {
    char* firstS = fileTest("file.txt");
    char* secondS = fileTest("file2.txt");
    printf("First file: %s \n", firstS);
    printf("Second file: %s", secondS);

    // 释放堆内存
    free(firstS);
    free(secondS);
    return 0;
}
关键注意点
  • 所有作为strcat目标的字符串,必须先初始化为以\0结尾的合法C字符串,且分配的内存大小必须大于等于「已有字符串长度 + 待追加字符串长度 + 1(存储空终止符)」,否则必然触发内存越界。
  • 不要使用while(!feof(fp))编写文件读取循环,这是C语言文件操作的经典错误写法。
  • 栈上定义的char arr[] = ""长度固定为1,仅能存储空字符串,不能用来承载任何非空文本内容。

内容的提问来源于stack exchange,提问作者Ugur A

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 11:27:18