如何在循环中使用fgets和sscanf作为整数

这里有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等)

提前致谢!

假设Abhijit提到的修复,为什么要将第一个转换为第二个? 您是否意识到第二种行为与第一种行为不同,因为添加了sscanf ? 如果你打算缩短第一个,那么第二个看起来很笨重。 而不是在情境中添加sscanf ,为什么不通过声明一个struct employee *e = employee + employee_num;缩短第一个struct employee *e = employee + employee_num; 并重复使用,而不是employee[employee_num]

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

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

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

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

当Loop遇到break语句时,它会过早地中断

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

未初始化的字符缓冲区strng_buffer ,巧合地将null作为导致strlen返回0的第一个字符

我相信你可能有意

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

作为循环终止符,这是你的部分错字导致过早的循环退出。

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

因此,要么在每个fgets上删除\n ,要么将支票更改为:

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

此外,当你获得缓冲区时,将1更改为更大的内容,例如

 fgets(strng_buffer, 10, stdin); 

但是,如果你想从每个fgets中删除\n ,你可以执行以下操作:

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

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

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