如何scanf只有整数?

时间:2014-10-27 08:39:50

标签: c scanf

我希望代码能够运行,直到用户输入整数值。

该代码适用于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

如何避免这种情况?

8 个答案:

答案 0 :(得分:26)

  1. 您选择scanf()
  2. 你把它扔进垃圾箱。
  3. 您使用fgets()获取整行。
  4. 使用strtol()将行解析为整数,检查它是否消耗了整行。
  5. 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));
    

答案 1 :(得分:4)

使用fgetsstrtol

指向s中整数表示后面的第一个字符的指针存储在p指向的对象中,如果*p\n不同,那么您有一个糟糕的投入。

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

int main(void) 
{
    char *p, s[100];
    int 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: %d\n", n);
    return 0;
}

答案 2 :(得分:3)

尝试在scanf中使用以下模式。它将一直读到行尾:

scanf("%d\n", &n)

由于getchar()将读取整行,因此您不会需要循环内的scanf。浮点数不会与scanf模式匹配,提示符将再次请求整数。

答案 3 :(得分:3)

  

我知道如何使用fgetsstrtol完成此操作,我想知道如何使用scanf()(如果可能)来完成此操作。

正如其他答案所说,scanf并非真的适合这种情况,fgetsstrtol是另一种选择(尽管fgets的缺点是{&1}} #39;难以检测到输入中的0字节,并且无法判断0字节后输入的内容(如果有的话)。

为了完整起见(假设有效输入是整数后跟换行符):

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

或者,在%n之前和之后使用%*1[\n]进行分配抑制。但请注意(来自Debian manpage):

  

虽然可以使用*赋值抑制字符来抑制转换,但这不是转换。   C标准说:&#34;执行%n指令不会增加执行完成时返回的赋值计数&#34;但是更正似乎与此相矛盾。   可能明智的做法是不对%n转换对返回值的影响做出任何假设。

答案 4 :(得分:2)

如果您已开始使用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
}

答案 5 :(得分:2)

使用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 ,则此方法不会重新提示。

答案 6 :(得分:2)

一个可能的解决方案是向后思考它:接受一个浮动作为输入,如果浮点数不是整数,则拒绝输入:

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

虽然这允许用户输入类似12.0或12e0等的内容

答案 7 :(得分:0)

也许不是最佳解决方案...但仅使用 scanfstrtol

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

typedef enum {false, true} bool;

bool isIntString(char* input ) {
    int i;
    for (i = 0; i < strlen(input); i++) {
        if(input[i] < '0' || input[i] > '9') {
            return false;
        }
    }
    return true;
}

int main()
{
    char s[10];
    char *end;
    bool correct = false;
    int result;


    printf("Type an integer value: ");
    do {
        scanf("%s",s);
        if ( isIntString(s)) {
            correct = true;
            result = strtol(s, &end, 10);
            break;
        } else {
            printf("you typed %s\n",s);
            printf("\ntry again: ");
        }
    } while (!correct);


    printf("Well done!! %d\n",result);

    return 0;
}