如何防止用户输入比 C 中要求的更多或更少的输入?
How to prevent user from entering more or less input than required in C?
我希望用户只输入两个整数,不能多于二,也不能少于二。此外,在无效输入时,我希望打印错误并提示用户再次输入这两个整数。用户应输入两个由 space 分隔的整数,而不是换行符。因此,例如:
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 个整数并忽略第三个。我想在那种情况下打印错误。
我的其他方法涉及 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 个整数并忽略第三个。我想在那种情况下打印错误。
所以我的问题是,我的要求是否可以通过修改第一种方法和第二种方法来实现?
谢谢。
为防止请求 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);
一种解决方案是在两次 %d
转换后使用 %n
转换规范。 %n
转换规范不匹配任何字符,而是将读取到此时的字符数存储在格式字符串中。所以,在通话中:
sscanf(line, "%d %d %n", &first, &second, &bufPos);
如果到达第二个%d
,则bufPos
将保存在line
中读取的最后一个字符之后的字符索引。由于 %n
之前有一个 space,因此在将索引值存储到 bufPos
之前,将读取并跳过零个或多个 white-space 个字符。因此,在有效输入后,bufPos
将指示 [=22=]
终止符。如果在此索引处的 line
中找到任何其他字符,则说明输入中存在无关字符。
这是您的第二个代码示例的修改版本。 fgets()
读取一行输入后,sscanf()
用于扫描字符串。如果少于 2 个匹配项,或者如果 line[bufPos]
不是 '[=27=]'
,则 badInput
设置为 true
。输入循环是一个 do
循环,执行一次,只要 badInput
是 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] != '[=11=]') {
badInput = true;
}
} while (badInput);
printf("First: %d Second: %d\n", first, second);
return 0;
}
交互示例:
Enter input: 1
Invalid input. Please enter again: 1 2 3
Invalid input. Please enter again:
Invalid input. Please enter again: 1 2
First: 1 Second: 2
与其他答案不同,您还可以使用 strtok()
解析输入,然后检查找到了多少个数字。这种方法很复杂,但它确实提供了对问题的不同看法。
在你的 while()
循环中,你可以检查从 fgets()
中找到了多少个间隔数字,然后如果只找到 2
,那么你可以 break
出来的循环。否则,继续寻找。一旦退出循环,您就可以从最近的输入读取中 sscanf()
两个整数。您还可以使用 strtol()
检查整数是否有效。
注意: strtok()
是可重入的,它确实修改了它解析的字符串。所以在这种情况下,您可能需要在某处创建它的副本。您可以使用 strdup()
or 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] = '[=10=]';
} 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 有更好的主意,我建议使用他的。
我希望用户只输入两个整数,不能多于二,也不能少于二。此外,在无效输入时,我希望打印错误并提示用户再次输入这两个整数。用户应输入两个由 space 分隔的整数,而不是换行符。因此,例如:
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 个整数并忽略第三个。我想在那种情况下打印错误。
我的其他方法涉及 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 个整数并忽略第三个。我想在那种情况下打印错误。
所以我的问题是,我的要求是否可以通过修改第一种方法和第二种方法来实现?
谢谢。
为防止请求 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);
一种解决方案是在两次 %d
转换后使用 %n
转换规范。 %n
转换规范不匹配任何字符,而是将读取到此时的字符数存储在格式字符串中。所以,在通话中:
sscanf(line, "%d %d %n", &first, &second, &bufPos);
如果到达第二个%d
,则bufPos
将保存在line
中读取的最后一个字符之后的字符索引。由于 %n
之前有一个 space,因此在将索引值存储到 bufPos
之前,将读取并跳过零个或多个 white-space 个字符。因此,在有效输入后,bufPos
将指示 [=22=]
终止符。如果在此索引处的 line
中找到任何其他字符,则说明输入中存在无关字符。
这是您的第二个代码示例的修改版本。 fgets()
读取一行输入后,sscanf()
用于扫描字符串。如果少于 2 个匹配项,或者如果 line[bufPos]
不是 '[=27=]'
,则 badInput
设置为 true
。输入循环是一个 do
循环,执行一次,只要 badInput
是 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] != '[=11=]') {
badInput = true;
}
} while (badInput);
printf("First: %d Second: %d\n", first, second);
return 0;
}
交互示例:
Enter input: 1
Invalid input. Please enter again: 1 2 3
Invalid input. Please enter again:
Invalid input. Please enter again: 1 2
First: 1 Second: 2
与其他答案不同,您还可以使用 strtok()
解析输入,然后检查找到了多少个数字。这种方法很复杂,但它确实提供了对问题的不同看法。
在你的 while()
循环中,你可以检查从 fgets()
中找到了多少个间隔数字,然后如果只找到 2
,那么你可以 break
出来的循环。否则,继续寻找。一旦退出循环,您就可以从最近的输入读取中 sscanf()
两个整数。您还可以使用 strtol()
检查整数是否有效。
注意: strtok()
是可重入的,它确实修改了它解析的字符串。所以在这种情况下,您可能需要在某处创建它的副本。您可以使用 strdup()
or 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] = '[=10=]';
} 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 有更好的主意,我建议使用他的。