首页 > 解决方案 > 为什么我们不能在单链表的追加/插入函数的函数参数中使用单个指针?

问题描述

所以我一直在使用 C 中的指针学习数据结构,我对为什么我们使用双指针作为函数参数以及为什么我们不能在单链表的 append 函数中使用单个指针有疑问?(仍然是初学者)

#include<stdio.h>
#include<stdlib.h>
    struct node
    {
        int number;
        struct node *next;
    };
    void insert(struct node **q,int value)//this is the part where I have the doubt
{
    struct node *temp,*r;
    temp=*q;
    if(*q==NULL)
    {       
        temp=(struct node*)malloc(sizeof(struct node));
        temp->number=value;
        temp->next=NULL;
        *q=temp;
    }
    else
    {
        temp=*q;
        while(temp->next!=NULL)
        temp=temp->next;
        r=(struct node*)malloc(sizeof(struct node));
        r->number=value;
        r->next=NULL;
        temp->next=r;
    }
}
void print(struct node *temp)
{
    printf("\n");
    while(temp!=NULL)
    {
        printf("%d\n",temp->number);
        temp=temp->next;
    }
}

int main()
{
    struct node *head;
    head=NULL;
    insert(&head,10);//call by reference
    insert(&head,20);//call by reference
    insert(&head,30);//call by reference
    insert(&head,40);//call by reference
    print(head);
    return 0;
}

上面的代码工作得很好,但是当我使用单指针作为参数时,它会执行但没有输出。这是插入/追加函数的单指针参数版本。基本上为什么它不适用于单个指针?, 为什么我们需要使用双指针作为参数才能使其工作?

void insert(struct node *q,int value)
{
    struct node *temp,*r;
    temp=q;
    if(q==NULL)
    {       
        temp=(struct node*)malloc(sizeof(struct node));
        temp->number=value;
        temp->next=NULL;
        q=temp;
    }
    else
    {
        temp=q;
        while(temp->next!=NULL)
        temp=temp->next;
        r=(struct node*)malloc(sizeof(struct node));
        r->number=value;
        r->next=NULL;
        temp->next=r;
    }
}```

标签: cpointersdata-structurespass-by-referencesingly-linked-list

解决方案


在函数中,您试图更改指向列表头节点的指针。

如果函数将像第二个函数定义中那样按值接受指针,则该函数将处理指向头节点的原始指针值的副本。更改副本不会影响原始指针。原始指针将保持不变。

您可以想象(第二个)函数定义及其调用方式如下。

struct node *head;
head=NULL;

insert( head, 10 );
//...

void insert( /*struct node *q,int value */ )
{
    struct node *q = head;
    int value = 10;
    //.. 

如您所见,该函数处理其自己的局部变量(函数参数是函数局部变量),该变量具有main 中定义q的指针值的副本。head因此,在函数中q,获得新值的是局部变量。指针头的值没有被改变。

所以你需要通过引用传递指针。在 C 中,通过引用传递一个对象意味着传递一个指向该对象的指针,该对象是使用该指针间接传递给一个函数的。

但无论如何,函数定义都是不好的。当内存分配失败时,可以更简单地定义它并且没有未定义的行为。例如

int insert( struct node **head, int value )
{
    struct node *new_node = malloc( sizeof( struct node ) );
    int success = new_node != NULL;

    if ( success )
    {
        new_node->number = value;
        new_node->next   = NULL;

        while ( *head != NULL ) head = &( *head )->next;

        *head = new_node;
    }

    return success;
}

如果不通过引用将指针传递给头节点,则需要从函数中返回指针的新值。在这种情况下,函数看起来像

struct node * insert( struct node *q, int value )
{
    struct node *new_node = malloc( sizeof( struct node ) );

    if ( new_node != NULL )
    {
        new_node->number = value;
        new_node->next   = NULL;

        if ( q == NULL )
        {
            q = new_node;
        }
        else
        {
            struct node *current = q;
            while ( current->next != NULL ) current = current->next;
            current->next = new_node;
        }
    }

    return q;
}

在这种情况下,必须在列表为空时第一次调用该函数,方法如下

head = insert( head, 10 );

推荐阅读