malloc for struct with pointer(revisited)

时间:2015-08-21 13:58:55

标签: c pointers struct malloc

如果这个似乎像一个重复的问题,我会抱歉,但我想对a previous question I found here有关使用malloc为包含指针的结构分配堆内存的一些说明。我已经找到了关于malloc和structs的各种其他问题,但由于某些原因它们似乎都涉及人们在定义结构时使用typedef,我不知道这是否会改变问题的上下文所以我想避免混淆新问题。

所以answers to this question似乎意味着使用如下的结构:

struct Vector {
    double *data;
    size_t size;
};

创建实例时,我们应该为结构本身分配内存空间:

struct Vector *retVal = malloc (sizeof (struct Vector));

AND指向结构内部数据的指针:

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;
 }

这是我开始哭泣并向后和向前摇晃的时刻,当我的大脑从我的耳朵里融化时流口水。对于malloc结构中nextnamedefn的指针,似乎没有任何nlist动作。这是对还是错?

感谢。

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

2 个答案:

答案 0 :(得分:2)

您的问题有几个部分:

  

指针似乎没有任何malloc动作   next中的namedefnnlist struct。这是对还是   错?

您从评论中看到,namedefn都有空间分配来保存相关字符串,因为strdup为您分配。 (因此,当{9}} freename不再需要时,您就会defn。{/ p>

问题的关键,以及似乎是您混淆的根源,是链接列表的next指针。正如Ahmad正确指出的那样,pointer是一种数据类型,与intchar相同。 (存储大小因操作系统而异,但一般情况下,您会在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);
     

本身很好。见Do I cast the result of malloc?

答案 1 :(得分:0)

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