一、单向链表的核心原理
单向链表是一种链式存储结构,每个节点包含两部分:
- 数据域:存储实际的数据(比如整数、结构体)
- 指针域:存储下一个节点的地址,形成“链”的结构
头节点 → 节点1 → 节点2 → 节点3 → NULL
1. 节点结构定义
在C语言中,我们用struct定义链表节点:
#include <stdio.h>
#include <stdlib.h>
// 链表节点结构
typedef struct Node {
int num; // 数据域:存储整数
struct Node *next; // 指针域:指向next节点
} Node;
2. 链表的优势
- 动态内存分配:需要多少节点就分配多少,不浪费RAM
- 插入/删除高效:不需要移动大量数据,只需要修改指针
- 长度可变:可以随时添加或删除节点,适配变长数据
二、单向链表的基本操作
1. 创建新节点
// 创建新节点
Node* NewNode(int num) {
Node *node = (Node*)malloc(sizeof(Node)); // 分配内存
if (node == NULL) {
printf("内存分配失败!\n");
return NULL;
}
node->num = num; // 赋值数据
node->next = NULL; // 初始化为空指针
return node;
}
2. 头插法:在链表头部插入节点
// 头插法:在链表头部插入新节点
void Add(Node **head, int v) {
Node *newNode = NewNode(v);
if (newNode == NULL) return;
newNode->next = *head; // 新节点的next指向原头节点
*head = newNode; // 更新头节点为新节点
}
3. 遍历链表:打印所有节点数据
// 遍历链表:打印所有节点数据
void Show(Node *head) {
Node *p = head;
while (p != NULL) {
printf("%d ", p->num);
p = p->next; // 移动到下一个节点
}
printf("\n");
}
4. 释放链表:释放所有节点内存
// 释放链表:释放所有节点内存
void FreeList(Node **head) {
Node *p = *head;
while (p != NULL) {
Node *temp = p;
p = p->next;
free(temp); // 释放当前节点
}
*head = NULL; // 头节点置空
}
三、完整可运行示例
int main() {
Node *head = NULL; // 头节点初始化为空
// 插入节点
Add(&head, 33);
Add(&head, 22);
Add(&head, 11);
printf("链表数据:");
Show(head); // 输出:11 22 33
// 释放链表
FreeList(&head);
return 0;
}
运行结果:
链表数据:11 22 33
四、单片机中的实战应用
在单片机中,我们可以用单向链表实现串口变长数据缓存:
// 串口数据节点
typedef struct UartData {
uint8_t len; // 数据长度
uint8_t buf[64]; // 数据缓冲区
struct UartData *next;
} UartData;
// 串口接收回调函数(示例)
UartData *uartHead = NULL;
void UART_RxHandler(uint8_t data) {
static UartData *currentNode = NULL;
static uint8_t index = 0;
// 假设帧头为0xAA,帧尾为0x55
if (data == 0xAA) {
// 新帧开始,创建新节点
currentNode = (UartData*)malloc(sizeof(UartData));
if (currentNode == NULL) return;
currentNode->len = 0;
currentNode->next = NULL;
index = 0;
} else if (data == 0x55 && currentNode != NULL) {
// 帧结束,将节点加入链表
currentNode->len = index;
currentNode->next = uartHead;
uartHead = currentNode;
currentNode = NULL;
} else if (currentNode != NULL) {
// 存储数据
currentNode->buf[index++] = data;
if (index >= 64) {
// 缓冲区满,丢弃当前帧
free(currentNode);
currentNode = NULL;
}
}
}
五、注意事项
- 内存分配失败:单片机RAM有限,
malloc可能失败,必须判断返回值 - 内存泄漏:必须调用
free释放不再使用的节点 - 指针操作:操作指针时要注意空指针,避免程序崩溃
- 中断安全:在中断中操作链表时,要关中断保护临界区
六、总结
单向链表是单片机中处理动态数据的必备工具,它的核心优势是动态内存分配和高效插入/删除。通过本文的代码示例,你可以快速在单片机项目中实现变长数据缓存,比如串口数据包、传感器数据采集等场景。
在实际开发中,你还可以扩展链表功能,比如实现尾插法、查找节点、删除指定节点等,以满足更多需求。
340

被折叠的 条评论
为什么被折叠?



