scanf("%d",i)是如何工作的?

时间:2014-08-22 19:47:38

标签: c scanf

考虑这个代码片段(而不是使用scanf(%d,& i)我故意使用scanf("%d",i))

int main()
{
 int i;
 scanf("%d", i);
 printf("%d", i);
 return 0;
}

这里我没有初始化,代码正在运行并带有警告,扫描输入并将垃圾值作为输出。

但如果我用某个值初始化,那么它会扫描输入和程序崩溃。

两种情况下scanf()的确如何运作?

3 个答案:

答案 0 :(得分:5)

我假设你使用了正确的#include <stdio.h>而没有提及它。

在这种情况下,只有一条坏线:

 scanf("%d", i); // This line is bad

您可以通过以下两种方式调用Undefined Behavior (UB)

  1. 读取i,即使它从未被分配,也会调用UB,因为它是自动存储类(堆栈分配的),并且您从不接受其地址(它符合register的条件)。 / LI>
  2. 传递int,其中scanf期望int*会导致UB全部出现。论证应该是&i 你知道你可能在那里摧毁了什么,如果它似乎有效吗?&#34;?
  3. 初始化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。

寻址的对象