考虑这个代码片段(而不是使用scanf(%d,& i)我故意使用scanf("%d",i))
int main()
{
int i;
scanf("%d", i);
printf("%d", i);
return 0;
}
这里我没有初始化,代码正在运行并带有警告,扫描输入并将垃圾值作为输出。
但如果我用某个值初始化,那么它会扫描输入和程序崩溃。
两种情况下scanf()的确如何运作?
答案 0 :(得分:5)
我假设你使用了正确的#include <stdio.h>
而没有提及它。
在这种情况下,只有一条坏线:
scanf("%d", i); // This line is bad
您可以通过以下两种方式调用Undefined Behavior (UB):
i
,即使它从未被分配,也会调用UB,因为它是自动存储类(堆栈分配的),并且您从不接受其地址(它符合register
的条件)。 / LI>
int
,其中scanf
期望int*
会导致UB全部出现。论证应该是&i
你知道你可能在那里摧毁了什么,如果它似乎有效吗?&#34;?初始化i
会删除UB的第一个但不是第二个原因。
除此之外:您应该始终假设输入可能会失败,因此请检查返回值。
BTW:如果你检查,编译器可以并且确实利用UB来修剪整个执行分支,这将导致它不可能,不需要担心它&#34;。如果你想知道你的编译器,你今天使用的版本以及你给它的确切代码和选项,请查看反汇编或者可能要求汇编列表。虽然没有任何结论,因为它是无害的&#34;。
答案 1 :(得分:3)
因此,您以两种方式调用了未定义的行为 1 :
int i;
scanf("%d", i);
首先,%d
转换说明符期望其对应的参数具有类型int *
。表达式i
的类型为int
;由于这与预期类型不匹配,因此行为未定义。如果sizeof (int *) != sizeof (int)
等问题,这肯定会成为一个问题。
其次,由于i
未初始化,它将包含一些 intederminate 值,scanf
将其解释为指针值,并尝试将输入写入该无效地址( 不是i
的地址。在这种特殊情况下,写入该无效地址并不会立即导致段错误(尽管它已被破坏某些东西;这些东西是否重要是一个悬而未决的问题)。请注意, i
未被修改;它仍然包含与它开始时相同的不确定值。
在第二种情况下,无论您初始化i
可能已解决为受限制的地址,这都是您崩溃的原因。
无论哪种方式,坏juju。
<小时/> 1。 未定义行为的定义是&#34;行为,在使用不可移植或错误的程序结构或错误数据时,[C语言标准]没有强制要求&#34; (2011 C standard,3.4.3)。编译器不需要发出诊断或暂停转换,也不需要生成执行任何特定操作的代码。代码可能崩溃,可能会损坏数据,可能使程序处于错误状态,或者可能看起来工作正常。
答案 2 :(得分:2)
您使用无效参数调用scanf。而不是
scanf("%d", i);
必须有
scanf("%d", &i);
该函数将提取的数字写入由&amp; i。
寻址的对象