将输入验证为给定范围c内的整数

将输入验证为给定范围c内的整数,c,validation,fgets,C,Validation,Fgets,我正在尝试在范围和to类型整数之间验证输入。目前我有以下代码。需要的范围是X为0-100,Y为0-50 for(loop=0;loop<3;loop++){ printf("\n\nEnter MAGENTA X coordinate from 0 to 100:\n"); scanf("%d",&mg[loop].x); printf("\nEnter MAGENTA Y coordinate from %d to 50:\n"); scanf("

我正在尝试在范围和to类型整数之间验证输入。目前我有以下代码。需要的范围是X为0-100,Y为0-50

for(loop=0;loop<3;loop++){
    printf("\n\nEnter MAGENTA X coordinate from 0 to 100:\n");
    scanf("%d",&mg[loop].x);
    printf("\nEnter MAGENTA Y coordinate from %d to 50:\n");
    scanf("%d",&mg[loop].y);
}

你可以使用scanf,这很好。为什么不呢?scanf返回成功读取的项目数,因此0表示格式错误。在此之后,您希望在请求另一个输入之前放弃剩余的输入

然后根据边界测试读取变量

您可以为用户希望退出指定一个特殊值,可能是一些类似“exit”的字符串,它使scanf失败,然后检查它是否为“exit”。当您想退出循环时,break命令非常方便。

您可以使用
scanf()
,但错误报告往往比较棘手。最低限度地调整您的代码:

for (loop = 0; loop < 3; loop++)
{
    int rc;
    printf("\n\nEnter YELLOW X coordinate from 0 to 100:\n");
    while ((rc = scanf("%d", &ylw[loop].x)) == 1 &&
           (ylw[loop].x < 0 || ylw[loop].y > 100)
        printf("Enter a value between 0 and 100\n");
    if (rc != 1)
    {
        fprintf(stderr, "Error reading x-value.\n");
        break;
    }
    printf("\nEnter YELLOW Y coordinate from 0 to 50:\n");
    while ((rc = scanf("%d", &ylw[loop].y)) == 1 &&
           (ylw[loop].x < 0 || ylw[loop].y > 50)
        printf("Enter a value between 0 and 50\n");
    if (rc != 1)
    {
        fprintf(stderr, "Error reading y-value.\n");
        break;
    }
}
不过,这并没有充分利用
fgets()
;当您希望在一行上显示多个数据项时,它会进行评分,因为这样您就可以报告输入的整行数据


警告:此代码均未编译

如果您希望强制每个输入都在其自己的输入行上(建议在交替提示和从stdin读取时),我建议首先将一行读取到临时行缓冲区,然后使用
sscanf
扫描该缓冲区。然后在最后一步中检查您的输入是否有效

因为这会使代码变得混乱,所以您可以为此编写自己的函数:

/*
 *      Read an integer from stdin. Repeat until a valid number between
 *      lo and hi has been given. Returns 0 when a number was read and
 *      -1 when the input has run out.
 */
int read_int(int *x, int lo, int hi)
{
    char buf[80];
    char c;

    for (;;) {
        if (fgets(buf, sizeof(buf), stdin) == NULL) return -1;

        if (sscanf(buf, "%d %c", x, &c) != 1 || *x < lo || *x > hi) {
            printf("Please enter a single value between %d and %d.\n",
                lo, hi);
        } else {
            break;
        }
    }

    return 0;
}
/*
*从stdin读取一个整数。重复此操作,直到在
*lo和hi已经给出。读取和删除数字时返回0
*-1当输入用完时。
*/
int read_int(int*x,int lo,int hi)
{
char-buf[80];
字符c;
对于(;;){
if(fgets(buf,sizeof(buf),stdin)=NULL)返回-1;
如果(sscanf(buf,“%d%c”,x和c)!=1 |*xhi){
printf(“请输入一个介于%d和%d之间的值。\n”,
罗,你好),;
}否则{
打破
}
}
返回0;
}
然后,您可以像这样读取坐标:

struct Coord ylw[3] = {{0, 0}};
int i;

for(i = 0; i < MAX; i++) {
    printf("\n\nEnter YELLOW X coordinate #%d from 0 to 100:\n", i);
    if (read_int(&ylw[i].x, 0, 100) < 0) break;

    printf("\nEnter YELLOW Y coordinate #%d from 0 to 50:\n", i);
    if (read_int(&ylw[i].y, 0, 50) < 0) break;
}
struct-Coord-ylw[3]={{0,0};
int i;
对于(i=0;i
如果用户键入文件字符的eod(Unix上的Ctrl-D,Windows上的Ctrl-Z),坐标数可以缩短。如果您想用某个关键字结束输入,比如“end”,您可以通过读取字符串并首先选中以下内容将其添加到函数中:

int read_int(int *x, int lo, int hi)
{
    char buf[80];
    char key[5];
    char c;

    for (;;) {
        if (fgets(buf, sizeof(buf), stdin) == NULL) return -1;

        if (sscanf(buf, "%4s ", key) == 1) {
            if (strcmp(key, "end") == 0) return -1;
            if (strcmp(key, "END") == 0) return -1;
        }

        if (sscanf(buf, "%d %c", x, &c) != 1 || *x < lo || *x > hi) {
            printf("Please enter a single value between %d and %d.\n",
                lo, hi);
        } else {
            break;
        }
    }

    return 0;
}
int-read\u-int(int*x,int-lo,int-hi)
{
char-buf[80];
字符键[5];
字符c;
对于(;;){
if(fgets(buf,sizeof(buf),stdin)=NULL)返回-1;
如果(sscanf(buf,“%4s”,键)=1){
if(strcmp(key,“end”)==0)返回-1;
if(strcmp(key,“END”)==0)返回-1;
}
如果(sscanf(buf,“%d%c”,x和c)!=1 |*xhi){
printf(“请输入一个介于%d和%d之间的值。\n”,
罗,你好),;
}否则{
打破
}
}
返回0;
}

(从字符串中提取字符串似乎是多余的,但这样用户可以在一些空格后键入“end”。您也可以使用不区分大小写的字符串比较函数。)

先编写验证代码,然后再考虑scanf。从流中读取字符,并将其作为C字符串存储到str中,直到读取(num-1)个字符,或者到达换行符或文件结尾,以先发生的为准。这真的是你想要的吗?我在这些论坛上读到了关于
scanf
的恐怖及其未定义的行为。在这个例子中,我只是在努力实现正确的测试@jfly您的意思是将
,&end
也添加到第一个扫描中(在第二个代码中)?虽然它不起作用,但至少这就是为什么在未初始化的情况下使用
警告。顺便说一句,
scanf
要求终端向您提供输入,而终端通常是面向行的。因此,在按下enter键之前,无法使程序获取该值。如果要立即获取每个字符,可能需要直接使用终端,或者使用库,例如
ncurses
。最初我使用的是
scanf(“%2d”,&mg[loop].x)这是有效的,但只适用于2位数的整数,不适用于输入100等。您建议这样做吗@PeterSchneider
int read,a;do{read=scanf(“%d”、&a);}while(read(0到100之间)&&a!=“exit”)
a!='退出“
,是毫无意义的,因为1)
int
中的a
,2)
'exit'
在C中无效(它应该是什么意思)。@MichaelWalz-between也不是C,我想它是伪代码。至少希望如此。我使用pseudo只是为了强调我的观点。我对这篇文章做了一些修改。也许这会让它更清晰一些@keltar@Michael沃尔兹:我想它应该是指伪代码;-)。j_prog,记住,read给出了转换项的计数,即本例中的1或0,这取决于scanf是否能够解析用户的编号。相反,a将包含已识别的值。注意:当scanf无法解析时,例如,因为它遇到了一个字母,剩余的输入仍在流中,需要“读取”,可能是以字符方式读取到下一个换行符。相当麻烦。
int prompt_for(const char *what, int min, int max, int err)
{
    int value;
    int rc;
    char line[4096];
    printf("\nEnter %s from %d to %d:", what, min, max);
    while (fgets(line, sizeof(line), stdin) != 0 &&
           (rc = sscanf(line, "%d", &value)) == 1 &&
           (value < min || value > max))
        printf("Enter a value between %d and %d\n", min, max);
    if (rc != 1)
    {
        fprintf(stderr, "Error reading %s.\n", what);
        return err;
    }
    return value;
}
/*
 *      Read an integer from stdin. Repeat until a valid number between
 *      lo and hi has been given. Returns 0 when a number was read and
 *      -1 when the input has run out.
 */
int read_int(int *x, int lo, int hi)
{
    char buf[80];
    char c;

    for (;;) {
        if (fgets(buf, sizeof(buf), stdin) == NULL) return -1;

        if (sscanf(buf, "%d %c", x, &c) != 1 || *x < lo || *x > hi) {
            printf("Please enter a single value between %d and %d.\n",
                lo, hi);
        } else {
            break;
        }
    }

    return 0;
}
struct Coord ylw[3] = {{0, 0}};
int i;

for(i = 0; i < MAX; i++) {
    printf("\n\nEnter YELLOW X coordinate #%d from 0 to 100:\n", i);
    if (read_int(&ylw[i].x, 0, 100) < 0) break;

    printf("\nEnter YELLOW Y coordinate #%d from 0 to 50:\n", i);
    if (read_int(&ylw[i].y, 0, 50) < 0) break;
}
int read_int(int *x, int lo, int hi)
{
    char buf[80];
    char key[5];
    char c;

    for (;;) {
        if (fgets(buf, sizeof(buf), stdin) == NULL) return -1;

        if (sscanf(buf, "%4s ", key) == 1) {
            if (strcmp(key, "end") == 0) return -1;
            if (strcmp(key, "END") == 0) return -1;
        }

        if (sscanf(buf, "%d %c", x, &c) != 1 || *x < lo || *x > hi) {
            printf("Please enter a single value between %d and %d.\n",
                lo, hi);
        } else {
            break;
        }
    }

    return 0;
}