ATOM表示指针,指向独占和常量字符串。 'C'中的字符串应以'\ 0'结尾。
我将展示两种在'C'中定义'ATOM TABLE'结构的方法:
struct atom1 {
struct atom1 *link;
int len;
char *str;
} *bucket[2048]
和
struct atom2 {
struct atom2 *link;
int len;
char str[1];
} *bucket[2048]
所以,当我想为这两种类型的ATOM分配内存时,我也有两种方式。
// memory + 1 for '\0'
struct atom1 *p = malloc(sizeof(*p) + len + 1);
和
// memory for '\0' is already in the define of struct atom
struct atom2 *p = malloc(sizeof(*p) + len);
所以我们可以看到,当我们想要分配内存时,'atom2'看起来更好。但另一方面,如果我们想要访问字符串的内存,我们将打破'C'的规则,因为'char str [1];'在'atom2'中
'atom2'真的很好吗?
答案 0 :(得分:5)
从C99开始,您可以选择使用灵活数组成员 - 即与atom2
相同但没有指定数组大小:
struct atom2 {
struct atom2 *link;
int len;
char str[];
} *bucket[2048];
通过这种方式,您可以在不违反语言规则的情况下将字符串和结构一起分配。
在这种情况下,当您分配内存时,请务必考虑nul字符串终止符:
struct atom2 *p = malloc(sizeof(*p) + len + 1);
(另请注意,您无需转换malloc
)的结果。
请注意,您的atom1
结构包含的char *
与char []
在语义上不同。指针是占用存储空间的数据成员,可以指向任何位置,而灵活数组成员不占用任何存储空间(除了为其明确分配的存储空间)并始终跟踪对象的其余部分。要使用atom1
,您需要分别为struct对象和字符串分配存储空间:
struct atom1 *p = malloc(sizeof(*p));
p->str = malloc(len + 1);
您在问题中建议的分配:
struct atom1 *p = malloc(sizeof(*p) + len + 1);
...至少要求你设置指针p->str
,指向正确的位置(类似p->str = ((char *) p) + sizeof(*p)
),但我不确定你不会如果您尝试将字符串存储在该位置,则调用未定义的行为。
答案 1 :(得分:0)
atom1没有任何意义,因为你应该为str
指向的内容动态分配内存,而不是整个结构。正如代码目前所示,没有一种方法可以使用atom1。
atom2调用未定义的行为。这被称为" struct hack"在旧的C标准,从来没有保证工作。即使您可能在结构的末尾分配了数据,也不允许写出超出固定数组的范围。因为你不知道结构的结束位置:它可能有填充字节。
是' atom2'真的很好吗?
两种方法都不好,不要使用它们中的任何一种。在现代C中,您可以通过使用灵活的数组成员以安全的方式执行此操作:
typedef struct atom3
{
struct atom3* link;
size_t lenght;
char str[];
} atom3_t;
然后将内存分配为:
atom3_t* p = malloc(sizeof(*p) + length + 1);
之后,您可以安全地使用str
,就好像它是任何大小为length + 1
的数组一样。