让我们首先正确地编写函数。
void deleteList( List **head )
{
while ( *head != NULL )
{
List *tmp = *head;
*head = ( *head )->next;
free( tmp );
}
}
指向头节点的指针通过引用传递给函数。
如果您将定义函数,例如
void deleteList( List *head )
{
while ( head != NULL )
{
List *tmp = head;
head = head->next;
free( tmp );
}
}
也就是说,如果指针不会通过引用传递,那么函数将处理指针的副本。更改副本不会影响原始指针。
考虑以下演示程序。
#include <stdio.h>
#include <stdlib.h>
void f( int *p )
{
p = NULL;
}
int main(void)
{
int x = 10;
int *px = &x;
printf( "Before the function call px = %p\n", ( void * )px );
f( px );
printf( "Adter the function call px = %p\n", ( void * )px );
return 0;
}
它的输出可能看起来像
Before the function call px = 0x7ffe26689a2c
Adter the function call px = 0x7ffe26689a2c
那就是原始指针px
没有改变,因为函数处理了指针的副本。
要更改指针,您需要通过引用将其传递给函数
#include <stdio.h>
#include <stdlib.h>
void f( int **p )
{
*p = NULL;
}
int main(void)
{
int x = 10;
int *px = &x;
printf( "Before the function call px = %p\n", ( void * )px );
f( &px );
printf( "Adter the function call px = %p\n", ( void * )px );
return 0;
}
现在程序输出可能看起来像
Before the function call px = 0x7ffed60815fc
Adter the function call px = (nil)
在函数中,您需要取消引用参数以访问通过引用传递的指针。
*p = NULL;
^^^^
同样的情况也发生在函数中deleteNode
。要检查传递的指针是否等于 NULL,请使用以下语句
while ( *head != NULL )
^^^
要访问原始指针指向的节点的数据成员next
,您必须再次取消引用参数才能访问原始指针
*head
所以这个表达式产生了原始指针。所以接下来要访问数据成员,你必须写
( *head )->next
您正在使用括号,因为后缀运算符 -> 具有更高的优先级,但您首先需要获取原始指针。
也就是说,如果你没有引用的指针,你会写
head->next
但是,当您有一个引用指针时,即当您有一个指向原始指针的指针时,要获取原始指针,您必须取消引用引用指针,例如
( *head )->next
您可以编写函数,而无需通过引用接受指向头节点的指针。但是在这种情况下,您应该在调用者中添加一个将指针头设置为 NULL 的语句。
例如
void deleteList( List *head )
{
while ( head != NULL )
{
List *tmp = head;
head = head->next;
free( tmp );
}
}
在调用者中你需要写
List *head - NULL;
// the code thatf fills the list
deleteList( head );
head = NULL;
或者该函数可以返回一个空指针,如
List * deleteList( List *head )
{
while ( head != NULL )
{
List *tmp = head;
head = head->next;
free( tmp );
}
return head;
}
在调用者中你可以写
List *head - NULL;
// the code thatf fills the list
head = deleteList( head );
定义通过引用接受指向头节点的指针的函数的优点是函数的用户不需要记住自己将指针设置为NULL。