19.链表
1.数组
优点:随机访问元素效率高
缺点:需要分配一块连续的存储区域(很大区域,有可能分配失败),删除和插入某个元素效率低。
2.链表
节点:数据域,指针域
尾结点:指针域指向NULL
优点:不需要一块连续的存储区域,删除和插入某个元素效率高。
缺点:随机访问元素效率低。
3.结构体嵌套
(1).结构体可以嵌套另外一个结构体的任何类型变量
(2).结构体嵌套本结构体普通变量(不可以);
本结构体的类型大小无法确定,类型本质:固定大小内存块别名;
(3).结构体嵌套本结构体指针变量(可以)指针变量的空间能确定,32位, 4字节, 64位, 8字节;
typedef struct A { int a; int b; char *p; }A; typedef struct B { int a; A tmp1; //ok A *p1; //ok //struct B tmp2; //结构体嵌套本结构体普通变量(不可以) //本结构体的类型大小无法确定,类型本质:固定大小内存块别名 struct B *next; //指针类型大小确定:32位, 4字节, 64位, 8字节 }B;
4.静态链表
typedef struct Stu { int id; //数据域 char name[100]; struct Stu *next; //指针域 }Stu; int main(void) { //初始化三个结构体变量 Stu s1 = { 1, "mike", NULL }; Stu s2 = { 2, "lily", NULL }; Stu s3 = { 3, "lilei", NULL }; s1.next = &s2; //s1的next指针指向s2 s2.next = &s3; s3.next = NULL; //尾结点 Stu *p = &s1; while (p != NULL) { printf("id = %d, name = %s\n", p->id, p->name); //结点往后移动一位 p = p->next; //&s2 }
5.链表的基本操作
(1).创建链表
(2).链表的遍历
(3).插入节点
(4).删除节点
(5).清空链表
6.函数指针
函数指针,它是指针,指向函数的指针;
//函数指针,它是指针,指向函数的指针 //定义函数指针变量有3种方式 //1、先定义函数类型,根据类型定义指针变量(不常用) //有typedef是类型,没有事变量 typedef int FUN(int a); //FUN函数类型 FUN *p1 = NULL; //函数指针变量 //p1 = &fun; p1 = fun; //p1 指向 fun函数 fun(5); //传统调用 p1(6); //函数指针变量调用方式 //2、先定义函数指针类型,根据类型定义指针变量(常用) typedef int(*PFUN)(int a); //PFUN, 函数指针类型 PFUN p2 = fun; //p2 指向 fun p2(7); //3、直接定义函数指针(常用) int(*p3)(int a) = fun; p3(8); int(*p4)(int a); p4 = fun; p4(9);
7.指针函数
它是函数,返回值是指针类型的函数;
8.回调函数
回调函数就是一个通过函数指针调用的函数;
把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。
int add(int a, int b) { return a + b; } //17:11 int minus(int a, int b) { return a - b; } //函数的参数是变量,可以是函数指针变量吗? //框架,固定变量, 17:10 //多态, 多种形态,调用同一接口,不一样表现 void fun(int x, int y, int(*p)(int a, int b) ) { printf("fun11111111\n"); int a = p(x, y); //回调函数 add(1,2) printf("a = %d\n", a); } typedef int(*Q)(int a, int b); //函数指针类型 void fun2(int x, int y, Q p) { printf("fun11111111\n"); int a = p(x, y); //回调函数 add(1,2) printf("a = %d\n", a); } int main(void) { //fun(1, 2, add); fun2(10, 5, minus); printf("\n"); system("pause"); return 0; }