从 C 中其他函数内部释放指针

发布于 2024-11-08 12:06:19 字数 439 浏览 0 评论 0原文

考虑一下 c 代码:

void mycode() {
  MyType* p = malloc(sizeof(MyType));
  /* set the values for p and do some stuff with it */
  cleanup(p);
}


void cleanup(MyType* pointer) {
  free(pointer);
  pointer = NULL;
}

我认为调用 cleanup(p); 后 p 的内容现在应该为 NULL,这是错误的吗? cleanup(MyType*pointer) 能否正确释放内存分配?

我正在编写我的大学作业,发现调试器仍然显示指针具有内存地址,而不是我期望的 0x0(或 NULL)。

我发现 C 中的内存管理非常复杂(我希望不仅仅是我)。任何人都可以阐明正在发生的事情吗?

Consider the c code:

void mycode() {
  MyType* p = malloc(sizeof(MyType));
  /* set the values for p and do some stuff with it */
  cleanup(p);
}


void cleanup(MyType* pointer) {
  free(pointer);
  pointer = NULL;
}

Am I wrong in thinking that after cleanup(p); is called, the contents of p should now be NULL? Will cleanup(MyType* pointer) properly free the memory allocation?

I am coding my college assignment and finding that the debugger is still showing the pointer to have a memory address instead of 0x0 (or NULL) as I expect.

