ほとんどの人が言うように、fgets(..., stdin)
を使用してこの問題を処理する方が良いです。
次のリンクで
、私はあなたが固体マクロによって、より安全な方法でscanf()
を交換してみましょう、安全で正しい手法を提案している:
A macro that safely replaces scanf()
私が持っているマクロ次のプログラムに示すように、提案された(互換C99コンパイラでの作業)、safe_scanf()
ある:
#include <stdio.h>
#define safe_scanf(fmt, maxb, ...) { \
char buffer[maxb+1] = { [maxb - 1] = '\0' }; \
fgets(buffer, maxb+1, stdin); \
if ((buffer[maxb - 1] != '\0') && (buffer[maxb - 1] != '\n')) \
while(getchar() != '\n') \
; \
sscanf(buffer, fmt, __VA_ARGS__); \
}
#define MAXBUFF 20
int main(void) {
int x; float f;
safe_scanf("%d %g", MAXBUFF+1, &x, &f);
printf("Your input was: x == %d\t\t f == %g", x, f);
return 0;
}
マクロsafe_scanf()
はかなりしっかりしているが、あなたは...あなたのニーズに応じてチューンに
をMAXBUFF
の値を持つことになり、
マクロ的なアプローチを使用して、いくつかの弱点があります。
ミッシング型チェックのパラメータについては、戻り値がありません(実際には「scanf()
関数とは異なりますが、を返し、エラーチェックのための貴重な情報を返します)。
問題が解決策を持っているが、それは別のトピックの一部であるすべての...
はたぶん、ほとんどの厳密解を組み合わせ、関節、stdarg.h
ライブラリを呼び出すことによって、パラメータの数が可変で機能my_scanf()
を定義することですfgets()
およびvsscanf()
である。ここでは、コードを持っている:(
#include <stdio.h>
#include <stdarg.h>
int my_scanf(const char* fmt, const unsigned int maxbuff, ...) {
va_list ptr;
int ret;
if (maxbuff <= 0)
return EOF; /* Bad size for buffer[] */
char buffer[maxbuff+1];
buffer[maxbuff-1] = '\0'; /* Quick buffer cleaning... */
if (fgets(buffer, maxbuff+1, stdin) == NULL)
return EOF; /* Error detected */
else {
if ((buffer[maxbuff-1] != '\n') && (buffer[maxbuff-1] != '\0'))
/* Condition logically equivalent to:
fgets() has not reached an '\n'
*/
while (getchar() != '\n')
; /* "Flushing" stdin... */
va_start(ptr, maxbuff);
ret = vsscanf(buffer, fmt, ptr);
va_end(ptr);
return ret;
}
}
#define MAXBUFF 20
int main(void) {
int x;
float z;
int scanf_ret = my_scanf("%d %g", MAXBUFF, &x, &z);
printf("\nTest:\n x == %d\n z == %g\n scanfret == %d", x, z, scanf_ret);
getchar();
return 0;
}
機能my_scanfを)それは他のどのscanf()
様が行うのと同じように動作フォーマット文字列fmt
を受け入れプロトタイプ
int my_scanf(const char* fmt, const int maxbuff, ...);
を持っています。
第2パラメータは、文字のの最大数であり、標準入力(キーボード)から効果的に受け入れられます。
戻り値はであり、maxbuff
に意味がない場合、または入力エラーが発生した場合はEOF
となります。負でない値が返された場合は、標準関数sscanf()
またはvsscanf()
によって返される値と同じです。
fgets()
は、追加の '\ 0'文字のための余裕があるため、maxbuff
は1でインクリメントされます。
maxbuff
の非正の値はすぐに破棄されます。
fgets()
文字列は、maxbuff
文字( '\ n'を含む)の大文字でstdin
(キーボード)から読み取られます。
ユーザーが非常に長い文字列を入力した場合、buが切り捨てられ、すべての文字を次の '\ n'(ENTER)に破棄するには、ある種の "フラッシュ"メカニズムが必要です。そうでない場合、次のキーボードの読みは古い文字を持つ可能性があります。
「フラッシング」の条件は、fgets()
がstdin
を読み取った後に '\ n'に達していないことです。
これは、buffer[maxbuff - 1]
が '\ 0'でも '\ n'でもない場合にのみ適用されます。
(はそれをチェック!)
最後に、stdarg.h
マクロと機能vsscanf()
のappropiateの組み合わせは、パラメータの変数リストを処理するために採用されています。
討議[こちら](http://stackoverflow.com/questions/9457325/how-to-use-sscanf-correctly-and-safely) –
フォーマット文字列内で 'MAX_STR_LEN'をどのように使うことができますか? – amulous
@amulous、厳密なANSI Cなので、実際の文字列変数には実際にアクセスできません。私はする必要があります:char * somestringし、malloc ... – tomdavies