简单链表无法打印

simple linked list failing to print

我正在学习如何制作链表,但它根本无法打印出任何内容,我不明白为什么???请帮忙。我相信这与我的指示有关,但我不知道它是什么。

#include <stdio.h>
#include <stdlib.h>

// typedef is used to give a data type a new name
typedef struct node * link ;// link is now type struct node pointer

/*
    typedef allows us to say "link ptr"
    instead of "struct node * ptr"
*/

struct node{
    int item ;// this is the data
    link next ;//same as struct node * next, next is a pointer
};

void printAll(link head); // print a linked list , starting at link head
void addFirst(link ptr, int val ); // add a node with given value to a list
link removeLast(link ptr); // removes and returns the last element in the link

//prints the link
void printAll(link head){
    link ptr = head;
    printf("\nPrinting Linked List:\n");
    while(ptr != NULL){
        printf(" %d ", (*ptr).item);
        ptr = (*ptr).next;// same as ptr->next
    }
    printf("\n");
}

//adds to the head of the link
void addFirst(link ptr, int val ){
    link tmp = malloc(sizeof(struct node));// allocates memory for the node
    tmp->item = val;
    tmp->next = ptr;
    ptr = tmp;
}

// testing
int main(void) {
    link head = NULL;// same as struct node * head, head is a pointer type

    //populating list
    for(int i = 0; i<3; i++){
        addFirst(head, i);
    }

    printAll(head);

    return 0;
}

输出:

正在打印链表:

进程返回 0 (0x0) 执行时间:0.059 秒

按任意键继续

这是因为您向函数传递了一个空指针,而退出循环的条件是该指针为空,所以什么也没有发生。 您的 addFirst 函数采用指针的值,但它不能修改您在 main() 内部声明的 head。 要修改 head,您需要将指针传递给 link,然后您可以取消引用该指针以访问您的 head,然后您可以更改它。

void addFirst(link *ptr, int val ){
    link tmp = malloc(sizeof(struct node));// allocates memory for the node
    tmp->item = val;
    tmp->next = *ptr;
    *ptr = tmp;
}

现在可以更改头指针了。只要记住在调用函数时将地址传递给它即可。 addFirst(&head,i)

在for循环中

for(int i = 0; i<3; i++){
    addFirst(head, i);
}

你创建了一堆指向 NULL 的指针。 head 永远不会改变,因为指针本身已被传递 "by value"。例如。 head 被复制并且在 addFirst 中对指针本身的所有修改在外部不可见。

这与说 int 相同。想象一下 void foo(int x);。此函数对 x 所做的任何事情在外部都是不可见的。

但是 link ptr 指向的内存的变化当然是可见的。

例如这一行什么都不做:

   tmp->next = ptr;
   ptr = tmp;      <=== this line
}

您可以通过多种方式解决此问题。一种是从 addFirst 到 return 新节点,另一种是使 link ptr 成为指向指针的指针:link *ptr。因为在这种情况下你想改变指针值(不是指针值):

//link *ptr here a pointer to pointer
void addFirst(link * ptr, int val ){
    link tmp = malloc(sizeof(struct node));// allocates memory for the node
    tmp->item = val;
    tmp->next = *ptr; //<<changed
    *ptr = tmp;    //<<changed
}

别忘了更新上面的声明。和电话:

void addFirst(link * ptr, int val ); // add a node with given value to a list

...
for(int i = 0; i<3; i++){
    addFirst(&head, i);
}

然后这段代码产生:

Printing Linked List:
 2  1  0

已添加: 重要的是要了解使用链表需要使用两种不同类型的数据。

首先是 struct node,您使用 links 传递此类数据。

其次是head。这是指向第一个节点的指针。当您想修改头部时,您会发现它不是 "node"。这是另一回事。它是列表中第一个节点的 "name"。这个名字本身就是一个指向节点的指针。查看 head 的内存布局与列表本身有何不同。

head[8 bytes]->node1[16 bytes]->node2[16 bytes]->...->nodek[16 bytes]->NULL;

顺便说一下 - 这里唯一有词汇名称的是 head。所有节点都没有名称,可以通过 node->next 语法访问。

你也可以在这里想象另一个指针,link last 将指向 nodek。同样,这将具有与节点本身不同的内存布局。如果你想在函数中修改它,你需要将函数指针传递给它(e.g.pointer 到指针)。

指针和它指向的数据是不同的东西。在您看来,您需要将它们分开。指针类似于 intfloat。它被传递 "by value" 给函数。是的 link ptr 已经是指针,它允许您更新它指向的数据。但是,指针本身是按值传递的,并且对指针的更新(在您的情况下 ptr=tmp)在外部不可见。

(*ptr).next=xxx 当然是可见的,因为数据已更新(不是指针)。这意味着你需要做一个额外的步骤 - 使你的指针在功能之外可见的变化,例如将指针本身 (head) 转换为另一个指针的数据,例如使用 struct node **ptr(这里的第一颗星表示这是指向节点的指针,第二颗星将该指针转换为另一个指针的数据。