【问题标题】:Skipping scanf for character input with %d使用 %d 跳过 scanf 字符输入
【发布时间】:2021-07-31 20:41:46
【问题描述】:
  int valid = 0;
  while (!valid) {

    printf("\nEnter number of characters (1-30)> ");
    scanf("%d", & n);
    printf("\nInclude numbers (Y/N)> ");
    scanf(" %c", & nf);
    printf("\nInclude symbols (Y/N)> ");
    scanf(" %c", & sf);
    //cond1 and cond2 initialized here
    if (cond1 && cond2)
      valid = 1;
    else
      printf("Invalid input");
  }

我需要为第一次整数扫描实现错误输入检测功能。如果用户输入一个字符而不是一个整数,则跳过第二个 scanf 并直接进入第三个 scanf。如果在 %d 上输入字符,如何阻止这种情况发生?如果用户输入字符而不是数字,我想再次要求输入

【问题讨论】:

  • 您还没有说明是要终止程序还是再次请求输入。
  • 请重新处理您的问题以包含minimal reproducible example。考虑在您对用户的说明中使用更具体的词,例如 “输入 1-30 位数字”,如果这是您想要的。或者 “输入 1 到 30 个字母字符”,如果这是你想要的。 characters 不明确。整个 ASCII 字符表是 characters
  • @alex01011 如果用户输入的是字符而不是数字,我想再次请求输入
  • 您最后的评论应该是您帖子的一部分,而不是评论。请编辑您的帖子。
  • cond1cond2 在您的代码中创建/初始化/设置在哪里?

标签: c loops io scanf


【解决方案1】:

只检查scanf()的返回值,在你的情况下:

if ((scanf("%d", &n) != 1) /* should return 1 if 1 int is read */
{ 
  fprintf(stderr,"Input not a number\n");
  exit(EXIT_FAILURE) /* include stdlib or just use return */
}

请注意,scanf() 不提供任何防止算术溢出的保护,在大数字的情况下。您可能希望使用 fgets() 并稍后使用 strtol() 等函数解析该字符串以确保安全。

示例:https://godbolt.org/z/oaMhac983

如果您想再次要求输入,我建议您改用fgets(),然后检查该字符串是否有非数字字符。

您可以使用strspn(),它返回第一个参数中出现在第二个参数中的字符数。

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

#define MAX_N 13 /* save space \0 and \n */

int main(void) {
  int num = 0;
  char n[MAX_N] = {0};
  char *numbers = "-+0123456789";

  while (1) {
    if (fgets(n, MAX_N, stdin) == NULL) /* check return value of fgets() */
    {
      exit(EXIT_FAILURE);
    }
    if (strspn(n, numbers) ==
        strlen(n) - 1) /* only numbers were read (exclude '\n')*/
    {
      if (sscanf(n, "%d", &num) != 1) /* check return value of scanf() */
      {
        exit(EXIT_FAILURE);
      }
      break;
    }
  }

  printf("%d\n", num);

  return 0;
}

示例:https://godbolt.org/z/d5KTrTGGE

【讨论】:

  • 如果我尝试在我的代码中: if ((scanf("%d", &n) != 1)) continue;它最终成为一个无限循环,而不是在下一次迭代中再次请求输入。
  • @zerb 我更新了我的答案。您可以使用它,或者使用 Vlad's,如果您希望它更简单,您可以修改我的以使用 isdigit() 函数。
  • char *numbers = "0123456789"; 对于 "-123\n", "+456\n", "0x789\n", "123" 这样的输入是不够的。
  • @chux-ReinstateMonica 我已经包含了前缀选项,至于十六进制选项,它需要在scanf() 格式说明符中进行修改。
【解决方案2】:

你的意思好像是这样的

#include <stdio.h>

int main(void) 
{
    int n;
    const int MIN = 1, MAX = 30;
    
    do
    {
        printf( "\nEnter number of characters (%d-%d)> ", MIN, MAX );
        
        if ( scanf( "%d", &n ) != 1 )
        {
            clearerr( stdin );
            scanf( "%*[^\n]" );
            scanf( "%*c" );
            n = 0;
        }
    } while ( n < MIN || MAX < n );
    
    printf( "n = %d\n", n );
    
    return 0;
}

程序输出可能看起来像

Enter number of characters (1-30)> Hello
Enter number of characters (1-30)> 0
Enter number of characters (1-30)> 31
Enter number of characters (1-30)> Bye
Enter number of characters (1-30)> 10
n = 10

或者类似的东西

#include <stdio.h>

int main(void) 
{
    int n = 0;
    const int MIN = 1, MAX = 30;
    
    printf( "\nEnter number of characters (%d-%d)> ", MIN, MAX );
        
    if ( scanf( "%d", &n ) != 1 )
    {
        clearerr( stdin );
        scanf( "%*[^\n]" );
        scanf( "%*c" );
        n = 0;
    }

    char nf, sf;
    
    if ( n != 0 )
    {
        printf("\nInclude numbers (Y/N)> ");
        scanf( " %c", &nf );
    }
    else
    {
        printf("\nInclude symbols (Y/N)> ");
        scanf(" %c", &sf);
    }
    
    return 0;
}

【讨论】:

    【解决方案3】:

    如果在 %d 上输入字符,我该如何阻止这种情况发生?

    检查scanf()的返回值。

    scanf("%d", &amp;n); 在各种条件下返回 3 个值中的 1 个:

    1 扫描成功。在n 中扫描int 值。
    0 由于非数字输入而导致扫描失败(OP 感兴趣的情况)。 n 中的值保持不变。
    由于没有更多输入(文件结尾),EOF 扫描失败。 n 中的值保持不变。
    由于输入错误(罕见),EOF 扫描失败。 n 中的值不确定。

    do { 
      printf("\nEnter number of characters (1-30)> ");
      int retval = scanf("%d", &n);
      if (retval == EOF) {
        printf("End of file or input error.  Quitting\n");
        exit(-1);
      }
      if (retval == 0) {
        // read in rest of line (except \n) and toss it.
        scanf("%*[^\n]");
        continue; 
      }
      // If here, valid `int` input read, now testfor range.
    } while (n < 1 || n > 30);
    
    ....
    

    考虑编写helper function 来编写提示并读取int

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多