C编程:如何检查用户是否仅在以下表达式中输入了数值?
C Programming: How to check if user has entered numeric values only in the following expression?
我采用以下格式将特定日期作为用户输入:mm/dd/yyyy。
我如何确定用户只输入了数字值,如果不是,则再次提示他输入有效日期。我已经在根据输入的值检查日期是否有效,但如果用户输入的值不完全是数字,那么程序就会崩溃。
请帮忙...
代码:
int x=0;
printf("\nEnter the date of birth(mm/dd/yyyy):");
do
{
scanf("%d/%d/%d",&add.dob.month,&add.dob.day,&add.dob.year);
if((add.dob.month<13 && add.dob.month>0) && (add.dob.day>0 && add.dob.day<32) && (add.dob.year<2016))
{
x=1;
}
else
{
printf("\nThe above date of birth is invalid.\nEnter a valid date of birth(mm/dd/yyyy):");
}
}while(x!=1);
您想检查 scanf 的 return 值,它将 return 读取的输入数。
就说input1 input2和input3是ints
int isValid = 0;
while (!isValid)
{
isValid = scanf("%d/%d/%d",&input1, &input2, &input3);
if(isValid != 3)
{
printf("\nThe above date of birth is invalid.\nEnter a valid date of birth(mm/dd/yyyy):");
}
else
{
// the user entered integers
if((add.dob.month<13 && add.dob.month>0) && (add.dob.day>0 && add.dob.day<32) && (add.dob.year<2016))
{
}
else
{
isValid = 0; // it didn't pass your date validation but it did pass integer validation
}
}
}
如果用户输入字符或字符串或任何非整数的内容,则 scanf 将 return 0 并且您可以使其循环。我在那里使用了一个非常糟糕的 if/else ,将 if 部分留空,否定每一个会更好,但这是另一回事。这个故事的寓意就是检查什么 scanf returns,如果它 returns > 1,用户输入数字,如果它 returns 0,那么他们尝试输入字母并且它失败。
您应该检查 scanf
的 return 值,看看它是否能够完成所有分配。如果没有,您需要在再次尝试之前消耗用户的输入,否则您将陷入无限循环,一遍又一遍地尝试读取相同的输入,但都失败了。例如:
do {
printf("\nEnter the date of birth(mm/dd/yyyy): ");
fflush(stdout);
if (scanf("%d/%d/%d", &month, &day, &year) != 3) {
scanf("%*[^\n]"); // consume line from input, do not assign
} else if (month < 13 && month > 0 && day < 32 && day > 0 && year < 2016) {
break;
}
printf("Invalid date!\n");
} while (!feof(stdin));
另外请注意,您缺少对日期有效性的检查,例如,用户仍然可以输入 02/30/-5。
edit:参考下面评论中的讨论,这里对corner cases的处理很差;假设这是一个旨在始终 运行 在本地终端上交互的程序。为了正确处理输入,我强烈建议从 scanf
切换到 fgets
(+ 之后可能 sscanf
)。然后应该检查 fgets
的 return 值并在那里处理错误,而不是可能有问题的 feof
检查。当然,scanf
解决方案可以通过正确检查不同的 return 值(例如 EOF
)来变得更加迂腐,但我认为它不值得。
您可以检查scanf()
的return值来测试输入的三个值是否属于int
类型。
代码:
int returnval = scanf("%d/%d/%d",&input1, &input2, &input3);
if (returnval == 3)
{
//The input is correct.
}
else
{
printf("The input is not correct.");
//The input is not correct.
}
您可以扫描输入,然后通过像 strtol()
这样的函数解析它。
strtol()
会告诉你是全数字还是混合。
这将为您省去很多麻烦,最后您要做的就是检查数字边界。
请查看 atoi()
— string to int
的答案
有几个问题。如果使用 scanf
检查其 return。除了数字有效性检查之外,您还需要在用户输入非整数的情况下刷新输入缓冲区的问题。虽然有多种方法可以做到这一点,但与您的方法保持一致的一种方法是简单地执行您正在执行的检查,然后使用第二个 do/while
循环手动刷新输入缓冲区。您还可以扭转您的逻辑并测试任何一个条件是否为真,从而强制另一个提示输入日期。如前所述,有很多方法可以解决这个问题。将此视为您收到的其他答案之一。
int c = 0; /* value to test for end of input buffer */
printf("\nEnter the date of birth(mm/dd/yyyy):");
while ((scanf("%d/%d/%d",&add.dob.month,&add.dob.day,&add.dob.year) != 3) ||
(add.dob.month < 1) ||
(add.dob.month > 12 ) ||
(add.dob.day < 1 ) ||
(add.dob.day > 31) ||
(add.dob.year < 1) ||
(add.dob.year > 2015))
{
printf("\nThe above date of birth is invalid.\nEnter a valid date of birth(mm/dd/yyyy):");
do { c = getchar(); } while (c != '\n' && c != EOF); /* flush input buffer */
}
如前所述,从 stdin
读取信息的一种更可靠的方法是使用 fgets
或 getline
将日期作为字符串读入缓冲区,然后解析缓冲区中的月、日、年信息。这也可以通过多种方式完成。由于您最终将从字符转换为十进制,因此您也可以只使用 strtol
来解析和转换,而不是使用指针逐步降低字符串或使用 strtok
或 strsep
进行解析(因为无论如何,每个都需要在分离后转换为十进制)。这是一个提供相当可靠解决方案的快速示例。除了 mm/dd/yyyy
:
之外,它还允许将日期输入为 mm-dd-yyyy
或 mm.dd.yyy
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#define SZDATE 12
int main (void) {
int mm = 0; // month/day/year values
int dd = 0;
int yyyy = 0;
int gooddate = 0; // flag signifying valid date
char datestr[SZDATE] = {0}; // buffer to hold input string
char *p = NULL; // pointer to use with strtol
char *endptr = NULL; // end pointer for strtol
long val = 0; // long value for strtol
while (gooddate == 0)
{
printf("\nEnter the date of birth (mm/dd/yyyy): ");
/* read string with fgets */
fgets (datestr, SZDATE-1, stdin);
/* test sufficient length */
if (strlen (datestr) < 8) {
printf ("\n insufficient date length entered, try again.\n");
continue;
}
/* parse month value with strtol (with error checking) */
errno = 0;
val = strtol (datestr, &endptr, 10);
if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
|| (errno != 0 && val == 0)
|| (endptr == datestr)
|| (*endptr != '/' && *endptr != '-' && *endptr != '.')
|| (val < 1)
|| (val > 12)) {
printf ("\n invalid month entered, try again.\n");
continue;
}
mm = (int) val; /* set month on successful conversion */
p = ++endptr; /* set p to start of day, reset endptr */
endptr = NULL;
/* parse day value with strtol (with error checking) */
errno = 0;
val = strtol (p, &endptr, 10);
if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
|| (errno != 0 && val == 0)
|| (endptr == p)
|| (*endptr != '/' && *endptr != '-' && *endptr != '.')
|| (val < 1)
|| (val > 31)) {
printf ("\n invalid day entered, try again.\n");
continue;
}
dd = (int) val; /* set day on successful conversion */
p = ++endptr; /* set p to start of year, reset endptr */
endptr = NULL;
/* parse year value with strtol (with error checking) */
errno = 0;
val = strtol (p, &endptr, 10);
if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
|| (errno != 0 && val == 0)
|| (endptr == p)
|| (*endptr != '\n' && *endptr != 0)
|| (val < 1900)
|| (val > 2015)) {
printf ("\n invalid year entered, try again.\n");
continue;
}
yyyy = (int) val; /* set year on successful conversion */
gooddate = 1; /* set gooddate flag ending loop */
}
printf ("\n valid date is: %d/%d/%d\n\n", mm, dd, yyyy);
return 0;
}
仔细考虑与 strtol
转化相关的检查。您可能还有更多想要添加的内容。另外,尝试用 strtok
之类的解析并进行比较。这只是将读取字符串然后进行解析的一种方法。它可以通过多种不同的方式完成。
我采用以下格式将特定日期作为用户输入:mm/dd/yyyy。
我如何确定用户只输入了数字值,如果不是,则再次提示他输入有效日期。我已经在根据输入的值检查日期是否有效,但如果用户输入的值不完全是数字,那么程序就会崩溃。
请帮忙...
代码:
int x=0;
printf("\nEnter the date of birth(mm/dd/yyyy):");
do
{
scanf("%d/%d/%d",&add.dob.month,&add.dob.day,&add.dob.year);
if((add.dob.month<13 && add.dob.month>0) && (add.dob.day>0 && add.dob.day<32) && (add.dob.year<2016))
{
x=1;
}
else
{
printf("\nThe above date of birth is invalid.\nEnter a valid date of birth(mm/dd/yyyy):");
}
}while(x!=1);
您想检查 scanf 的 return 值,它将 return 读取的输入数。
就说input1 input2和input3是ints
int isValid = 0;
while (!isValid)
{
isValid = scanf("%d/%d/%d",&input1, &input2, &input3);
if(isValid != 3)
{
printf("\nThe above date of birth is invalid.\nEnter a valid date of birth(mm/dd/yyyy):");
}
else
{
// the user entered integers
if((add.dob.month<13 && add.dob.month>0) && (add.dob.day>0 && add.dob.day<32) && (add.dob.year<2016))
{
}
else
{
isValid = 0; // it didn't pass your date validation but it did pass integer validation
}
}
}
如果用户输入字符或字符串或任何非整数的内容,则 scanf 将 return 0 并且您可以使其循环。我在那里使用了一个非常糟糕的 if/else ,将 if 部分留空,否定每一个会更好,但这是另一回事。这个故事的寓意就是检查什么 scanf returns,如果它 returns > 1,用户输入数字,如果它 returns 0,那么他们尝试输入字母并且它失败。
您应该检查 scanf
的 return 值,看看它是否能够完成所有分配。如果没有,您需要在再次尝试之前消耗用户的输入,否则您将陷入无限循环,一遍又一遍地尝试读取相同的输入,但都失败了。例如:
do {
printf("\nEnter the date of birth(mm/dd/yyyy): ");
fflush(stdout);
if (scanf("%d/%d/%d", &month, &day, &year) != 3) {
scanf("%*[^\n]"); // consume line from input, do not assign
} else if (month < 13 && month > 0 && day < 32 && day > 0 && year < 2016) {
break;
}
printf("Invalid date!\n");
} while (!feof(stdin));
另外请注意,您缺少对日期有效性的检查,例如,用户仍然可以输入 02/30/-5。
edit:参考下面评论中的讨论,这里对corner cases的处理很差;假设这是一个旨在始终 运行 在本地终端上交互的程序。为了正确处理输入,我强烈建议从 scanf
切换到 fgets
(+ 之后可能 sscanf
)。然后应该检查 fgets
的 return 值并在那里处理错误,而不是可能有问题的 feof
检查。当然,scanf
解决方案可以通过正确检查不同的 return 值(例如 EOF
)来变得更加迂腐,但我认为它不值得。
您可以检查scanf()
的return值来测试输入的三个值是否属于int
类型。
代码:
int returnval = scanf("%d/%d/%d",&input1, &input2, &input3);
if (returnval == 3)
{
//The input is correct.
}
else
{
printf("The input is not correct.");
//The input is not correct.
}
您可以扫描输入,然后通过像 strtol()
这样的函数解析它。
strtol()
会告诉你是全数字还是混合。
这将为您省去很多麻烦,最后您要做的就是检查数字边界。
请查看 atoi()
— string to int
有几个问题。如果使用 scanf
检查其 return。除了数字有效性检查之外,您还需要在用户输入非整数的情况下刷新输入缓冲区的问题。虽然有多种方法可以做到这一点,但与您的方法保持一致的一种方法是简单地执行您正在执行的检查,然后使用第二个 do/while
循环手动刷新输入缓冲区。您还可以扭转您的逻辑并测试任何一个条件是否为真,从而强制另一个提示输入日期。如前所述,有很多方法可以解决这个问题。将此视为您收到的其他答案之一。
int c = 0; /* value to test for end of input buffer */
printf("\nEnter the date of birth(mm/dd/yyyy):");
while ((scanf("%d/%d/%d",&add.dob.month,&add.dob.day,&add.dob.year) != 3) ||
(add.dob.month < 1) ||
(add.dob.month > 12 ) ||
(add.dob.day < 1 ) ||
(add.dob.day > 31) ||
(add.dob.year < 1) ||
(add.dob.year > 2015))
{
printf("\nThe above date of birth is invalid.\nEnter a valid date of birth(mm/dd/yyyy):");
do { c = getchar(); } while (c != '\n' && c != EOF); /* flush input buffer */
}
如前所述,从 stdin
读取信息的一种更可靠的方法是使用 fgets
或 getline
将日期作为字符串读入缓冲区,然后解析缓冲区中的月、日、年信息。这也可以通过多种方式完成。由于您最终将从字符转换为十进制,因此您也可以只使用 strtol
来解析和转换,而不是使用指针逐步降低字符串或使用 strtok
或 strsep
进行解析(因为无论如何,每个都需要在分离后转换为十进制)。这是一个提供相当可靠解决方案的快速示例。除了 mm/dd/yyyy
:
mm-dd-yyyy
或 mm.dd.yyy
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#define SZDATE 12
int main (void) {
int mm = 0; // month/day/year values
int dd = 0;
int yyyy = 0;
int gooddate = 0; // flag signifying valid date
char datestr[SZDATE] = {0}; // buffer to hold input string
char *p = NULL; // pointer to use with strtol
char *endptr = NULL; // end pointer for strtol
long val = 0; // long value for strtol
while (gooddate == 0)
{
printf("\nEnter the date of birth (mm/dd/yyyy): ");
/* read string with fgets */
fgets (datestr, SZDATE-1, stdin);
/* test sufficient length */
if (strlen (datestr) < 8) {
printf ("\n insufficient date length entered, try again.\n");
continue;
}
/* parse month value with strtol (with error checking) */
errno = 0;
val = strtol (datestr, &endptr, 10);
if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
|| (errno != 0 && val == 0)
|| (endptr == datestr)
|| (*endptr != '/' && *endptr != '-' && *endptr != '.')
|| (val < 1)
|| (val > 12)) {
printf ("\n invalid month entered, try again.\n");
continue;
}
mm = (int) val; /* set month on successful conversion */
p = ++endptr; /* set p to start of day, reset endptr */
endptr = NULL;
/* parse day value with strtol (with error checking) */
errno = 0;
val = strtol (p, &endptr, 10);
if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
|| (errno != 0 && val == 0)
|| (endptr == p)
|| (*endptr != '/' && *endptr != '-' && *endptr != '.')
|| (val < 1)
|| (val > 31)) {
printf ("\n invalid day entered, try again.\n");
continue;
}
dd = (int) val; /* set day on successful conversion */
p = ++endptr; /* set p to start of year, reset endptr */
endptr = NULL;
/* parse year value with strtol (with error checking) */
errno = 0;
val = strtol (p, &endptr, 10);
if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
|| (errno != 0 && val == 0)
|| (endptr == p)
|| (*endptr != '\n' && *endptr != 0)
|| (val < 1900)
|| (val > 2015)) {
printf ("\n invalid year entered, try again.\n");
continue;
}
yyyy = (int) val; /* set year on successful conversion */
gooddate = 1; /* set gooddate flag ending loop */
}
printf ("\n valid date is: %d/%d/%d\n\n", mm, dd, yyyy);
return 0;
}
仔细考虑与 strtol
转化相关的检查。您可能还有更多想要添加的内容。另外,尝试用 strtok
之类的解析并进行比较。这只是将读取字符串然后进行解析的一种方法。它可以通过多种不同的方式完成。