在不同的函数中分配*内存?

时间:2022-03-29 21:22:28

I'm trying to learn C and I'm currently trying to write a basic stack data structure, but I can't seem to get basic malloc/free right.

我正在尝试学习C语言,目前正在尝试编写一个基本的堆栈数据结构,但是我似乎无法获得基本的malloc/free right。

Here's the code I've been using (I'm just posting a small part here to illustrate a specific problem, not the total code, but the error message was generated just by running this example code in valgrind)

下面是我一直在使用的代码(我只是在这里发布了一小部分来说明一个特定的问题,而不是总代码,但是错误消息是通过在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;
}

When I run it through valgrind with --leak-check=full --track-origins=yes, I get the following error:

当我在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

I think this error means that the destroyEntry function is not allowed to modify memory allocated explicitly in main. Is that right? Why can't I just free the memory I allocated in main in another function? (and is this behavior somehow specific to main?)

我认为这个错误意味着驱逐舰入口函数不允许修改主显式分配的内存。是这样吗?为什么我不能释放我在main函数中分配的内存呢?(这种行为是main独有的吗?)

3 个解决方案

#1


50  

Whenever you pass a parameter to a function, a copy is made, and the function works on that copy. So in your case, you are trying to free a copy of the original object, which doesn't make any sense.

每当您向一个函数传递一个参数时,就会生成一个副本,并且该函数在该副本上工作。在你的例子中,你试图释放一个原始对象的拷贝,这没有任何意义。

You should modify your function to take a pointer, and then you can have it call free directly on that pointer.

你应该修改你的函数来获取一个指针,然后你可以让它直接在那个指针上调用free。

#2


36  

This is passing by value, which means that copy is created, thus you try to free the memory, where local variable entry resides. Note that entry is an object with automatic storage duration and memory where it resides will be freed automatically when your program goes out of scope of destroyEntry function.

这是通过值传递的,这意味着复制被创建,因此您试图释放本地变量条目所在的内存。注意,entry是一个具有自动存储持续时间的对象,当程序超出destroyEntry函数的范围时,它驻留的内存将被自动释放。

void destroyEntry(Entry entry)
{
    Entry *entry_ptr = &entry;
    free(entry_ptr);
    return;
}

Your function should take a pointer (passing by reference):

您的函数应该取一个指针(通过引用传递):

void destroyEntry(Entry *entry)
{
    free(entry);
}

Then instead of destroyEntry(*(apple)); you just call destroyEntry(apple);. Note that if there is no other functionality connected with destroyEntry function, it's redundant and it's better to just directly call free(apple).

然后代替destroyEntry(*(苹果));你就叫destroyEntry(苹果);。请注意,如果没有其他与驱逐舰入口功能相关的功能,这是多余的,最好直接调用free(apple)。

#3


9  

The other answers here point out the main problem -- because you dereference your apple when you call destroyEntry in main(), it passes by reference, creating a copy.

这里的其他答案指出了主要的问题——因为当您在main()中调用destroyEntry时,它通过引用传递,创建一个副本。

Even once you know your problem, it helps to go back to the error and try to connect the text of what you're seeing to the problem, so that the next time it comes up you might be more likely to figure it out quickly. I find C and C++ errors can seem maddeningly ambiguous sometimes.

即使你知道了你的问题,它也会帮助你回到错误,并尝试把你所看到的文本与问题连接起来,这样下次它出现的时候,你可能会更快地找到它。我发现C和c++的错误有时看起来非常模糊。

Generally, when I'm having trouble freeing pointers or deleting objects, I like to print out addresses, especially right when I allocate it and right when I try to free it. valgrind already gave you the address of the bad pointer, but it helps to compare it to a good one.

一般来说,当我在释放指针或删除对象时遇到困难时,我喜欢打印地址,尤其是在分配地址时,以及在尝试释放地址时。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
}

After doing that, you'd notice the printf() statement gave you an address something like 0x8024712 (just making up an address in the right general range), but your valgrind output gave 0x4028E58. You'd notice they're in two very different places (in fact, "0x4..." is on the stack, not the heap where malloc() allocates from, but I'm assuming if you're just starting out that's not a red flag for you yet), so you know you're trying to free memory from the wrong place, hence "invalid free()".

这样做之后,您会注意到printf()语句给出了一个地址,比如0x8024712(只是在正确的一般范围内构造了一个地址),但是您的valgrind输出给出了0x4028E58。你会注意到它们在两个非常不同的地方(事实上,“0 x4…”是在堆栈上,不是malloc()分配的堆,但我假设如果你刚开始,还没有一个红旗),所以你知道你想从错误的地方释放内存,因此“无效的*()”。

So from there you can say to yourself "Okay, somehow my pointer is getting corrupted." You already boiled down your problem to a small, compilable example, so it won't take you long to solve it from there.

从这里你可以对自己说"好吧,我的指针坏了"您已经将您的问题归结为一个小型的、可编译的示例,因此从这里开始不需要很长时间就可以解决它。

