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

说我们想删除磅。理论上我明白了。您将 la->next 更改为指向 lc。但我对指针业务感到困惑。deleteList() 的参数是什么?是,deleteList(la->next)?或者是其他东西?然后是真正令人困惑的部分。*p = ... 应该是 la->next 因为这是我们要更改的指针。但是...(*p)->next,这不就是磅吗?但是我们想要lc?所以看起来 *p 在同一行中有不同的含义?!

4

2 回答 2

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 的语句。

例如

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。

于 2020-05-23T21:11:05.130 回答
0

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

void deleteList (List **p) {
  while(*p != NULL){
    List *nextNode = (*p)->next;
    free(*P);
    *p= nextNode;
  }
}
于 2020-05-23T21:12:20.580 回答