先搞懂核心概念:链表(新手版)
你可以把链表想象成「手拉手的小朋友队伍」:
- 每个小朋友 = 链表的节点 (对应代码里的
struct list) - 小朋友手里的数字 = 节点的
data(存具体数值) - 小朋友拉着下一个人的手 = 节点的
next(存下一个节点的地址,相当于 "指向" 下一个小朋友) - 队伍第一个小朋友 = 链表的头节点 (
head指针指向它) - 最后一个小朋友没人拉 = 尾节点的
next是NULL(空)
我们这段代码的目标:先根据一个数字数组,创建这样的 "小朋友队伍",再挨个看小朋友手里的数字,找出最大的那个。
逐部分拆解代码(新手友好版)
1. 头文件和编译指令(代码最开头)
c
运行
#include <stdio.h> // 标准输入输出头文件:printf、scanf这些函数都靠它
#include <stdlib.h> // 标准库头文件:malloc(申请内存)、exit(退出程序)这些函数需要它
#pragma warning (disable:4996) // 屏蔽VS编译器的4996警告(比如用scanf时的警告,新手不用纠结)
这部分是 "准备工作",告诉编译器:我接下来要用这些库函数,你帮我加载好。
2. 定义链表节点(结构体)
c
运行
struct list // 定义一个叫list的结构体,就是"小朋友"的模板
{
int data; // 小朋友手里的数字(存储整数数据)
struct list *next; // 指向另一个list结构体的指针(小朋友拉的手,指向下一个小朋友)
};
struct list:自定义的一种数据类型,专门用来描述链表节点。data:存具体的数值(比如数组里的 123、21 这些数)。next:是一个指针 (可以理解成 "地址标签"),它的值是下一个struct list节点的内存地址,这样就能把所有节点串起来。
3. 创建链表的函数:createlist
这个函数的作用:把数组里的数字,一个个变成 "手拉手的小朋友",最后返回队伍第一个小朋友(头节点)的地址。
c
运行
struct list *createlist(int data[], int n) // 参数:数字数组、数组长度;返回值:头节点地址
{
struct list *head = 0, *p, *q; // 定义3个指针:head(头节点)、p(临时新节点)、q(当前最后一个节点)
int i;
// 第一步:创建头节点(队伍第一个小朋友)
head = (struct list *) malloc(sizeof(struct list)); // malloc:申请一块内存给头节点(给第一个小朋友找位置)
head->data = data[0]; // 头节点的data存数组第一个数(第一个小朋友拿数组第一个数字)
p = q = head; // p和q都先指向头节点(先让临时指针、尾指针都指向第一个小朋友)
// 第二步:循环创建剩下的节点(给剩下的小朋友找位置、拉手)
for(i=1; i<n; i++) // i从1开始,因为数组第0个已经给头节点了
{
p = (struct list *) malloc(sizeof(struct list)); // 给新节点申请内存(新小朋友到位)
p->data = data[i]; // 新节点存数组的第i个数(新小朋友拿对应数字)
q->next = p; // 让当前最后一个节点(q)的"手"指向新节点(p)(老最后一个拉新小朋友的手)
q = p; // q移到新节点,变成新的"最后一个节点"(q跟着队伍末尾走)
}
p->next = NULL; // 循环结束,最后一个节点的"手"设为NULL(最后一个小朋友没人拉)
return head; // 返回头节点地址(告诉调用者:队伍的第一个小朋友在这)
}
4. 找最大值的函数:func(重点补全的部分)
这个函数的作用:从链表头节点开始,挨个看每个节点的data,找出最大的那个值返回。
c
运行
int func(struct list *head) // 参数:链表头节点地址;返回值:找到的最大值(int型)
{
// 新手补充:先判断链表是不是空的(防止传个空地址导致程序崩溃)
if (head == NULL) {
printf("链表为空!\n");
exit(1); // 链表空的话,直接退出程序(避免后续操作出错)
}
int pmax = head->data; // 第一步:先把第一个节点的数值当成"当前最大值"
struct list *p = head->next; // p指针指向第二个节点(准备开始遍历)
// 循环遍历:只要p不是NULL(还有小朋友没看),就继续
while(p != NULL)
{
// 如果当前节点的数值比"当前最大值"大,就更新最大值
if(p->data > pmax) pmax = p->data;
// ___2___ 补全:p = p->next (关键!让p指向下一个节点)
// 比喻:看完当前小朋友,手指移到下一个小朋友身上
// 不写这个的话,p永远指向第二个节点,会陷入死循环!
p = p->next;
}
// ___3___ 补全:return pmax; (关键!返回找到的最大值)
// 函数声明是int型,必须返回一个整数,否则编译器报错
// 把最终找到的最大值返回给调用这个函数的地方(main函数)
return pmax;
}
5. 主函数:main(程序入口)
所有代码从这里开始执行,负责 "调用函数、收尾输出"。
c
运行
void main()
{
// 定义数组(要存到链表的数字)、pmax(存找到的最大值)
int data[] = {123, 21, 65, 789, 32, 310, 671, 651, 81, 101}, pmax;
struct list *head; // 定义头节点指针(准备接收创建好的链表头地址)
head = createlist(data, 10); // 调用createlist,创建链表,返回头地址给head
pmax = func(head); // 调用func,找最大值,返回值存到pmax
printf("Max=%d\n", pmax); // 输出最大值(结果是789)
}
代码执行的完整流程(新手视角)
- 程序启动,进入
main函数。 - 定义数组
data(10 个数字),定义pmax存最大值。 - 调用
createlist(data, 10):- 先创建头节点,存 123;
- 循环创建 9 个节点,依次存 21、65、789...101,每个节点 "手拉手";
- 最后返回头节点地址,存在
head里。
- 调用
func(head):- 先把第一个节点的 123 当成当前最大值;
- 遍历第二个节点(21):21<123,最大值还是 123;
- 遍历第三个节点(65):65<123,最大值还是 123;
- 遍历第四个节点(789):789>123,最大值更新为 789;
- 继续遍历剩下的节点,都比 789 小,最大值保持 789;
- 遍历结束,返回 789,存在
pmax里。
- 执行
printf,输出Max=789,程序结束。
新手必记的核心要点
- 链表遍历的关键 :必须用
指针->next移动指针,直到指针为NULL,否则会死循环。 - 函数返回值 :声明为
int型的函数,必须用return返回一个整数,编译器才不会报错。 - 指针判空 :操作链表前先检查头指针是不是
NULL,避免程序崩溃(新手容易忽略)。 - malloc 的作用:给链表节点申请内存空间,没有这一步,节点就 "没有地方放",程序会出错。