C 为什么在链接列表中插入节点后返回指针

C 为什么在链接列表中插入节点后返回指针,c,pointers,linked-list,C,Pointers,Linked List,我不明白为什么在一个节点被添加到链表之后,我们必须返回指向head节点的指针 struct node *append(int v) { struct node *ptr; struct node *t; ptr=head; while (ptr->next != tail) ptr = ptr->next; t=(struct node *) malloc(sizeof *t); t->value=v; t->nex

我不明白为什么在一个节点被添加到链表之后,我们必须返回指向head节点的指针

struct node *append(int v) {
    struct node *ptr;
    struct node *t;
    ptr=head;
    while (ptr->next != tail) ptr = ptr->next;
    t=(struct node *) malloc(sizeof *t);
    t->value=v;
    t->next = tail;
    ptr->next = t;
    return ptr; // why return ptr?
}

这取决于你问题的背景。通常,在链表问题中,您必须返回列表的头部,以便数据结构保持一致,但我从您的代码推断,头部是一个全局变量

除非调用此函数的代码需要知道创建的新节点的位置,否则不需要返回节点,因为head是一个全局变量(同样,如果我的假设正确的话)


除此之外,我建议修改您的函数,因为我看到您在这里遗漏了一些情况(例如,如果列表为空,您必须更改标题怎么办?

当列表为空时,链接列表通常使用空标题实现。在这种情况下,如果head是一个局部变量,或者是一个全局变量,并且希望使用同一个函数有多个列表,则必须返回列表的head。添加节点时,头部可能已更改,即使在尾部添加,如果列表为空,则会出现新头部

但另一种方法是在头部始终有一个节点,仅在此处指示头部,并在该头部之后添加/读取/删除节点,以便处理列表中的数据。在这种情况下,返回头部是无用的,因为头部永远不会改变

当节点n:
n->next==NULL
为空时,可以使用等于NULL的头来检测列表的尾部,如下代码所示:

// add at the tail of the list:
struct node * add_to_list_tail(struct node * head,int v) {
  struct node *t;
  t=(struct node *) malloc(sizeof(struct node));
  t->value = v;
  t->next = NULL; // next is set to NULL because it is the new tail

  if(head == NULL) {
    // in the case the list is empty
    head = t; // t become the new head, because the list was empty
  } else {
    // in the case the list isn't empty
    struct node * n = head;
    // the following loop will stop when n->next == NULL, and n will point to the tail
    while(n->next != NULL) {
      n = n->next;
    }
    n->next = t;
  }      
  return head;
}

// add at the head of the list:
struct node * add_to_list(struct node * head,int v) {
    struct node *t;
    t=(struct node *) malloc(sizeof(struct node));
    t->value = v;
    t->next = head; // make t become the new head
    return t; // return t because it is the new head
}

int main() {
  struct node * head = NULL;
  head = add_to_list(head,1);
  head = add_to_list(head,2);
  head = add_to_list_tail(head,3);
}
如果不想返回head,还可以传递指向head指针的指针,作为操作列表的函数的参数。一个简短的示例代码:

void add_to_list(struct node ** head,int v) {
    struct node *t;
    t=(struct node *) malloc(sizeof(struct node));
    t->value = v;
    // make t become the new head:
    t->next = *head;
    *head = t;
}

int main() {
  struct node * head = NULL;
  // we pass &head, the adress of variable head, as parameter:
  add_to_list(&head,1);
  add_to_list(&head,2);

  struct node * n = head;
  while(n != NULL) {
    printf("\nvalue: %d",n->value);
    n = n->next;
  }
}

首先,该函数无效。当列表为空且添加了第一个元素时,
head
可以等于
NULL
。因此,使用函数代码中对应于
ptr->next
的表达式
head->next
会导致内存访问冲突

此外,我认为将
NULL
命名为
tail
不是一个好主意。我会显式地使用
NULL
。否则,代码可能会使读者感到困惑

尽管如此,函数可以按以下方式查看

struct node * append( int v ) 
{
    struct node *t = ( struct node * )malloc( sizeof( *t ) );
    t->value = v;
    t->next  = tail;

    if ( head == tail )
    {
        head = t;
    }
    else
    {
        struct node *current = head;
        while ( current->next != tail ) current = current->next;
        current->next = t;
    }

    return t;
}
struct node *head = NULL;

struct node *current;
int i;

head = append( head, 0 );

for ( i = 1, current = head; i < 10; i++ ) current = append( current, i ); 
至于你的问题,我也不明白为什么函数返回
ptr
而不是
t
。它应该返回
t
。在这种情况下,函数将更加正确和高效,因为当第一个元素附加到空列表时,以及当下一个非第一个值附加到列表时,函数将返回head,并且head将是某个节点(不需要head本身)while循环没有迭代,因为第一个表达式
ptr->next
已经等于NULL

该函数应该返回最后一个附加的节点,如我所示的实现中所示

我确信这只是函数设计中的一个错误

如果不在函数中使用全局变量
head
,而是将其声明为函数参数,则此缺点将更加明显。比如说

struct node * append( struct node *head, int v ) 
{
    struct node *t = ( struct node * )malloc( sizeof( *t ) );
    t->value = v;
    t->next  = tail;

    if ( head == tail )
    {
        head = t;
    }
    else
    {
        struct node *current = head;
        while ( current->next != tail ) current = current->next;
        current->next = t;
    }

    return t;
}
在这种情况下,main中的函数调用可以如下所示

struct node * append( int v ) 
{
    struct node *t = ( struct node * )malloc( sizeof( *t ) );
    t->value = v;
    t->next  = tail;

    if ( head == tail )
    {
        head = t;
    }
    else
    {
        struct node *current = head;
        while ( current->next != tail ) current = current->next;
        current->next = t;
    }

    return t;
}
struct node *head = NULL;

struct node *current;
int i;

head = append( head, 0 );

for ( i = 1, current = head; i < 10; i++ ) current = append( current, i ); 
struct node*head=NULL;
结构节点*当前;
int i;
head=append(head,0);
对于(i=1,current=head;i<10;i++)current=append(current,i);

在这种情况下,
append
的调用将非常有效,因为在函数中,while循环甚至不会进行一次迭代。

我认为您必须解释更多关于上下文的内容才能得到回答。您没有在此处返回“指向头部节点的指针”;这一定是一个外部变量,所以不需要返回。您将返回指向插入节点之前的节点的指针。根据您的要求,它可用于撤消追加和其他操作。