我去了一个采访中,我被问到这个问题:
您对以下内容有何看法?
int i; scanf ("%d", i); printf ("i: %d\n", i);
我回答了:
该程序将成功编译.
它将错误地打印数字,但它将一直运行直到结束而不会崩溃
我做出的回应是错误的.我不堪重负.
在那之后他们解雇了我:
在某些情况下,程序会崩溃并导致核心转储.
我不明白为什么程序会崩溃?谁有人解释我的原因?任何帮助赞赏.
定义变量时,编译器为该变量分配内存.
int i; // The compiler will allocate sizeof(int) bytes for i
i
上面定义的内容未初始化且具有不确定的值.
要将数据写入分配给的内存位置i
,需要指定变量的地址.该声明
scanf("%d", &i);
将int
用户将数据写入分配给的内存位置i
.
如果&
之前未放置i
,scanf
则会尝试将输入数据写入内存位置i
而不是&i
.由于i
包含不确定值,因此可能包含一个等于内存地址值的值,或者它可能包含一个超出内存地址范围的值.
在任何一种情况下,程序可能表现不正常并将导致未定义的行为.在那种情况下,一切都可能发生
因为它调用了未定义的行为.该scanf()
系列函数期望一个指向整数时,"%d"
符中找到.您传递的是一个整数,可以解释为某个整数的地址,但事实并非如此.这在标准中没有定义的行为.它确实会编译(但会发出一些警告)但它肯定会以一种意想不到的方式工作.
在代码中,还有另一个问题.该i
变量从未初始化,所以它会产生不确定的值,另一个原因未定义行为.
请注意,标准没有说明当您在预期某个其他类型时传递给定类型时会发生什么,无论您交换什么类型,它都是未定义的行为.但是这种特殊情况属于特殊考虑因素,因为指针可以转换为整数,但只有在转换回指针并且整数类型能够正确存储值时才会定义行为.这就是它编译的原因,但肯定无法正常工作.
您传递了具有错误类型(int*
预期但int
已通过)的数据scanf()
.这将导致未定义的行为.
任何事情都可能发生在未定义的行为上.该程序可能会崩溃,可能不会崩溃.
在典型的环境中,我猜程序会在指向操作系统不允许写入的位置的某个"地址"传递给程序时崩溃scanf()
,并且写入操作系统会终止应用程序,它将被视为崩溃.
其他答案尚未提及的一点是在某些平台上,sizeof (int) != sizeof (int*)
.如果参数以某种方式传递*,scanf
可能会吞噬另一个变量或返回地址的一部分.更改返回地址很可能会导致安全漏洞.
*我不是汇编语言专家,所以请耐心等待.
我不明白为什么程序会崩溃?任何人都可以解释我的原因.任何帮助赞赏.
也许更多应用:
int i = 123; scanf ("%d", &i);
使用第一个命令,您可以为一个整数值分配内存,并在此内存块中写入123.对于这个例子,假设这个内存块有地址0x0000ffff
.使用第二个命令读取输入,scanf将输入写入内存块0x0000ffff
- 因为您没有访问(取消引用)此变量的值,i
而是它的地址.
如果您使用该命令,scanf ("%d", i);
则将输入写入内存地址 123
(因为这是存储在此变量中的值).显然,这可能会非常错误并导致崩溃.