C语言精通大牛笔记DAY5_链表与回调函数
1.链表
1.链表要素
- 链表由节点构成
- 每个节点由数据域和指针域组成
2.数组与链表比较
3.链表的分类
链表分类1:
- 静态链表 链表分配在栈上
- 动态链表 链表分配在堆区
链表分类2:
- 单向链表
- 双向链表
链表分类3:
- 单向循环链表
- 双向循环链表
4.带头节点的链表
5.链表完整功能示例
#include "NodeList.h"
//初始化链表
NodeList* init_NodeList()
{
NodeList*pHeader = malloc(sizeof(NodeList));
if (pHeader == NULL)
{
return NULL;
}
pHeader->num = -1;
pHeader->next = NULL;
NodeList*pTail = pHeader;
int in_num = 0;
while (1)
{
printf("请输入链表数据,-1表示停止输入\n");
scanf("%d", &in_num);
if (in_num == -1)
{
break;
}
NodeList*new_Node = malloc(sizeof(NodeList));
new_Node->num = in_num;
new_Node->next = NULL;
pTail->next = new_Node;
pTail = new_Node;
}
return pHeader;
}
//遍历链表
void foreach_NodeList(NodeList*pHeader)
{
NodeList*nextNode = pHeader->next;
while(nextNode!=NULL)
{
printf("%d\n", nextNode->num);
nextNode = nextNode->next;
}
}
//链表的插入
void insert_NodeList(NodeList*pHeader, int old_val, int new_val)
{
NodeList*cur_node = pHeader->next;
NodeList*prv_node = pHeader;
while (cur_node!=NULL)
{
if (cur_node->num == old_val)
{
break;
}
prv_node = cur_node;
cur_node = cur_node->next;
}
NodeList*new_node = malloc(sizeof(NodeList));
new_node->num = new_val;
new_node->next = cur_node;
prv_node->next = new_node;
}
//删除节点
void delete_NodeList(NodeList*pHeader, int val)
{
NodeList*cur_node = pHeader->next;
NodeList*prv_node = pHeader;
while (cur_node!=NULL)
{
if (cur_node->num == val)
{
prv_node->next = cur_node->next;
free(cur_node);
break;
}
prv_node = cur_node;
cur_node = cur_node->next;
}
if (cur_node==NULL)
{
//printf("未找到想要删除的数据\n");
}
return;
}
//清空链表
void clean_NodeList(NodeList*pHeader)
{
NodeList*cur_node = pHeader;
NodeList*next_node = NULL;
while (cur_node!=NULL)
{
next_node = cur_node->next;
free(cur_node);
cur_node = next_node;
}
pHeader->next = NULL;
}
//销毁链表
void free_NodeList(NodeList*pHeader)
{
NodeList*cur_node = pHeader;
NodeList*next_node = NULL;
while (cur_node!=NULL)
{
next_node = cur_node->next;
free(cur_node);
cur_node = next_node;
}
}
2.函数指针
1.函数指针
- 指向函数入口地址的指针
2.函数名
- 函数的入口地址
3.函数指针的写法
void function(int a)
{
printf("hello world\n");
}
void(*pFunc)(int) = function;
//返回值类型 + (指针变量名)(形参列表)
4.函数指针的定义方式
void func(int a,char b)
{
printf("hello world\n");
}
void test01()
{
//先定义出函数的类型,再通过类型定义函数指针变量
typedef void(FUNC_TYPE)(int,char);//定义出一个函数类型,返回值是void,形参列表(int,char)
FUNC_TYPE * pFunc = func;
pFunc(10,'a');
}
void test02()
{
//先定义出函数指针的类型,通过类型定义函数指针变量
typedef void(*FUNC_TYPE)(int,char);
FUNC_TYPE pFunc = func;
pFunc(20,'a');
}
void test03()
{
//直接定义函数指针变量
void(*pFunc)(int,char) = func;
pFunc(20,'a');
}
//函数指针数组
void func1()
{
printf("func1的调用\n");
}
void func2()
{
printf("func2的调用\n");
}
void func3()
{
printf("func3的调用\n");
}
void test04()
{
void(*fun_arr[3])();
fun_arr[0] = func1;
fun_arr[1] = func2;
fun_arr[2] = func3;
for(int i = 0; i < 3; i++)
{
fun_arr[i]();
}
}
3.函数指针做函数参数 — 回调函数
1.少废话,先举例
#include<stdio.h>
int Callback_1(int x) // Callback Function 1
{
printf("Hello, this is Callback_1: x = %d ", x);
return 0;
}
int Callback_2(int x) // Callback Function 2
{
printf("Hello, this is Callback_2: x = %d ", x);
return 0;
}
int Callback_3(int x) // Callback Function 3
{
printf("Hello, this is Callback_3: x = %d ", x);
return 0;
}
int Handle(int y, int (*Callback)(int))
{
printf("Entering Handle Function. ");
Callback(y);
printf("Leaving Handle Function. ");
}
int main()
{
int a = 2;
int b = 4;
int c = 6;
printf("Entering Main Function. ");
Handle(a, Callback_1);
Handle(b, Callback_2);
Handle(c, Callback_3);
printf("Leaving Main Function. ");
return 0;
}
2.回调函数的思考
引用
主要还是方便应用程序的开发吧,有点像考试填空的感觉,一般api的提供者做好了大部分必要的工作,剩下需要程序员自己写的代码就是具体应用所需要的代码,举个例子,假设操作系统(或者某框架)提供了执行程序的方法:
void execute()
{
init(); //初始化必要的资源
dosomething(); //由程序员自己填写的代码,即回调函数
destory(); //释放使用到的资源
}
其中第一步和第三步已经实现了,需要程序员根据实际的情况来填写第二步到底要做什么事情,这就是回调函数的典型应用场景.
在高级语言中,回调函数也就是观察者模式的一种应用.