我不明白为什么str1
在这里有所变化。请帮忙。
#include<stdio.h>
#include<string.h>
int main (){
char str1[]="stackoverflowwwwwww";//str1
char str2[] = "stackoverflow";
char str3[40];
char str4[40];
char str5[] = "asdfgh";
strcpy(str2, str1);
strcpy(str3, "successful");
strcpy(str4, str5);
printf("str1: %s\nstr2: %s\nstr3:%s\nstr4:%s\n", str1, str2, str3, str4);
return 0;
}
输出为:
str1: www
str2: stackoverflowwwwwww
str3: successful
str4: asdfgh
str1
为什么要在这里更改?
答案 0 :(得分:2)
您的程序包含缓冲区溢出。 str2
是一个缓冲区,其大小为14个字节(“ stackoverflow”的长度+终止NULL字符)。当执行strcpy(str2, str1)
时,由于str1
的长度超过14个字节,因此该缓冲区溢出。 strcpy
无法知道缓冲区的大小,因此(根据其定义)它会盲目地从一个缓冲区复制到另一个缓冲区。
现在,为什么这会改变str1
?好吧,因为当strcpy
复制的字符数超过目标缓冲区的大小时,这些字符数必须放在某个地方。
由于str2
和str1
都是在堆栈上分配的,因此它们彼此紧邻放置。因此,当strcpy
复制到str2
并溢出其大小时,它将继续移动到内存中它旁边的任何内容-在您的情况下为str1
。
因此,正在复制最后的字符strcpy
-将str1
中的最后几个字符复制回str1
的开头。
答案 1 :(得分:2)
首先,目标str2
比字符串长度str1
短,因此这是未定义的行为。
但是要了解为什么会发生这种情况,请考虑以下因素。
当我打印出字符串的内存地址时,在对系统中的代码进行任何修改之前,都是这样的。
printf("str1: %p (%d) \nstr2: %p (%d)\n", str1, strlen (str1), str2, strlen (str2));
str1: 0x7ffd394e85d0 (19)
str2: 0x7ffd394e85c2 (13)
str1: wwwww
str2: stackoverflowwwwwww
str3:successful
str4:asdfgh
记下str1
和str2
的地址。 str2
首先开始(低位地址),而0x7ffd394e85d0 - 0x7ffd394e85c2 = e
(十进制的13,即字符串的确切长度)。
因此初始布局为
Initial layout
0x7ffd394e85c2 0x7ffd394e85d0
str2 str1
| |
| |
V V
s t a c k o v e r f l o w \0 s t a c k o v e r f l o w w w w w w w \0
将字符串从str1
复制到str2
时,strcpy
将按以下方式对齐并复制字符串。这里str2
缓冲区的末尾被违反了。
When being copied
0x7ffd394e85c2 0x7ffd394e85d0
str2 str1
| |
| |
V V
s t a c k o v e r f l o w \0 s t a c k o v e r f l o w w w w w w w \0
s t a c k o v e r f l o w w w w w w w \0
复制后的状态如下
After copy
0x7ffd394e85c2 0x7ffd394e85d0
str2 str1
| |
| |
V V
s t a c k o v e r f l o w w w w w w w \0 v e r f l o w w w w w w w \0
现在str1
指向缓冲区的开头,以'w'开头,它有五个连续的'w',直到达到'\ 0'。因此,如您在输出中看到的,str1
所指向的C字符串现在是“ wwwww”。
注意,这是针对我的系统的,我得到了五个连续的“ w”。在其他系统中,编译器可能会生成在str2
的末尾与str1
的末尾之间有一些空白字节的代码,因此它们可以具有不同数量的'w'。另外,请注意,由于这是未定义的行为,并且未定义两个字符串的存储布局,因此输出可以是任何内容。
答案 2 :(得分:0)
该程序的结果未知,可能各种各样,原因是: 使用str3和str4时不进行初始化,最好像这样进行初始化:
char str3[40] = {0};
char str4[40] = {0};
因此,遵守40号尺寸的边框将在程序员的控制下。
很明显,如果执行'strcpy(str2,str1);',str2的空间会引起问题。