I am finding the memory management in C to be very complicated (I hope that's not just me). can any shed some light onto what's happening?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

乖乖兔^ω^ 2024-11-15 12:06:19

是的,这将正确释放内存。

cleanup函数内部的pointer是一个局部变量;仅为该函数在本地存储的传入值的副本。

这可能会增加您的困惑,但您可以从 cleanup 内部调整变量 p 的值(对于 mycode 方法来说是本地的) > 方法如下:

void cleanup(MyType** pointer) {
  free(*pointer);
  *pointer = NULL;
}

在这种情况下,pointer 存储指针的地址。通过取消引用,您可以更改存储在该地址的值。您将像这样调用 cleanup 方法:(

cleanup(&p);

也就是说,您想要传递指针的地址,而不是其值的副本。)

我会注意到,处理这种情况通常是很好的做法在软件的同一逻辑“级别”上进行分配和释放 - 即不要让调用者负责分配内存,然后在函数内释放它。保持一致并处于同一水平。

Yes that will free the memory correctly.

pointer inside the cleanup function is a local variable; a copy of the value passed in stored locally for just that function.

This might add to your confusion, but you can adjust the value of the variable p (which is local to the mycode method) from inside the cleanup method like so:

void cleanup(MyType** pointer) {
  free(*pointer);
  *pointer = NULL;
}

In this case, pointer stores the address of the pointer. By dereferencing that, you can change the value stored at that address. And you would call the cleanup method like so:

cleanup(&p);

(That is, you want to pass the address of the pointer, not a copy of its value.)

I will note that it is usually good practice to deal with allocation and deallocation on the same logical 'level' of the software - i.e. don't make it the callers responsibility to allocate memory and then free it inside functions. Keep it consistent and on the same level.

乞讨 2024-11-15 12:06:19

cleanup 将正确释放 p,但不会更改其值。 C 是一种按值传递语言,因此您无法从被调用函数更改调用者的变量。如果您想从 cleanup 设置 p,您需要执行以下操作:

void cleanup(MyType **pointer) {
  free(*pointer);
  *pointer = NULL;
}

并这样称呼它:

cleanup(&p);

您的代码有点不惯用,您能解释一下吗更好一点为什么要编写这个cleanup函数?

cleanup will properly free p, but it won't change its value. C is a pass-by-value language, so you can't change the caller's variable from the called function. If you want to set p from cleanup, you'll need to do something like:

void cleanup(MyType **pointer) {
  free(*pointer);
  *pointer = NULL;
}

And call it like:

cleanup(&p);

Your code is a little bit un-idiomatic, can you explain a bit better why you want to write this cleanup function?

一张白纸 2024-11-15 12:06:19

是:有一块内存是由malloc(3)神奇地产生的。您已将此内存的地址(但不是内存本身)以任何有意义的方式分配给指针 p,该指针是 mycode()< 中的 auto 变量/代码>。

然后,按值将 p 传递给 cleanup(),这将复制指针,并使用 cleanup() 的本地副本,释放该块。 cleanup() 然后将它自己的指针实例设置为 NULL,但这没有用。一旦函数完成,参数指针就不再存在。

回到mycode(),您仍然有指针p保存地址,但是该块现在位于空闲列表上,并且在再次分配之前对于存储并不是很有用。

您可能会注意到,您甚至仍然可以存储到 *p, 并从中读回,但是会发生各种数量的下游损失,因为该内存块现在属于库,并且您可能会损坏其数据结构或 malloc() 块的未来所有者的数据。

仔细阅读 C 语言可以让您对变量生存期有一个抽象的概念,但是将参数传递和局部变量分配的近乎通用(无论如何对于编译语言)实现可视化为堆栈操作要容易得多。在 C 课程之前学习汇编课程会有所帮助。

Yes

Yes

Yes: There is a block of memory magically produced by malloc(3). You have assigned the address of this memory, but not the memory itself in any meaningful way, to the pointer p which is an auto variable in mycode().

Then, you pass p to cleanup(), by value, which will copy the pointer and, using the copy local to cleanup(), free the block. cleanup() then sets it's own instance of the pointer to NULL, but this is useless. Once the function is complete the parameter pointer ceases to exist.

Back in mycode(), you still have pointer p holding an address, but the block is now on the free list and not terribly useful for storage until allocated again.

You may notice that you can even still store to and read back from *p, but various amounts of downstream lossage will occur, as this block of memory now belongs to the library and you may corrupt its data structures or the data of a future owner of a malloc() block.

Carefully reading about C can give you an abstract idea of variable lifetime, but it's far easier to visualize the near-universal (for compiled languages, anyway) implementation of parameter passing and local variable allocation as stack operations. It helps to take an assembly course before the C course.

枉心 2024-11-15 12:06:19

这不起作用,因为 cleanup() 中的指针是本地的,因此调用函数看不到为其分配NULL。有两种常见的方法可以解决这个问题。

  1. 不要发送清理指针,而是向其发送指向该指针的指针。因此,将 cleanup() 更改如下:
void cleanup(MyType** 指针)
{
  自由(*指针);
  *指针=空;
}

然后只需调用cleanup(&p)

  1. 第二种非常常见的选项是使用#define 宏来释放内存并清理指针。

如果您使用 C++,则还有第三种方法,将 cleanup() 定义为:

void cleanup(MyType& *pointer)
{
// 你的旧代码保持不变
}

This won't work as the pointer in cleanup() is local, and thus assigning it NULL is not seen by the calling function. There are two common ways of solving this.

  1. Instead of sending cleanup the pointer, send it a pointer to the pointer. Thus change cleanup() as follows:
void cleanup(MyType** pointer)
{
  free(*pointer);
  *pointer = NULL;
}

and then just call cleanup(&p).

  1. A second option which is quite common is to use a #define macro that frees the memory and cleans the pointer.

If you are using C++ then there is a third way by defining cleanup() as:

void cleanup(MyType& *pointer)
{
// your old code stays the same
}

东风软 2024-11-15 12:06:19

这里有两个问题:

我的想法是不是错了?
清理(​​p);被称为,内容
p 现在应该为 NULL?

是的,这是错误的。调用free后,指针指向的内存被释放。这并不意味着指针指向的内容被设置为 NULL。另外,如果您期望指针 pmycode 中变为 NULL,则不会发生这种情况,因为您正在传递 p 的副本清理。如果您希望 mycode 中的 p 为 NULL,那么您需要一个指向 cleanup 中的指针,即 cleanup 签名将为 清理(​​MyType**)

第二个问题:

将正确清理(MyType* 指针)
释放内存分配?

是的,由于您正在对 malloc 返回的指针执行 free 操作,因此内存将被释放。

There are two questions are here:

Am I wrong in thinking that after
cleanup(p); is called, the contents of
p should now be NULL?

Yes, this is wrong. After calling free the memory pointed by the pointer is deallocated. That doesn't mean that the content pointed by the pointer is set to NULL. Also, if you are expecting the pointer p to become NULL in mycode it doesn't happen because you are passing copy of p to cleanup. If you want p to be NULL in mycode, then you need a pointer to pointer in cleanup, i.e. the cleanup signature would be cleanup(MyType**).

Second question:

Will cleanup(MyType* pointer) properly
free the memory allocation?

Yes, since you are doing free on a pointer returned by malloc the memory will be freed.

巷子口的你 2024-11-15 12:06:19

不只是你。

cleanup() 将正确清理您的分配,但不会将指针设置为 NULL (恕我直言,这应该被视为与清理分开。)数据指向的指针通过指针传递给cleanup(),并正确地free(),但指针本身按值传递,因此当您将其设置为 NULL 时您只会影响 cleanup() 函数的指针的本地副本,而不是原始指针。

有三种方法可以解决这个问题:

  1. 使用指向指针的指针。

    void cleanup(struct MyType **p) { free(*p); } *p = 空; }
    
  2. 使用宏。

    #define cleanup(p) do { free(p); p = 空;而(0)
    

    或者(可能更好):

    void cleanup_func(struct MyType *p) { /* 更复杂的清理 */ }
    #define cleanup(p) do { cleanup_func(p); p = 空;而(0)
    
  3. 将设置指向NULL的指针的责任留给调用者。这可以避免不必要的赋值以及代码混乱或损坏。

It's not just you.

cleanup() will properly clean up your allocation, but will not set the pointer to NULL (which should IMHO be regarded as separate from cleanup.) The data the pointer points to is passed to cleanup() by pointer, and is free()ed properly, but the pointer itself is passed by value, so when you set it to NULL you're only affecting the cleanup() function's local copy of the pointer, not the original pointer.

There are three ways around this:

  1. Use a pointer to a pointer.

    void cleanup(struct MyType **p) { free(*p); *p = NULL; }
    
  2. Use a macro.

    #define cleanup(p) do { free(p); p = NULL; } while(0)
    

    or (probably better):

    void cleanup_func(struct MyType *p) { /* more complicated cleanup */ }
    #define cleanup(p) do { cleanup_func(p); p = NULL; } while(0)
    
  3. Leave the responsibility of setting pointers to NULL to the caller. This can avoid unnecessary assignments and code clutter or breakage.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文