村官 举措 村级网站建设,原网站开发新功能,秦皇岛做网站公司排名,单页面网站源码很多人学 C 语言时#xff0c;都会在「函数、指针、结构体、链表」之间来回卡壳。
真正的难点并不是语法#xff0c;而是不知道如何用函数去“组织数据的行为”。本文将从 C 函数最基础用法 出发#xff0c;逐步引入 指针、结构体、动态内存#xff0c;最终用 函数完整封装…很多人学 C 语言时都会在「函数、指针、结构体、链表」之间来回卡壳。真正的难点并不是语法而是不知道如何用函数去“组织数据的行为”。本文将从C 函数最基础用法出发逐步引入指针、结构体、动态内存最终用函数完整封装一个单链表让你真正理解C 语言的工程本质结构体 数据函数 行为一、为什么「函数」是 C 语言的核心在 C 语言中结构体只负责描述数据函数负责对数据进行操作如果你只会写结构体而不会用函数去操作它那么你写的代码永远只能停留在「演示级」。一个反例没有函数的 C 代码struct Student { int id; int score; }; int main() { struct Student s; s.id 1; s.score 100; printf(%d\n, s.score); }问题是所有逻辑堆在main完全无法复用一旦复杂就失控解决方案用函数封装行为二、C 语言函数的最基础形态1️⃣ 函数的定义与调用int add(int a, int b) { return a b; } int main() { int result add(3, 5); printf(%d\n, result); return 0; }函数由三部分组成返回值类型参数列表函数体2️⃣ 函数的本质一段可复用的逻辑你可以把函数理解为“给一组输入产生一个结果的逻辑单元”但在 C 语言里这还远远不够。三、为什么 C 语言函数必须配合「指针」1️⃣ 值传递的局限void change(int x) { x 10; } int main() { int a 5; change(a); printf(%d\n, a); // 仍然是 5 }原因函数拿到的是变量的拷贝外部变量不会被修改2️⃣ 使用指针修改外部变量关键void change(int* p) { *p 10; } int main() { int a 5; change(a); printf(%d\n, a); // 10 }C 的函数想要“产生副作用”必须使用指针四、函数 结构体工程代码的起点1️⃣ 定义一个结构体typedef struct { int id; int score; } Student;2️⃣ 通过函数操作结构体void print_student(Student* s) { printf(id%d, score%d\n, s-id, s-score); }注意永远传结构体指针而不是结构体本身避免拷贝提高效率五、从结构体走向链表1️⃣ 链表节点的结构体定义typedef struct Node { int data; struct Node* next; } Node;链表的本质结构体中包含指向同类型结构体的指针六、用函数一步步封装一个链表1️⃣ 创建节点返回指针Node* create_node(int value) { Node* node (Node*)malloc(sizeof(Node)); if (node NULL) { return NULL; } node-data value; node-next NULL; return node; }这里你第一次看到函数返回指针动态内存分配2️⃣ 尾插节点修改头指针void append(Node** head, int value) { Node* newNode create_node(value); if (*head NULL) { *head newNode; return; } Node* cur *head; while (cur-next ! NULL) { cur cur-next; } cur-next newNode; }⚠️ 重点为什么是Node** head因为函数内部要修改head本身Node** head 是二级指针3️⃣ 遍历链表void print_list(Node* head) { Node* cur head; while (cur ! NULL) { printf(%d - , cur-data); cur cur-next; } printf(NULL\n); }4️⃣ 删除节点void remove_node(Node** head, int value) { Node* cur *head; Node* prev NULL; while (cur ! NULL) { if (cur-data value) { if (prev NULL) { *head cur-next; } else { prev-next cur-next; } free(cur); return; } prev cur; cur cur-next; } }5️⃣ 释放整个链表非常重要void destroy_list(Node* head) { Node* cur head; while (cur ! NULL) { Node* next cur-next; free(cur); cur next; } }七、完整测试示例int main() { Node* head NULL; append(head, 1); append(head, 2); append(head, 3); print_list(head); remove_node(head, 2); print_list(head); destroy_list(head); return 0; }输出1 - 2 - 3 - NULL1 - 3 - NULL八、从链表到 MessageQueue 的思想迁移你会发现链表 存数据函数 操作数据头指针 队列入口这和 Android 的 MessageQueue / Looper 在思想层面是完全一致的。九、总结一句话非常重要C 语言不是“语法语言”而是“内存 行为设计语言”当你学会用函数封装结构体行为你才真正开始写 C 的工程代码。