为什么这会打印出“测试”?:
char *str;
str = (char *)malloc(1);
str[0] = 't';
str[1] = 'e';
str[2] = 's';
str[3] = 't';
我正在尝试动态扩展字符串并尝试了解 malloc/realloc 的工作原理,而上述行为让我感到困惑,因为 malloc()/realloc() 建议扩展 char* 。
提前致谢。
未定义的行为意味着任何事情都可能发生。包括看起来“工作”,什么都没有,或分段错误。您的示例代码确实很糟糕,但 C 标准不保证它会做任何“有用”的事情,也不保证在编译时或运行时一定会发生任何“坏事”。
您正在写超出“正式”分配的内存的末尾。大多数内存分配系统都有内部使用的最小大小,您可能实际上并没有超出该边界,因此您的代码似乎可以正常工作。如果你让字符串足够长,你最终会传递一个对操作系统很重要的边界,你的程序就会崩溃。
您可以分配一个随机数str
,然后也将其视为一个指针,并且每隔一段时间它就会真正起作用。但是你不知道你可能在写什么。与您的内存溢出相同。内存分配器可能会将分配打包得足够紧,以至于您正在覆盖程序中的其他内容。
您应该始终确保您不会超出任何数组的范围。 曾经。缓冲区溢出(和欠载)正是许多黑客利用来侵入系统的原因。确保您不允许它们,并且您已经比那里的大量旧代码更好。
显然,这段代码是完全错误的——您正在访问超出数组边界的内存。
它有效,因为:
没有适当的机制来检测每一个无效的内存访问。许多此类尝试会导致分段错误,但并非每次都发生。很多时候,这样的错误代码只是简单地覆盖了一些随机变量等——这就是为什么像这样的调试问题会很快成为一场噩梦的原因之一。我建议您熟悉Valgrind。
在这种特殊情况下,我会说malloc()
将分配的内存块四舍五入到(至少)4的倍数,所以在这种情况下它可能会按预期工作。但它仍然是一个错误。
你也没有明确地终止字符串,而且再次 - 行为真的是随机的,真的str[4]
可以有任何价值。这取决于很多事情——从堆分配器的实现到纯粹的巧合。