这是我写的代码,
char *foo();
void main()
{
char *str=foo();
strcpy(str,"Holy sweet moses! I blew my stack!!");
printf("%s",str);
}
char * foo()
{
char str[256];
return str;
}
当我在函数foo()中使用char数组时,main()函数中的strcpy不会将字符串复制到str中。但是,当我在函数foo()中使用int数组时,main()strcpy成功复制。
即
int str[256]; //in function foo
输出
Holy sweet moses! I blew my stack!!
如果
char str[256]; //in foo()
输出:没有!
答案 0 :(得分:5)
你在做什么显然是UNDEF,但是..让我们试着理解为什么它适用于整数而不是字符..
TL; DR:printf使用堆栈,覆盖str指向的一些空间,但由于int数组在内存中比char数组大,所以它在堆栈中“遥遥领先”并且没有被覆盖。
int是4个字节,因此256个int将是1024个字节。
如果数组在堆栈中,这将指向RBP - 1024,例如。
使用chars,char为1字节,256个字符为256字节。
如果数组在堆栈中,这将指向RBP - 256,例如。
这是什么意思?当foo返回时,str指针将指向当前堆栈指针“前面”的1024或256字节。
所以..当你调用strcpy(str,“yourstring”)时;内存可能会被strcpy和printf使用的堆栈覆盖。这里的事情是它被覆盖但不是所有的堆栈,只是一点点,但足以覆盖256个字节,因此,该函数可以覆盖复制的字符串,这不会发生在你的int数组,因为字符串将在堆栈指针之前复制1024位,strcpy和printf不要使用这么多堆栈。
让我告诉你堆栈最终会如何结束:
如果更改char数组的大小,它可能会起作用。
所有这些都是未定义的行为,完全取决于您的架构,计算机和编译器。我目前正在使用Linux x86_64。
答案 1 :(得分:2)
您知道Scope and Lifetime Of Variables Concept吗?如果您是,那么您确实知道您要做的事情会调用"Undefined Behavior"。你很幸运,你的代码甚至可以打印出一些或者根本不打印,而不是引用未分配的内存并因堆损坏而崩溃。
来自SO Soln ::
操作系统或语言控制堆栈/堆的程度 运行
操作系统在创建线程时为每个系统级线程分配堆栈。通常,语言运行库会调用OS来为应用程序分配堆。
他们的范围是什么?
堆栈附加到一个线程,因此当线程退出堆栈时会被回收。堆通常在应用程序启动时由运行时分配,并在应用程序(技术过程)时回收退出。
是什么决定了每个人的身材?
创建线程时设置堆栈的大小。堆的大小在应用程序启动时设置,但可以在需要空间时增长(分配器从操作系统请求更多内存)。
答案 2 :(得分:0)
当函数foo()
返回时,它返回堆栈中字符串的地址。当函数退出时,你的指针是无用的,因为当foo()停止时你的字符串被从堆栈中删除。所以你有一个指向记忆中某个地方的指针,但不知道那里有什么
阅读编译器警告,我敢打赌至少有一个告诉你你的函数返回指向局部变量的指针。(我的确做了几次)。
答案 3 :(得分:0)
从关于吹嘘堆栈的字符串中我得出结论,你知道你所做的是错的。因此我的答案是:未定义的未定义行为。写入内存不是你的内容写入任何事情都可能发生,包括你可能期望的事情和你可能没想到的事情。其他未定义的行为可能有点探索,写入不属于你的内存不是。这总是错的,它总会做一些你不期望的事情,并且没有任何情况下正确的解决方案是除了不再做它之外的任何事情。
当你将数组从char更改为int时,你会改变数组的大小,因为很可能堆栈在你的体系结构上变大,它会改变你不应该首先覆盖的内存的地址。