web-dev-qa-db-ja.com

整数のみをスキャンする方法は?

ユーザーが整数値を入力するまでコードを実行したい。

コードはcharおよびchar配列に対して機能します。

私は次のことをしました:


#include<stdio.h>
int main()
{
    int n;
    printf("Please enter an integer: ");
    while(scanf("%d",&n) != 1)
    {
        printf("Please enter an integer: ");
        while(getchar() != '\n');
    }
    printf("You entered: %d\n",n);
    return 0;
}

問題は、ユーザーがフロート値を入力した場合、scanfがそれを受け入れます。

Please enter an integer: abcd
Please enter an integer: a
Please enter an integer: 5.9
You entered: 5

どうすればそれを回避できますか?

11
user1336087
  1. scanf()を使用します。
  2. あなたはそれを箱に捨てます。
  3. fgets()を使用して、行全体を取得します。
  4. strtol()を使用して、行を整数として解析し、行全体を消費したかどうかを確認します。
char *end;
char buf[LINE_MAX];

do {
     if (!fgets(buf, sizeof buf, stdin))
        break;

     // remove \n
     buf[strlen(buf) - 1] = 0;

     int n = strtol(buf, &end, 10);
} while (end != buf + strlen(buf));

fgetsstrtolを使用します。

sの整数表現に続く最初の文字へのポインタは、pが指すオブジェクトに格納されます。*p\nと異なる場合、入力が間違っています。

#include <stdio.h>
#include <stdlib.h>

int main(void) 
{
    char *p, s[100];
    long n;

    while (fgets(s, sizeof(s), stdin)) {
        n = strtol(s, &p, 10);
        if (p == s || *p != '\n') {
            printf("Please enter an integer: ");
        } else break;
    }
    printf("You entered: %ld\n", n);
    return 0;
}
7
David Ranieri

fgetsstrtolを使用してこれを行う方法を知っています。scanf()(可能な場合)を使用してこれを行う方法を知りたいです。

他の答えが言うように、scanfはこれに本当に適していません。fgetsstrtolは代替です(fgetsには難しいという欠点があります)入力で0バイトを検出し、0バイトの後に入力された内容がある場合はそれを判別することは不可能です)。

完全を期すために(および有効な入力が整数とそれに続く改行であると仮定すると):

while(scanf("%d%1[\n]", &n, (char [2]){ 0 }) < 2)

あるいは、%nの前後に%*1[\n]を割り当て抑制とともに使用します。ただし、注意してください( Debian manpage から):

これは変換ではありませんが、*割り当て抑制文字で抑制することができます。 C標準では、「%nディレクティブを実行しても、実行の完了時に返される割り当てカウントは増加しません」とありますが、正誤表はこれと矛盾しているようです。おそらく、戻り値に対する%n変換の効果について仮定を行わないのが賢明です。

4
mafso

scanfで次のパターンを使用してみてください。行の終わりまで読み取ります:

_scanf("%d\n", &n)
_

scanfは行全体を読み取るため、ループ内でgetchar()は必要ありません。フロートはscanfパターンと一致せず、プロンプトは再び整数を要求します。

4
vicsana1

考えられる解決策は、逆に考えることです。フロートを入力として受け入れ、フロートが整数でない場合は入力を拒否します。

int n;
float f;
printf("Please enter an integer: ");
while(scanf("%f",&f)!=1 || (int)f != f)
{
    ...
}
n = f;

これにより、ユーザーは12.0や12e0などを入力できます。

3
hcs

scanfを使用するように設定されている場合、次のようなことができます。

int val;
char follow;  
int read = scanf( "%d%c", &val, &follow );

if ( read == 2 )
{
  if ( isspace( follow ) )
  {
    // input is an integer followed by whitespace, accept
  }
  else
  {
    // input is an integer followed by non-whitespace, reject
  }
}
else if ( read == 1 )
{
  // input is an integer followed by EOF, accept
}
else
{
  // input is not an integer, reject
}
3
John Bode

fgets()を使用する方が優れています。

入力にscanf()のみを使用して解決するには、intおよび次のcharをスキャンします。

int ReadUntilEOL(void) {
  char ch;
  int count;
  while ((count = scanf("%c", &ch)) == 1 && ch != '\n')
    ; // Consume char until \n or EOF or IO error
  return count;
}

#include<stdio.h>
int main(void) {
  int n;

  for (;;) {
    printf("Please enter an integer: ");
    char NextChar = '\n';
    int count = scanf("%d%c", &n, &NextChar);
    if (count >= 1 && NextChar == '\n') 
      break;
    if (ReadUntilEOL() == EOF) 
      return 1;  // No valid input ever found
  }
  printf("You entered: %d\n", n);
  return 0;
}

このアプローチは、ユーザーが次のような空白のみを入力する場合は再プロンプトしません Enter

3
chux