如果我在C中有一段时间或做while循环,是否有一些(本机)方式我可以在第二个循环中发生某些事情?
我要求获得投入;我有这个:
int size;
do {
printf("Size of tower (0 <= x <= 23): ");
scanf("%i", &size);
} while (size > 23 || size < 0);
如果用户输入的值不在0到23之间,我想显示错误信息并要求另一个值。显然我可以这样做:
int size;
int error = 0;
do {
if (error) { printf("Invalid size\n"); }
printf("Size of tower (0 <= x <= 23): ");
scanf("%i", &size);
error = 1;
} while (size > 23 || size < 0);
然而,这感觉很糟糕。我正在寻找一个优雅的解决方案,我认为在第二个循环上运行某些东西会起作用。
答案 0 :(得分:4)
我想你想要这样的东西:
int size = -1;
int MAX_TRIES = 10;
while (MAX_TRIES--)
{
printf("Size of tower (0 <= x < 23): ");
if (scanf("%i", &size) != 1)
{
printf("Read error!!\n");
break;
}
if (size >= 0 && size < 23)
{
break;
}
printf("Error: You entered '%d' which is not in the range 0 <= x < 23\n", size);
}
通过这种方式编写,在编写代码时,您不必在心理上计算布尔条件逻辑的否定。
此外,检查scanf()
的返回值很重要。感谢 Weather Vane's comment提醒您
此外,最好限制此循环的执行次数,而不是让它运行到无穷大。 (感谢Jonathan Leffler's comment)
答案 1 :(得分:1)
转换和错误报告可以移动到一个函数来简化调用代码。输入由fgets
获取,值由strtol
在函数中解析。此函数返回成功或失败。其他值通过指针返回给调用者。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
int get_int_range ( char *line, char **next, char *delim, int *value, int min, int max);//prototype
int main( int argc, char *argv[])
{
char line[100] = {'\0'};//input buffer
int valid = 0;
int size = 0;
do {
printf ( "Size of tower (0 <= x <= 23) or quit\n");
fgets ( line, sizeof ( line), stdin);//read a line
if ( strcmp ( line, "quit\n") == 0) {
valid = 0;
break;// if quit is entered, exit loop
}
valid = get_int_range ( line, NULL, "\n", &size, 0, 23);// call to parse a value
} while ( !valid);// on failure, keep looping the above
if ( valid) {
printf ( "Size of tower is %d\n", size);
}
return 0;
}
//inputs
// char *line : pointer to text to be parsed
// char **next : pointer to pointer to allow modification of caller's pointer
// char *term : pointer to characters to be considered terminators
// int *value : pointer to int to allow modification of caller's int
// int min : minimum value of range
// int max : maximum value of range
// returns : 0 failure or 1 success
int get_int_range ( char *line, char **next, char *delim, int *value, int min, int max)
{
long int input = 0;
char *end = NULL;//will point to end of parsed value
if ( line == NULL) {
printf ( "no text to parse\n");
return 0;
}
if ( value == NULL) {
printf ( "unable to save parsed value\n");
return 0;
}
errno = 0;
input = strtol ( line, &end, 10);//get the integer from the line. end will point to the end of the parsed value
if ( ( errno == ERANGE && ( input == LONG_MAX || input == LONG_MIN))
|| ( errno != 0 && input == 0)){// parsing error from strtol
perror ( "input");
return 0;
}
if ( end == line) {// nothing was parsed. no digits
line[strcspn ( line, "\n")] = '\0';//remove newline
printf ( "input [%s] MUST be a number\n", line);
return 0;// return failure
}
// *end is the character that end points to
if ( *end != '\0' && !( delim && strchr ( delim, *end))) {// is *end '\0'? is *end in the set of term characters?
line[strcspn ( line, "\n")] = '\0';//remove newline
printf ( "problem with input terminator: [%s] \n", line);
return 0;
}
if ( input < min || input > max) {// parsed value is outside of range
printf ( "input out of range %d to %d\n", min, max);
return 0;
}
if ( next != NULL) {// if next is NULL, caller did not want pointer to end of parsed value
*next = end;// *next allows modification to caller's pointer
}
*value = input;// *value allows modification to callers int
return 1;// success
}
答案 2 :(得分:0)
我首选的技术是复制输入,但会简化你的循环:
printf("Size of tower (0 <= x <= 23): "); // Try to get good input once.
scanf("%i", &size);
while (size < 0 || 23 < size ) { // While the user is wrong:
printf("Invalid size\n");
printf("Size of tower (0 <= x <= 23): "); // Try, try again.
scanf("%i", &size);
}