3

私の目的は、の区切り文字scanfを「\n」に変更することです。使用してみscanf("%[^\n]s",sen);ましたが、単一入力で正常に動作します。しかし、同じ行を複数の文のループ内に置くと、forガベージ値が返されます。

誰かが理由を知っていますか?


これが私のコードです:

char sen[20];
for (i=0;i<2;i++)
{
    scanf("%[^\n]s",sen);
    printf("%s\n",sen);
}
4

5 に答える 5

14

この(C99)コードを考えてみましょう:

#include <stdio.h>

int main(void)
{
    char buffer[256];

    while (scanf("%255[^\n]", buffer) == 1)
        printf("Found <<%s>>\n", buffer);
    int c;
    if ((c = getchar()) != EOF)
        printf("Failed on character %d (%c)\n", c, c);
    return(0);
}

それを実行して文字列を入力すると、「スペースTABTABタブが豊富なものなら何でも!」と表示されます。

Found <<absolutely anything with   spaces       tabs galore!>>
Failed on character 10 (
)

もちろん、 ASCII(UTF-8)1010は改行です。

これはあなたの問題を理解するのに役立ちますか?


この場合(単一行の場合)は機能しますが、配列の配列に複数行の入力を取りたい場合は失敗します。scanfそして、私はあなたのコードでどのように値を返すのかわかりませんか?

多くの(ほとんど?)経験豊富なCプログラマーが疫病を避けscanf()、好む理由があります。fscanf()正しく動作させるのは難しすぎます。を使用して、この代替手段をお勧めします。sscanf()これは、と同じ実行を取得しませscanf()fscanf()

#include <stdio.h>

int main(void)
{
    char line[256];
    char sen[256];

    while (fgets(line, sizeof(line), stdin) != 0)
    {
        if (sscanf(line, "%255[^\n]", sen) != 1)
            break;
        printf("Found <<%s>>\n", sen);
    }
    int c;
    if ((c = getchar()) != EOF)
        printf("Failed on character %d (%c)\n", c, c);
    return(0);
}

これは入力行を読み取り(これを使用しfgets()てバッファオーバーフローが発生しないようにします(gets()関数を聞いた場合は、コンピュータを金属とシリコンのプールに溶かします)、sscanf()その行を処理するために使用します。これは改行を処理します。 、これは元のコードの失敗です。

char sen[20];
for (i=0;i<2;i++)
{
    scanf("%[^\n]s",sen);
    printf("%s\n",sen);
}

問題:

  1. scanf()成功したかどうかはチェックしません。
  2. 最初の反復で改行をバッファに残します。2回目の反復では、最初に読み取る文字が改行であるため、戻り値0が生成されます。これは、スキャンセットによって除外される文字です。
  3. あなたが見るジブリッシュは、おそらく入力の最初の行であり、繰り返されます。実際、制限付きループがなければ、それ以上何かを入力するのを待つことはありません。それは最初の行を何度も何度も吐き出します。

からの戻り値scanf()

scanf()(ISO / IEC 9899:1999から)の定義は次のとおりです。

§7.19.6.4scanf関数

あらすじ

 #include <stdio.h>
 int scanf(const char * restrict format, ...);

説明

2この関数は、の引数の前に引数を挿入したscanf場合と同等です。fscanfstdinscanf

戻り値

3scanf変換前に入力エラーが発生した場合、この関数はマクロEOFの値を返します。それ以外の場合、scanf関数は割り当てられた入力項目の数を返します。これは、早期のマッチングが失敗した場合に、提供された数より少なくなるか、ゼロになる可能性があります。

最初のプログラムのループが終了すると、scanf()EOFではなく0が返されたためであることに注意してください。

于 2012-10-14T19:41:45.117 に答える
3

%[^\n]改行をバッファに残します。%[^\n]%*c改行文字を食べます。いずれの場合も、%[^\n]任意の数の文字を読み取ることができ、バッファオーバーフローまたはそれ以上の事態を引き起こす可能性があります。フォーマット文字列を使用して%*[^\n]%*c、ファイルからの入力行の残りの部分をゴブリングします。たとえば、数値を読み取り、行の残りを。で破棄できます%d%*[^\n]%*c。これは、番号の後にコメントやラベルがある場合、またはその他の不要なデータがある場合に役立ちます。

于 2014-12-07T18:29:14.303 に答える
1
char sen[20];
for (i=0;i<2;i++)
{
  scanf("%[^\n]s",sen);
  printf("%s\n",sen);
  getchar();
}

これがお役に立てば幸いです...実際には「\n」はストリーム入力バッファに残ります...Eeはscanfが再度呼び出される前にそれをフラッシュする必要があります

于 2014-04-28T21:56:26.927 に答える
0

遅れていることはわかっていますが、久しぶりにCをテストしたところ、同じ問題が発生しました。
ここでの問題は、新しい行が次の反復の入力と見なされることです。

だから、これが私の解決策ですgetchar()、入力ストリームの改行を破棄するために使用します:

char s[10][25];
int i;

for(i = 0; i < 10; i++){
    printf("Enter string: ");
    scanf("%s", s[i]);
    getchar();
}

それが役に立てば幸い :)

于 2021-02-06T15:37:59.567 に答える
0

scanf("%[^\n]", sen)ループで使用しているときに発生する問題\nは、入力バッファー内にとどまり、フラッシュされないことです。その結果、次回、同じ入力構文が使用されると、を読み取り、\nそれをnull入力と見なします。この問題に対処するためのシンプルで効果的な解決策は、次を使用することです。

char sen[20];
for (i=0;i<2;i++)
{
    scanf("%[^\n]%*c",sen);
    printf("%s\n",sen);
}

%*c\n入力バッファ内の文字を削除します。

于 2021-05-25T07:25:09.653 に答える