ほとんどの人が言うように、fgets(..., stdin)
この問題を処理するには を使用することをお勧めします。
次のリンクでは、確実なマクロscanf()
を使用して、より安全な方法に置き換えることができる安全で正しい手法を提案しました。
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;
}
必要に応じて の値を調整MAXBUFF
する必要があります...
マクロsafe_scanf()
はかなりしっかりしています
が、マクロ アプローチの使用にはいくつかの弱点があります:
パラメータの型チェックの欠落、「戻り値」の欠落 (これは、intscanf()
を返す「true」関数と、エラー チェックのための貴重な情報) など。
すべての問題には解決策がありますが、それは別のトピックの一部です...
おそらく、最も正確な解決策は、との組み合わせに結合しmy_scanf()
てライブラリを呼び出すことにより、可変数のパラメーターを持つ関数を定義することです。ここにコードがあります: stdarg.h
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() にはプロトタイプがあります
int my_scanf(const char* fmt, const int maxbuff, ...);
他の-likefmt
と同じように動作するフォーマット文字列を受け入れます。2 番目のパラメーターは、標準入力 (キーボード) から有効に受け入れられる文字
の最大数です。
戻り値はintです。意味がないか、何らかの入力エラーが発生した場合です。負でない値が返された場合、標準関数またはによって返される値と同じです。 scanf()
EOF
maxbuff
sscanf()
vsscanf()
関数内では、'\0' 文字を追加するための余地ができるmaxbuff
ため、1 ずつインクリメントされます。
の正でない値はすぐに破棄されます。(キーボード)から読み取られる文字列を読み取り、'\n' を含む最大文字数の余地があります。ユーザーが非常に長い文字列を入力した場合、文字列は切り捨てられます。次の '\n' ( ENTER )
までのすべての文字を破棄するには、ある種の「フラッシュ」メカニズムが必要です。そうでない場合、次のキーボード読み取りで古い文字が使用される可能性があり、まったく望ましくありません。
「フラッシュ」の条件は、読み取り後に '\n' に達していないことです。
これは、次の場合にのみ当てはまります。fgets()
maxbuff
fgets()
stdin
maxbuff
fgets()
stdin
buffer[maxbuff - 1]
'\0' にも '\n' にも等しくありません。
(確認してください! )最後に、マクロと関数
の適切な組み合わせを使用して、パラメーターの可変リストを処理します。 stdarg.h
vsscanf()