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

时间:2019-11-20 00:09:14

标签: c pointers memory struct free

我的程序中有两个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时,我将ourHuffCoder的大小分配给huffcoder,然后将用于X个元素的内存分配给struct huffchar * tree:< / p>

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

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

但是,我稍后需要将这棵树变大,并且不知道最后这棵树上将有多少个元素。换句话说,每次添加元素时,我都会使用realloc()创建一个新树,该树大一个元素,然后将treehuffcoder的指针设置为此新的{ {1}}。

以下几行代码旨在实现这一目标:

updatedTree

请注意,在将 struct huffchar * updatedTree = realloc(ourHuffCoder -> tree, (ourHuffCoder->sizeOfTree+1)*sizeof(struct huffchar)); free(ourHuffCoder -> tree); ourHuffCoder -> tree = updatedTree; 指针更新为free(ourHuffCoder -> tree)之前,我使用行tree释放了先前分配给树的内存。但是,当我到达updatedTree行时,分配给HuffCoder指针free(ourHuffCoder -> tree) entirety 的内存将被释放,而不仅仅是分配给ourHuffCoder的内存。

这是我的变量窗口,之前,运行tree行: enter image description here

这是在之后运行free(ourHuffCoder->tree)行: enter image description here

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

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

free()

这显然不是我应该做的,因为我很快就会用光内存,但是我想看看是否将 struct huffchar * updatedTree = realloc(ourHuffCoder -> tree, (ourHuffCoder->sizeOfTree+1)*sizeof(struct huffchar)); ourHuffCoder -> tree = updatedTree; 中指向tree的指针更新为指向{{1 }},其中包括:

huffcoder之前

updatedTree之后 enter image description here

我的问题是,为什么要释放分配给整个ourHuffCoder -> tree = updatedTree;结构的内存,而不是仅仅释放给ourHuffCoder -> tree = updatedTree;的内存?我该如何解决?是否有更好的方法来增加分配给huffcoder的内存?

1 个答案:

答案 0 :(得分:3)

我看到的错误是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返回“相同”指针的情况下,程序也无法轻易分辨出来。旧指针已失效,因此任何使用都是未定义的行为:

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
}