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

C语言函数返回指针导致数组中先前存储的元素值不断变化问题

问题原因及修复方案

核心问题

你遇到的修改覆盖问题本质是返回了栈上局部变量的指针,属于C语言常见的未定义行为:

  • get_song_name内部定义的char str[9999]是函数栈上的局部数组,函数执行结束后,这块栈空间会被操作系统回收,允许后续函数调用复用这块内存
  • 你每次调用get_song_name返回的都是同一块栈内存的地址,所有name[i]指针最终都指向同一个地址,自然每次调用都会覆盖之前的内容,表现为之前下标的值被修改

其他隐含问题

  • feof用法错误:feof是在文件读操作失败后才会置位,直接放在循环开头会导致最后一次读操作重复执行,你的代码里虽然因为第一次循环就return不会触发这个问题,但属于不良写法
  • 文件资源泄漏:fopen打开文件后没有调用fclose关闭,会持续占用文件句柄
  • 路径转义错误:Windows路径中的反斜杠需要转义,应该写为"c:\\Users\\Marian\\Desktop\\beatles",否则会被识别为转义字符
  • 没有判断fopen的返回值,如果文件打开失败会导致后续读操作崩溃

修复方案

方案1:动态分配内存返回堆指针

把存储字符串的缓冲区改为malloc在堆上分配,堆内存不会随函数退出自动回收,需要手动在使用完后释放避免内存泄漏:

char* get_song_name(const char* song)
{
    // 如果strip函数会修改入参,需要先把song拷贝到本地缓冲区再处理
    FILE* fp = fopen(song, "r");
    if (!fp) return NULL;
    // 动态分配缓冲区
    char* str = malloc(9999);
    if (!str) {
        fclose(fp);
        return NULL;
    }
    // 直接用fgets返回值判断是否读取成功,不需要feof
    if (fgets(str, 9999, fp)) {
        strip(str);
    } else {
        str[0] = '\0';
    }
    fclose(fp);
    return str;
}

使用完name数组后,需要遍历释放每个元素:

for (int i = 0; i < lines; i++) {
    free(name[i]);
}

方案2:传入外部缓冲区存储结果

如果name是二维字符数组,可以直接把每个元素的缓冲区传入函数,不需要动态分配:

// 函数改为接收外部缓冲区参数
void get_song_name(const char* song, char* buf, int buf_len)
{
    FILE* fp = fopen(song, "r");
    if (!fp) {
        buf[0] = '\0';
        return;
    }
    if (fgets(buf, buf_len, fp)) {
        strip(buf);
    } else {
        buf[0] = '\0';
    }
    fclose(fp);
}

调用方式修改为:

for(i=0;i<lines;i++)
{
    char *st = fgets(buff, 250, fp);
    st = create_path("c:\\Users\\Marian\\Desktop\\beatles", st);
    get_song_name(st, name[i], 9999); // 直接传入二维数组的行地址
}

内容的提问来源于stack exchange,提问作者noor napso

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 12:54:05