2012-04-14 139 views
-1
#include 
    int main(void) 
    { 
     char str[100]="88888888888888"; 
     char t[20]=""; 
     gets(t); 
     puts(str); 
     puts(t); 
     return 0; 
    }

enter image description here阵列堆栈溢出

第一行

555555555555555555555555555555555 

是插嘴说。

为什么str55555555555?为什么str不是8888888888888888855555555555588888

+2

不要使用'gets'。 http://www.gidnetwork.com/b-56.html – DCoder 2012-04-14 15:46:19

+0

请在发布前搜索。例如,http://stackoverflow.com/questions/2843073/warninggets-function-is-dangerous – 2012-04-14 16:13:30

+0

出于充分的理由,'gets'从POSIX和C11中移除。 – 2012-04-14 16:14:59

回答

6

您覆盖了t缓冲区,并到达str缓冲区,其中输入的其余部分和空终止符均已设置。并且puts仅打印到空终止符。

差不多的样子说:

[ t (20)    ][str(100)         ] 
55555555555555555555 5555555555555\0 

注意,虽然t被声明为char[20],当你打印你得到完整的输入(超过20),因为在空终止puts停止(再)。

顺便说一句,这是一个缓冲区溢出,而不是一个stackoverflow,但堆栈溢出可能在这个codeas上。

1

正如Binyamin所说,它是由于输入字符串太长而引发的溢出引起的。然而,这是一个随机的事情 - 有时两个内存分配会紧挨着发生,字符串将扩展到相邻变量,有时可能不会发生。

我建议你为这种溢出放置警戒条件。

如果您在getsdocumentation看到:

注意,获得不表现完全一样与fgets:标准输入确实为 的说法:首先,结束换行符不附带 获得,而用于fgets它是。其次,get不允许指定 限制要读取的字符数量,因此您必须小心 以及str指向的数组大小,以避免缓冲区溢出。

在你的情况下,如果你不知道尺寸apriory可能是更好的主意使用fgets,因为它更安全(虽然有点慢)。

+0

这两个变量将在堆栈中,而不是堆 - 它们彼此的接近将在编译时确定(在调试模式下编译可能会在它们之间插入填充,编译优化可能会重新排列它们...),所以这不是我会叫* random *的东西。 – DCoder 2012-04-14 15:53:16

+0

@DCoder我不太明白你。一旦你提到它们在堆栈中的位置取决于编译参数。我也知道,如果引入新变量,他们可能会将变量分开。在上下文中的随机应该被解读为:“取决于许多情况,难以确定性地预测”。 – 2012-04-14 15:56:17

+0

我同意DCoder的观点 – ytyisme 2012-04-14 15:58:59

1

当您输入超过20个的字符串时,它会超出分配给t的缓冲区,并延伸到分配给str的缓冲区。

然后它显示str的内容,这是您输入的字符串,从第21个字符开始。

最后,它显示的t内容,但因为该字符串不以空字符结束,则继续显示存储器(这是assiged到str缓冲器),直到它遇到所有5年代后空字符。

0

为了避免这些分配重叠的问题,你可以试试这个替代方案,从而使配置在运行时发生,如果我没有错:

#include <iostream> 

    int main(void) 
    { 
     char *str; 
     char *t; 
     str = new char(100); 
     str = (char*)"88888888888888"; 
     t = new char(20); 
     std::cin >> t; 
     puts(str); 
     puts(t); 
     return 0; 
    }