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

C语言堆分配字符串函数外访问损坏问题求助

问题:C语言字符串子串替换函数的堆内存损坏问题

我参考教程写了个C语言的字符串子串替换函数,原函数在替换串长度大于原子串时会出现缓冲区溢出。因为程序里只传入动态分配的字符串,我试了两种扩容方式:一是用realloc直接调整内存,二是通过malloc分配新内存、拷贝内容后释放原内存并更新指针。但多次调用函数替换同一字符串的不同子串时,出现函数内部输出正常,但外部访问字符串显示乱码(堆内存损坏)的问题。


代码实现

static bool StrReplaceSubstringFirstOccurance(char* source, char* substring, char* replace) {
    char* substring_occurance = strstr(source, substring);
    if (substring_occurance == NULL) {
        printf("No substring: %s found.\n", substring);
        return false;
    }

    if (strlen(replace) > strlen(substring)) {
        size_t new_size = strlen(source) + (strlen(replace)-strlen(substring))+1;
        // Approach 1
        // char* temp = malloc(new_size);
        // memcpy(temp, source, strlen(source)+1);
        // free(source);
        // source = temp;

        // Approach 2
        source = realloc(source, new_size);
    }

    substring_occurance = strstr(source, substring);
    memmove(substring_occurance + strlen(replace),
            substring_occurance + strlen(substring),
            strlen(substring_occurance) - strlen(substring)+1);
        
    memcpy(substring_occurance, replace, strlen(replace));
    printf("\nInside: %s\n", source);
    return true;
}

int main(void) {
    char* first_page = GetFileContents("first_page.html");

    StrReplaceSubstringFirstOccurance(first_page, "[[say]]", "CUSTOM!");
    StrReplaceSubstringFirstOccurance(first_page, "[[say]]", "CUSTOM!");
    printf("\nFirst Print: %s\n", first_page);
    StrReplaceSubstringFirstOccurance(first_page, "[[to]]", "NOT CUSTOM!");
    printf("\nSecond Print: %s\n", first_page);
    StrReplaceSubstringFirstOccurance(first_page, "[[to]]", "NOT CUSTOM!");
    printf("\nThird Print: %s\n", first_page);

    printf("Reached the end!\n");
    return 0;
}

程序输出

Inside: <!DOCTYPE html>
<html lang="en-US">
  <title>CUSTOM! [[to]]</title>
  <body>
    [[say]]
      <h1>This is a header!</h1>
      [[to]]
  </body>
</html>

Inside: <!DOCTYPE html>
<html lang="en-US">
  <title>CUSTOM! [[to]]</title>
  <body>
    CUSTOM!
      <h1>This is a header!</h1>
      [[to]]
  </body>
</html>

First Print: <!DOCTYPE html>
<html lang="en-US">
  <title>CUSTOM! [[to]]</title>
  <body>
    CUSTOM!
      <h1>This is a header!</h1>
      [[to]]
  </body>
</html>

Inside: <!DOCTYPE html>
<html lang="en-US">
  <title>CUSTOM! NOT CUSTOM!</title>
  <body>
    CUSTOM!
      <h1>This is a header!</h1>
      [[to]]
  </body>
</html>

Second Print: α#F^Ñ☻
No substring: [[to]] found.

Third Print: α#F^Ñ☻
Reached the end!

first_page.html内容

<!DOCTYPE html>
<html lang="en-US">
  <title>[[say]] [[to]]</title>
  <body>
    [[say]]
      <h1>This is a header!</h1>
      [[to]]
  </body>
</html>

问题分析与解决

核心问题:指针传递方式错误

函数StrReplaceSubstringFirstOccurance的第一个参数是char* source,这是值传递。当你在函数内部用realloc或malloc更新source指针时,修改的只是函数内部的局部变量,外部的first_page指针完全不会同步更新。

一旦realloc返回新的内存地址,函数内部的source指向新内存,但外部的first_page还指向原来的旧内存(已被realloc释放或失效),后续访问first_page就会访问失效的堆内存,直接导致乱码和堆损坏。

解决方法:使用指针的指针(char**)传递参数

修改函数参数为char** source,这样就能在函数内部修改外部指针的指向:

修改后的函数代码:

static bool StrReplaceSubstringFirstOccurance(char** source, char* substring, char* replace) {
    char* src = *source;
    char* substring_occurance = strstr(src, substring);
    if (substring_occurance == NULL) {
        printf("No substring: %s found.\n", substring);
        return false;
    }

    size_t sub_len = strlen(substring);
    size_t repl_len = strlen(replace);
    if (repl_len > sub_len) {
        size_t new_size = strlen(src) + (repl_len - sub_len) + 1;
        // 检查realloc返回值,避免分配失败
        char* temp = realloc(src, new_size);
        if (temp == NULL) {
            perror("realloc failed");
            return false;
        }
        // 更新外部指针指向新内存
        *source = temp;
        src = temp;
        // 重新查找子串,原指针已失效
        substring_occurance = strstr(src, substring);
    }

    // 计算需要移动的字节数(包含终止符)
    size_t move_len = strlen(substring_occurance) - sub_len + 1;
    memmove(substring_occurance + repl_len, substring_occurance + sub_len, move_len);
    memcpy(substring_occurance, replace, repl_len);
    printf("\nInside: %s\n", src);
    return true;
}

同时修改main函数中的调用方式:

StrReplaceSubstringFirstOccurance(&first_page, "[[say]]", "CUSTOM!");
StrReplaceSubstringFirstOccurance(&first_page, "[[say]]", "CUSTOM!");
StrReplaceSubstringFirstOccurance(&first_page, "[[to]]", "NOT CUSTOM!");
// 后续调用同理

额外注意事项

  • 必须检查realloc返回值:如果内存分配失败,realloc会返回NULL,此时原内存不会被释放,需要妥善处理错误。
  • 扩容后重新查找子串:realloc可能会将内存迁移到新地址,原substring_occurance指针会失效。
  • 内存泄漏处理:确保GetFileContents返回动态分配的内存,在main末尾调用free(first_page)释放内存。

内容的提问来源于stack exchange,提问作者Ali Awan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 14:35:20