web-dev-qa-db-ja.com

whileループでscanfを使用する

おそらく、この非常に単純な質問に対する非常に単純な答えです。

Prattaの「CPrimerPlus」を読んでいて、彼は例を使い続けています

while (scanf("%d", &num) == 1)...

== 1は本当に必要ですか?次のように書くことができるようです。

while (scanf("%d", &num))

Scanfは読み取られたオブジェクトの数を返し、1はwhileループを真にするため、等価性テストは不要のようです。読み取られる要素の数が正確に1であることを確認する理由はありますか、それともこれは完全に不要ですか?

13
Tyler Brock

Cでは、0はfalseと評価され、その他はすべてtrueと評価されます。したがって、scanfが負の値であるEOFを返した場合、ループはtrueと評価されますが、これは必要なものではありません。

26
JRL

scanfはファイルの終わりに値EOF(-1)を返すため、記述されたループは正しいです。入力に_%d_に一致するテキストが含まれている限り実行されます。そして、最初の不一致またはファイルの終わりで停止します。

scanfが複数の入力を期待していた場合は、一目でわかりやすくなります。

_while (scanf("%d %d", &x, &y)==2) { ... }
_

ファイルの終わりファイルの終わり(scanfがEOF(-1)を返す))または入力マッチングエラーのいずれかが原因で、最初に2つの値を一致させることができなかったときに、ループを終了します。 (たとえば、入力_xyzzy 42_が_%d %d_と一致しないため、scanfは最初の失敗で停​​止し、2未満の値を返すと0 xまたはyに書き込むことなくを返します。 。

もちろん、scanfnot通常の人間からの実際の入力を解析するときの友達です。エラーケースの処理には多くの落とし穴があります。

編集:エラーを修正しました:scanfは、ファイルの終わりにEOFを返すか、正常に設定された変数の数をカウントする負でない整数を返します。

重要な点は、ゼロ以外の値はCではTRUEであるため、このようなループで戻り値を正しくテストしないと、予期しない動作が発生しやすくなることです。特に、while(scanf(...))は、その形式に従って変換できない入力テキストに遭遇しない限り、無限ループです。

そして、scanfnotあなたの友達であることを強調することはできません。 fgetssscanfの組み合わせは、いくつかの単純な解析には十分かもしれませんが、それでも、Edgeのケースとエラーに簡単に圧倒されます。

10
RBerteig

あなたはCコードを正しく理解しました。

読み取られたアイテムの数をテストする理由は、入力が予期されたタイプと一致しなかったときにscanfが早期に終了するのではなく、すべてのアイテムが読み取られたことを確認したいためです。この特定のケースでは、それは問題ではありませんでした。

通常、scanfは、人間のユーザーからの対話型入力のニーズを満たさないため、関数の選択としては適切ではありません。通常、fgetsとsscanfを組み合わせると、より良い結果が得られます。この特定のケースでは、それは問題ではありませんでした。

後の章で、ある種のコーディング手法がこの些細な例よりも優れている理由を説明しているのであれば、それは良いことです。しかしそうでない場合は、読んでいる本を捨てるべきです。

一方、代替コードは完全に代替ではありません。 scanfが-1を返すと、whileループが実行されます。

3

あなたは正しいですが、それは厳密には必要ではありませんが、いくつかの理由でそれを好む人もいます。

まず、1と比較すると、明示的なブール値(trueまたはfalse)になります。比較せずに、整数でテストしています。整数はCで有効ですが、それ以降の言語(C#など)では有効ではありません。

次に、while([return value])ではな​​くwhile([function])の観点から2番目のバージョンを読み、明確に意味するのが戻り値のテストである場合に、関数をテストすることで一時的に混乱する人もいます。

これは完全に個人的な好みの問題である可能性があり、私に関する限り、両方とも有効です。

1
abelenky

明示的な比較なしでそれを書くことができるかもしれませんが(JRLの答えを参照してください)、なぜそうするのでしょうか?比較のない条件は、明示的にブール値のセマンティクスを持つ値(たとえば、isdigit()呼び出しなど)でのみ使用する必要があると思います。他のすべては、明示的な比較を使用する必要があります。この場合(scanfの結果)、セマンティクスは明らかに非ブール値であるため、明示的な比較が適切です。

また、通常省略できる比較は、通常、zeroとの比較です。他のもの(この場合は1など)との比較を省略したいという衝動を感じるときは、よく考えて、自分が何をしているのかを確認することをお勧めします(JRLの回答をもう一度参照してください)。

いずれにせよ、比較を安全に省略でき、実際に省略しても、条件の実際の意味的な意味は同じままです。それがあなたが心配していることであるならば、それは結果のコードの効率に全く影響を与えません。

1
AnT