预备知识
1.初识指针
对于刚刚入门的小伙伴来说,指针似乎是一种很神奇的东西,老师在课堂上的解释往往不够形象,这给理解指针带来了很大的不便。下面我用一张图片来解释什么是指针。
(图一)
如上图所示,图中未加粗的方框表示四块内存单元。在我所使用的Visual Studio 2022集成开发环境和64位操作系统的计算机中,内存采用0x+16位十六进制数字表示。图中的每一串18个字符长度的编码表示一块地址,也就是指针。每一个18个字符长度的编码都表示一块内存单元。图一左上角的编码0x0000012907850890表示左上角的内存单元,左上角加粗的方框中的编码0x0000012907850520表示右下角的内存单元。
在C语言编写的链表结构中,每一块加粗的方框表示一个结构体,这个结构中包含两个数据类型,一个int类型数据和一个结构体指针类型数据。使用操作符 - >可以访问每一个结构体中的数据。
2.认识调试
在小伙伴们学习编程的过程中,我可以很负责地表示,调试一定很重要。可能你们学校的老师压根就没有使用过Visual Studio中的“本地Windows调试器”,但是在编程中,尤其是使用高版本的编译器的过程中,调试对找bug意义重大。比如,在Visual Studio 2022中,我就遇到过编译器不报错,但是程序执行时不会输出任何结果。当代码量很大的时候,找bug就会显得非常困难。但是使用调试可以看清程序执行的步骤,可以看到每一个变量的值的变化情况,这对于初学者排错来说非常重要。
调试过程如下图:
(图二)
(图三)
创建链表
1.创建头节点
如下图所示,我们用一个结构体表示一个节点的值和下一个节点的地址
struct SingleList
{
int data;
struct SingleList* next;
};
(图四)
图四所示的代码可形象地表示为
(图五)
2.为头节点分配内存
struct SingleList* Header = (struct SingleList*)malloc(sizeof(struct SingleList));
(图六)
此时链表的头节点内存表示为
(图七)
3.初始化头节点
void Init(struct SingleList* Header)
{
Header->data = 1;
Header->next = NULL;
}
(图八)
此时链表的头节点内存表示为
(图九)
4.头插法创建链表
void AppendNode_HeadInsert(struct SingleList* Header)
{
for (int i = 0; i < 5; i++)
{
struct SingleList* Node = (struct SingleList*)malloc(sizeof(struct SingleList));
Node->data = i+2;
Node->next = Header->next;
Header->next = Node;
}
}
(图十)
利用调试得出各个节点的地址,其内存表示为
(图十一)
5.尾插法创建链表
void AppendNode_TailInsert(struct SingleList* Header)
{
int i = 0;
while (Header != NULL && i != 5)
{
struct SingleList* Node = (struct SingleList*)malloc(sizeof(struct SingleList));
Node->data = i+2;
Node->next = Header->next;
Header->next = Node;
Header = Header->next;
i++;
}
}
(图十二)
利用调试得出各个节点的地址,其内存表示为
(图十三)
6.综合代码
#include<stdio.h>
#include<stdlib.h>
struct SingleList
{
int data;
struct SingleList* next;
};
void Init(struct SingleList* Header)
{
Header->data = 1;
Header->next = NULL;
}
void AppendNode_HeadInsert(struct SingleList* Header)
{
for (int i = 0; i < 5; i++)
{
struct SingleList* Node = (struct SingleList*)malloc(sizeof(struct SingleList));
Node->data = i+2;
Node->next = Header->next;
Header->next = Node;
}
}
void AppendNode_TailInsert(struct SingleList* Header)
{
int i = 0;
while (Header != NULL && i != 5)
{
struct SingleList* Node = (struct SingleList*)malloc(sizeof(struct SingleList));
Node->data = i+2;
Node->next = Header->next;
Header->next = Node;
Header = Header->next;
i++;
}
}
int main()
{
struct SingleList* Header = (struct SingleList*)malloc(sizeof(struct SingleList));
Init(Header);
//AppendNode_HeadInsert(Header);
AppendNode_TailInsert(Header);
while (Header!= NULL)
{
printf("%d ", Header->data);
Header = Header->next;
}
return 0;
}
注意事项
1.将代码直接复制粘贴后运行,则执行尾插法。
2.由于分配内存单元具有随机性,故每次调试的地址值会不相同
3.本文使用C语言进行编码,故在创建源文件时应将后缀名更改为.c
4.代码中NULL表示的内存单元为0x0000000000000000