如果在 'scanf' 语句中不放入 '&' 会发生什么情况?
What will happen if '&' is not put in a 'scanf' statement?
我去参加了一个面试,被问到这个问题:
What do you think about the following?
int i;
scanf ("%d", i);
printf ("i: %d\n", i);
我回复了:
- 程序将编译成功。
- 它会打印错误的数字,但它会 运行 直到最后
没有崩溃
我的回复是错误的。我不知所措。
之后他们解雇了我:
The program would crash in some cases and lead to an core dump.
我无法理解为什么程序会崩溃?谁能给我解释一下原因?任何帮助表示赞赏。
因为它调用了未定义的行为。当找到 "%d"
说明符时,scanf()
系列函数需要一个指向整数的指针。您传递的整数可以解释为某个整数的地址,但事实并非如此。这在标准中没有定义的行为。它确实会编译(但是会发出一些警告)但是它肯定会以意想不到的方式工作。
在代码中,还有一个问题。 i
变量永远不会被初始化,因此它将有一个不确定的值,这是 未定义行为 .
的另一个原因
请注意,标准没有说明当您传递给定类型而预期其他类型时会发生什么,无论您交换什么类型,它都只是未定义的行为。但这种特殊情况属于特殊考虑,因为指针可以转换为整数,尽管只有在转换回指针并且整数类型能够正确存储值时才会定义行为。这就是它编译的原因,但肯定不能正常工作。
您向 scanf()
传递了错误类型的数据(预期 int*
,但传递了 int
)。这将导致未定义的行为。
对于未定义的行为,任何事情都可能发生。程序可能会崩溃也可能不会崩溃。
在典型的环境中,我猜当某些指向操作系统不允许写入的位置的 "address" 被传递给 scanf()
时程序会崩溃,并且写入那里将 OS 终止应用程序,并将被视为崩溃。
定义变量时,编译器会为该变量分配内存。
int i; // The compiler will allocate sizeof(int) bytes for i
i
上面定义的未初始化且具有不确定的值。
要将数据写入分配给 i
的内存位置,您需要指定变量的地址。语句
scanf("%d", &i);
将由用户写入一个int
数据到为i
分配的内存位置。
如果&
没有放在i
之前,那么scanf
会尝试将输入数据写入内存位置i
而不是&i
.由于 i
包含不确定的值,因此有可能它包含一个等于内存地址值的值,或者它可能包含一个超出内存地址范围的值。
在任何一种情况下,程序都可能会出现异常行为并导致未定义的行为。那样的话什么事都有可能发生。
其他答案尚未提及的一件事是,在某些平台上,sizeof (int) != sizeof (int*)
。如果参数以某种方式*传递,scanf
可能会吞噬另一个变量或 return 地址的一部分。更改 return 地址很可能会导致安全漏洞。
* 我不是汇编语言专家,所以对此持保留态度。
I could not understand why the program would crash? Could anyone explain me the reason. Any help appreciated.
可能应用的多一点:
int i = 123;
scanf ("%d", &i);
使用第一个命令,您为一个整数值分配内存并在该内存块中写入 123。对于这个例子,假设这个内存块的地址是 0x0000ffff
。使用第二个命令,您读取输入,scanf 将输入写入内存块 0x0000ffff
- 因为您没有访问(取消引用)此变量 i
的值,而是地址。
如果您使用命令 scanf ("%d", i);
而不是将输入写入内存 地址 123
(因为这是存储在该变量中的值) .显然,这可能会出现严重错误并导致崩溃。
由于scanf中没有&(ampersand)(标准要求),所以只要我们输入这个值,程序就会突然终止,不管程序中再写多少行代码.
-->> 我执行并在代码块中发现。
相同的程序,如果我们在 turbo c 编译器中 运行 那么它将 运行 完美地处理所有行,即使是在 scanf 之后的行,但唯一的事情,因为我们知道 i 打印的值会成为垃圾。
结论:- 因为在某些编译器中它会 运行 而在某些编译器中不会,所以这不是一个有效的程序。
我去参加了一个面试,被问到这个问题:
What do you think about the following?
int i; scanf ("%d", i); printf ("i: %d\n", i);
我回复了:
- 程序将编译成功。
- 它会打印错误的数字,但它会 运行 直到最后 没有崩溃
我的回复是错误的。我不知所措。
之后他们解雇了我:
The program would crash in some cases and lead to an core dump.
我无法理解为什么程序会崩溃?谁能给我解释一下原因?任何帮助表示赞赏。
因为它调用了未定义的行为。当找到 "%d"
说明符时,scanf()
系列函数需要一个指向整数的指针。您传递的整数可以解释为某个整数的地址,但事实并非如此。这在标准中没有定义的行为。它确实会编译(但是会发出一些警告)但是它肯定会以意想不到的方式工作。
在代码中,还有一个问题。 i
变量永远不会被初始化,因此它将有一个不确定的值,这是 未定义行为 .
请注意,标准没有说明当您传递给定类型而预期其他类型时会发生什么,无论您交换什么类型,它都只是未定义的行为。但这种特殊情况属于特殊考虑,因为指针可以转换为整数,尽管只有在转换回指针并且整数类型能够正确存储值时才会定义行为。这就是它编译的原因,但肯定不能正常工作。
您向 scanf()
传递了错误类型的数据(预期 int*
,但传递了 int
)。这将导致未定义的行为。
对于未定义的行为,任何事情都可能发生。程序可能会崩溃也可能不会崩溃。
在典型的环境中,我猜当某些指向操作系统不允许写入的位置的 "address" 被传递给 scanf()
时程序会崩溃,并且写入那里将 OS 终止应用程序,并将被视为崩溃。
定义变量时,编译器会为该变量分配内存。
int i; // The compiler will allocate sizeof(int) bytes for i
i
上面定义的未初始化且具有不确定的值。
要将数据写入分配给 i
的内存位置,您需要指定变量的地址。语句
scanf("%d", &i);
将由用户写入一个int
数据到为i
分配的内存位置。
如果&
没有放在i
之前,那么scanf
会尝试将输入数据写入内存位置i
而不是&i
.由于 i
包含不确定的值,因此有可能它包含一个等于内存地址值的值,或者它可能包含一个超出内存地址范围的值。
在任何一种情况下,程序都可能会出现异常行为并导致未定义的行为。那样的话什么事都有可能发生。
其他答案尚未提及的一件事是,在某些平台上,sizeof (int) != sizeof (int*)
。如果参数以某种方式*传递,scanf
可能会吞噬另一个变量或 return 地址的一部分。更改 return 地址很可能会导致安全漏洞。
* 我不是汇编语言专家,所以对此持保留态度。
I could not understand why the program would crash? Could anyone explain me the reason. Any help appreciated.
可能应用的多一点:
int i = 123;
scanf ("%d", &i);
使用第一个命令,您为一个整数值分配内存并在该内存块中写入 123。对于这个例子,假设这个内存块的地址是 0x0000ffff
。使用第二个命令,您读取输入,scanf 将输入写入内存块 0x0000ffff
- 因为您没有访问(取消引用)此变量 i
的值,而是地址。
如果您使用命令 scanf ("%d", i);
而不是将输入写入内存 地址 123
(因为这是存储在该变量中的值) .显然,这可能会出现严重错误并导致崩溃。
由于scanf中没有&(ampersand)(标准要求),所以只要我们输入这个值,程序就会突然终止,不管程序中再写多少行代码.
-->> 我执行并在代码块中发现。
相同的程序,如果我们在 turbo c 编译器中 运行 那么它将 运行 完美地处理所有行,即使是在 scanf 之后的行,但唯一的事情,因为我们知道 i 打印的值会成为垃圾。
结论:- 因为在某些编译器中它会 运行 而在某些编译器中不会,所以这不是一个有效的程序。