1.字符指针
const关键字:
1.修饰局部变量,表示变量的值不能被改变了,用const修饰变量时,一定要给变量初始化,否则之后不能赋值
const 用于修饰常量字符串
2.常量指针与指针常量
指针常量指向的地址不能改变,但是地址中存储的值可以改变
3.修饰函数的参数
- int main()
- {
- char ch = 'a';
- char* pc = &ch;
-
- const char* ps = "abcdef";//将字符串首字符'a’的位置存放在指针中 ps指向字符串
- //ps存放的是字符串首字符'a'的地址
- //const可以修饰指针变量 使得指针存放的值不能被修改 用const ps维护指针更加安全
- return 0;
- }
字符指针——指向字符的指针——存放字符的地址
char ch = 'a';
char* pc = &ch;
整形指针——指向整形的指针——存放整形的地址
int num = 10;
int* pa = #
数组指针——本质是指针——存放数组的地址
int arr[10] = { 0 };
*********int (*p)[10] = &arr;*********//拿到的是数组的地址
数组名的理解:
数组名绝大部分情况下,数组名是数组首元素的地址
1.sizeof (数组名),数组名表示整个数组,计算的是整数数组的大小
2.&数组名,数组名也表示整个数组,取出的是整个数组的地址
除此之外,所有的数组名都是数组首元素的地址!
二维数组传参的时候,传递的是数组首元素的地址,也就是第一行的地址,就可以使用数组指针来接收
3.指针数组
指针数组——本质是数组——是存放指针的数组
char* arr[5];//存放字符指针的数组
int* arr2[6];//存放整形指针的数组
使用数组指针来模拟一个二维数组:
- //使用数组指针来模拟一个二维数组:
-
- int main()
- {
- int arr1[5] = { 1,2,3,4,5 };
- int arr2[5] = { 2,3,4,5,6 };
- int arr3[5] = { 3,4,5,6,7 };
- int* arr[3] = { arr1,arr2,arr3};
- for (int i = 0; i < 3; i++)
- {
- for (int j = 0; j < 5; j++)
- {
- printf("%d ", arr[i][j]);
- }
- printf("\n");
- }
- return 0;
- }
标答:
- int main()
- {
- int arr1[] = { 1,2,3,4,5 };
- int arr2[] = { 2,3,4,5,6 };
- int arr3[] = { 3,4,5,6,7 };
- //int* int* int*
- int* arr[] = { arr1,arr2,arr3 };
- for (int i = 0; i < 3; i++)
- {
- for (int j = 0; j < 5; j++)
- {
- printf("%d ", arr[i][j]);//通过访问数组下标来访问每一个元素
- }
- printf("\n");
- }
- return 0;
- }
4.数组传参和指针传参
数组传参的时候:
1.传递的是数组首元素的地址
1>一维数组传参,传递的是第一个元素的地址
2>二维数组传参,传递的是第一行的地址
2.数组传参的时候,形参可以写成数组名,也可以写成指针
举例:
形参是数组
test(int a[10]){}
test(int a[]){}
形参是指针
test(int *p){}
二维数组传参
int arr[10];
test(arr);
形参写成数组:test(int arr[3][5]){}
test(int arr[][5]{} 行数可省略,列数不可省略
形参写成指针:test(int (*p)[5]){}//指针默认指向数组第一行
函数指针:函数指针:指向函数的指针 存放的是函数的地址 类比字符指针 整形指针 数组指针
- int Add(int x, int y)
- {
- return x + y;
- }
&函数名和函数名 都是函数的地址
- int main()
- {
- printf("%p\n", &Add);//打印的是函数的地址 00007FF7CA5611CC
- printf("%p\n", Add);//打印的是函数的地址 00007FF6DEDB11CC
- int (*pf)(int, int) = &Add;
- // 返回类型 参数类型 函数名或取地址函数名
- printf("%p\n", pf);//pf是函数指针变量 打印的是函数的地址 00007FF6DEDB11CC
-
- int arr[10];
- int(*pa)[10] = &arr;//数组指针
-
- printf("%p\n", pa);//pa是数组指针变量 打印的是数组的地址 000000C3848FFAB8
-
- int ret = pf(3, 5);//可以通过函数指针直接调用函数 (*pf)(3, 5); *可有可无
- int ret2 = Add(3, 5);//也可以通过函数名直接调用函数
- printf("%d\n", ret);
- printf("%d\n", ret2);
- return 0;
- }
6.函数指针数组
函数指针数组:
char* arr[5] ;字符指针数组 数组 存放的是字符指针
int* arr2[6]; 整形指针数组 数组 存放的是整形指针
函数指针数组 数组 存放的是函数指针
- int Add(int x, int y)
- {
- return x + y;
- }
-
- int Sub(int x, int y)
- {
- return x - y;
- }
-
- int main()
- {
- int (*pf1)(int, int) = &Add;
- int (*pf2)(int,int) = ⋐
- //数组中可以存放类型相同的多个元素
- int (* pfArr[4])(int, int) = { &Add, &Sub };//pfArr是函数指针数组 是存放函数指针的数组
- //数组有四个元素 每个元素都是存放一个地址的指针
-
- return 0;
- }
函数指针数组的应用 函数指针数组的用途
模拟计算器
- void menu()
- {
- printf("*****************************************\n");
- printf("************ 1.add 2.sub ***********\n");
- printf("************ 3.mul 4.div ***********\n");
- printf("************ 0.exit ***********\n");
- printf("*****************************************\n");
- }
-
- int add(int x, int y)
- {
- return x + y;
- }
-
- int sub(int x, int y)
- {
- return x - y;
- }
-
- int mul(int x, int y)
- {
- return x * y;
- }
-
- int div(int x, int y)
- {
- return x / y;
- }
-
- int main()
- {
- int input = 0;
- int x = 0;
- int y = 0;
- int ret = 0;
- do
- {
- menu();
- printf("请选择:>\n");
- scanf("%d", &input);
- //创建一个函数指针数组
- //函数指针数组 转移表
- int (*pfarr[])(int, int) = { null,add,sub,mul,div };
- // 0 1 2 3 4
- if (0 == input)
- {
- printf("退出计算器\n");
- }
- else if (input >= 1 && input <= 4)
- {
- printf("请输入两个操作数\n");
- scanf("%d %d", &x, &y);
- ret = pfarr[input](x, y);
- printf("ret=%d\n", ret);
- }
- else
- {
- printf("选择错误,重新选择!\n");
- }
- } while (input);
- return 0;
- }
7.指向函数指针数组的指针
- int Add(int x, int y);
- int Sub(int x, int y);
- int Mul(int x, int y);
- int Div(int x, int y);
-
- int main()
- {
- int a = 10;
- int b = 20;
- int c = 30;
- int* arr[] = { &a,&b,&c };//整型指针数组
- int* (*p)[3] = &arr;//p是指针,是指向整形指针数组的指针
- int (*pfArr[5])(int, int) = { NULL,Add,Sub,Mul,Div };//pfArr是函数指针数组
- int(*(*p)[5])(int,int) = &pfArr;//p是存放函数指针数组的指针
- return 0;
- }
8.回调函数
依赖函数指针,有函数指针才能实现回调函数,在另一个函数内部通过指针寻找该函数的地址,调用该函数
回调函数就是一个通过函数指针调用的函数,如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数
回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外一方调用,用于对该事件或条件进行响应
举例:
利用函数指针,实现回调函数,解决了代码的冗余
- void menu()
- {
- printf("*****************************************\n");
- printf("************ 1.add 2.sub ***********\n");
- printf("************ 3.mul 4.div ***********\n");
- printf("************ 0.exit ***********\n");
- printf("*****************************************\n");
- }
-
- int Add(int x, int y)
- {
- return x + y;
- }
-
- int Sub(int x, int y)
- {
- return x - y;
- }
-
- int Mul(int x, int y)
- {
- return x * y;
- }
-
- int Div(int x, int y)
- {
- return x / y;
- }
-
- void calc(int (*pf)(int, int))//函数指针
- {
- int x = 0;
- int y = 0;
- int ret = 0;
- printf("请输入两个操作数\n");//没有直接调用函数,将地址传给这个函数,在这个函数内部调用
- scanf("%d %d", &x, &y);//这里的加减乘除就是回调函数
- ret = pf(x, y);//调用函数并返回
- printf("ret = %d\n", ret);
- }
-
- int main()
- {
- int input = 0;
-
- do
- {
- menu();
- printf("请选择:>\n");
- scanf("%d", &input);
- switch (input)
- {
- case 1:
- calc(*Add);
- break;
- case 2:
- calc(*Sub);
- break;
- case 3:
- calc(*Mul);
- break;
- case 4:
- calc(*Div);
- break;
- case 0:
- printf("退出计算器\n");
- break;
- default:
- break;
- }
- } while (input);
- return 0;
- }
回调函数案例:qsort函数
qsort是一个库函数
底层使用的是快速排序的方式,对数据进行排序
这个函数可以直接使用
这个函数可以用来排序任意类型的数据
对数据进行排序:
冒泡排序
快速排序
选择排序
插入排序
- void bubble_sort(int arr[], int sz)
- {
- int i = 0;
- //比较的趟数 n个元素要进行n-1次冒泡排序 n个元素有n-1对元素要进行排序
- for (i = 0; i < sz - 1; i++)
- {
- //每一趟冒泡排序
- int j = 0;
- for (j = 0; j < sz-1-i; j++)
- {
- if (arr[j] > arr[j + 1])
- {
- int t = 0;
- t = arr[j];
- arr[j] = arr[j + 1];
- arr[j + 1] = t;
- }
- }
- }
- }
-
- void print_arr(int arr[],int sz)//这个函数只能排序整形数据
- {
- int i = 0;
- for (i = 0; i < sz; i++)
- {
- printf("%d ", arr[i]);
- }
- printf("\n");
- }
-
- int main()
- {
- int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };
- int sz = sizeof(arr) / sizeof(arr[0]);
- print_arr(arr, sz);
- bubble_sort(arr, sz);//冒泡排序
- print_arr(arr, sz);
- return 0;
- }
***************************qsort函数举例*****************************//
qsort函数的使用方法:
回忆冒泡排序的算法
给一组整形数据,使用冒泡排序算法,拍成升序
核心思想:相邻两组元素进行比较
n个元素要进行n-1次冒泡排序 n个元素有n-1对元素要进行排序
- int cmp_int(const void* e1, const void* e2)
- {
- return *(int*)e1 - *(int*)e2;//强制转换为整形指针
- //compare函数返回值-1 0 1
- }
-
- void print_arr(int arr[], int sz)//这个函数只能排序整形数据
- {
- int i = 0;
- for (i = 0; i < sz; i++)
- {
- printf("%d ", arr[i]);
- }
- printf("\n");
- }
-
- //void qsort(void* base,//指针待排序数组的第一个元素的地址
- // size_t num,//待排序数组元素的个数
- // size_t size,//待排序数组中一个元素的大小
- // int(*cmp)(const void* e1, const void* e2)//函数指针名-cmp指向了一个函数,这个函数是用来比较两个元素大小
- // );
- // e1和e2中存放的是需要比较的两元素的地址
-
- //将比较方法的函数抽离出来,最后根据需求结合
- //1.排序整型数组,两个整形可以直接使用>比较
- //2.排序结构体数组,两个结构体的数据可能不能直接使用>比较
- //也就是不同类型的数据,比较大小,方法是有差距的
-
- //测试qsort排序整形数据
- void test1()
- {
- int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
- int sz = sizeof(arr) / sizeof(arr[0]);
- print_arr(arr, sz);
- qsort(arr, sz, sizeof(arr[0]), cmp_int);
- print_arr(arr, sz);
- }
-
- //测试qsort排序结构体数据
- //结构体
- //1.按照年龄比较
- //2.按照名字比较
-
- struct Stu
- {
- char name[20];
- int age;
- };
-
- //1.按照年龄比较
- int cmp_stu_by_age(const void* e1, const void* e2)
- {
- return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
- }
-
- int cmp_stu_by_name(const void* e1, const void* e2)
- {
- return strcmp(((struct Stu*)e1)->name ,((struct Stu*)e2)->name);
- }
-
-
- void test2()
- {
- struct Stu arr[] = { {"zhangsan",20},{"lisi",30},{"wangwu",12} };
- int sz = sizeof(arr) / sizeof(arr[0]);
- qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
- }
-
- void test3()
- {
- struct Stu arr[] = { {"zhangsan",20},{"lisi",30},{"wangwu",12} };
- int sz = sizeof(arr) / sizeof(arr[0]);
- qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);
- }
- int main()
- {
- test1();
- //test2();
- //test3();
- return 0;
- }
*****************************\n***************************//
void* 类型的指针,他不能进行解引用操作,也不能进行+-整数的操作
void* 类型的指针可以用来存放任意类型数据的地址
void* 是无具体类型的指针,用来接收任意类型的地址
- int main()
- {
- char c = 'w';
- char* pc = &c;
- int* p = &c;
- void* pv = &c;
- int a = 100;
- pv = &a;
-
- return 0;
- }
........