web-dev-qa-db-ja.com

scanf()を使用して行を読み取るのは良くありませんか?

_scanf(" %[^\n]",line);
_

私の友人は、上記のステートメントのようにfgets()を使用するよりも、入力として行を読み取るためにscanf()を使用することをお勧めします。彼は正当化されますか?

15
amulous

char * fgets ( char * str, int num, FILE * stream ); は、 buffer overflow の問題を回避するため、安全に使用できます。_num-1_個のcharのみをスキャンします。

ストリームから文字を読み取り、(num-1)文字が読み取られるか、改行またはファイルの終わりに達するまで(どちらか早い方)、C文字列としてstrに格納します。

ここで、2番目の引数numは、strにコピーされる最大文字数(終端のヌル文字を含む)です。

たとえば、コードの文字列配列の容量が、以下のように_5_文字だけであるとします。

_ char str[5];
 fgets (str, 5, fp);  //5 =you have provision to avoid buffer overrun 
_

上記のコードを使用して、fpからの入力が_4_ charsより長い場合、fgets()は最初に_4_ charsを読み取り、その後_\0_(、およびその他の余分な入力文字を破棄し、_str[]_)に5文字を格納します。

scanf(" %[^\n]",str);は_\n_が見つからなくなるまで読み取り、入力文字列が長い場合は_4_ chars scanf()buffer overflow の原因になります(scanfは_4_の最大インデックス_str[]_を超えてメモリにアクセスしようとします)。

21
Grijesh Chauhan

C FAQには、scanfの問題に関する詳細な説明があります。

より一般的には、scanfは比較的構造化され、フォーマットされた入力用に設計されています(その名前は実際には「スキャンフォーマット済み」から派生しています)。注意を払うと、成功したか失敗したかがわかりますが、失敗したおおよその場所のみがわかり、方法や理由はわかりません。エラー回復を行う機会はほとんどありません。

詳細については here を参照してください。

8
Yu Hao

簡単に言えば、はい、fgetsがより良い選択です。

私はあなたのscanfフォーマット指定子を見ましたが、私は不可解でした。それが何をするかを正確に理解するには、manページを読むのに時間がかかります。

また、scanfコードはバッファオーバーランの影響を受けやすくなります。

シンプルに保つと、メンテナンスコストが削減され、バグを見つけにくくなります。

3
Klas Lindbäck

fgetsは、このscanfよりも優れています。 OPで指定されているscanfには次の問題がある可能性があります

1)@Grijeshが示唆するバッファオーバーフロー

2)入力ストリームに改行が残っているため、この後の次のscanfは機能しません。(空白が欠落している場合)

3
Dayal rai

はい、fgetsは標準入力から行を読み取るためのより安全で安全な方法です。

さらに、コードが読みやすくなります。あなたから与えられたscanfステートメントを見てください。

それを見た二人目は完全に混乱します。ただし、fgetsの方が読みやすくなり、理解しやすくなります。

3
Kranthi Kumar