我正在学习如何制作链表,但它根本无法打印出任何东西,我不知道为什么???请帮忙。我相信这与我的指针有关,但我不知道它是什么。
#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
按任意键继续
这是因为您将一个 null 指针传递给您的函数,并且退出循环的条件是该指针为 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)
在 for 循环中
for(int i = 0; i<3; i++){
addFirst(head, i);
}
您创建了一堆指向NULL
的指针。head
永远不会改变,因为指针本身是"按值"传递的。F.D.head
被复制,并且对addFirst
中的指针本身的所有修改在外部都不可见。
这与int
相同。想象一下void foo(int x);
.无论此函数对 x 做什么,在外面都是不可见的。
但是,link ptr
指向的内存的变化当然是可见的。
例如,此行不执行任何操作:
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
。这是指向第一个节点的指针。当您想修改头部时,您会发现它不是一个"节点"。这是另一回事。它是列表中第一个节点的"名称"。此名称本身就是指向节点的指针。了解head
的内存布局与列表本身有何不同。
head[8 bytes]->node1[16 bytes]->node2[16 bytes]->...->nodek[16 bytes]->NULL;
顺便说一句 - 这里唯一有词法名称的是head
.所有节点都没有名称,可通过node->next
语法访问。
你也可以想象这里的另一个指针,link last
它将指向nodek
。同样,这将具有与节点本身不同的内存布局。如果你想在函数中修改它,你需要传递给函数指针(例如,指针到指针(。
指针和它指向的数据是不同的东西。在你的脑海中,你需要将它们分开。指针类似于int
或float
。它"按值"传递给函数。是的,link ptr
已经是指针,这允许您更新它指向的数据。但是,指针本身是按值传递的,并且对指针的更新(在您的情况下ptr=tmp
(在外面不可见。
当然,(*ptr).next=xxx
是可见的,因为数据已更新(而不是指针(。这意味着你需要做一个额外的步骤 - 使对指针的更改在函数之外可见,例如将指针本身(head
(转换为另一个指针的数据,例如使用struct node **ptr
(这里的第一个星表示这是指向节点的指针,第二个星号将该指针转换为另一个指针的数据。