この質問に対する簡単な答えは
#define SCAN_ONEENTRY_WITHCHECK(FORM,X,COND)\
while(scanf(" "FORM, X)<1 || !(COND))
printf("Invalid input, enter again: ");
次の方法でコードで上記のマクロを呼び出す
int a;
SCAN_ONEENTRY_WITHCHECK("%d", &a, (a>3 && a<15))
これに等しい
int a;
while(scanf(" %d", &a)<1 || !(a>3 && a<15))
printf("Invalid input, enter again: ");
しかし、上記の答えは間違っています。たとえば、ユーザーが入力aaa
として入力すると、aaa
入力がscanf(" %d", &a)
. そのため、ユーザーがそのような入力を入力した場合に stdin をクリーンアップするものを追加する必要があります。を追加scanf("%*[^\n]")
すると、その解決策になる可能性があります。上記のコードは次のようになります
int a;
while(scanf(" %d", &a)<1 || !(a>3 && a<15)) {
scanf("%*[^\n]"); // clean stdin
printf("Invalid input, enter again: ");
}
ただし、上記のコードにはまだ制限があります。たとえば、ユーザーが有効な整数 ( 20
) を入力すると、積分は条件を尊重しません(a>3 && a<15)
。この場合、stdin は既にクリーンアップされているため、クリーンアップする必要はありません。そうしないと、ユーザーは入力データを 2 回要求されます。この問題は、次の解決策で解決できます。
int a;
int c;
while((c=(scanf(" %d", &a)<1)) || !(a>3 && a<15)) {
if (c) scanf("%*[^\n]"); // clean stdin
printf("Invalid input, enter again: ");
}
上記のコードは基準input data should be followed by white space
を尊重しません。たとえば、ユーザーが入力10abc
として入力した場合、上記のコードは入力整数として 10 をキャッチし、残りを消去しますabc
。isspace()
この問題は、次の文字が (関数を使用して) 空白であることを確認すれば解決できます。
int a;
char tmp;
int c;
while((c=(scanf(" %d%c", &a, &tmp)!=2 || !isspace(tmp))) || !(a>3 && a<15)) {
if (c) scanf("%*[^\n]"); // clean stdin
printf("Invalid input, enter again: ");
}
さて、マクロに戻りたいと思います。マクロコードは次のようになります。
#define SCAN_ONEENTRY_WITHCHECK(FORM,X,COND) \
do {\
char tmp;\
int c;\
while ((c=(scanf(" "FORM"%c", X, &tmp)!=2 || !isspace(tmp)))\
|| !(COND)) {\
if (c) scanf("%*[^\n]");\
printf("Invalid input, please enter again: ");\
}\
} while(0)
マクロの追加については、このリンクdo {...} while(0)
で説明できます
上記のマクロは別の方法で書くことができます
#define SCAN_ONEENTRY_WITHCHECK(FORM,X,COND) \
do {\
char tmp;\
while(((scanf(" "FORM"%c",X,&tmp)!=2 || !isspace(tmp)) && !scanf("%*[^\n]"))\
|| !(COND)) {\
printf("Invalid input, please enter again: ");\
}\
} while(0)
マクロの使用例:
int main()
{
int decision;
double q;
char buf[32];
printf("Input data, valid choice 1 or 0: ");
SCAN_ONEENTRY_WITHCHECK("%d",&decision,(decision==0 || decision==1));
printf("You have entered good input : %d\n", decision);
printf("Input unsigned double: ");
SCAN_ONEENTRY_WITHCHECK("%lf",&q, (q == (unsigned int) q));
printf("You have entered good input : %lf\n", q);
printf("Input name: ");
SCAN_ONEENTRY_WITHCHECK("%s",buf, (strcmp(buf,"kallel")==0));
printf("You have entered good input : %s\n", buf);
printf("Input data should be valid integer: ");
SCAN_ONEENTRY_WITHCHECK("%d",&decision,1);
// COND is 1 ==> we do not have any check in the input integer
printf("You have entered good input : %d\n", decision);
}
実行
$ ./test
Input data, valid choice 1 or 0: 4
Invalid input, please enter again: a4
Invalid input, please enter again: a1
Invalid input, please enter again: 1a
Invalid input, please enter again: 1
You have entered good input : 1
Input unsigned double: 2.3
Invalid input, please enter again: a.0a
Invalid input, please enter again: 2.0a
Invalid input, please enter again: a2.0
Invalid input, please enter again: 2.0
You have entered good input : 2.000000
Input name: an
Invalid input, please enter again: anyad
Invalid input, please enter again: adny
Invalid input, please enter again: any
You have entered good input : any
Input data should be valid integer: 2.5
Invalid input, please enter again: -454f
Invalid input, please enter again: -454
You have entered good input : -454