在C语言中删除一个带有指针的列表。

问题描述 投票:0回答:1

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

所以我有一些问题

  1. 那么函数deleteList()中的*p是什么?它是 pointer_1 还是别的什么?
  2. 在=之前的*p和在=号之后的*p意思一样吗?
  3. *p和(*p)之间有区别吗?

假设我们有。

... la --> lb --> lc --> ld ....

假设我们要删除lb. 理论上,我明白了。你改变了la->接下来指向lc。但我对指针业务感到困惑。deleteList()的参数是什么?是,deleteList(la->next)?还是别的什么?然后就是真正让人困惑的部分了,*p=...应该是la->next,因为这是我们要改变的指针,但是...(*p)->next,这不就是lb吗?但是我们要的是lc?这样看来,*p在同一行中的意义是不同的?

c pointers linked-list double-pointer pass-by-pointer
1个回答
0
投票

让我们;首先正确地写出这个函数。

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。


1
投票

deleteList 函数:在你传递给下一个元素之前,你必须释放你指向的元素。

void deleteList (List **p) {
  while(*p != NULL){
    List *nextNode = (*p)->next;
    free(*P);
    *p= nextNode;
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.