scanf を使用してユーザー入力を検証するにはどうすればよいですか。今、私はこのようなものを持っていますが、うまくいきません。
注:scanf検証が機能することを検証するためだけにatoiがあります。
scanf("%[0987654321.-]s",buf);
i = atoi(buf);
if(i)
index = i;
失敗するとポインターが不明な位置に残るため、使用scanf()
は通常、ユーザー入力には適していません。FILE
これscanf
は、「スキャン形式」の略であり、ユーザー入力よりも形式化されていないものがほとんどないためです。
fgets()
を使用して行を取得し、続いsscanf()
て文字列を実際にチェックして処理することをお勧めします。
これにより、必要な文字の文字列を (ループまたは正規表現を使用して) チェックすることもできますscanf
。
例として、orを使用scanf()
すると最初の数字以外の文字で停止するため、 のような末尾のエラーはキャッチされず、127 が返されます。また、制限なしで使用すると、バッファ オーバーフローが発生します。"%d"
"%f"
"127hello"
%s
本当に[]
フォーマット指定子を使用する必要がある場合 (scanf
または sscanf
で)、その後にs
.
また、そのアドバイスを使用した堅牢な入力ソリューションについては、こちらを参照してください。入力行を文字列としてsscanf
取得したら、心ゆくまで行うことができます。
文字列を入力として検証したいようです。文字列に 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 は何かが正しくない場合に例外をスローします。
私のアプローチは、ユーザー入力を文字列に読み取り、それを 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 拡張です)。string
GNU を使用していない場合は、string
手動で割り当てて、scanf()
フォーマットの最大サイズを制限してください。
このアプローチにより、エラー処理が改善されます。
の最初の引数に指定したのscanf
は、変換指定子です。scanf
入力をフォーマットに変換しようとしますが、それが何と一致するのか驚くかもしれません:)
最初に行うべきチェックは、scanf からの戻り値です (一致する入力の数がわかります)。期待した数値が得られない場合は、入力に何か問題があることがわかります。あなたの場合、それは1でなければなりません。
if( scanf("%[0987654321.-]s", buf) == 1 )
{
if( sanit_check( buf ) )
{
/* good input */
}
else
{
/* invalid input */
}
}
else
{
/* invalid input */
}
それを超えて、実行するように要求した変換について、独自の健全性チェックを行う必要がありますscanf
。
数値のみを読み取ろうとしている場合は、次を使用します。
int i;
scanf( "%d", &i );
より複雑なチェックを行う必要がある場合は、自分で行う必要があります。Scanf はそれを行いません。
「buf」はポインタである必要があります。値渡しをしているようです。