首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在循环中使用fgets和sscanf for integers

如何在循环中使用fgets和sscanf for integers
EN

Stack Overflow用户
提问于 2013-01-23 11:31:50
回答 3查看 4.3K关注 0票数 0

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

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

代码语言:javascript
复制
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我不能清除?):

代码语言:javascript
复制
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等)。

提前感谢!

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-01-23 12:27:27

假设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", &employee[employee_num].salary);如果我输入"fubar\n"作为输入,你认为x会是什么?
  2. 你认为来自"fubar\n"'f'会去哪里?
  3. 如果它回到<ungetc>D23ungetc>,你的下一个员工的姓氏会是什么?如果我在Windows上运行这段代码,并按CTRL+Z将D28ungetc>发送给Windows,你希望D33会是什么,假定scanf成功地将值放入两个变量yz

票数 1
EN

Stack Overflow用户

发布于 2013-01-23 11:35:10

遇到break语句时,循环过早中断

代码语言:javascript
复制
if(strlen(strng_buffer) == 0)
        break;

未初始化的字符缓冲区strng_buffer恰巧具有null作为导致strlen返回0的第一个字符

我相信你可能是有意

代码语言:javascript
复制
if(strlen(employee[employee_num].last_name) == 0)
            break;

作为循环终止符,这是您的部分中的一个打字错误导致了过早的循环退出。

票数 2
EN

Stack Overflow用户

发布于 2013-01-23 12:27:25

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

因此,要么在每个fgets上剥离\n,要么将检查更改为:

代码语言:javascript
复制
if(strlen(employee[employee_num].last_name) == 1) break;

此外,在获取缓冲区时,将1更改为更大的值,例如

代码语言:javascript
复制
fgets(strng_buffer, 10, stdin);

但是,如果您确实想要从每个fget中剥离\n,您可以这样做:

代码语言:javascript
复制
employee[employee_num].last_name[strlen(employee[employee_num].last_name)-1] = 0;

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

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14472004

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档