为什么scanf在“int”的情况下给出最大值,但在超过限制时在“char”的情况下崩溃程序?
#include<stdio.h>
main(){
int a;
char ch[10];
scanf("%d",&a);
printf("%d",a);
scanf("%s",ch);
printf("%s",ch);
}
答案 0 :(得分:6)
在这种情况下,它崩溃了你的程序,因为scanf()
有一个固有的不安全的字符串接口。它无法知道您的参数ch
是一个足以容纳9个字符的字符串加上其终止nul的数组。因此,非常乐意继续阅读stdin
中的字符,并将它们存储在数组末尾的内存中。
如果你的程序崩溃了,你真的很幸运。在最糟糕的情况下,攻击者使用精心设计的字符串来操纵堆栈的内容,以便控制您的计算机。这是缓冲区溢出攻击的一个示例。这听起来不太可能,但据记载,它已在很多场合发生。
仅用于数字,scanf
通常足够安全,但它在处理输入错误方面不是很好。因此,通常使用fgets()
之类的东西来读取输入(它有一个缓冲区长度参数来控制溢出)和sscanf()
从该缓冲区解析,测试其返回值通常是个好主意。为了理智,你去。
编辑:正如R的评论指出的那样,我夸大了scanf
界面固有的危险。小心地在所有字符串上正确使用字段宽度说明符,scanf
变得更安全。但是,您负责保证指定的宽度确实适合缓冲区。例如,您应该编写scanf("%9s",ch);
,因为您的缓冲区被声明为十个字节长,并且您需要留出终止空间的空间。
请注意,您还应该测试scanf()
的返回值。它返回成功匹配的字段数,如果发生I / O错误,则返回EOF
。例如,如果用户在预期数字时输入“abc”,则它可能返回0。
答案 1 :(得分:1)
因为你没有读一个字符,所以你正在读一个字符串。而scanf并不“知道”你只有10个字符的空间(包括null)。这是C编程的乐趣。
在这种情况下,您可以通过添加宽度修饰符来保护自己:
%9s