如何在循环中使用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
手册并回答以下问题:
-
int x = scanf("%d", &employee[employee_num].salary);
如果我输入"fubar\n"
作为输入,你会认为x
是什么? - 你认为
"fubar\n"
的'f'
会在哪里? - 如果它不能回到
stdin
,那么你下一个员工的姓氏是什么? -
int x = scanf("%d", &employee[employee_num].salary);
如果我在Windows上运行此代码并按CTRL + Z将EOF
发送到stdin
您认为x
将是什么? -
int x = scanf("%d %d", &y, &z);
你期望x
是什么,假设scanf
成功地将值放入两个变量y
和z
?
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
而只是以这种方式剥离可能会导致问题。