C语言的部分代码在这里。
typedef struct List {
double v;
struct List *next;
} List;
void deleteList (List **p) {
*p = (*p)->next;
}
我对deleteList函数的工作原理感到困惑。所以论证的是一个指向List结构的指针。所以我们有。
p : pointer_2 --> pointer_1 --> List
所以我有一些问题
假设我们有。
... la --> lb --> lc --> ld ....
假设我们要删除lb. 理论上,我明白了。你改变了la->接下来指向lc。但我对指针业务感到困惑。deleteList()的参数是什么?是,deleteList(la->next)?还是别的什么?然后就是真正让人困惑的部分了,*p=...应该是la->next,因为这是我们要改变的指针,但是...(*p)->next,这不就是lb吗?但是我们要的是lc?这样看来,*p在同一行中的意义是不同的?
让我们;首先正确地写出这个函数。
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。但在这种情况下,你应该在调用者中再添加一条语句,将指针head设置为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。
在 deleteList
函数:在你传递给下一个元素之前,你必须释放你指向的元素。
void deleteList (List **p) {
while(*p != NULL){
List *nextNode = (*p)->next;
free(*P);
*p= nextNode;
}
}