2012-02-14 4 views
34

多くの人がscanfgetlineと同じように「より深刻なプログラム」で使用しないでください。Cのユーザからの入力を得るための最良の方法はどれですか?

私は失われ始めました:私が人々に渡ったすべての入力機能が私がそれらのどれを使うべきではないと言ったら、私は何を使うべきですか?私が気づいていない入力を得るための「標準的な」方法がありますか?

+1

などstrtoksscanfまたはそれらの組み合わせ、strtolstrtodを、使用して入力を変換することです。 'ほとんどの場合、' scanf'を使うことをお勧めし、戻り値をチェックします。 – asaelr

+1

'scanf'はCで書式化された入力を得るための標準的なメソッドであり、' fgets'/'fgetc'は行全体または単一文字を取得するのに推奨される標準関数です。その他のほとんどの関数は、非標準またはプラットフォーム固有のものです。 –

+1

深刻なプログラムで 'getline'を使わない理由はありません。あなたのプラットフォームにそれがない場合は、 'fgets'と' malloc'の観点から実装することができます。 –

答えて

33

通常、fgets()が適切なオプションとみなされます。それは、バッファに全体の行を読み取り、そこからあなたが必要なものを行うことができます。 scanf()のような振る舞いが必要な場合は、読み取った文字列をsscanf()に渡すことができます。

この主な利点は、文字列が変換に失敗した場合は回復が容易であるのに対し、scanf()の場合は、排除する必要があるstdinの入力が残っていることです。さらに、scanf()とライン指向の入力を混在させると、\nのようなものが残ってしまい、頭痛の原因になります。stdinは、入力コールが完全に無視されたと考える新しいコーダーです。このような

何かがあなたの好みに合わせて次のようになります。

char line[256]; 
int i; 
if (fgets(line, sizeof(line), stdin)) { 
    if (1 == sscanf(line, "%d", &i)) { 
     /* i can be safely used */ 
    } 
} 

あなたが注意しなければならない上、そのfgets()戻り、私はifに包み理由である、EOFまたはエラーのNULLsscanf()呼び出しは、正常に変換されたフィールドの数を返します。

fgets()は、行がバッファよりも大きければ、行全体を読むことができないことに注意してください。これは、「深刻な」プログラムでは、考慮すべき点です。

+1

'fgets()'の直後に 'fflush(stdin)'を追加して、過剰な入力バッファ(255文字以上)が 'fgets()'へのその後の呼び出しに影響を与えないようにする方法はありますか? – Twonky

+1

@Twonky: 'fflush(stdin)'はCが関係する限りは定義されていません(しかし、いくつかのプラットフォームではあなたが提案したことを行います)。しかし、ええ、それはその点でより頑強にすることができます。 – FatalError

11

入力の長さに固定の制限を設定できる簡単な入力の場合は、端末からのデータをfgets()で読むことをおすすめします。 fgets()は、あなたが(まさにこの理由のために、かなりは、ヒトからの入力を読み取るために使用しないでgets()とは対照的に)バッファサイズを指定することができますので、

これは、次のとおりです。

char line[256]; 

if(fgets(line, sizeof line, stdin) != NULL) 
{ 
    /* Now inspect and further parse the string in line. */ 
} 

は、ということを忘れないでください例えば改行文字は驚くかもしれません。

UPDATE:コメントに指摘されているように、メモリを追跡する責任がある場合は、より良い方法があります。getline()これはおそらくPOSIXコードのための最良の汎用ソリューションです。なぜなら、読み込む行の長さには静的な制限がないからです。

+0

"入力の長さに固定の制限を設定できる簡単な入力"は "深刻な"プログラムのようには聞こえません。 POSIXの 'getline'関数ははるかに柔軟です。 –

+0

@larsmans素晴らしいキャッチ、それを指摘してくれてありがとう。 – unwind

+0

もし私が私の質問に2つの勝者を置くことができれば、getline()ディテールのために2番目になります。しかし、FatalErrorの答えには、このテクニックの使い方の詳細がありました。 – user1115057

2

fgetsを使用してデータを取得し、sscanf(または別の方法)を使用してそれらを解釈します。使用する方が確実です。

学ぶために、このページを参照してくださいfgets + sscanfではなくscanf

http://c-faq.com/stdio/scanfprobs.html

5

いくつかのscanfを使用してに問題があります:プレーンでテキストを読む

  • は、 %s変換指定子はgets()と同じリスクがあります。ユーザーが、ターゲットバッファが保持するサイズよりも長い文字列を入力すると、バッファオーバーランが発生します。

  • 数値入力を読み取るために%d%fを使用している場合、特定の悪いパターンがキャッチされ、完全に拒否することはできません - あなたは%dと整数を読み取り、ユーザーが「12r4」、している場合scanfは変換し12を割り当てます入力ストリームにr4を残しておけば、次の読み込みを無効にできます。

  • 一部の変換指定子は空白をスキップしますが、それ以外のものは考慮しないため、入力を一部スキップすると問題が発生することがあります。

基本的に、それはscanfを使用して読み込み、防弾に余分な労力の多くかかります。

良い代替はfgets()を使用してテキストとしてすべての入力を読み、次にトークン化し、非常にあなたのプログラム何を行うに依存

+1

ありがとう、今私は人々がscanfが悪いと言う理由は何かを知っている。 – user1115057

関連する問題