次のコードに出くわしました:
int i;
for(; scanf("%s", &i);)
printf("hello");
私の理解では、整数入力scanf
を指定すると読み取りに失敗し、0 が返されるため、ループは一度も実行されません。ただし、すべてのタイプの入力を読み取りの成功として受け入れることにより、無限に実行されます。
誰かが親切にこの振る舞いを説明してくれますか?
int
これは、 : should beの不適切な書式指定子です"%d"
。
文字列を変数に読み込もうとしておりint
、おそらくメモリを上書きしています。指定されているよう"%s"
に、すべての入力が読み取られるためscanf()
、ゼロより大きい値が返されます。
(編集:この回答は受け入れられるべきではなかったと思います。賛成かもしれませんが、受け入れられませんでした。無限ループについてはまったく説明していません。@hmjdはそうしています。)
(これは実際には質問に答えるものではありません。他の回答はそれを行いますが、興味深く、知っておくとよいでしょう。)
hmjd が言うように、このように使用すると、メモリへの書き込みが開始されるため、scanf
メモリが上書きされます ( 「スタックを破壊する」 )。ビットプラットフォーム)。i
i
説明のために、次のコードを考えてみましょう。
#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
フォーマット指定子を使用することも決して行われるべきではありません.