0

我正在阅读“编程大师”,在 Stroustup 的介绍性章节中,他提到:

char buf[MAX_BUF];
gets(buf);

将导致缓冲区溢出,但是:

string s;
cin >> s;

将不会。谁可以给我解释一下这个?

4

5 回答 5

7

没有办法告诉gets函数缓冲区中有多少空间。它只是将接收输入写入您将其发送到的缓冲区。如果输入多于空间,它很可能会超出范围。

std::string另一方面,它是一个跟踪大小的容器,它会动态增长以适应输入。

gets是无可救药的破坏功能。永远不要使用它。

编辑:正如 James Kanze 指出的那样,gets已完全从 C 语言库中删除。

于 2013-08-13T14:32:12.193 回答
5

gets读取直到找到一个'\n'. 如果一行中有多个 MAX_BUF字符,它将继续写入超出缓冲区末尾的字符。(gets已被弃用,因为没有办法安全地使用它。)

cin >> s读取直到如果找到空白(所以语义不一样),如果需要的话会增长字符串。因为它增长了“缓冲区”,所以它永远不会超出它的末尾。

于 2013-08-13T14:34:00.303 回答
3

不像std::string哪个是通过operator >>引用传递给可以修改的,buf是固定的,它是通过指针传递的。缓冲区只能容纳您分配的数据,并且不能随着用户输入的大小而增长。gets不知道缓冲区的限制在哪里,所以它不会检查它,可能会写入超过分配空间的末尾。这是未定义的行为,可以利用它来用代表可执行代码的数据填充内存,以进行堆喷射类型的恶意攻击。

如果签名是gets(char **), 的编写者gets可能需要malloc-ed 空间并用于realloc扩展缓冲区;但是,考虑到当前指定 API 的方式,即使理论上也无法修复溢出。

这个问题非常严重,以至于 C 库的设计者决定gets在即将发布的语言标准中从标准库中删除。

于 2013-08-13T14:33:40.503 回答
2

接口完全不同。第一种情况,内存缓冲区有一个固定的大小,这个大小并没有传递给函数gets,所以它没有办法控制它是否写超出限制。

在第二种情况下,内存缓冲区由 管理std::string,该函数将确保它根据需要增长。也就是说,std::string将增长到有足够的空间容纳整个输入。

于 2013-08-13T14:33:01.057 回答
1

gets() 不检查长度,因此您可以通过 MAX_BUF 而不进行任何边界检查(因为 c/c++ 不进行边界检查)。通常在编译时或运行时,您会收到关于 gets() 不安全的警告。您应该使用进行一些检查的函数。std::string 将动态调整自身大小以适应您放入其中的任何大小数据,因此也可能只是将 MAX_BUF 更改为更大数字的问题。

于 2013-08-13T14:33:15.157 回答