【问题标题】:how to use fgets and sscanf for integers in loop如何在循环中使用 fgets 和 sscanf 处理整数
【发布时间】:2013-01-23 03:31:50
【问题描述】:

这里是 C 初学者。我正在尝试运行一个循环,其中将字符串和ints 输入到struct 的各个字段中。当提示输入“姓氏”时,用户可以在没有其他输入的情况下按 Enter 键,循环应该结束。

问题在于,使用此代码,循环不会结束(姓和名输入请求一起在同一行上运行)并且薪水的值总是错误(0 或某个大数字)

while (employee_num <= 2)
{
    printf("Enter last name ");
    fgets(employee[employee_num].last_name, sizeof(employee[employee_num].last_name), stdin);                   

    if(strlen(employee[employee_num].last_name) == 0)
        break;

    printf("Enter first name ");
    fgets(employee[employee_num].first_name, sizeof(employee[employee_num].first_name), stdin);

    printf("Enter title ");
    fgets(employee[employee_num].title, sizeof(employee[employee_num].title), stdin);

    printf("Enter salary ");
    fgets(strng_buffer, 1, stdin);
    sscanf(strng_buffer, "%d", &employee[employee_num].salary);     
    ++employee_num;
    getchar();
}

如果我尝试使用此代码,我可以在第一次运行后正确退出循环,但之后无法退出(通过在姓氏部分按 Enter 键 - 也许是 \n 我似乎无法清除? ):

char strng_buffer[16];
while (employee_num <= 5)
{
    printf("Enter last name ");
    fgets(strng_buffer, sizeof(strng_buffer), stdin);                   
    sscanf(strng_buffer, "%s", employee[employee_num].last_name);       

    if(strlen(employee[employee_num].last_name) == 0)
        break;

    printf("Enter first name ");
    fgets(strng_buffer, sizeof(strng_buffer), stdin);
    sscanf(strng_buffer, "%s", employee[employee_num].first_name);


    printf("Enter title ");
    fgets(strng_buffer, sizeof(strng_buffer), stdin);
    sscanf(strng_buffer, "%s", employee[employee_num].title);

    printf("Enter salary ");
    scanf("%d", &employee[employee_num].salary);        
    ++employee_num;
    getchar();
}

我很好奇如何按预期进行这项工作,以及此类条目的最佳实践是什么(即使用 sscanf、fgets 等)

提前致谢!

【问题讨论】:

    标签: c fgets scanf


    【解决方案1】:

    循环在遇到 break 语句时提前中断

    if(strlen(strng_buffer) == 0)
            break;
    

    未初始化的字符缓冲区strng_buffer,恰好第一个字符为null,导致strlen返回0

    我相信你可能有意

    if(strlen(employee[employee_num].last_name) == 0)
                break;
    

    作为循环终止符,这是您的拼写错误导致循环过早退出。

    【讨论】:

    • 你说得对(我有点累了)。我进行了编辑,显示了我两次尝试的更多代码。不过,我仍然无法让其中任何一个正常工作。有人提到使用 fgets() 然后 sscanf() 来读取 int 部分的薪水,但我在搜索中找不到任何明确的方法来做到这一点 - 这实际上是一个可行的选择吗?
    【解决方案2】:

    假设 Abhijit 提到了修复,为什么要将第一个转换为第二个?您是否知道由于添加了sscanf,第二个的行为与第一个不同?如果您的意图是缩短第一个,那么第二个似乎相当庞大。与其在情况中添加sscanf,不如通过声明struct employee *e = employee + employee_num; 并重复使用它来缩短第一个,而不是employee[employee_num]

    关于fgets 的一个“最佳实践”是检查它的返回值。如果遇到EOF,您认为fgets 可能会返回什么?如果成功,您认为fgets 会返回什么?

    关于scanf 的一个“最佳实践”是检查它的返回值。关于scanf的返回值,建议仔细阅读this scanf manual并回答以下问题:

    1. int x = scanf("%d", &amp;employee[employee_num].salary); 如果我输入 "fubar\n" 作为输入,你认为 x 会是什么?
    2. 您认为来自"fubar\n"'f' 会去哪里?
    3. 如果是ungetc'd 回到stdin,你下一个员工的姓是什么?
    4. int x = scanf("%d", &amp;employee[employee_num].salary); 如果我在 Windows 上运行此代码并按 CTRL+Z 将 EOF 发送到 stdin,您认为 x 会是什么?
    5. int x = scanf("%d %d", &amp;y, &amp;z); 假设scanf 成功地将值放入yz 两个变量中,您期望x 是什么?

    附: EOF 可以通过stdin 在 Windows 中通过 CTRL+Z 发送,在 Linux 和朋友中通过 CTRL+D 发送,此外还可以使用管道和重定向来重定向来自其他程序和文件的输入。

    【讨论】:

    • 谢谢!解决这些问题让我对使用 scanf() 时发生的事情有了更好的理解。如果我错了,请纠正我,但是我可以将标准输入写入数组并使用 sscanf() 将 int 值读回变量?
    • 是的,fgets 和 sscanf 可以这样工作。请注意,%s 格式说明符告诉 sscanf 复制一个 word(例如,零个或多个非空白字符,直到第一个空白)。你的 fgets'd 线的其余部分会发生什么?这是您的第二个帖子与您的第一个不同的一个方式。
    【解决方案3】:

    问题在于fgets 返回包含换行符(\n)的字符串。因此,即使用户在没有输入信息的情况下按下回车,字符串也不会为空。另外,salary 的缓冲区太小。

    因此,要么去掉每个 fgets 上的 \n,要么将支票更改为:

    if(strlen(employee[employee_num].last_name) == 1) break;
    

    另外,当你获得缓冲区时,将 1 更改为更大的值,例如

    fgets(strng_buffer, 10, stdin);
    

    但是,如果您确实想从每个 fget 中删除 \n,您可以执行以下操作:

    employee[employee_num].last_name[strlen(employee[employee_num].last_name)-1] = 0;
    

    您可以为每个字符串执行此操作,或者更好的是,创建一个执行此操作的函数。

    编辑:如果您可以保证用户在每次输入后都会按回车键,那么您可以放心地假设这一点。但是,如果情况并非总是如此,则最后一个字符可能不是 \n 并且仅以这种方式剥离可能会导致问题。

    【讨论】:

    • fgets 并不总是返回带有换行符的字符串。我建议 e->last_name[strcspn(e->last_name, "\n")] = '\0';处理不存在 '\n' 的情况,因为您的建议会丢弃有用的字符,从而引入错误。
    • 是的,但我关注的是他的情况,即用户应该按回车键(假设不会有 EOF)。仅减去 1 是危险的,因为 strlen 可以返回 0。我将更新评论以说明所有这些。
    • char strng_buffer[10]; fgets(strng_buffer, 10, 标准输入);如果 fgets 在到达 '\n' 之前读取 9 个字节呢?
    猜你喜欢
    • 1970-01-01
    • 2013-08-01
    • 1970-01-01
    • 2011-04-27
    • 1970-01-01
    • 2014-04-15
    • 1970-01-01
    • 1970-01-01
    • 2016-08-14
    相关资源
    最近更新 更多