对函数内部的自由指针有点困惑
Little bit confusing about free pointer inside function
几周前,我了解了如何在函数内部分配和释放指针的正确方法,如示例 linkedList:
typedef struct _node {
void *data;
struct _node *next;
} Node;
typedef struct _linkedList {
Node *head;
Node *tail;
Node *current;
} LinkedList;
在我看来,销毁队列的正确方法是使用获取指向我要删除的节点的指针的函数:
void destroy (Node ** node)
或者在更真实的示例中,指针指向要删除的指针和指向列表的指针。
void destroy (LinkedList * list, Node ** node)
但现在我正在读书 "Understanding C pointers" 我遇到了问题,因为在第 6 章指向结构的指针中有函数 destroyList 的示例:
void delete(LinkedList *list, Node *node) {
if (node == list->head) {
if (list->head->next == NULL) {
list->head = list->tail = NULL;
} else {
list->head = list->head->next;
}
} else {
Node *tmp = list->head;
while (tmp != NULL && tmp->next != node) {
tmp = tmp->next;
}
if (tmp != NULL) {
tmp->next = node->next;
}
}
free(node); //free on pointer copy value not pointer
}
所以在这个例子中作者 运行 释放了按值传递的指针,所以在我看来这不应该起作用。但是我查看了勘误表,没有关于这个例子的注释。
在这种情况下,我理解 List 是使用正确列表实例的函数参数,但应该是:
free(list->head) ; //It should work?
然后还为分配的列表释放内存。
我说的对吗?因为看了这个例子,感觉自己对这个话题的理解有点问题。
我还去了 Linux 手册页,我看到了免费的原型:
void free(void *ptr); // http://linux.die.net/man/3/free
那么,为什么每个人都告诉您要释放内存时将指针传递给指针,但在标准库中,相同的自由函数将指针作为参数而不是指向指针的指针,它如何正确工作?
您不需要使用:
void destroy (LinkedList * list, Node ** node)
使用
void destroy (LinkedList * list, Node * node)
足够了。
您可以使用:
void destroy(int* pointer)
{
free(pointer);
}
int* ip = malloc(sizeof(int));
destroy(ip);
到free
由malloc
和相关函数分配的内存。
正在使用
void destroy(int** pointer)
{
free(pointer);
}
int* ip = malloc(sizeof(int));
destroy(&ip);
错了。
您可以使用:
void destroy(int** pointer)
{
free(*pointer);
}
int* ip = malloc(sizeof(int));
destroy(&ip);
但这使用了不必要的额外 &
和 *
。
正如您所说的那样,free( void *p )
释放了 p
指向的内存,但是由于地址是按值传递的,因此对于调用者而言它将保持不变。因此你可能 运行 遇到这样的问题:
int *p = malloc( sizeof *p );
*p = 1;
free( p );
...
if( p )
*p = 2; // Undefined Behaviour!!! although p is free()'d it's still != NULL
所以你会经常发现
free( p );
p = NULL;
尽管如此,在我看来,编写一个 free()
类的函数是可以的,只要函数的描述清楚地表明指针 不能 之后使用(无论可能是什么类型的指针)。但是当然,您可以自由地使用双指针定义函数,并将您有 free()'d 的所有内容设置为 NULL
内部,就像在这个非常简单的示例中一样:
void myfree( void **pp )
{
free( *p );
*p = NULL;
}
...
int *p = malloc( sizeof *p );
...
myfree( &p );
// now p == NULL
我会尽力在这里澄清。当您释放内存时,您应该释放实际分配的内存。当你调用像 malloc 这样的函数时,你应该给出你想要 malloc 的数据大小。在您的情况下,'node' 会像 'malloc(sizeof(node))' 一样被分配。
同样,当您调用 free 时,您打算释放分配的整个内存块。如果你要释放一个指向内存的指针,你实际上并没有释放内存,而是释放了指向它的东西。现在您已经泄漏了内存,因为没有任何东西可以再访问 malloced 节点。
所以在你引用的代码中,他没有释放节点的值,他释放了分配给节点的内存。当他调用 free(node)
时,他正在传递一个指向节点的指针(因为节点指针被传递给函数),然后 free 释放节点的内存。
几周前,我了解了如何在函数内部分配和释放指针的正确方法,如示例 linkedList:
typedef struct _node {
void *data;
struct _node *next;
} Node;
typedef struct _linkedList {
Node *head;
Node *tail;
Node *current;
} LinkedList;
在我看来,销毁队列的正确方法是使用获取指向我要删除的节点的指针的函数:
void destroy (Node ** node)
或者在更真实的示例中,指针指向要删除的指针和指向列表的指针。
void destroy (LinkedList * list, Node ** node)
但现在我正在读书 "Understanding C pointers" 我遇到了问题,因为在第 6 章指向结构的指针中有函数 destroyList 的示例:
void delete(LinkedList *list, Node *node) {
if (node == list->head) {
if (list->head->next == NULL) {
list->head = list->tail = NULL;
} else {
list->head = list->head->next;
}
} else {
Node *tmp = list->head;
while (tmp != NULL && tmp->next != node) {
tmp = tmp->next;
}
if (tmp != NULL) {
tmp->next = node->next;
}
}
free(node); //free on pointer copy value not pointer
}
所以在这个例子中作者 运行 释放了按值传递的指针,所以在我看来这不应该起作用。但是我查看了勘误表,没有关于这个例子的注释。
在这种情况下,我理解 List 是使用正确列表实例的函数参数,但应该是:
free(list->head) ; //It should work?
然后还为分配的列表释放内存。
我说的对吗?因为看了这个例子,感觉自己对这个话题的理解有点问题。
我还去了 Linux 手册页,我看到了免费的原型:
void free(void *ptr); // http://linux.die.net/man/3/free
那么,为什么每个人都告诉您要释放内存时将指针传递给指针,但在标准库中,相同的自由函数将指针作为参数而不是指向指针的指针,它如何正确工作?
您不需要使用:
void destroy (LinkedList * list, Node ** node)
使用
void destroy (LinkedList * list, Node * node)
足够了。
您可以使用:
void destroy(int* pointer)
{
free(pointer);
}
int* ip = malloc(sizeof(int));
destroy(ip);
到free
由malloc
和相关函数分配的内存。
正在使用
void destroy(int** pointer)
{
free(pointer);
}
int* ip = malloc(sizeof(int));
destroy(&ip);
错了。
您可以使用:
void destroy(int** pointer)
{
free(*pointer);
}
int* ip = malloc(sizeof(int));
destroy(&ip);
但这使用了不必要的额外 &
和 *
。
正如您所说的那样,free( void *p )
释放了 p
指向的内存,但是由于地址是按值传递的,因此对于调用者而言它将保持不变。因此你可能 运行 遇到这样的问题:
int *p = malloc( sizeof *p );
*p = 1;
free( p );
...
if( p )
*p = 2; // Undefined Behaviour!!! although p is free()'d it's still != NULL
所以你会经常发现
free( p );
p = NULL;
尽管如此,在我看来,编写一个 free()
类的函数是可以的,只要函数的描述清楚地表明指针 不能 之后使用(无论可能是什么类型的指针)。但是当然,您可以自由地使用双指针定义函数,并将您有 free()'d 的所有内容设置为 NULL
内部,就像在这个非常简单的示例中一样:
void myfree( void **pp )
{
free( *p );
*p = NULL;
}
...
int *p = malloc( sizeof *p );
...
myfree( &p );
// now p == NULL
我会尽力在这里澄清。当您释放内存时,您应该释放实际分配的内存。当你调用像 malloc 这样的函数时,你应该给出你想要 malloc 的数据大小。在您的情况下,'node' 会像 'malloc(sizeof(node))' 一样被分配。
同样,当您调用 free 时,您打算释放分配的整个内存块。如果你要释放一个指向内存的指针,你实际上并没有释放内存,而是释放了指向它的东西。现在您已经泄漏了内存,因为没有任何东西可以再访问 malloced 节点。
所以在你引用的代码中,他没有释放节点的值,他释放了分配给节点的内存。当他调用 free(node)
时,他正在传递一个指向节点的指针(因为节点指针被传递给函数),然后 free 释放节点的内存。