TL;DR - when running into pointer-related errors, try printing the addresses or finding them in your favorite debugger. It often at least points you in the right direction.

当遇到指针相关的错误时,尝试打印地址或在您喜欢的调试器中找到它们。它通常至少能让你找到正确的方向。

None of this is to discourage posting your question on Stack Exchange, of course. Hundreds of programmers will likely benefit from your having done so.

当然,这并不是要阻止您在堆栈交换中发布您的问题。数百名程序员可能会从您这样做中获益。

#1


50  

Whenever you pass a parameter to a function, a copy is made, and the function works on that copy. So in your case, you are trying to free a copy of the original object, which doesn't make any sense.

每当您向一个函数传递一个参数时,就会生成一个副本,并且该函数在该副本上工作。在你的例子中,你试图释放一个原始对象的拷贝,这没有任何意义。

You should modify your function to take a pointer, and then you can have it call free directly on that pointer.

你应该修改你的函数来获取一个指针,然后你可以让它直接在那个指针上调用free。

#2


36  

This is passing by value, which means that copy is created, thus you try to free the memory, where local variable entry resides. Note that entry is an object with automatic storage duration and memory where it resides will be freed automatically when your program goes out of scope of destroyEntry function.

这是通过值传递的,这意味着复制被创建,因此您试图释放本地变量条目所在的内存。注意,entry是一个具有自动存储持续时间的对象,当程序超出destroyEntry函数的范围时,它驻留的内存将被自动释放。

void destroyEntry(Entry entry)
{
    Entry *entry_ptr = &entry;
    free(entry_ptr);
    return;
}

Your function should take a pointer (passing by reference):

您的函数应该取一个指针(通过引用传递):

void destroyEntry(Entry *entry)
{
    free(entry);
}

Then instead of destroyEntry(*(apple)); you just call destroyEntry(apple);. Note that if there is no other functionality connected with destroyEntry function, it's redundant and it's better to just directly call free(apple).

然后代替destroyEntry(*(苹果));你就叫destroyEntry(苹果);。请注意,如果没有其他与驱逐舰入口功能相关的功能,这是多余的,最好直接调用free(apple)。

#3


9  

The other answers here point out the main problem -- because you dereference your apple when you call destroyEntry in main(), it passes by reference, creating a copy.

这里的其他答案指出了主要的问题——因为当您在main()中调用destroyEntry时,它通过引用传递,创建一个副本。

Even once you know your problem, it helps to go back to the error and try to connect the text of what you're seeing to the problem, so that the next time it comes up you might be more likely to figure it out quickly. I find C and C++ errors can seem maddeningly ambiguous sometimes.

即使你知道了你的问题,它也会帮助你回到错误,并尝试把你所看到的文本与问题连接起来,这样下次它出现的时候,你可能会更快地找到它。我发现C和c++的错误有时看起来非常模糊。

Generally, when I'm having trouble freeing pointers or deleting objects, I like to print out addresses, especially right when I allocate it and right when I try to free it. valgrind already gave you the address of the bad pointer, but it helps to compare it to a good one.

一般来说,当我在释放指针或删除对象时遇到困难时,我喜欢打印地址,尤其是在分配地址时,以及在尝试释放地址时。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
}

After doing that, you'd notice the printf() statement gave you an address something like 0x8024712 (just making up an address in the right general range), but your valgrind output gave 0x4028E58. You'd notice they're in two very different places (in fact, "0x4..." is on the stack, not the heap where malloc() allocates from, but I'm assuming if you're just starting out that's not a red flag for you yet), so you know you're trying to free memory from the wrong place, hence "invalid free()".

这样做之后,您会注意到printf()语句给出了一个地址,比如0x8024712(只是在正确的一般范围内构造了一个地址),但是您的valgrind输出给出了0x4028E58。你会注意到它们在两个非常不同的地方(事实上,“0 x4…”是在堆栈上,不是malloc()分配的堆,但我假设如果你刚开始,还没有一个红旗),所以你知道你想从错误的地方释放内存,因此“无效的*()”。

So from there you can say to yourself "Okay, somehow my pointer is getting corrupted." You already boiled down your problem to a small, compilable example, so it won't take you long to solve it from there.

从这里你可以对自己说"好吧,我的指针坏了"您已经将您的问题归结为一个小型的、可编译的示例,因此从这里开始不需要很长时间就可以解决它。

TL;DR - when running into pointer-related errors, try printing the addresses or finding them in your favorite debugger. It often at least points you in the right direction.

当遇到指针相关的错误时,尝试打印地址或在您喜欢的调试器中找到它们。它通常至少能让你找到正确的方向。

None of this is to discourage posting your question on Stack Exchange, of course. Hundreds of programmers will likely benefit from your having done so.

当然,这并不是要阻止您在堆栈交换中发布您的问题。数百名程序员可能会从您这样做中获益。