在C语言中释放零长度数组的分配内存

4
我今天学了一个新技巧,就是在一个结构体末尾加上一个长度为零的数组,这样可以动态地调整数组大小以满足需要。这非常方便,可以帮助我在运行时而不是编译时决定结构体所需的空间大小,从而节省大量内存。
使用它们非常完美;然后我想起需要释放已分配的内存,于是我只是在那里写了一个free(struct); 但令我失望的是,这引发了一个错误:
    *** glibc detected *** ./program: free(): invalid next size (fast): <address>
    ======= Backtrace: =========
     <omitted>
    ======= Memory Map: ========
     <omitted>

这是一个简单的例子,代码格式很差:

   struct Stuff {
     int size; // defines the amount of bytes the entire struct will take up
     char data[0];
   }

   ...

   // This gives me an int and a char[30].
   struct Stuff *ptr = (struct Stuff *) malloc(sizeof(struct Stuff) + 30); 

   ... 
   doStuff();
   ...

   free(ptr);

我在free(ptr);处遇到了错误。

有什么想法吗?


你在 doStuff 方法中对 ptr 做了什么操作(问题可能就出在这里)? - Cédric Julien
你可能在超出data的末尾并破坏堆中的某些内容 - 问题直到调用free()才会显示出来,但free()本身不是问题所在。 - Paul R
请注意,不应将 malloc 的返回值强制转换,并且长度为零的字段是非标准的,因此不可移植。后者的标准方法是省略终止数组字段的大小。 - Jens Gustedt
4个回答

6
你的malloc()/free()代码没问题。为了验证,可以在malloc()free()之间注释掉所有内容,看看问题是否消失(我敢打赌它会)。
你几乎肯定在分配的内存结尾处写入了数据(可能是在doStuff()中)。例如,如果doStuff()使用ptr->size来确定ptr->data的大小,请确保正确初始化ptr->size

这两个可能看起来像是问题的原因。我尝试在malloc之后释放内存,剩下的代码运行得很好,就好像根本没有被释放一样。我想我需要进行一番大规模的错误调试。 - MaxGhost
嗯,我在问题结构体上使用了几个memset(),似乎解决了问题。感谢你的提示! - MaxGhost
"seemed to clear up the problem" -> "暂时掩盖了我的代码中的错误,但很可能会在以后出现问题。" - Paul R
不,你只是在假设。问题与字符串未正确终止有关,这就是为什么它会超出边界。使用memset可以解决这个问题。 - MaxGhost

1

删除doStuff(),只留下free(ptr)并重试。你还有同样的错误吗?


1

也许你的代码在某个地方改变了ptr的值。

使用:

struct Stuff * const ptr = ...

改为:

struct Stuff * ptr = ...

在编译时检测此类问题。


0

很可能你在doStuff()中所做的事情使用了超过结构体头部分配的30个额外字节。请确保你正在正确计算所需空间的数量。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接