简单的链表无法打印

时间:2018-05-29 19:02:05

标签: c linked-list singly-linked-list

我正在学习如何制作一个链表,但它没有打印出任何东西,我无法弄清楚为什么???请帮忙。我相信它与我的指针有关,但我不知道它是什么。

#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 s

按任意键继续

2 个答案:

答案 0 :(得分:1)

这是因为你正在向你的函数传递一个空指针,并且退出循环的条件是该指针为null,所以没有任何反应。 您的addFirst函数接受指针的值,但它不能修改您在main()中声明的head。 要修改head,您需要将指针传递给链接,然后您可以取消引用该指针以访问您的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)

答案 1 :(得分:1)

在for循环中

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

你创建了一堆指向NULL的指针。 head永远不会改变,因为指针本身被传递&#34;由值&#34;。例如。 head被复制,addFirst中对指针本身的所有修改都在外面不可见。

这与说int相同。想象一下void foo(int x);。无论这个函数对x做什么都不在外面看。

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

E.g。这条线什么都不做:

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

您可以通过多种方式解决此问题。一种是从addFirst返回新节点,另一种是使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,您使用link传递此类数据。

第二个是head。这是指向第一个节点的指针。当你想修改头部时,你发现它不是一个节点&#34;。这是另一回事。这是一个&#34;名称&#34;对于列表中的第一个节点。此名称本身是指向节点的指针。了解head的内存布局与列表本身的不同之处。

head[8 bytes]->node1[16 bytes]->node2[16 bytes]->...->nodek[16 bytes]->NULL;
顺便说一下 - 这里唯一有词汇名称的是head。所有节点都没有名称,可通过node->next语法访问。

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

它指向的指针和数据是不同的东西。在你的脑海里,你需要将它们分开。指针类似于intfloat。它通过&#34;按价值&#34;功能。是link ptr已经是指针,允许您更新它指向的数据。但是,指针本身是按值传递的,并且指针(在您的情况下为ptr=tmp)的更新在外部不可见。

当然可以看到

(*ptr).next=xxx,因为数据已更新(不是指针)。这意味着你需要做一个额外的步骤 - 在函数外部对指针进行更改,例如将指针本身(head)转换为另一个指针的数据,例如使用struct node **ptr(这里的第一个星说这是指向一个节点的指针,第二个星指针将该指针转换为另一个指针的数据。