我正在尝试学习 C,我目前正在尝试编写基本的堆栈数据结构,但我似乎无法正确获得基本的malloc
/free
。
这是我一直在使用的代码(我只是在这里发布一小部分来说明一个特定问题,而不是总代码,但错误消息是通过在 valgrind
中运行此示例代码生成的
#include <stdio.h>
#include <stdlib.h>
typedef struct Entry {
struct Entry *previous;
int value;
} Entry;
void destroyEntry(Entry entry);
int main(int argc, char *argv[])
{
Entry* apple;
apple = malloc(sizeof(Entry));
destroyEntry(*(apple));
return 0;
}
void destroyEntry(Entry entry)
{
Entry *entry_ptr = &entry;
free(entry_ptr);
return;
}
当我用--leak-check=full --track-origins=yes
运行它时valgrind
,我收到以下错误:
==20674== Invalid free() / delete / delete[] / realloc()
==20674== at 0x4028E58: free (vg_replace_malloc.c:427)
==20674== by 0x80485B2: destroyEntry (testing.c:53)
==20674== by 0x8048477: main (testing.c:26)
==20674== Address 0xbecc0070 is on thread 1's stack
我认为此错误意味着不允许destroyEntry
函数修改在main中显式分配的内存。是吗?为什么我不能只free
我在main
中分配的内存到另一个函数中?(这种行为是否以某种方式特定于 main?
每当将参数传递给函数时,都会创建一个副本,并且该函数在该副本上工作。 因此,在您的情况下,您正在尝试free
原始对象的副本,这没有任何意义。
您应该修改函数以获取指针,然后您可以让它直接在该指针上调用free
。
这是按值传递的,这意味着创建了副本,因此您尝试释放内存,局部变量entry
所在的位置。请注意,entry
是一个具有自动存储持续时间的对象,当程序超出destroyEntry
函数范围时,它所在的内存将自动释放。
void destroyEntry(Entry entry)
{
Entry *entry_ptr = &entry;
free(entry_ptr);
return;
}
你的函数应该接受一个指针(通过引用传递):
void destroyEntry(Entry *entry)
{
free(entry);
}
然后,您不必destroyEntry(*(apple));
,只需致电destroyEntry(apple);
.请注意,如果没有其他功能与destroyEntry
函数连接,则它是多余的,最好直接调用free(apple)
。
这里的其他答案指出了主要问题 - 因为当你在main()中调用destroyEntry时,你取消了对苹果的引用,它通过引用传递,创建一个副本。
即使你知道你的问题,回到错误并尝试将你所看到的文本与问题联系起来也会有所帮助,这样下次出现它时,你更有可能很快弄清楚。 我发现 C 和 C++ 错误有时看起来非常模棱两可。
通常,当我在释放指针或删除对象时遇到问题时,我喜欢打印出地址,尤其是在我分配地址时和尝试释放地址时。 Valgrind 已经给了你坏指针的地址,但它有助于将其与一个好的指针进行比较。
int main()
{
Entry * apple;
apple = malloc(sizeof(Entry));
printf("apple's address = %p", apple); // Prints the address of 'apple'
free(apple); // You know this will work
}
这样做之后,你会注意到 printf() 语句给了你一个类似于 0x8024712 的地址(只是在正确的一般范围内编造一个地址),但你的 valgrind 输出给出了0x4028E58。 你会注意到它们在两个非常不同的地方(事实上,"0x4......"在堆栈上,而不是 malloc() 分配的堆上,但我假设如果你刚刚开始,这对你来说还不是一个危险信号),所以你知道你试图从错误的地方释放内存,因此"无效的free()"。
所以从那里你可以对自己说:"好吧,不知何故我的指针被损坏了。 您已经将问题归结为一个小的、可编译的示例,因此从那里解决它不会花费很长时间。
TL;DR - 遇到与指针相关的错误时,请尝试打印地址或在你喜欢的调试器中找到它们。 它通常至少会为你指明正确的方向。
当然,所有这些都不是为了阻止在Stack Exchange上发布您的问题。 数以百计的程序员可能会从你这样做中受益。