C语言中for循环中scanf的行为

3
我看到了以下的代码:

我看到了以下的代码:

int i;
for(; scanf("%s", &i);)
    printf("hello");

据我理解,如果我们提供整数输入,则 scanf 将无法读取并返回0,因此循环不应该运行一次。然而,它接受所有类型的输入作为成功读取而无限运行。
请问有人能解释这种行为吗?

请参见我回答顶部的编辑。 :) - huon
2个回答

9

这是一个错误的格式说明符,用于int类型应该是"%d"

它试图将字符串读入int变量中,可能会覆盖内存。由于指定了"%s" ,因此所有输入都将被读取,因此scanf()返回大于零的值。


2
(编辑:我认为这个答案不应该被接受。或许可以点赞,但不能被接受。它根本没有解释无限循环,@hmjd 才做到了。)
(这并不是真正回答问题,其他答案已经回答了,但这很有趣,值得知道。)
正如 hmjd 所说,像这样使用 scanf 会覆盖内存("破坏堆栈"),因为它开始写入内存中的 i,然后继续进行,甚至超出了 i 占用的 4 字节内存(或者在 64 位平台上占用的 8 字节内存)。
为了说明这一点,考虑以下代码片段:
#include<stdio.h>

int main() {
    char str_above[8] = "ABCDEFG";
    int i;
    char str_below[8] = "ABCDEFG";

    scanf("%s", &i);

    printf("i = %d\n", i);
    printf("str_above = %s\nstr_below = %s\n", str_above, str_below);

    return 0;
}

编译并运行它,输入1234567890会产生以下输出:
i = 875770417
str_above = 567890
str_below = ABCDEFG

一些要点:
  • i 与整数 1234567890 几乎没有对应关系(它与字符 '1'、...、'4' 的值以及系统的字节序相关)。
  • scanf 修改了 str_above:字符 '5'、...、'0''\0' 超出了为 i 保留的内存块的末尾,并被写入了为 str_above 保留的内存。
  • 堆栈已向“上”破坏,即 str_above 存储在内存中比 i 更晚,而 str_below 存储在内存中更早。 (换句话说,&str_above > &i 并且 &str_below < &i。)
这是“缓冲区溢出攻击”的基础,其中通过向数组写入过多的数据来修改堆栈上的值。这也是为什么gets是危险的(并且应该永远不要使用),使用带有通用%s格式说明符的scanf也不应该这样做。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接