抱歉,如果这看起来像是一个重复的问题,但我想澄清一下我在这里找到的关于使用 malloc 为包含指针的结构分配堆内存的问题。我发现了有关malloc和结构体的各种其他问题,但是由于某种原因,它们似乎都涉及人们在定义结构时使用typedef,我不知道这是否会改变问题的上下文,所以我想通过提出一个新问题来避免混淆。
因此,这个问题的答案似乎暗示
了这样的结构:struct Vector {
double *data;
size_t size;
};
创建实例时,我们应该为结构本身分配内存空间:
struct Vector *retVal = malloc (sizeof (struct Vector));
和指向结构内数据的指针:
retVal->data = malloc (sz * sizeof (double));
问题是我一直在读Brian Kernighan和Dannis Ritchie的"ANSI C编程语言"(第二版(,这是一本很古老的书,但我认为它是好东西。不幸的是,它没有详细介绍malloc
。然后,我在第 119 页上遇到了以下代码,它说明了符号表管理(例如,对于预处理器(如何工作的示例。它为符号定义一个结构 (nlist( 和要用来替换符号的文本。nlist 存储在静态数组 (hashtab( 中,使用简单的哈希函数然后使用哈希的模数组大小来计算数组索引,因此如果发生冲突,则有一个指向下一个 nlist 的指针:
struct nlist { /* table entry: */
struct nlist *next; /* next entry in chain */
char *name; /* defined name */
char *defn; /* replacement text */
};
然后有一个安装函数,用于将新的nlist添加到hashtab:
struct nlist *lookup(char *);
char *strdup(char *);
/* install: put (name, defn) in hashtab */
struct nlist *install(char *name, char *defn)
{
struct nlist *np;
unsigned hashval;
if ((np = lookup(name)) == NULL) { /* not found */
np = (struct nlist *) malloc(sizeof(*np));
if (np == NULL || (np->name = strdup(name)) == NULL)
return NULL;
hashval = hash(name);
np->next = hashtab[hashval];
hashtab[hashval] = np;
} else /* already there */
free((void *) np->defn); /*free previous defn */
if ((np->defn = strdup(defn)) == NULL)
return NULL;
return np;
}
这时,我开始哭泣,前后摇晃,流口水,因为我的大脑从耳朵里融化了。对于指向nlist
结构中next
、name
或defn
的指针,似乎没有任何malloc
操作。这是对还是错?
谢谢。
PS 查找函数为:
/* lookup: look for s in hashtab */
struct nlist *lookup(char *s)
{
struct nlist *np;
for (np = hashtab[hash(s)]; np != NULL; np = np->next)
if (strcmp(s, np->name) == 0)
return np; /* found */
return NULL; /* not found */
}
您的问题有几个部分:
指针似乎没有任何
malloc
操作next
,name
或defn
nlist struct
。这是对的还是 错?
您从注释中看到,name
和defn
都分配了空间来保存关联的字符串,并且strdup
为您分配。(因此,当不再需要name
和defn
时,您需要free
它们。
问题的关键,以及似乎是您困惑的根源,是链表的next
指针。正如艾哈迈德正确指出的那样,pointer
是一种数据类型,就像int
或char
一样。(存储大小因操作系统而异,但通常您会在 x86 上找到4-byte
指针,在x86_64上找到8-byte
指针,嵌入式系统等也有极端情况。
正如int
可以保存整数,char
可以在不进一步分配的情况下保存字符一样,pointer
可以保存内存地址而无需进一步分配。如果您查看链表,特别是如何使用next
指针以及next
指针保存的内容,您将看到next
只用于保存以下节点的地址:
+----+ +----+ +----+
|1st | |2nd | |3rd |
|node| +-->|node| +-->|node|
| | | | | | | |
|next|--+ |next|--+ |next|-->...
+----+ +----+ +----+
节点本身分配:
np = (struct nlist *) malloc(sizeof(*np)); [see: footnote 1]
分配每个节点时,还会分配next
指针的空间。无需进一步分配next
.它可以愉快地独自保存下一个节点的地址。您只需要为指针指向的内容分配一个内存块,而不是指针本身。
在许多情况下,您分配的内容可能是指针,例如:
#define NUMPTRS 10
char **list;
list = malloc (NUMPTRS * sizeof *list);
但如果你仔细观察,它遵循规则。您不是在分配空间来保存list
的地址,而是在分配10
指针来保存其他东西的地址。
希望这能增加艾哈迈德试图解释的内容,并使你的头脑更清晰一点。如果您有任何问题,请告诉我。
脚注:
1.
没有必要投malloc
的回归.np = malloc (sizeof *np);
本身就很好。 请参阅我是否投射结果 马洛克?
如果我理解了你的问题,这就是答案。(顺便说一下,K&R是最好的(指针保存一个内存地址,好吗?当你分配一个,比如说,int * 或 char * 时,它们都会在内存中分配相同的空间来分别引用 int 和 char。在 32 位系统中,如果您从 int * 和 char * 中获取 sizeof,您会发现它们已经分配了 4 字节的内存。为什么?因为它们必须足够大才能在 32 位计算机中容纳 Ram 的最大地址。因此,如果他们已经占用了一个空间,为什么我们需要使用 malloc?这是因为对于大小为 5 的字符串,您需要 6 字节的内存 ( 5 + '\0' (。您可以使用 malloc 分配该内存,然后在 char * 中记下第一个字节的地址。我们不会直接将其写入 char * 中,因为这 4 个字节用于存储字符串的地址。右?但是假设你只想引用系统中的另一个结构(而不是创建一个(,那么你只需将分配结构的第一个字节的地址放在你的结构指针中。希望我已经理解了你的问题,否则,请随时发表评论。