如何防止用户输入比C中要求的更多或更少的输入?

时间:2017-01-29 01:28:13

标签: c input fgets scanf

我希望用户只输入两个整数,但不能超过两个或少于两个。此外,在无效输入时,我希望打印错误并提示用户再次输入两个整数。用户应输入由空格分隔的两个整数,而不是换行符。因此,例如:
1)有效输入为:1 2
2)输入无效:1
3)输入无效:1 2 3

我尝试了以下两种方法:

#include<stdio.h>

int main(){

   int first;
   int second;
   printf("Enter input:\n");
   int returnValue = scanf("%d %d", &first, &second);
   while(returnValue != 2){
        printf("Invalid input. Please enter again: \n");
        returnValue = scanf("%d %d", &first, &second);
   }
   printf("First: %d Second: %d\n", first, second);
   return 0;
}

在涉及scanf的第一种方法中,我无法阻止用户在换行符上输入每个整数。我也不能将输入限制为仅2个数字。也就是说,如果用户输入的整数超过2个,则程序接受前2个整数并忽略第3个整数。我想在那种情况下打印错误。

我的另一种方法涉及fgets和sscanf:

#include<stdio.h>

int main(){

  int first;
  int second;
  printf("Enter input:\n");
  char line[20];
  fgets(line, sizeof(line), stdin);
  int returnValue = sscanf(line, "%d %d", &first, &second);

  while(returnValue != 2){
     printf("Invalid input. Please enter again: \n");
     fgets(line, sizeof(line), stdin);
     returnValue = sscanf(line, "%d %d", &first, &second);
  }

  printf("First: %d Second: %d\n", first, second);
  return 0;
 } 

在这种方法中,如果用户在输入一个整数后命中输入,我就能够打印错误。但我无法将输入限制为仅2个数字。也就是说,如果用户输入的整数超过2个,则程序接受前2个整数并忽略第3个整数。我想在那种情况下打印错误。

所以我的问题是,通过修改第一种方法和第二种方法,我的要求是否可以实现?

感谢。

3 个答案:

答案 0 :(得分:3)

一种解决方案是在两次success: function(data) { $('#partial').html(data); } 次转化后使用%n转换规范。 %d转换规范与任何字符都不匹配,但会在格式字符串中存储读取到此点的字符数。所以,在电话中:

%n

如果达到第二个sscanf(line, "%d %d %n", &first, &second, &bufPos); ,则%d将保留bufPos中读取的最后一个字符后的字符索引。由于line之前有空格,因此在将索引值存储到%n之前,将读取并跳过零个或多个空白字符。因此,在有效输入后,bufPos将指示bufPos终止符。如果在此索引的\0中找到任何其他字符,则输入中会出现无关的字符。

以下是您的第二个代码示例的修改版本。在line读取输入行后,fgets()用于扫描字符串。如果匹配次数少于2次,或者sscanf()不是line[bufPos],则'\0'设置为badInput。输入循环是true循环,只执行一次,只要dobadInput,就会继续执行。

true

示例互动:

#include <stdio.h>
#include <stdlib.h>                 // for exit()
#include <stdbool.h>                // for bool type

#define BUF_SIZE  100

int main(void)
{
    int first;
    int second;
    char line[BUF_SIZE];
    int returnValue;
    int bufPos;
    bool badInput = false;

    do {
        if (badInput) {
            printf("Invalid input. Please enter again: ");
            badInput = false;
        } else {
            printf("Enter input: ");
        }
        if (fgets(line, sizeof(line), stdin) == NULL) {
            perror("Error in fgets()");
            exit(EXIT_FAILURE);
        }

        returnValue = sscanf(line, "%d %d %n", &first, &second, &bufPos);

        if (returnValue < 2 || line[bufPos] != '\0') {
            badInput = true;
        }

    } while (badInput);

    printf("First: %d Second: %d\n", first, second);

    return 0;
}

答案 1 :(得分:1)

要在char *提出要求时防止出现问题,您可以使用regular expression。 如果你没有被迫得到二合一scanf,你可以使用这个功能:

int secure_input(int max, int min) {
    int choice,buffer;
    do {
        choice = -1;//initialize in a values not included among min and max
        scanf("%d", &choice);
        while ((buffer =  getchar()) != '\n' ? buffer != EOF : false); // empty the buffer to avoid infinite loop
    } while (choice > max ? true : choice < min); 
    return choice;
}

在你的主要功能中你只需要调用这个函数:

first = secure_input(2;1);

答案 2 :(得分:0)

与其他答案不同,您还可以使用strtok()解析输入,然后检查找到的数量。这种方法很复杂,但它确实提供了对问题的不同看法。

while()循环中,您可以查看fgets()中找到的间隔号码数,如果只找到2,那么您可以break环。否则,继续搜索。一旦退出循环,那么您可以从最近的输入读取中sscanf()两个整数。您还可以使用strtol()检查整数是否有效。

注意: strtok()是reeantrant,它确实修改了它解析的字符串。所以在这种情况下,您可能需要在某处创建它的副本。您可以使用strdup()malloc()执行此操作。

以下是一些示例代码:

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

#define LINESIZE 20
#define BASE 10

int main(void) {
    char line[LINESIZE];
    const int n = LINESIZE;

    char *number, *copy, *endptr;
    const char *delim = " ";

    int first, second, check, invalidnum;
    size_t slen, count;

    while (1) {
        printf("Enter input: ");
        if (fgets(line, n, stdin) == NULL) {
            printf("Error reading buffer from fgets()\n");
            exit(EXIT_FAILURE);
        }

        slen = strlen(line);
        if (slen > 0 && line[slen-1] == '\n') {
            line[slen-1] = '\0';
        } else {
            printf("Buffer overflow detected\n");
            exit(EXIT_FAILURE);
        }

        copy = strdup(line);

        count = 0;
        invalidnum = 0;
        number = strtok(copy, delim);
        while (number != NULL) {
            check = strtol(number, &endptr, BASE);
            if (endptr == number || check == 0) {
                invalidnum = 1;
                break;
            }
            count++;
            number = strtok(NULL, delim);
        }
        free(copy);
        copy = NULL;

        if (count != 2 || invalidnum) {
            printf("Invalid input\n\n");
        } else {
            break;
        }
    }

    if (sscanf(line, "%d %d", &first, &second) != 2) {
        printf("Unexpected error from sscanf()\n");
        exit(EXIT_FAILURE);
    }
    printf("first = %d, second = %d\n", first, second);

    return 0;
}

这只是解决问题的另一种方法。在简单性方面,@ David Bowling有更好的主意,我建议使用他的。