5

scanf を使用してユーザー入力を検証するにはどうすればよいですか。今、私はこのようなものを持っていますが、うまくいきません。

注:scanf検証が機能することを検証するためだけにatoiがあります。

scanf("%[0987654321.-]s",buf);

i = atoi(buf);

if(i)
    index = i;
4

6 に答える 6

15

失敗するとポインターが不明な位置に残るため、使用scanf()は通常、ユーザー入力には適していません。FILEこれscanfは、「スキャン形式」の略であり、ユーザー入力よりも形式化されていないものがほとんどないためです。

fgets()を使用して行を取得し、続いsscanf()て文字列を実際にチェックして処理することをお勧めします。

これにより、必要な文字の文字列を (ループまたは正規表現を使用して) チェックすることもできますscanf

例として、orを使用scanf()すると最初の数字以外の文字で停止するため、 のような末尾のエラーはキャッチされず、127 が返されます。また、制限なしで使用すると、バッファ オーバーフローが発生します"%d""%f""127hello"%s

本当に[]フォーマット指定子を使用する必要がある場合 (scanf または sscanfで)、その後にs.

また、そのアドバイスを使用した堅牢な入力ソリューションについては、こちらを参照してください。入力行を文字列としてsscanf取得したら、心ゆくまで行うことができます。

于 2009-01-19T01:44:52.137 に答える
5

文字列を入力として検証したいようです。文字列に double または int が含まれていることを検証するかどうかによって異なります。以下は double をチェックします (先頭と末尾の空白は許可されています)。

bool is_double(char const* s) {
    int n;
    double d;
    return sscanf(s, "%lf %n", &d, &n) == 1 && !s[n];
}

sscanf変換されたアイテムを返します ('%n' なし)。n処理された入力文字の量に設定されます。すべての入力が処理された場合、s[n] は終端の 0 文字を返します。2 つの書式指定子の間のスペースは、オプションの末尾の空白を考慮します。

以下は int をチェックします。同じ手法が使用されています。

bool is_int(char const* s) {
    int n;
    int i;
    return sscanf(s, "%d %n", &i, &n) == 1 && !s[n];
}

ここで質問がありました。これには、lexical_cast などのブーストの文字列ストリームや関数を使用するなど、これを行うためのより C++ 的な方法も含まれています。scanf やアドレスに '%' を渡すのを忘れやすいため、通常は scanf などの関数よりも優先する必要があります。scanf はそれを認識しませんが、代わりに任意のことを行いますが、たとえば、lexical_cast は何かが正しくない場合に例外をスローします。

于 2009-01-19T01:45:25.693 に答える
1

私のアプローチは、ユーザー入力を文字列に読み取り、それを long を使用して変換することstrtol()です。strtol()処理に失敗した入力文字列の最初の文字へのポインターを返すため、この文字を確認することで、次のように完全な文字列が解析されたかどうかがわかります。

char *string;
char *endptr;
long result;

scanf("%as", string);
errno = 0;
result = strtol(string, &endptr, 10);
if (ERANGE == errno)
    printf("Input number doesn't fit into long\n");
else if (*endptr)
    printf("%s is not a valid long number - it contains invalid char %c\n",
        string, *endptr);
else
    printf("Got %ld\n", result);

このスニペットでは、フォーマット修飾子「a」を使用して十分な大きscanf()さを自動的に割り当てるように指示されています(これは GNU 拡張です)。stringGNU を使用していない場合は、string手動で割り当てて、scanf()フォーマットの最大サイズを制限してください。

このアプローチにより、エラー処理が改善されます。

于 2009-01-19T07:27:40.277 に答える
0

の最初の引数に指定したのscanfは、変換指定子です。scanf入力をフォーマットに変換しようとしますが、それが何と一致するのか驚くかもしれません:)

最初に行うべきチェックは、scanf からの戻り値です (一致する入力の数がわかります)。期待した数値が得られない場合は、入力に何か問題があることがわかります。あなたの場合、それは1でなければなりません。

if( scanf("%[0987654321.-]s", buf) == 1 )
{
      if( sanit_check( buf ) ) 
      {
      /* good input */
      }
      else
      {
      /* invalid input */
      }
}
else 
{
/* invalid input */
}

それを超えて、実行するように要求した変換について、独自の健全性チェックを行う必要がありますscanf

于 2009-01-19T01:43:18.583 に答える
-1

数値のみを読み取ろうとしている場合は、次を使用します。

int i;
scanf( "%d", &i );

より複雑なチェックを行う必要がある場合は、自分で行う必要があります。Scanf はそれを行いません。

于 2009-01-19T01:38:25.817 に答える
-4

「buf」はポインタである必要があります。値渡しをしているようです。

于 2009-01-19T01:43:37.053 に答える