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

练习5-3:编写strcat指针版本,求解同字符串参数时程序失效原因

Why Passing the Same String to Custom strcat Breaks Things

嘿,这个问题我之前踩过坑!咱们来掰扯清楚为啥你把同一个字符串传给自己写的strcat会出问题。

首先先把你的代码贴出来方便分析:

#include <string.h> // 你代码里没写,但strlen需要这个头文件

void strcat(char *s, char *t) { 
    int len = strlen(s); 
    while (*t != '\0') 
        *(s + len++) = *t++; 
    *(s + len) = '\0'; 
}

int main (void) { 
    char s[] = "123"; 
    strcat(s, s); 
    return 0; 
}

问题出在哪?

咱们一步步走一遍执行流程:

  1. 一开始s是{'1','2','3','\0'},strlen(s)返回3,len被设为3。
  2. 进入循环:*t就是s[0]也就是'1',把它赋值给s[3]——这时候原来的结束符'\0'被覆盖成'1'了!
  3. t++指向s[1],len变成4,接着把s[1]的'2'赋值给s[4]。
  4. 接下来循环会一直继续:因为t指向的是s本身,而我们一直在往s后面加字符,原来的结束符早就没了,*t != '\0'这个条件永远成立!

循环会无限运行,不断往内存里写数据,直到超出数组s的边界,触发内存越界,程序直接崩溃。

额外说一句:标准库的strcat也救不了你

其实标准库的strcat明确规定不支持重叠的输入参数,当s和t指向的内存区域有重叠时,行为是未定义的——也就是说你可能得到奇怪的结果,或者直接崩溃,完全看运气。你的实现只是把这种未定义行为变成了更直观的无限循环而已。

怎么改?

如果确实需要实现字符串自我拼接(比如把"123"变成"123123"),得换一种思路:先把原字符串的内容保存下来,或者用反向复制的方式,避免覆盖还没读取的内容。比如这样写:

#include <string.h>

// 方式1:用临时内存保存原内容
void strcat_self_safe(char *s) {
    // 先获取原字符串的长度
    size_t orig_len = strlen(s);
    // 这里要保证temp足够大,或者用动态内存malloc
    char temp[100]; 
    strcpy(temp, s);
    // 再把temp拼到s后面
    size_t i = 0;
    while (temp[i] != '\0') {
        s[orig_len + i] = temp[i];
        i++;
    }
    s[orig_len + i] = '\0';
}

// 方式2:反向复制,不用额外内存
void strcat_self_reverse(char *s) {
    size_t s_len = strlen(s);
    size_t t_len = s_len; // 因为t就是s本身
    char *s_dest = s + s_len + t_len;
    *s_dest = '\0'; // 先放结束符
    // 从后往前复制原字符串内容
    while (t_len > 0) {
        *--s_dest = s[--t_len];
    }
}

总结一下

  • 你的strcat实现中,当s和t指向同一个字符串时,会覆盖掉原字符串的结束符,导致循环无法终止,最终内存越界崩溃。
  • 永远不要把重叠的字符串传给strcat(不管是自定义的还是标准库的),这属于未定义行为。
  • 如果需要自我拼接,得用安全的方式先保存原内容,或者反向复制避免覆盖。

内容的提问来源于stack exchange,提问作者Andy Xu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 13:58:16