2017-01-06 7 views
-6

gets()のような空白を含む文字列全体をscanf()に読み込むことはできますか?ScanfのC言語での説明

gets()機能を使用することができます。

char s[30]; 
gets(s); 

これは、一連の文字を読み取ります。 scanf()でこれを行うことはできますか?

+1

私はあなたのハウムワークスの1つを推測していますか? –

+1

['scanf'](http://en.cppreference.com/w/c/io/fscanf)を使って行を読むことはできますが、それは最善のツールではありません。代わりに['fgets'](http://en.cppreference.com/w/c/io/fgets)を使うことをお勧めします。 *** ***を使用しないでください。それは危険で悪い機能です。また、C99標準では推奨されず、C11標準から完全に削除されています。 –

+0

@SeekAddoあなたの['scanf("%30 [^ \ n] "、s);'](http://stackoverflow.com/questions/41499535/scanf-clarification-in-c-language#comment70204953_41499535)は、間違った幅制限と同じ問題がこの[回答](http://stackoverflow.com/questions/41499535/scanf-clarification-in-c-language#comment70204925_41499577) – chux

答えて

1

scanf()またはgets()機能を使用しないでください。代わりにfgets()を使用してください。しかし、上記の質問の答えを見つけてください。私が代わりにfgets()を使用するために最初に言いましたように

int main() { 
    char a[30]; 
    scanf ("%29[^\n]%*c", name); 
    printf("%s\n", a); 
    return 0; 
} 

そのも強くお勧めします。私たちは明らかに奇妙な要件を理解していません。私は文字を読むのにfgets()を使っていたでしょう。

fgets(a, size(a), stdin); 
+2

'printf("%s "、a)で' scanf( "%[^ \ n]"、a); 'を使用して、読み込みを試みた最初の文字が' '\ n''ならばUBになります。 ; '。 'scanf()'の戻り値を確認する方が良いでしょう。 – chux

+0

'scanf("%[^ \ n]%* c "、name);'は同じ[problem]を持っています(http://stackoverflow.com/questions/41499535/scanf-clarification-in-c-language#comment70204925_41499577 )。 – chux

+0

私のコンパイラでチェックして、問題を再現することができません。また、scanfでやっているのも嫌です。私はユーザーにそれを行う方法を与えたばかりです。私はこれをfgetsでどうやってできるのかについて私の投稿を編集しようとしています。 –

2

あなたはscanf()で、空白スペースを含め、ラインを読むことができますが、この機能は微妙であり、それを使用すると、非常にエラーが発生しやすいです。 変換指定子を使用すると、scanf()に文字を一致させて文字列を作成することができます('\n'文字は除く)。これを行う場合は、最大フィールド幅を指定する必要があります。この幅は一致する最大文字数を指定するため、'\0'ターミネータのためのスペースを残す必要があります。

入力ストリームの最初の文字が'\n'である可能性があります。この場合、scanf()は、改行に遭遇する前に一致がなかったので、0という値を返します。ただし、sには何も格納されないため、未定義の動作が発生する可能性があります。これを避けるには、最初にscanf()とし、%*[\n]の変換指定子を使用して、先頭の'\n'文字を破棄します。

文字列が読み取られた後、入力ストリームに追加の文字があります。少なくとも'\n'が存在し、ユーザーが最大フィールド幅を超えて入力した場合は、さらに多くの文字が含まれます。これらの余分な文字を破棄して、それ以上の入力を妨げないようにすることができます。以下のコードには、この操作を行うためのループが含まれています。

scanf()の最初の呼び出しは、改行文字以外の文字が見つかるまで、入力ストリームのすべての改行文字を消費します。 scanf()への2回目の呼び出しは常に成功するはずですが、戻り値scanf()(成功した割り当ての数)を常にチェックすることをお勧めします。この値をresultに保存しておき、文字列を印刷する前に確認してください。 scanf()が予期しない結果を返すと、エラーメッセージが出力されます。

fgets()を使用して行全体を読み取る方がよいでしょう。 fgets()は末尾の改行を保持しているので、削除することを忘れないでください。また、ユーザーが入力ストリームに残りの文字を残して、バッファが格納するより多くの文字を入力する可能性もあります。追加の入力を促す前に、余分な文字を削除することができます。

また、戻り値fgets()を確認する必要があります。この関数は、ストレージバッファの最初の要素へのポインタを返します。エラーの場合はポインタNULLを返します。以下のコードは、文字列中の末尾の改行文字を置き換え、入力ストリームから余分な文字を破棄し、fgets()への呼び出しが成功した場合にのみ文字列を出力します。それ以外の場合は、エラーメッセージが出力されます。

#include <stdio.h> 

int main(void) 
{ 
    char s[30]; 
    int result; 

    printf("Please enter a line of input:\n"); 
    scanf("%*[\n]");    // throw away leading '\n' if present 
    result = scanf("%29[^\n]", s); // match up to 29 characters, excluding '\n' 

    /* Clear extra characters from input stream */ 
    int c; 
    while ((c = getchar()) != '\n' && c != EOF) 
     continue;     // discard extra characters 

    if (result == 1) { 
     puts(s); 
    } else { 
     fprintf(stderr, "EOF reached or error in scanf()\n"); 
    } 

    printf("Please enter a line of input:\n");  
    char *ps = fgets(s, 30, stdin); // keeps '\n' character 

    if (ps) { 
     while (*ps && *ps != '\n') { 
      ++ps; 
     } 
     if (*ps) {     // replace '\n' with '\0' 
      *ps = '\0'; 
     } else { 
      while ((c = getchar()) != '\n' && c != EOF) 
       continue;   // discard extra characters 
     } 

     puts(s); 

    } else { 
     fprintf(stderr, "EOF reached or error in fgets()\n"); 
    } 

    return 0; 
} 

入力行を取得するこれらの2つの方法は全く同じではありません。ここに書かれているscanf()メソッドは、空白の行(すなわち、'\n'文字のみからなる行)を受け入れませんが、他の空白文字で構成される行を受け入れます。 fscanf()メソッドは空行を入力として受け入れます。

先頭の空白文字を無視するように許容可能である場合も、scanf()にのみ単一の呼び出しを使用することをコメントでジョナサン・レフラーによって与えられた勧告に従うことを単純に次のようになります。

result = scanf(" %29[^\n]", s); 

これは無視します改行を含む空白文字を先導する。

+1

先頭の空白やタブが重要でない場合は、 'scanf()'を2回呼び出すのではなく、 'scanf("%29 [^ \ n "、s)'を使用する方が簡単です。 2番目の 'scanf()'が何かをうまく読み込んでいることを確認する必要があります。私は '静的なインラインvoid gobble(void){int c; while((c = getchar())!= EOF && c!= '\ n'); } 'を使用し、ループを2回書き出すのではなく2回使用します。 –

+0

@ JonathanLeffler--先頭の空白が文字列内にあるかどうかは分かりませんでした。したがって、2つの呼び出しを持つわかりにくい 'scanf()'解決策です。通常は、ストリームクリアコードを関数に取り除きますが、ここには2つの異なるアプローチが示されているので、私はここにはいないと決めました。 'scanf()'からの戻り値をチェックしないのは良い言い訳ではありません。それはまだ私にとどまっていた。私はそれが常に1でなければならないと思う。まあ、私は関数にエラーがある可能性があると思います。私は編集します。 –

+0

あなたの回答が良いです。注意:1)scanf()の入力エラーを提案します。 " - >' 'scanf()のファイルの終わりまたは入力エラー' '2)' 'scanf("%* [\ n] "); 'は空白行を入力することを禁止します。 – chux