C 中的 gets() 和缓冲区

gets() and buffer in C

我知道,使用 gets() 是一个非常糟糕的主意,因为它可能会导致缓冲区溢出。但我有一些疑问。

假设一个c程序有如下代码-

    char word[6];
    gets(word);
    puts(word);

如果我输入例如 - HELLO WORLD,假设gets()将其读取为[H] [E] [L] [L] [O] [ ],其余进入输入缓冲区是否正确?

如果发生这种情况,puts() 如何获取数据以显示完整的字符串?

不,假设它用完就停止是不正确的space;它不知道有多少 space 可用。 gets 只是不断地读入字符并写入邻近的内存,调用未定义的行为。您可能会很幸运,并且没有使用相邻的内存(在 gets 之前或之后),并且 puts "just works"。或者它可能会覆盖您的堆栈指针,然后一切都会爆炸。或者它可能正确写入缓冲区,但缓冲区的位在 puts 到达之前被覆盖。或其他任何东西;这是未定义的行为。

不要这样做。永远不要使用 gets.

gets 函数一次读取整行。因此,在您的示例中,它将尝试将 11 个字符的 "HELLO WORLD" 读取到只有 6 个字符宽的缓冲区中。这会导致缓冲区溢出 undefined behavior.

并且因为 gets 无法限制它可以读取的字符数,这使得它很危险,这就是它从 C11 标准中删除的原因。

is it correct to assume that gets() reads it as [H] [E] [L] [L] [O] [ ], and the rest goes into the input buffer ?

没有。试图溢出缓冲区 word[]未定义的行为。任何事情都可能发生。其余代码无关紧要。发生这种情况时,没有指定缓冲区的内容。

你的问题表明你认为 gets 可能以某种方式知道 word 只有 6 个字符长,所以它只用 6 个字符填充它并将其余的留在与输入流关联的缓冲区中.事实并非如此。调用 gets(word) 仅将 word 的起始地址传递给 gets。这就是它收到的全部信息——一个起始位置。它不接收有关长度的任何信息。 gets 从输入流中读取,直到读取换行符或遇到文件结尾或发生错误。

如果你输入“HELLO WORLD”,程序打印出来,是因为gets读取数据写入内存,超出了word的范围。没有任何奇特的缓冲或交互发生——只是被写入未分配给该目的的内存。它可能会破坏您程序中的某些内容。但看起来你很“幸运”,因为错误并没有立即破坏你的程序,数据一直在那里,直到 puts 可以从内存中读取它并将其写入输出。

但是,您永远不应该期待这种行为。以这种方式工作的一个原因是你有一个非常简单的程序,它没有对内存做任何其他事情。在更复杂的程序中,有很多对象和活动,溢出缓冲区更有可能以多种方式破坏程序。

这正是 gets 的问题;一旦读取到 6 个字符,它 将不会 停止,它将继续读取,直到它看到一个换行符,并将这些字符立即分配给 word 缓冲区末尾后的内存。这就是缓冲区溢出 。如果 word 缓冲区之后的几个字节没有任何 重要的 内容(例如堆栈帧的 return 地址,或另一个局部变量),则覆盖内存不会导致 明显的 问题,并且 puts 会做几乎相同的事情 - 从 word 和它后面的内存中读取 直到它看到字符串终止符。