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
相关产品推荐
相关产品推荐

