我去了一个采访中,我被问到这个问题:
您对以下内容有何看法?
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
变量从未初始化,因此它将具有不确定的值,这是Undefined Behavior的另一个原因。
请注意,标准没有说明当您在预期某个其他类型时传递给定类型时会发生什么,无论您交换什么类型,它都是未定义的行为。但是这种特殊情况属于特殊考虑因素,因为指针可以转换为整数,但只有在转换回指针并且整数类型能够正确存储值时才会定义行为。这就是它编译的原因,但肯定无法正常工作。
你传递了错误类型的数据(int*
是预期的,但int
被传递)到scanf()
。这将导致未定义的行为。
任何事情都可能发生在未定义的行为上。该程序可能会崩溃,可能不会崩溃。
在一个典型的环境中,我想程序会崩溃,当一些指向操作系统不允许写入的位置的“地址”传递给scanf()
,写入那里将使操作系统终止应用程序,它将被视为崩溃。
其他答案尚未提及的一件事是在某些平台上,sizeof (int) != sizeof (int*)
。如果参数以某种方式传递*,scanf
可能会吞噬另一个变量或返回地址的一部分。更改返回地址很可能会导致安全漏洞。
*我不是汇编语言专家,所以请耐心等待。
我不明白为什么程序会崩溃?任何人都可以解释我的原因。任何帮助赞赏。
也许更多应用:
int i = 123;
scanf ("%d", &i);
使用第一个命令,您可以为一个整数值分配内存,并在此内存块中写入123。对于这个例子,假设这个内存块的地址为0x0000ffff
。使用第二个命令读取输入,scanf将输入写入内存块0x0000ffff
- 因为您没有访问(解除引用)此变量i
的值,但它的地址。
如果使用命令scanf ("%d", i);
,则将输入写入内存地址123
(因为这是存储在此变量中的值)。显然,这可能会非常错误并导致崩溃。