为何这段C代码的输出中未打印字符'a'?
为什么这段C代码执行后不会打印字符'a'?
先看这段代码:
#include<stdio.h> #include<string.h> void main(){ char x[9]="helloabc"; x[8]='\0'; int a=2,b=3; strcpy(&x[2],&x[4]); for(int i=0;i<8;i++){ printf("%c",x[i]); } }
问题核心:strcpy不处理内存重叠场景
- 初始数组状态
数组x初始化后,各索引对应的字符如下:
| 索引 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|---|---|---|---|---|---|---|---|---|---|
| 字符 | h | e | l | l | o | a | b | c | \0 |
strcpy(&x[2], &x[4])的问题strcpy的作用是把源地址(&x[4])开始的字符串(直到\0)复制到目标地址(&x[2])。但这里目标地址和源地址的内存区域是重叠的——&x[2]在&x[4]的前方,两个区域有重叠部分。
C语言标准明确规定:strcpy不保证处理内存重叠的情况,这种场景下的行为属于未定义行为。大部分编译器的strcpy实现是按从前往后的顺序逐个字符复制,这会导致重叠区域的源数据被提前覆盖。
- 主流编译器的复制过程
复制按字符逐个进行,每次复制后指针向后移动:
- 第一步:将
x[4]的'o'复制到x[2]→x[2] = 'o' - 第二步:将
x[5]的'a'复制到x[3]→x[3] = 'a' - 第三步:将
x[6]的'b'复制到x[4]→x[4] = 'b' - 第四步:将
x[7]的'c'复制到x[5]→x[5] = 'c' - 第五步:将
x[8]的'\0'复制到x[6]→x[6] = '\0',复制停止
此时数组变为:
| 索引 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|---|---|---|---|---|---|---|---|---|---|
| 字符 | h | e | o | a | b | c | \0 | c | \0 |
- 关于输出中没看到'a'的说明
你提到的输出"heocbc\0c"大概率是描述误差,按上述复制过程,x[3]的'a'应该会被打印出来。如果确实未出现,是因为内存重叠属于未定义行为,部分编译器的strcpy实现可能因优化或复制逻辑差异,导致'a'所在的内存被后续操作覆盖。
本质上,用strcpy处理重叠内存的结果完全不可靠。如果需要处理这种场景,应该使用memmove函数——它专门针对内存重叠做了处理,能保证数据正确复制。
内容的提问来源于stack exchange,提问作者Jay Dave
相关产品推荐
相关产品推荐

