带指针的结构的malloc(重新访问)

带指针的结构的malloc(重新访问),c,pointers,struct,malloc,C,Pointers,Struct,Malloc,如果这似乎是一个重复的问题,我很抱歉,但我想澄清一下关于使用malloc为包含指针的结构分配堆内存的问题。我发现了关于malloc和struct的各种其他问题,但出于某种原因,它们似乎都涉及到在定义struct时使用typedef的人,我不知道这是否会改变问题的上下文,因此我想通过提出一个新问题来避免混淆 因此,似乎意味着使用结构,例如: struct Vector { double *data; size_t size; }; 创建实例时,我们应该为结构本身分配内存空间: s

如果这似乎是一个重复的问题,我很抱歉,但我想澄清一下关于使用malloc为包含指针的结构分配堆内存的问题。我发现了关于malloc和struct的各种其他问题,但出于某种原因,它们似乎都涉及到在定义struct时使用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)和替换符号的文本。nlists存储在一个静态数组(hashtab)中,使用一个简单的哈希函数,然后使用哈希的模数组大小来计算数组索引,因此如果发生冲突,则会有一个指向下一个nlist的指针:

struct nlist { /* table entry: */
     struct nlist *next; /* next entry in chain */
     char *name; /* defined name */
     char *defn; /* replacement text */
 };
然后有一个安装函数,用于向hashtab添加新的nlist:

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 */
 }

如果我理解了你的问题,下面是答案。(顺便说一句,K&R是最好的)
指针包含一个内存地址,好吗?当分配int*或char*时,它们都在内存中分配相同的空间,分别引用int和char。怎么用?在32位系统中,如果从int*和char*中获取sizeof,您会发现它们已经分配了4字节的内存。为什么?因为它们必须足够大,以容纳32位计算机中最大的Ram地址。那么,如果他们已经占用了一个空间,为什么我们需要使用malloc呢?这是因为对于大小为5的字符串,您需要6字节的内存(5+'\0')。使用malloc分配内存,然后在char*中写下第一个字节的地址。我们不会直接将其写入char*中,因为这4个字节用于存储字符串的地址。正确的?但是假设您只想引用系统中的另一个结构(而不是创建一个),那么您只需将分配的结构的第一个字节的地址放在结构指针内。希望我已经理解了你的问题,否则请随意评论。

你的问题有几个部分:

指针似乎没有执行任何
malloc
操作 到
nlist结构中的
next
name
defn
。这是对的还是错的 错了吗

您已经从注释中看到,
name
defn
都通过
strdup
为您分配空间来保存关联字符串。(因此,当不再需要
free
name
defn
时,您就可以使用它们了。)

问题的关键,以及您困惑的根源,是链表的
next
指针。正如Ahmad正确指出的,
指针
是一种数据类型,与
int
char
一样。(存储大小因操作系统而异,但通常您会在x86上找到
4字节
指针,在x86_64上找到
8字节
指针。嵌入式系统也有一些特殊情况等。)

正如
int
可以保存整数,
char
可以保存字符而无需进一步分配一样,
指针可以保存内存地址而无需进一步分配。如果查看链接列表,特别是
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);
它本身就很好。看


我看不出你的代码和你正在读的书中的代码之间的联系你的假设是错误的,调用
malloc
。哦,我的上帝。谢谢Michael-strdup用于初始化name和defn,它包含对malloc的调用。我只是不明白。我猜“下一个”nlist也会经历同样的过程。谢谢你的帮助。Zachi,我已经从书中逐字复制了代码,所以不确定你的意思。K&R第二版确实很旧,过时,充满了不好的实践和几个错误。我不会接受