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

C语言中使用printf时fgets获取的字符串数据丢失问题求助

C语言中使用printf时fgets获取的字符串数据丢失问题求助

兄弟,我一眼就揪出你代码里的关键问题了!你遇到的字符串打印异常、数据丢失的诡异情况,根源全在get_string()这个函数里!

问题核心:返回局部变量的指针导致野指针

你看这个函数:

char *get_string() {
    char str[100];
    puts("Please enter a string");
    return fgets(str, sizeof(str), stdin);
}

这里的str是局部数组,它存在函数的栈帧里。当get_string()执行完毕返回时,这个栈帧会被销毁,str占用的内存会被操作系统回收或者后续函数调用覆盖。你返回的指针就变成了「野指针」——指向的内存已经不属于你的程序了!

后续你用carray = get_string();拿到这个野指针后,第一次printf可能刚好内存还没被修改,能勉强打出内容;但后面执行了其他函数(比如打印菜单、读取用户选择的fgets),这块内存被覆盖了,第二次printf自然就看不到正确的字符串了,甚至可能出现更奇怪的崩溃行为,这都是C语言里的未定义行为。

给你两种靠谱的解决方案

方案1:让调用方提供缓冲区(推荐,避免内存泄漏)

把get_string()改成接收外部传入的缓冲区和大小,这样内存的生命周期由调用方控制:

// 修改get_string函数
char *get_string(char *buf, size_t buf_size) {
    puts("Please enter a string");
    return fgets(buf, buf_size, stdin);
}

然后在main里调整你的代码:

// 先把原来的functions数组改大,5个长度太小,用户输入容易溢出
char functions[100] = "";
char *carray = functions;

// 当选择操作0时,这样调用
if (opNum == 0)
    get_string(carray, sizeof(functions)); // 直接用main里的缓冲区

这样缓冲区是在main的栈上,只要main没结束,内存就一直有效,不会出现野指针问题。

方案2:用动态内存分配(记得要释放内存)

如果一定要在get_string()里分配内存,就用malloc在堆上申请,堆内存不会随函数返回释放:

char *get_string() {
    // 申请100字节的堆内存
    char *str = malloc(100 * sizeof(char));
    if (str == NULL) {
        perror("malloc failed"); // 处理内存分配失败的情况
        return NULL;
    }
    puts("Please enter a string");
    // 如果fgets读取失败,要释放内存避免泄漏
    if (fgets(str, 100, stdin) == NULL) {
        free(str);
        return NULL;
    }
    return str;
}

但要注意,用了malloc就必须在不需要这个字符串的时候调用free(carray);,比如在程序结束前:

// 在main的末尾,break之后或者return之前
if (carray != functions) { // 只有动态分配的才需要free
    free(carray);
}

不然会造成内存泄漏。

额外提醒:别忽略缓冲区大小的问题

你原来定义的char functions[5] = "";长度只有5,用户输入的字符串如果超过3个字符(加上换行符和字符串终止符\0)就会缓冲区溢出,这也是未定义行为的来源之一,一定要把缓冲区设得足够大,比如100,和fgets的读取长度匹配。

备注:内容来源于stack exchange,提问作者Din Yair Sadot

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 10:12:57