1

多くの同様の質問が繰り返されていることを Stack Overflow で見ました。それらは、標準入力から 1 つの入力データ項目を読み取り、その有効性を確認することに関連しています。

データは integer "%d"、 double "%f"、 string "%s"、 unsigned int "%u"...のいずれかです。

そして、これらの質問の大部分に使用できる共通のマクロを開発したいと考えています。

質問例1

OPは次のよ​​うに尋ねることができます:

  • 入力データをスキャンする
  • データは整数でなければならないため、、、、...11a入力は許可されません。空白が続く整数のみが許可されます ( isspace()を参照)。aaaaa44
  • 次のような他の条件が質問に存在する可能性があります。入力整数はおよびである必要が>3あります<15

質問例2

OPは次のよ​​うに尋ねることができます:

  • 入力データをスキャンする
  • データは double でなければならないので11.2aaaaaa44.3、... 入力は許可されません。double の後に空白が続く( isspace()を参照) のみが許可されます。
  • 次のような他の条件が質問に存在する可能性があります>3.2<15.0

のような一般的なマクロを開発することは可能ですか?

#define SCAN_ONEENTRY_WITHCHECK(FORM,X,COND)
// FORM: format of the input data like "%d", "%lf", "%s"
// X: address where to store the input data
// COND: condition to add in the check of the input data

....

// example of calling the macro in the main()

int a;
SCAN_ONEENTRY_WITHCHECK("%d", &a,(a>3 && a<15))

マクロはデータをスキャンし、次の条件のいずれかに該当しない場合は、ユーザーに再入力を求めるメッセージを出力します。ユーザーが有効なデータを入力するまでそれを繰り返しますか?

基準:

  • 入力データ型は、フォーマットで示されるものと同じでなければなりません
  • 入力データの後には、 isspace()で示される空白が続く必要があります。
  • 入力データは条件が有効である必要がありますCOND
4

1 に答える 1

1

この質問に対する簡単な答えは

#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 をキャッチし、残りを消去しますabcisspace()この問題は、次の文字が (関数を使用して) 空白であることを確認すれば解決できます。

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
于 2013-04-03T16:31:38.817 に答える