为什么char name 可以容纳多个字符?

当我遇到这种情况时,我正在对一个主题进行一些研究。 假设以下C代码:

#include  int main() { char name[1]; scanf("%s",name); printf("Hi %s",name); return 0; } 

我已经使用-fno-stack-protector进行了编译,并使用大于1的输入进行了测试,就像John一样,令我惊讶的是,它有效!
当输入长于1时,它不应该抛出分段错误吗?
最终它打破了Alexander作为输入(9),但它适用于任何小于9的东西。
为什么输入的时间长于名称数组长度?
PS:我使用Ubuntu(64位),gcc版本4.8.4(Ubuntu 4.8.4-2ubuntu1~14.04)和CLion作为IDE。

这是未定义的行为。 您的程序有一个缓冲区溢出,因为它只分配一个字符,这足以存储空的以空字符结尾的字符串。

但是,缓冲区附近的内存尚未分配给您的程序。 scanf将您的输入放入该内存,因为它不知道您的字符串缓冲区有多长。 当预先确定的字节序列被放入你的字符串中时,这是一个很大的危险和无数黑客攻击的来源,希望覆盖一些重要元素,并最终获得控制权。

这就是为什么%s没有指定大小%s情况下使用%s是危险的。 您需要始终为%s添加适当的大小限制,否则您的程序将面临缓冲区溢出的危险。

 char name[120]; scanf("%119s",name); 

此程序是安全的,因为即使恶意用户输入超过120个字符, scanf也会忽略超过第119个字符的所有内容,如%119s格式所指定。

存储输入的变量的大小和类型与scanf无关。

scanf只传递一个地址(指针),用于存放从用户获得的输入。

聪明的编译器现在警告你,如果传递给scanf的格式字符串与参数的类型不匹配,但原则上你甚至可以将name声明为整数:

 int name; 

它会很好地保存输入字符串,最多三个字符(第四个是字符串结束,即零),假设int的大小是32位,即4个字节

它工作的事实是纯粹的坏运气,因为输入数据,当由scanf存储时,运行超过为它分配的缓冲区的末尾( name )。

注意:为字符串分配一个字符永远不会起作用,即使只对一个字符的输入字符串也是如此。 您始终需要考虑用于终止它们的EOS。 所以name应该声明为char name[2]; 至少。