C语言不同长度子串替换问题:替换后残留原字符如何修复?
C语言字符串替换代码bug排查及修复
初始输入字符串为
aaabbbcccqwerdd,执行替换命令sbqwerbkkk(s为替换操作标识,b为分隔符,含义为将子串qwer替换为kkk),预期输出aaabbbccckkkdd,实际输出为aaabbbccckkkrdd。
问题根因
- 核心问题是替换逻辑仅拷贝了新子串的内容,没有处理原被替换子串剩余的字符:本次案例中原被替换子串
qwer长度为4,新子串kkk长度为3,strncpy仅覆盖了目标位置的前3个字符,原位置第4位的r没有被移除,直接残留到结果中,就是多余r的来源。 - 额外存在其他隐患:如果新子串长度大于原被替换子串长度,现有代码会直接覆盖原串后方的无关内容,甚至可能超出
MAXLEN触发数组越界;strncpy拷贝后未手动补终止符,极端场景下会导致字符串无结束标识。
修复方案
替换逻辑调整为三步:
- 计算原被替换子串长度、新子串长度,以及被替换子串之后的剩余内容长度(包含终止符)
- 用支持内存重叠的
memmove先把剩余内容移动到正确的位置:新子串更短就往前移,更长就往后移(需要做长度校验避免越界) - 再将新子串拷贝到目标位置
修复后完整代码如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXLEN 1023 int main() { char str[MAXLEN + 1]; // 多留1位存终止符 scanf("%s", str); char command[MAXLEN + 1]; while (scanf("%s", command) != EOF) { if (command[0] == 'p') { printf("%s\n", str); } else if (command[0] == 's') { char delimiter[] = {"0"}; strncpy(delimiter, command+1, 1); char *a = strtok(command, delimiter); a = strtok(NULL, delimiter); char *b = strtok(NULL, delimiter); // 容错判断,避免非法命令崩溃 if (a == NULL || b == NULL) { continue; } int alength = strlen(a); int blength = strlen(b); char *bereplaced = strstr(str, a); if (bereplaced == NULL) { continue; } // 校验整体长度不超过MAXLEN if (strlen(str) - alength + blength > MAXLEN) { continue; } // 移动剩余内容(包含终止符) int rest_len = strlen(bereplaced + alength) + 1; memmove(bereplaced + blength, bereplaced + alength, rest_len); // 拷贝新子串 memcpy(bereplaced, b, blength); } } return 0; }
内容的提问来源于stack exchange,提问作者Leung
相关产品推荐
相关产品推荐

