3

次のコードに出くわしました:

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

私の理解では、整数入力scanfを指定すると読み取りに失敗し、0 が返されるため、ループは一度も実行されません。ただし、すべてのタイプの入力を読み取りの成功として受け入れることにより、無限に実行されます。

誰かが親切にこの振る舞いを説明してくれますか?

4

2 に答える 2

9

intこれは、 : should beの不適切な書式指定子です"%d"

文字列を変数に読み込もうとしておりint、おそらくメモリを上書きしています。指定されているよう"%s"に、すべての入力が読み取られるためscanf()、ゼロより大きい値が返されます。

于 2012-06-18T08:00:28.407 に答える
2

(編集:この回答は受け入れられるべきではなかったと思います。賛成かもしれませんが、受け入れられませんでした。無限ループについてはまったく説明していません。@hmjdはそうしています。)

(これは実際には質問に答えるものではありません。他の回答はそれを行いますが、興味深く、知っておくとよいでしょう。)

hmjd が言うように、このように使用すると、メモリへの書き込みが開始されるため、scanfメモリが上書きされます ( 「スタックを破壊する」 )。ビットプラットフォーム)。ii

説明のために、次のコードを考えてみましょう。

#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'およびシステムのエンディアンに関連しています)。
  • str_aboveは によって変更されましたscanf: 文字'5',...,'0'が に'\0'予約されたメモリ ブロックの末尾をオーバーランし、 に予約iされたメモリに書き込まれましたstr_above
  • スタックは「上向き」に破壊されました。つまりstr_above、メモリに格納されるのは後でメモリにi格納str_belowされ、メモリに格納されます。(別の言い方をすれば&str_above > &i&str_below < &i

これは、配列に大量のデータを書き込むことによってスタック上の値が変更される「バッファ オーバーラン攻撃」の基礎となります。getsそして、それが危険であり(そして決して使用すべきではない)理由でscanfあり、一般的な%sフォーマット指定子を使用することも決して行われるべきではありません.

于 2012-06-18T08:32:41.633 に答える