0

我有这段代码来验证用户输入。条件:输入的值只能是零或正数。不接受负值和字母字符。

这是我的代码,它一直在循环:

#include <stdio.h>

int main ()
{
   int a, b, c, d;

   printf ("enter value for a:");
   do {
      b = 0;
      scanf ("%d", &a);
      if (!isdigit(a)) {
         printf("Number must be numeric!:\n");
         b++;
      }
      else if (a < 0) {
         printf ("number must be postive\n");
         b++;
      } else {
         printf("\neverything is goood\n");
      }
   } while (b != 0);
}
4

5 回答 5

4

isdigit()期待一个 ASCII 编码的字符,但是scanf使用%d参数将 ASCII 编码的数字(字符串)转换为实际数字。

IE。如果您输入'1'ASCII 码0x31scanf("%d",...会将其转换为值1。ASCII 码 1不是数字。

要解决此问题,请执行以下任一操作:

  • 制作a类型char并使用scanf格式说明符%c,然后isdigit()会做你想做的事。
  • 用于strtol读取多个字符并使用char **endptr参数执行您自己的错误检查。

此外,您应该打开编译器警告并包含包含isdigit()函数的头文件,ctype.h.

于 2012-07-15T01:39:03.717 回答
1

我可以发现您的代码存在以下几个问题:

  1. 您使用已经将输入解析为整数值的格式说明符scanf%d因此,无需检查它是否为数字isdigit。事实上,isdigit是检查一个十进制数字字符,所以你的用法是不正确的。
  2. 你从不检查scanf退货。你应该。如果出现错误(即值不是数字),则不会从流中删除输入。换句话说,你会在试图一遍又一遍地解析相同的错误值时陷入困境。
  3. 您有未使用的变量并且忘记包含某些头文件。但在您的情况下,这些都是次要的事情(但在某些情况下可能是主要的!)。

话虽如此,这里有一些可能适合您的代码:

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

static void skip_input(FILE *stream)
{
    int c;
    do {
        c = fgetc (stream);
    } while (c != EOF && c != '\n');
}

int main()
{
    int a;
    int r;

    printf("Please enter a value: ");

    for (;;) {
        r = scanf("%d", &a);
        if (r == EOF)
            return EXIT_FAILURE;
        if (r != 1) {
            printf("Number must be numeric!\n");
            skip_input(stdin);
        } else if (a < 0) {
            printf("Number must be postive\n");
            skip_input(stdin);
        } else {
            printf("Everything is goood\n");
            break;
        }
    }

    return EXIT_SUCCESS;
}

希望能帮助到你。

于 2012-07-15T01:50:26.493 回答
1

一旦用户出错,b 总是 > 0。您需要在输入正确信息后添加一行设置 b = 0(即在您的 printf("\neverything is good\n"); 语句之后。请确定将 { & } 添加到它前面的 else 语句中,以便 printf & new b = 0; 语句将包含在该分支中)

于 2012-07-15T01:33:21.953 回答
0

这里有几个问题。

首先是没有检查 scanf() 的返回值。如果输入可用,则 scanf 返回已分配的变量数,在这种情况下可以是 0 或 1(因为您只尝试分配一个变量)。如果用户输入非数字字符,则循环将重复执行而无需等待更多用户输入,因为有可用输入但它永远不会匹配您的“%d”转换。如果你想使用 scanf() 那么你必须检查返回值。如果返回值为零,则输入了一个非数字值,这意味着您必须通过读取直到行尾将该值从输入缓冲区中清除。如果返回值等于 EOF,那么要么发生了 I/O 错误,要么您到达了流的末尾。

例程 isdigit() 接受一个整数参数,但它希望该整数值代表一个字符。由于您使用 scanf() 将输入转换为整数,因此存储在 a 中的值不再代表字符;它代表一个实际数字。因此,只有当用户输入与数字字符对应的数字时,对 isdigit() 的调用才会返回真值。在我的语言环境中,这意味着只有当用户输入介于 48 和 57 之间的数字(包括 48 到 57)时,验证才会成功。如果您使用的是 scanf(),则不需要进行 isdigit() 检查,因为仅当用户输入数字值时,scanf() 才会返回值 1。

然而,老实说,如果我可以避免它,我不会使用 scanf() 来读取用户输入,因为如果用户输入错误则需要刷新输入缓冲区。我不完全确定您的要求是什么,但我假设您应该从命令行读取一个正整数并且位数无关紧要。

在这种情况下,您可能希望使用 fgets() 读取用户输入,然后使用 strtol() 将值转换为有符号长整数并同时执行验证:

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <errno.h>
#include <ctype.h>
#include <string.h>

int main () {
  long result;
  long len;
  int is_valid = 0;
  char buf[128];
  char *arg;
  char *end;

  while (!is_valid) {

    /* Prompt the user for the integer. */
    printf("Enter a non-negative integer: ");
    if (fgets(buf, sizeof(buf), stdin) == NULL) {
      printf("Giving up so soon?\n");
      break;
    }

    /* Verify that the input doesn't exceed our buffer length. */
    len = strlen(buf);
    if (buf[len] != '\n') {
      printf("Input buffer length exceeded - aborting.\n");
      exit(1);
    }

    /* Skip any leading whitespace. */
    for (arg = buf; isspace(*arg); arg++);

    /* Attempt to convert the argument. */
    errno = 0;
    result = strtol(arg, &end, 10);
    if (errno == EINVAL) {
      printf("Please enter a numeric value.\n");
      continue;
    }
    if (errno == ERANGE) {
      printf("Numeric value out of range.\n");
      continue;
    }

    /* Check for non-whitespace characters after the end of the integer. */
    for (; isspace(*end); end++);
    if (*end != '\0') {
      printf("Please enter a numeric value.\n");
      continue;
    }

    /* Verify that the number is non-negative. */
    if (result < 0) {
      printf("Please enter a positive value.\n");
      continue;
    }

    /* The number is valid. */
    printf("Excellent!\n");
    is_valid = 1;
  }

  return 0;
}

这并不完美。如果超过输入缓冲区长度则中止并不完全是用户友好的。但是,它应该处理验证问题。

于 2012-07-15T02:52:48.357 回答
0

您正在使用 b 作为错误标志。

在“一切都很好”块中,尝试设置b=0;
此外,如果你这样做,你可以摆脱这些b++;行,并简单地初始化b=1;
你应该只在b++你需要报告用户搞砸了多少次时才这样做,我就是假设你不需要?

于 2012-07-15T01:33:19.863 回答