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

时间:2022-12-04 11:45:16

Consider the c code:

考虑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;
}

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?

在清理之后我认为错了(p);被调用,p的内容现在应该是NULL?清理(​​MyType *指针)会正确释放内存分配吗?

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.

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

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?

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

6 个解决方案

#1


18  

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 from the mycode method like so:

这可能会增加您的困惑,但您可以从mycode方法调整变量p的值,如下所示:

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.

在这种情况下,指针存储指针的地址。通过解除引用,您可以更改存储在该地址的值。

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.

我将注意到,在软件的同一逻辑“级别”上处理分配和释放通常是一种好习惯 - 即不要让调用者负责分配内存然后将其释放到函数内部。保持一致并保持在同一水平。

#2


10  

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:

清理将正确释放p,但不会改变其值。 C是一种按值传递的语言,因此您无法从被调用函数更改调用者的变量。如果你想从清理中设置p,你需要做类似的事情:

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?

你的代码有点不恰当,你能解释一下为什么要编写这个清理函数吗?

#3


7  

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().

是的:malloc(3)神奇地产生了一块内存。您已将此内存的地址(而非内存本身)以任何有意义的方式分配给指针p,它是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.

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

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.

回到mycode(),你仍然有指针p持有一个地址,但是该块现在在空闲列表中,并且在再次分配之前对存储没有特别的用处。

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.

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

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.

仔细阅读C可以给出一个关于变量生命周期的抽象概念,但是将参数传递和局部变量分配的近通用(对于编译语言,无论如何)实现为堆栈操作要容易得多。它有助于在C课程之前参加装配课程。

#4


3  

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.

这不起作用,因为cleanup()中的指针是本地的,因此调用函数看不到它为NULL。有两种常见的解决方法。

  1. Instead of sending cleanup the pointer, send it a pointer to the pointer. Thus change cleanup() as follows:
  2. 而不是发送清理指针,向它发送指针指针。因此,更改cleanup()如下:

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

and then just call cleanup(&p).

然后只需调用cleanup(&p)。

  1. A second option which is quite common is to use a #define macro that frees the memory and cleans the pointer.
  2. 第二个选项很常见,就是使用一个释放内存并清除指针的#define宏。

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

如果您使用的是C ++,那么将cleanup()定义为第三种方法:

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

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

#5


1  

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?

在清理之后我认为错了(p);被调用,p的内容现在应该是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**).

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

Second question:

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

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

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

是的,因为你在malloc返回的指针上做空,所以内存将被释放。

#6


1  

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.

cleanup()将正确清理你的分配,但是不会将指针设置为NULL(这应该被视为与清理分开。)指针指向的数据通过指针传递给cleanup(),并且是free()正确编辑,但指针本身是按值传递的,所以当你将它设置为NULL时,你只会影响cleanup()函数的指针本地副本,而不是原始指针。

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.

    将指针设置为NULL的责任留给调用者。这可以避免不必要的分配和代码混乱或破坏。

#1


18  

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 from the mycode method like so:

这可能会增加您的困惑,但您可以从mycode方法调整变量p的值,如下所示:

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.

在这种情况下,指针存储指针的地址。通过解除引用,您可以更改存储在该地址的值。

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.

我将注意到,在软件的同一逻辑“级别”上处理分配和释放通常是一种好习惯 - 即不要让调用者负责分配内存然后将其释放到函数内部。保持一致并保持在同一水平。

#2


10  

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:

清理将正确释放p,但不会改变其值。 C是一种按值传递的语言,因此您无法从被调用函数更改调用者的变量。如果你想从清理中设置p,你需要做类似的事情:

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?

你的代码有点不恰当,你能解释一下为什么要编写这个清理函数吗?

#3


7  

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().

是的:malloc(3)神奇地产生了一块内存。您已将此内存的地址(而非内存本身)以任何有意义的方式分配给指针p,它是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.

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

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.

回到mycode(),你仍然有指针p持有一个地址,但是该块现在在空闲列表中,并且在再次分配之前对存储没有特别的用处。

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.

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

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.

仔细阅读C可以给出一个关于变量生命周期的抽象概念,但是将参数传递和局部变量分配的近通用(对于编译语言,无论如何)实现为堆栈操作要容易得多。它有助于在C课程之前参加装配课程。

#4


3  

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.

这不起作用,因为cleanup()中的指针是本地的,因此调用函数看不到它为NULL。有两种常见的解决方法。

  1. Instead of sending cleanup the pointer, send it a pointer to the pointer. Thus change cleanup() as follows:
  2. 而不是发送清理指针,向它发送指针指针。因此,更改cleanup()如下:

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

and then just call cleanup(&p).

然后只需调用cleanup(&p)。

  1. A second option which is quite common is to use a #define macro that frees the memory and cleans the pointer.
  2. 第二个选项很常见,就是使用一个释放内存并清除指针的#define宏。

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

如果您使用的是C ++,那么将cleanup()定义为第三种方法:

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

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

#5


1  

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?

在清理之后我认为错了(p);被调用,p的内容现在应该是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**).

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

Second question:

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

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

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

是的,因为你在malloc返回的指针上做空,所以内存将被释放。

#6


1  

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.

cleanup()将正确清理你的分配,但是不会将指针设置为NULL(这应该被视为与清理分开。)指针指向的数据通过指针传递给cleanup(),并且是free()正确编辑,但指针本身是按值传递的,所以当你将它设置为NULL时,你只会影响cleanup()函数的指针本地副本,而不是原始指针。

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.

    将指针设置为NULL的责任留给调用者。这可以避免不必要的分配和代码混乱或破坏。