10

使い方がわからなくてずっと悩んでいましたscanf()。かなり単純なので、整数で問題なく動作するようですscanf("%d", &i)

私が問題に直面しているのはscanf()、入力を読み取ろうとする in ループの使用です。例えば:

do {
  printf("counter: %d: ", counter);
  scanf("%c %c%d", &command, &prefix, &input);
} while (command != 'q');
  1. のような有効に構造化された入力を入力するとc P101、プロンプトが表示される前に再びループするようです。これは、単一でも発生するようです:

    scanf("%c", &c) 
    

    while ループで。再度プロンプトを表示する前に、ループを 2 回実行します。2 回ループさせているのは何ですか?どうすれば停止できますか?

  2. プログラムで などの別の文字や数字を持たない少ない量の入力を入力するとq、Enter キーを押すと、さらに入力するように求められるようです。scanf()1文字入力と 2 文字入力の両方を処理するにはどうすればよいですか?

4

5 に答える 5

19

「」と入力するとc P101、プログラムは実際に「c P101\n」を受け取ります。ほとんどの変換指定子は、改行を含む先頭の空白をスキップしますが、スキップ%cしません。1回目は「\n」が読み込まれるまで、2回目は「\ n」が読み込まれcommand、「c」が読み込まれprefix、「P」は数値ではないため、変換に失敗し、「P101\n」はストリームに残しました。次回「P」がコマンドに保存されると、「1」はプレフィックスに保存され、1(残りの「」から)「 」が次回のストリームに残ったまま01入力に保存されます。\n

2番目のケースでも同様のことが起こります。「」を入力するとq、「q\n」がストリームに入力され、最初に「q」の周りが読み取られ、2回目に「\n」が読み取られ、3回目の呼び出しでのみ2番目の" q"読み取り、フォーマット文字列の先頭にスペース文字を追加することで、問題を再度回避できます。

これを行うためのより良い方法は、fgets()のようなものを使用して一度に行を処理してから、sscanf()を使用して解析を行うことです。

于 2008-10-19T22:59:58.210 に答える
1

本当に壊れています!知らなかった

#include <stdio.h>

int main(void)
{
    int counter = 1;
    char command, prefix;
    int input;

    do 
    {
        printf("counter: %d: ", counter);
        scanf("%c %c%d", &command, &prefix, &input);
        printf("---%c %c%d---\n", command, prefix, input);
        counter++;
    } while (command != 'q');
}
counter: 1: a b1
---a b1---
counter: 2: c d2
---
 c1---
counter: 3: e f3
---d 21---
counter: 4: ---e f3---
counter: 5: g h4
---
 g3---

出力はロバートの答えと一致しているようです。

于 2008-10-19T23:01:08.487 に答える
1

Once you have the string that contains the line. i.e. "C P101", you can use the parsing abilities of sscanf.

See: http://www.cplusplus.com/reference/clibrary/cstdio/sscanf.html

于 2008-10-19T23:14:28.087 に答える
1

printf()質問 1 については、末尾の「\n」がないため、 に問題があると思われます。

のデフォルトの動作printfは、完全な行になるまで出力をバッファリングすることです。これは、 のバッファリングを明示的に変更しない限りですstdout

質問 2 については、 の最大の問題の 1 つにぶつかったところscanf()です。入力が指定したスキャン文字列と正確に一致しない限り、結果は期待したものとはまったく異なります。

scanf()オプションがある場合は、独自の解析を無視して実行することで、より良い結果が得られます (セキュリティの問題が少なくなります) 。たとえば、 を使用fgets()して行全体を文字列に読み込み、文字列の個々のフィールドを処理しますsscanf()

于 2008-10-19T22:40:38.763 に答える
0

おそらく do...while ループではなく、while ループを使用すると役立つでしょう。このようにして、コードの実行前に条件がテストされます。次のコード スニペットを試してください。

 while(command != 'q')
    {
        //statements
    }

また、文字列の長さが事前にわかっている場合は、'while' ループよりも 'for' ループの方がはるかに簡単に操作できます。長さを動的に決定するためのよりトリッキーな方法もあります。

最後の暴言として:scanf()「吸う」ことはありません。それはそれがすることをします、そしてそれはすべてです。

このgets()関数は、入力のチェックをネイティブに行わないため、非常に危険です (リスクのないアプリケーションには便利ですが)。これはエクスプロイト、特にバッファ オーバーフロー攻撃のポイントとして非常によく知られており、その変数に割り当てられていないレジスタのスペースを上書きします。したがって、それを使用することを選択した場合は、しっかりとしたエラーチェック/修正に時間を費やしてください。

ただし、ほとんどの場合、行を読み取るにはfgets()または POSIXを使用する必要があります。またはを使用して、読み取りから末尾の改行を削除できます— これは確実に機能します。getline()gets()stringfgets()getline()string[strcspn(string, "\n")] = '\0';

于 2012-11-20T11:00:39.890 に答える