我不明白C中动态分配的字符串是如何工作的。下面,我有一个例子,我认为我已经创建了一个指向字符串的指针,并将其分配给0内存,但我仍然可以给它字符。我显然做错了什么,但是什么?
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
char *str = malloc(0);
int i;
str[i++] = 'a';
str[i++] = 'b';
str[i++] = '\0';
printf("%s\n", str);
return 0;
}
答案 0 :(得分:3)
您正在做的是未定义的行为。它似乎现在可以工作,但不需要工作,如果有任何变化可能会中断。
malloc
通常会返回您可以使用的给定大小的内存块。在你的情况下,恰好碰到你正在触摸的那个块之外的有效内存。那个记忆不应该被触动; malloc
可能会使用该内存进行内部管理,它可能会将这些内存作为某些malloc
调用的结果,或完全不同的内容。无论是什么,它都不是你的,触摸它会产生不确定的行为。
答案 1 :(得分:0)
当前C标准的第7.20.3节部分说明:
“如果请求的空间大小为零,则行为为 实现定义:返回空指针,或者 行为就像大小是一些非零值,除了 返回的指针不得用于访问对象。“
这将是实现定义。它可以发送一个NULL指针,或者提到一些无法引用的东西
答案 2 :(得分:0)
通过执行malloc(0)
,您将创建一个NULL
指针或一个可以传递给free
的唯一指针。那条线没什么问题。问题在于执行指针运算并将值分配给尚未分配的内存时。因此:
str[i++] = 'a'; // Invalid (undefined).
str[i++] = 'b'; // Invalid (undefined).
str[i++] = '\0'; // Invalid (undefined).
printf("%s\n", str); // Valid, (undefined).
做两件事总是好的:
malloc
0字节。malloc
ed的内存块有效。 ...要检查malloc
请求的内存块是否有效,请执行以下操作:
if ( str == NULL ) exit( EXIT_FAILURE );
...致电malloc
后。
答案 3 :(得分:0)
您正在覆盖未分配的内存。这可能看似有效。但是当你调用free
时,你会遇到麻烦,其中堆函数试图给回内存块。
每个malloc()
返回的内存块都有一个标题和一个预告片。这些结构至少保持分配的内存的大小。有时你会有额外的警卫。您正在覆盖此堆内部结构。这就是free()
抱怨或崩溃的原因。
所以你有一个未定义的行为。
答案 4 :(得分:0)
你的malloc(0)错了。正如其他人已经指出的那样,可能会或者可能不会最终分配一些内存,但不管malloc实际上用0做什么,你应该在这个简单的例子中分配至少3 * sizeof(char)字节的内存。
所以我们这里有一个正确的麻烦。假设您为字符串分配了20个字节,然后用19个字符和一个空填充它,从而填充内存。到现在为止还挺好。但是,请考虑您希望在字符串中添加更多字符的情况;因为你只分配了20个字节并且你已经使用过它们,所以你不能将它们放在适当位置。您所能做的就是分配一个全新的缓冲区(比如40个字节),将原始的19个字符复制到其中,然后在末尾添加新字符,然后释放原始的20个字节。声音低效不是吗。这是低效的,分配内存需要做很多工作,而且与其他语言(例如C ++)相比,它听起来像是一个特别大量的工作,你只需要将字符串连接到str1 + str2。
除了在引擎盖下,这些语言必须完全相同的事情分配更多的内存和复制现有的数据。如果一个人关心高性能C会让你更清楚地花时间,而C ++,Java,C#等隐藏了方便使用的类背后的昂贵操作。这些类可以非常聪明(例如,为了以防万一,分配更多的内存而不是严格必要的内容),但如果你有兴趣从你的硬件中提取最佳性能,那么你必须要掌握这些内容。
这类问题正是Facebook和Twitter等运营部门在发展服务方面遇到的困难所在。迟早那些方便但效率低下的课程方法会增加不可持续的东西。