C 在不同功能中分配的可用内存?
我正在尝试学习C语言,目前我正在尝试编写一个基本的堆栈数据结构,但我似乎无法正确使用基本的C 在不同功能中分配的可用内存?,c,pointers,memory-management,malloc,free,C,Pointers,Memory Management,Malloc,Free,我正在尝试学习C语言,目前我正在尝试编写一个基本的堆栈数据结构,但我似乎无法正确使用基本的malloc/free 下面是我一直在使用的代码(我只是在这里发布一小部分来说明一个特定的问题,不是全部代码,而是通过在valgrind中运行此示例代码生成的错误消息) 我认为这个错误意味着不允许destroyEntry函数修改main中显式分配的内存。是这样吗?为什么我不能在另一个函数中释放在main中分配的内存?(这种行为在某种程度上特定于main吗?每当您将参数传递给函数时,就会生成一个副本,并且函数
malloc
/free
下面是我一直在使用的代码(我只是在这里发布一小部分来说明一个特定的问题,不是全部代码,而是通过在valgrind
中运行此示例代码生成的错误消息)
我认为这个错误意味着不允许
destroyEntry
函数修改main中显式分配的内存。是这样吗?为什么我不能在另一个函数中释放在main
中分配的内存?(这种行为在某种程度上特定于main吗?每当您将参数传递给函数时,就会生成一个副本,并且函数会在该副本上工作。因此,在您的情况下,您试图释放
原始对象的副本,这没有任何意义
您应该修改您的函数以获取指针,然后您可以让它直接在该指针上调用free
。这是通过值传递的,这意味着创建了副本,因此您尝试释放本地变量条目
所在的内存。请注意,entry
是一个具有自动存储持续时间的对象,当您的程序超出destroyEntry
功能的范围时,它所在的内存将自动释放
void destroyEntry(Entry entry)
{
Entry *entry_ptr = &entry;
free(entry_ptr);
return;
}
函数应采用指针(通过引用传递):
然后,而不是destroyEntry(*(apple))代码>你只需调用销毁条目(苹果)代码>。请注意,如果没有其他与destroyEntry
功能相关的功能,这是多余的,最好直接调用free(apple)
这里的其他答案指出了主要问题——因为在main()中调用destroyEntry时取消了对apple的引用,它通过引用传递,创建了一个副本
即使你知道了你的问题,回到错误并尝试将你所看到的文本与问题联系起来也是有帮助的,这样下次出现问题时,你可能会更快地找到答案。我发现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()从中分配的堆,但我假设如果您刚刚开始,这对您来说还不是一个危险信号),因此您知道您试图从错误的位置释放内存,因此“invalid free()”
因此,从那里你可以对自己说“好吧,不知怎么的,我的指针被破坏了。”你已经把你的问题归结为一个小的、可编译的例子,所以从那里解决问题不需要太长时间
TL;DR-遇到指针相关错误时,请尝试打印地址或在您喜爱的调试器中查找地址。它通常至少为你指明了正确的方向
当然,所有这些都不是为了阻止在Stack Exchange上发布您的问题。数百名程序员可能会从您这样做中受益。+1用于明确问题和SSCCE。@MatteoItalia我以前从未听说过。这绝对是个好主意。谢谢你向我介绍它。谢谢你发布这篇文章…这是一个关于用指针等找出错误的非常好的观点。我一直在学习堆栈和堆,但没有意识到它们有通用的内存地址。(所以,NULL
-->0x0
,stack
-->0x4
和heap是什么?)此外,我不能对你的帖子进行一个字符的更改,但是在printf字符串中:苹果的地址=%d”
格式字符串应该是%p
,而不是%d
,对吗?我不能百分之百肯定地告诉你堆地址总是“0x8…”,堆栈地址总是“0x4…”。老实说,我现在主要做嵌入式编程,地址空间定义得很好,只有你的进程在运行。然而,我的理解是,在x86上,每个进程都有自己的虚拟地址空间,根据我的经验,这些“规则”似乎是正确的。感谢您指出%d问题。它可以工作(因为它可以打印地址),但更难阅读。我自己通常使用“0x%x”,因为这是我习惯于看到它的方式。因此,为了清楚起见,将*(apple)
传递到DestroyEntry
函数中会创建一个新的Entry
结构,它与原始的apple
结构分离?
void destroyEntry(Entry *entry)
{
free(entry);
}
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
}