在结构中的指针上使用 free() 释放整个结构的内存

Using free() on a pointer within a struct frees memory for the entire struct

我的程序中有两个 struct。第一个 huffchar 在下面,只显示了一般结构(大部分与问题无关),但第二个 huffcoder 是我遇到问题的那个:

struct huffchar {   
    int freq;   
    int is_compound;   
    int seqno;   
    union {
        struct {
        struct huffchar * left;
        struct huffchar * right;
        } compound;
        unsigned char c;   
    } u; 
};


struct huffcoder {   
    int freqs[NUM_CHARS];
    int code_lengths[NUM_CHARS];
    unsigned long long codes[NUM_CHARS];
    struct huffchar * tree;
    int sizeOfTree; 
};

当我在程序中初始化 huffcoder 时,我 malloc ourHuffCoder a huffcoder 的大小,然后将 X 许多元素的内存 malloc 到 struct huffchar * tree :

struct huffcoder * ourHuffChar = malloc(sizeof(struct huffcoder));

ourHuffChar -> tree = malloc(sizeof(struct huffchar)*NUM_CHARS);

不过,我以后需要把这棵树变大,不知道最后这棵树上会有多少元素。换句话说,每次我添加一个元素时,我都会创建一个 realloc() 大一个元素的新树,然后将 huffcodertree 的指针设置为这个新的 updatedTree.

以下代码行旨在实现此目的:

    struct huffchar * updatedTree = realloc(ourHuffCoder -> tree, (ourHuffCoder->sizeOfTree+1)*sizeof(struct huffchar));
    free(ourHuffCoder -> tree);
    ourHuffCoder -> tree = updatedTree;

请注意,在将 tree 指针更新为 updatedTree 之前,我使用行 free(ourHuffCoder -> tree) 释放之前分配给树的内存。但是,当我到达 free(ourHuffCoder -> tree) 行时,分配给 HuffCoder 指针 ourHuffCoderentirety 的内存被释放,而不仅仅是分配给 [=23] 的内存=].

这是我的变量 window before 运行ning free(ourHuffCoder->tree) 行:

这里是 运行free(ourHuffCoder->tree)行之后:

我也曾尝试创建一个全新的指针 huffchar * ourTree = ourHuffCoder -> tree 并将此变量用于 free() 方法,但我得到了相同的结果。

只是为了测试我的代码,我修改了上面的代码以删除 free() 行,

    struct huffchar * updatedTree = realloc(ourHuffCoder -> tree, (ourHuffCoder->sizeOfTree+1)*sizeof(struct huffchar));
    ourHuffCoder -> tree = updatedTree;

这显然不是我应该做的,因为我很快就会 运行 内存不足,但我想看看 huffcoder 中指向 tree 的指针是否会更新指向 updatedTree,它有:

之前 ourHuffCoder -> tree = updatedTree;

ourHuffCoder -> tree = updatedTree;之后

我的问题是,为什么分配给整个 huffcoder 结构的内存被释放,而不是只分配给 tree 的内存?我该如何解决这个问题?有没有更好的方法来增加分配给 tree 的内存?

我看到的错误是 realloc 已经是 mallocfree 的组合。这里的 free 调用是不必要和错误的:

struct huffchar * updatedTree = realloc(ourHuffCoder -> tree, (ourHuffCoder->sizeOfTree+1)*sizeof(struct huffchar));
free(ourHuffCoder -> tree);
ourHuffCoder -> tree = updatedTree;

也就是说,当我们调用realloc(ptr)时,ptr被释放并返回一个新的指针。分配器有时可以通过调整旧对象的大小来优化流程。

没有必要释放ptr,事实上我们也不能这样做。

如果我们不关心优化,我们几乎可以这样写realloc

#include <string.h>
#include <stdlib.h>
#define min(a, b) ((a) < (b) : (a) : (b))

void *our_realloc(void *oldptr, size_t newsize)
{
   if (newsize == 0) {
      free(oldptr);
      return 0;
   } else {
      void *newptr = malloc(newsize);
      if (oldptr) {
         size_t oldsize = __obtain_old_size_in_nonportable_way(oldptr);
         memcpy(newptr, oldptr, min(oldsize, newsize));
         free(oldptr); // !!!!
      }
      return newptr;
   }
}

即使在 realloc returns "same" 指针的情况下,程序也无法轻易辨别。旧指针已经失效,所以对它的任何使用都是未定义的行为:

newptr = realloc(oldptr, size);

if (newptr == oldptr) {  // did it really move?

这里使用 oldptr 在技术上是未定义的行为。我们永远不会同时持有两个指针;我们用一个换了另一个,交易发生在 realloc 黑匣子内。

我们可以捕获打印图像:

char oldptr_txt[64], newptr_txt[64];
snprintf(oldptr_txt, sizeof oldptr_txt, "%p", (void *) oldptr);
newptr = realloc(oldptr, size);
snprintf(newptr_txt, sizeof newptr_txt, "%p", (void *) newptr);

if (strcmp(oldptr_txt, newptr_txt) == 0) {
  // almost certainly stayed in place
} else {
  // almost certainly moved
}