为何无法直接给内存地址加int寻址数组?test1崩溃原因解析
字符串覆盖操作中的指针类型错误
可正常运行的实现(test2.c)
#include <stdio.h> #include <string.h> int main() { char s[] = "Hello, World!"; char a[] = "aaa"; printf("%d\n", &s); printf("%d\n", &s[2]); memcpy(&s[2], a, sizeof(a)-1); printf("%s\n", s); return 0; }
运行结果:
$ gcc -o test test2.c && ./test 520783106 520783108 Heaaa, World!
存在错误的实现(test1.c)
#include <stdio.h> #include <string.h> int main() { char s[] = "Hello, World!"; char a[] = "aaa"; printf("%d\n", &s); printf("%d\n", sizeof(char)*2); printf("%d\n", &s + (sizeof(char)*2)); memcpy(&s + (sizeof(char)*2), a, sizeof(a)-1); printf("%s\n", s); return 0; }
编译及运行结果:
$ gcc -o test test1.c && ./test test1.c: In function ‘main’: test1.c:12:4: warning: ‘memcpy’ writing 3 bytes into a region of size 0 overflows the destination [-Wstringop-overflow=] 12 | memcpy(&s + (sizeof(char)*2), a, sizeof(a)-1); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ test1.c:5:9: note: at offset 28 into destination object ‘s’ of size 14 5 | char s[] = "Hello, World!"; | ^ 1547566642 2 1547566670 Hello, World! Segmentation fault
1. 为什么test1无法正常运行?
test1的核心错误是指针算术的类型不匹配,导致memcpy的目标地址指向了数组s的内存范围之外:
&s的类型是指向长度为14的char数组的指针,C语言中指针算术是以指针指向的类型大小为单位计算的。- 执行
&s + 2时,实际偏移字节数是2 * sizeof(s),也就是2*14=28字节。而数组s本身仅14字节,偏移后的地址已超出s的合法内存区域,属于非法访问。 memcpy向非法地址写入数据时,触发内存越界,最终导致段错误。
2. 为什么1547566642加2得到1547566670而非1547566644?
这完全是指针类型导致的计算规则差异:
&s是指向14字节char数组的指针,指针加法的单位是指针指向类型的整体大小,而非单个字节。- 实际地址计算为:
原地址 + 2 * sizeof(s)=1547566642 + 2*14 = 1547566670,并非简单的字节数加2。
3. &s的类型是什么?
char s[] = "Hello, World!";中,s是长度为14的char数组(包含末尾的'\0'),&s的类型是指向长度为14的char数组的指针,即char (*)[14]。
而&s[2]的类型是char*(指向单个char的指针),指针加法以1字节为单位,这也是test2能正常运行的原因:&s[2]正好是s起始地址偏移2字节的位置,符合预期的覆盖需求。
内容的提问来源于stack exchange,提问作者Paul Chabanon
相关产品推荐
相关产品推荐

