关于结构内存分配机制的一些混淆?

时间:2018-03-15 01:18:37

标签: c linux dynamic-memory-allocation

在我的项目中,我遇到了C程序。

  1. 如下所示,htmp是结构指针。我们首先为它分配一个内存。但是为什么我们要再为它的元素word分配一个内存呢?
  2. 如果为结构的每个元素分配内存至关重要,为什么不为其他元素idnext分配内存?
  3. #define HASHREC bitewisehash  
    
    
    typedef struct hashrec {
        char    *word;
        long long id;
        struct hashrec *next;
    } HASHREC;
    
    /* Move-to-front hashing and hash function from Hugh Williams, http://www.seg.rmit.edu.au/code/zwh-ipl/ */
    
    /* Simple bitwise hash function */
    unsigned int bitwisehash(char *word, int tsize, unsigned int seed) {
        char c;
        unsigned int h;
        h = seed;
        for (; (c =* word) != '\0'; word++) h ^= ((h << 5) + c + (h >> 2));
        return((unsigned int)((h&0x7fffffff) % tsize));
    }
    
    /* Insert string in hash table, check for duplicates which should be absent */
    void hashinsert(HASHREC **ht, char *w, long long id) {
        HASHREC *htmp, *hprv;
        unsigned int hval = HASHFN(w, TSIZE, SEED);
        for (hprv = NULL, htmp = ht[hval]; htmp != NULL && scmp(htmp->word, w) != 0; hprv = htmp, htmp = htmp->next);
        if (htmp == NULL) {
            htmp = (HASHREC *) malloc(sizeof(HASHREC)); # allocate memory for htmp
            htmp->word = (char *) malloc(strlen(w) + 1); # why allocate memory again ?
            strcpy(htmp->word, w);    # 
            htmp->id = id;            # why not allocate memory for htmp->id ?
            htmp->next = NULL;        # why nor allocate memory for htmp->next?
            if (hprv == NULL) ht[hval] = htmp;
            else hprv->next = htmp;
        }
        else fprintf(stderr, "Error, duplicate entry located: %s.\n",htmp->word);
        return;
    }
    

3 个答案:

答案 0 :(得分:3)

你需要在脑海中分离两件事(1)我想存储的东西是什么内存? (2)什么变量(指针)将地址保存到存储的位置,以便我可以再次找到它。

首先声明两个指向struct hashrec的指针:

HASHREC *htmp, *hprv;

指针只不过是一个变量,它将地址保存为其他值作为其值。当您第一次声明两个指针时,它们是未初始化并且不保留地址。然后,你以一种相当尴尬的方式,在for循环声明中初始化两个指针,例如: hprv = NULL, htmp = ht[hval]以及之后hprv = htmp, htmp = htmp->next所以大概两个指针现在都有一个地址并指向某处。

在循环(使用空体)之后,您测试if (htmp == NULL),这意味着htmp未指向地址(如果您找到了感兴趣的哈希索引,则可能就是这种情况空)。

然后,为了为一个HASHREC(例如struct hashrec)提供存储空间,您需要分配存储空间,以便在内存块中存储要存储的内容。所以你分配一个块来保存一个结构。 (见:Do I cast the result of malloc?

现在,看看为内存分配的内容:

typedef struct hashrec {
    char    *word;
    long long id;
    struct hashrec *next;
} HASHREC;

您为包含(1)char *word;的结构分配了存储空间(指向char的指针 - 8字节(x86上为4字节)); (2)一个long long id;(两个都是8个字节)和(3)一个指针,用于保存序列中下一个HASHREC的地址。

毫无疑问id可以保留long long值,但wordnext呢?它们都是指针。指针有什么作用?可以找到他们指向的东西的地址。哪里可以word找到?你想要的东西目前由w指向,但不能保证w将继续保留你想要的单词,所以你要制作一份副本并将其存储为HASHREC。所以你看:

htmp->word = malloc(strlen(w) + 1);    /* useless cast removed */

现在malloc会返回什么?它将地址返回到新的内存块的开头,strlen(w) + 1个字节长。由于指针将其他值保存为其值,因此htmp->word现在将地址存储到新内存块的开头作为其值。所以htmp->word “指向”到新的内存块,您可以使用htmp->word作为参考来引用该内存块。

接下来发生的事情很重要:

    strcpy(htmp->word, w);    # 
    htmp->id = id;            # why not allocate memory for htmp->id ?
    htmp->next = NULL;        # why nor allocate memory for htmp->next?

strcpy(htmp->word, w);w复制到新的内存块中。 htmp->id = id;id的值分配给htmp->id不需要分配,因为当您分配时:

htmp = malloc(sizeof(HASHREC));  /* useless cast removed */

您为(1)char *指针,(2)long long id;和(3)struct hashrec*指针分配存储 - 您已经已分配对于long longhtmp->id可以将id的值存储在long long的内存中。

htmp->next = NULL;        # why nor allocate memory for htmp->next?

您尝试存储的内容是什么,需要htmp->next的新分配? (提示:目前没有)它将指向下一个struct hashrec。目前它已初始化为NULL,以便下次迭代到所有struct hashrec next指针的末尾时,当您到达NULL时,您知道自己就在最后。

另一种思考方式是,之前的struct hashrec next现在可以指向刚分配的节点。同样不需要额外的分配,前一个节点->next指针只是依次指向下一个节点,不需要分配任何特定的新内存。它仅用作引用(或指向)链中下一个节点的引用。

这里有很多信息,但是当你经历了确定(1)在我想要存储的东西存储的思维过程中? (2)什么变量(指针)将地址保存到存储的位置,以便我可以再次找到它... - 事情开始落实到位。希望这会有所帮助。

答案 1 :(得分:1)

当为结构分配内存时,只为成员word分配了足够的内存来保存指针,该指针也必须指向有效的内存,然后你可以分配它。

如果没有指向有效内存,它的值是 indeterminate 并尝试使用 indeterminate 值取消引用此类指针是未定义的行为。

答案 2 :(得分:1)

malloc(size)将分配给定大小的内存并返回已分配内存的起始地址。地址存储在指针变量中。

char *word中,变量word是指针类型,它只能保存char类型的指针,即内存中字符数据的地址。

所以,当你为结构类型变量htmp分配内存时,它将按如下方式分配内存, 2 字节为*word 4 id的字节数和*next

2 字节

现在,假设您要将以下内容存储到结构中:

{
word = Elephant
id = 1245
}

现在,您可以通过执行此id将ID直接保存到htmp->id = 1245成员中。但你也想保存一个单词&#34; 大象&#34;在你的结构中,如何实现这个目标?

htmp->word = 'Elephant'会导致错误,因为word是指针。所以,现在你分配内存来存储实际的字符串文字大象,并将起始地址存储在htmp->word

您可以使用char *word而不是在您的结构中使用char word[size],而无需为成员word单独分配内存。不这样做的原因是你要为单词选择一些随机大小,如果你存储较少的字符会浪费内存,如果单词太大则甚至会掉落。