在 while 循环中,gets() 只能接受一次输入

3

我是C语言的新手,正在做一些练习,但在while循环中使用gets()时遇到了问题。经过搜索,我认为这可能与\n字符有关,但我希望有人能够更全面地解释一下这里发生了什么:

这个循环只会运行一次 - 它会再次将“输入姓氏”打印到屏幕上,然后在gets()有机会再次获取任何输入之前退出循环:

while (employee_num <= 10)
{
    printf("Enter last name ");
    gets(employee[employee_num].last_name);
    if(strlen(employee[employee_num].last_name) == 0)
        break;
    printf("Enter first name ");
    gets(employee[employee_num].first_name);
    printf("Enter title ");
    gets(employee[employee_num].title);
    printf("Enter salary ");
    scanf("%d", &employee[employee_num].salary);        
    ++employee_num;
}

提前感谢您!


员工编号最初设置为什么? - Ryan M
3
绝对不要使用gets函数。该函数已经无法修复,其自身的手册告诉你不要使用它:“决不使用gets()。因为在不事先知道数据量的情况下,无法确定gets()将读取多少个字符,而且gets()会继续存储超出缓冲区末尾的字符,所以使用它非常危险。 它已被用于破坏计算机安全。请改用fgets()。” - ThiefMaster
employee_num 最初被设置为0。我刚开始了解 gets() 的问题,但我仍然很好奇为什么它无法正确循环。 - Gitarooman
如果正确使用,函数 gets() 不会做任何事情。在使用 gets() 后,请使用 fflush()。 - Mihai8
1
@user1929959 在输入流上使用fflush是未定义行为,所以不,那将是一个非常糟糕的想法。两个相邻的危险函数不能互相抵消... - Lundin
1
顺便说一下,在当前标准中,gets已经从C语言中删除。它不再是有效的C语言。 - Lundin
2个回答

5
在读取薪水后,输入缓冲区内会有一个换行符(\n),在第二次迭代中这个符号会被当作姓氏而被读取。你可以通过在最后一个 scanf 后添加 getchar() 来忽略它:
while (employee_num <= 10) {
    ...
    printf("Enter salary ");
    scanf("%d", &employee[employee_num].salary);        
    ++employee_num;
    getchar();
}

这个有效。谢谢!如果使用fgets()代替gets(),我假设这个问题就不会存在了 - 这是正确的吗? - Gitarooman
1
是的。不过,您需要去掉输入字符串末尾的额外\n。至于薪水,您可能想将其fgets到一个字符串缓冲区中,然后在该缓冲区上使用sscanf()(而不是scanf)。 - LSerni
1
一般情况下,将 gets() 替换为 fgets()! - Mats Petersson
每次读入更多数据之前,是否有必要清空正在使用的字符串缓冲区,或者我完全错了? - Gitarooman
scanf()函数不会接受在输入中输入空格后的任何内容吗? - muhammad tayyab
我强烈反对在输入字符串时使用scanf(),它只适用于字符串或字符。 - muhammad tayyab

2

参考skjaidev的回答,使用gets()函数时,如果发现换行符(\n),则不会将其复制到字符串中,这就是您遇到问题的原因。

另外,需要注意的是,gets函数与fgets函数有很大的不同:gets函数不仅使用stdin作为源,而且在返回的字符串中不包括结束的newline字符,并且不允许指定str的最大大小(这可能导致缓冲区溢出)。

在程序中使用gets()被认为是一种不好的做法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接