C语言中,scanf函数之后如何使用gets函数?

3

我有两个问题:

  1. 为什么只有在"%d "中添加空格时,scanf("%d ", &num);才能正常工作?

我尝试在scnaf和gets之间使用fflush(stdin) \ _flushall(),但它不起作用,跳过了gets。

  1. 当我加上空格后,它首先执行scanf,然后是gets,最后打印数字并输出字符串。
void main()
{
    char ch, str[10];
    int num;
    printf("请输入你的数字:");
    scanf("%d ", &num);
    printf("%d\n",num);
    gets(str);
    puts(str);
    system("pause");
}

3
只有在输入数字后输入非空格字符,scanf("%d ", &num); 才会返回。 - chux - Reinstate Monica
8
永远不要使用 gets 函数。你不应该担心它如何与 scanf 交互,因为你绝对不应该使用它。 - William Pursell
2
请勿使用 fflush(stdin) - Ed Heal
3
也许阅读手册页面会很有用。 - Ed Heal
5
在C语言中没有gets()函数。main函数必须返回int类型。 - n. m.
显示剩余13条评论
2个回答

3
为什么只有在"%d " -> scanf("%d ", &num); 中加入空格时才有效?
没有在"%d"后面加上空格的scanf("%d", &num);在读取数字后停止扫描。因此,对于输入123Enter'\n'保留在stdin中供下一个输入函数使用,例如现在已不再建议使用的gets()函数。gets()读取单个'\n'并返回。通过添加空格,scanf("%d ", &num);消耗数字后的空格,并且在输入数字后非空白字符输入之前不返回。
当我加入空格后,它首先执行scanf,然后是gets,最后打印数字和字符串。
通过添加空格,scanf("%d ", &num);在数字后非空白字符输入之前不返回(例如以下代码中的'a')。由于stdin通常是行缓冲的,这意味着需要先输入2行。 123Enter abcEnter
建议改用fgets()来读取用户输入的
char str[10*2]; // no need for such a small buffer
int num;
printf("Enter your number : ");
fflush(stdout);
fgets(str, sizeof str, stdin);
sscanf(str, "%d", &num);
printf("%d\n",num);

printf("Enter data : ");
fflush(stdout);
fgets(str, sizeof str, stdin);
fputs(str, stdout);

更健壮的代码会检查 fgets(),sscanf() 的结果,并使用 strtol() 而不是 sscanf()

3

C FAQ涵盖了所有与scanf有关的问题。请参阅为什么每个人都说不要使用scanf?我应该使用什么来代替?以及相关条目。通常,你会使用fgets,然后处理生成的行,例如使用sscanf并检查sscanf是否成功。这避免了留下未解析的输入和冒险进入无限循环。

int number;
char line[255];

fgets( line, sizeof(line), stdin );
if( sscanf( line, "%d", &number ) != 1 ) {
    fputs("That doesn't look like a number.\n", stdin);
}

请注意,fgets 函数会读取到换行符 或者与缓冲区大小相同的内容。如果一行字符超过了缓冲区的大小,函数只会读取部分内容。下一个读操作会继续读取这一行剩余的内容。有一些方法可以避免这种情况,比如使用POSIX getline 函数,但至少你不会陷入无限循环中。
让我们来解读一些注释。

永远不要使用 gets 函数。请使用 fgets 函数。

不使用 gets 函数的原因是,它不能限制从标准输入流(stdin)读取的内容长度。这意味着用户可以溢出缓冲区,造成极大的破坏。
char buffer[32];

// What the line is more than 31 characters?
gets(buffer);

fgets()函数接受缓冲区的大小,并最多读取那么多个字符。这可以防止缓冲区溢出。

char buffer[32];

// If there's more than 31 characters it will stop reading.
// The next read of stdin will get the rest of the line.
fgets( buffer, sizeof(buffer), stdin );

"C语言中没有gets()函数。"

事实上,C语言中确实有gets()函数。

事实上,C语言中确实没有gets()函数。

这取决于你所说的是哪个版本的C语言。

有些人说“C语言”时指的是当前标准C11。其他人说“C语言”时指的是先前的标准C99。仍然有一些人坚持使用最初的标准C90。在C90中有一个gets()函数,在C99中被弃用,在C11中被从语言中删除。

C编译器和文档远远落后于标准。许多编译器仍在努力支持C99。如果你使用C11,你会对缺乏支持感到非常惊讶。如果你希望你的代码能够在大多数编译器上运行,请写成C99。

总之,不要使用gets


该问题没有标记任何特定版本,因此我们必须假设使用标准C,即仅限于C11-请阅读标签Wiki!如果您认为这很重要,则正确的方法是要求OP进行澄清。 - too honest for this site
1
@Olaf 一个询问scanf基本问题的人可能甚至不知道C11或C标准的存在。如果你在技术上是正确的,但是提问者不理解,那有什么意义呢?你在跟谁说话? - Schwern
"C编译器和文档与标准相比相差甚远。在全操作系统托管环境中,只有MSVC落后了至少18年。gcc和clang都很好,连同大多数相关库的部分(顺便说一下,它们不是这两个编译器的一部分)也很好。" - too honest for this site
很多人不幸地使用MSVC,或者使用过时的编译器和资料进行学习。如果他们在询问scanf和gets,那么他们可能就是这些人之一。 - Schwern

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