0

如果 scanf 遇到不匹配,我想给出一条错误消息,然后继续读取其余的输入。如果其中一个输入格式不正确,我当前的代码将进入无限循环。

预期输入:

101,Betty,Hay,123 Main St.,23
234,Sheila,Benn,937 Ash Ave.,46
384,Ron,Jewell,3991 Cedar Ave.,30
291,Bill,Read,83 Crescent St.,19
103,Alexander,Ott,100 2nd St.,21
115,Tricia,Munson,585 Oxen Ave.,28
118,Sam,Munson,585 Oxen Ave.,35
110,Valerie,Parker,1513 Copper Rd.,37

代码:

#include <stdio.h>

int main()
{
    int sum = 0;
    int count = 0;
    while (1)
    {
        int id;
        char first[80], last[80], addr[80];
        int age;
        scanf("%d,%80[^,],%80[^,],%80[^,],%d", &id, first, last, addr, &age);
        if (feof(stdin)) break;
        printf("id=%d first=%s last=%s addr=%s age=%d\n",
               id, first, last, addr, age);
        sum += age;
        count++;
    }

    printf("Average age is %f\n", (float)sum / count);

    return 0;
}

我试图通过将 scanf 放在 if 语句中将其与预期的读取次数进行比较来解决此问题,这适用于显示错误消息,但无助于读取输入的其余部分。有没有办法跳到下一行输入?

4

3 回答 3

2

您需要scanf()直接测试结果。在这种情况下(以及大多数其他情况下),我建议使用fgets()and sscanf()over plain scanf()

#include <stdio.h>

int main(void)
{
    int sum = 0;
    int count = 0;
    int lineno = 0;
    char line[4096];
    while (fgets(line, sizeof(line), stdin) != 0)
    {
        int id;
        char first[80], last[80], addr[80];
        int age;
        lineno++;
        if (sscanf(line, "%d,%79[^,],%79[^,],%79[^,],%d", &id, first, last, addr, &age) != 5)
            fprintf(stderr, "Invalid data in line %d:\n%s", lineno, line);
        else
        {
            printf("id=%d first=%s last=%s addr=%s age=%d\n",
                   id, first, last, addr, age);
            sum += age;
            count++;
        }
    }

    printf("Average age is %f\n", (float)sum / count);

    return 0;
}

修复包括:

  1. 直接检查输入函数 ( fgets()) — 使用feof()通常是不合适的。
  2. 检查sscanf()调用是否找到 5 个值。
  3. 确保字符串不会溢出分配的缓冲区;sscanf()等人需要一个不包括最后的空字节的大小——因此格式从 80 变为 79。
  4. 能够报告有缺陷的整行,因为它全部被读入。scanf()相反,它已经咬掉了行的不确定的初始部分,留下谁知道剩下什么来报告错误。在这里,你得到了整行,并且可以更有意义地报告错误。我包括了一个行号以进一步改进。
于 2013-09-18T03:24:52.860 回答
1

scanf()读取失败时,它会停在失败的地方。您需要忽略该行的其余部分。

一种方法是逐个字符读取,直到看到换行符。您可以getc()为此使用函数。您也可以使用 fgets() 一口气阅读其余部分。然后继续使用scanf().

于 2013-09-18T03:14:12.743 回答
1

scanf由于这个确切的原因,使用并不是最好的主意。我建议使用fgets将整行文本从stdin您的字符数组中捕获。然后用于strtok标记字符串并处理每个输入。

也许是这样的:

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

int main()
{
    int sum = 0;
    int count = 0;
    while (1)
    {
        int id;
        char line[240], * token;
        char first[80], last[80], addr[80];
        int age;

        if (fgets(line,240,stdin) == NULL) break;
        line[strlen(line) - 1] = '\0'; /* remove \n */
        id = atoi(strtok(line,","));
        strcpy(first,strtok(NULL,","));
        strcpy(last,strtok(NULL,","));
        strcpy(addr,strtok(NULL,","));
        age = atoi(strtok(NULL,","));
        printf("id=%d first=%s last=%s addr=%s age=%d\n",
               id,first, last, addr, age);
        sum += age;
        count++;
    }

    printf("Average age is %f\n", (float)sum / count);

    return 0;
}
于 2013-09-18T03:22:57.117 回答