为什么在声明动态变量时,保留超过指定的数量

时间:2013-11-18 17:56:37

标签: c dynamic-memory-allocation

我有以下代码

char *str = (char *) malloc(sizeof(char)*5);
printf("Enter a string: ");
scanf("%s", str);
printf("%s\n", str);

此代码假设将在内存ex: 5 * 8 bit中保留5个位置,这意味着将存储5个字符 现在,当输入任意数量的字符(仅限最多五个)时,无论是在编译时还是在运行时都不会出现任何错误。
这是正常的吗?或者我的代码中有一个我不理解的错误?

5 个答案:

答案 0 :(得分:1)

C不会阻止你在脚下射击。 scanf将很乐意覆盖给定的缓冲区,从而调用未定义的行为。在运行时无法可靠地检测到此错误,并且将以无法预测的方式无声地破坏内存并破坏应用程序的运行时。

作为程序员,您有责任防止这种情况发生 - 在这种情况下,例如,将scanf替换为更安全fgets

答案 1 :(得分:0)

动态分配内存时,将分配比指定的空间更多的空间。通常malloc实现将请求的大小舍入为8或16的倍数或其他2 ^ n。这可能是您没有收到任何错误的原因之一。

答案 2 :(得分:0)

您确实只为5个字节分配空间(即最多4个字符的字符串+终止NUL),但您的scanf不知道。它将幸福地溢出分配的缓冲区。您有责任确保不会发生这种情况;你需要相应地改变你的代码。溢出缓冲区是未定义的行为,因此理论上“任何事情”可能发生或不发生,但实际上它往往会覆盖相邻内存中的其他内容,破坏其他变量的内容,甚至可能破坏程序代码(导致漏洞利用)恶意用户可以制作输入字符串以执行任意代码的地方。

(另外请注意,根据定义,sizeof char始终为1,您无需与其相乘。)

答案 3 :(得分:0)

您已经分配了5个字节,但scanf将很乐意继续写入* un *已分配的内存。这是一个缓冲区溢出,C运行时假设您知道自己在做什么;没有进行边界检查。

请勿使用scanf。使用fgets读取最多5个字节的行:

char *str = malloc(5);
fgets(str, 5, stdin);

如果您输入的行数超过4个,fgets只会丢弃额外的字符。

答案 4 :(得分:0)

你要求5个字符,你得到的内存可以包含至少 5个字符;分配器可以自由地为内部原因提供更多内存,但是没有标准的方法可以知道它给你带来了多少。

此外,通常没有即时错误,即使你实际上溢出了缓冲区 - 标准没有强制执行边界检查,它只是说这是“未定义的行为”,即任何事情都可能发生,从“你的程序似乎通过鼻子恶魔来“通过”宇宙死亡。

在大多数实现中发生的实际是你很乐意写下你的缓冲区之后发生的事情 - 通常是其他局部变量或堆栈变量的返回地址,其他内存块和分配器的数据结构用于堆分配。由于更改了无关变量,堆损坏(通常在调用free时发现),分段错误等,效果通常是“不可能”的错误。

您必须非常小心这种错误,因为缓冲区溢出不仅会破坏应用程序的稳定性,还会被用于安全漏洞。因此,永远不要随意写入缓冲区 - 始终使用允许您指定缓冲区总大小的函数,并在其边界处停止。