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