目录
🍎1.常量指针、指针常量
🍌1.1常量指针
🍌 1.2指针常量
?🍌1.3const即修饰指针,又修饰变量
🍌代码?
?🍎2.数组参数、指针参数
🍌2.1一维数组传参
🍌2.2二维数组传参
?数组指针的内存原理
🍌2.3一级指针传参
?思考
🍌2.4二级指针传参
?思考:
🍎3.函数指针
🍌参考数组指针
🍌列1:
🍌列2:
🍌分析代码
?代码1:
?代码2:
?改写函数
🍎4.函数指针数组
🍌应用:
?案例1:
?案例2:
🍎5.指向函数指针数组的指针
🍎6.回调函数
🍌qsort函数
?使用qsort函数
?实现qsort函数
🍎1.常量指针、指针常量
🍌1.1常量指针
语法:const? 类型* 变量名;
- const修饰指针
- 指针指向可以修改,指针指向的指针不可以修改
🍌 1.2指针常量
语法: 类型*? const? 变量名;
- const修饰变量
- 指针指向的值可以改变,指针指向不可以改变
?🍌1.3const即修饰指针,又修饰变量
语法: const? 类型*? const? 变量名;
🍌代码?
int main()
{
int a = 10;
int b = 20;
//1.const修饰的是指针,指针指向可以修改,指针指向的值不可以修改
const int* p1 = &a;
p1 = &b;
//*p1=100;//报错,此表达式左值不可修改
printf("p1=%d\n", *p1);
//2.const修饰的是变量,为指针常量,指针的指向不可以改,指针指向的值可以修改
int* const p2 = &a;
*p2 = 100;
//p2=&b;//报错,指针的指向不可以修改
printf("p2=%d\n", *p2);
printf("a=%d\n", a);
//3.const即修饰指针又修饰常量,指针的指向和指针指向的值都不可以修改
const int* const p3 = &a;
printf("p3=%d\n", *p3);
return 0;
}
?🍎2.数组参数、指针参数
🍌2.1一维数组传参
?void test(int arr[])//形参是数组
?{}
??
?void test(int* arr)//形参是指针
?{}
??
?void test(int arr[10])//形参是数组
?{}
??
?void text1(int** arr2)//形参是指针
?{}
?//此处arr2接收的是,数组arr2首元素的地址(以首元素为例)
?//第一次解引用,得到数组首元素的值(也是地址)
?//第二次解引用,得到首元素值(地址)对应的值
??
?void text1(int* arr[20])//形参是数组
?{}
??
?int main()
?{
? int arr[10] = { 0 };
? int* arr2[20] = { 0 };
??
? test(arr);
? text1(arr2);
? return 0;
?}
🍌2.2二维数组传参
?void test(int arr1[3][5])
?{}
??
?void test(int arr1[][])//错误用法
?{}
??
?void test(int arr1[][5])
?{}
?//总结:二维数组传参,函数形参的设计只能省略第一个[]的数字。
?//因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。
?//这样才方便运算。
??
?void test(int* arr1)//用法错误,
?{}
??
?void test(int* arr1[5])
?{}
?//错误用法,指针数组
?//数组传过去需要用指针接收
??
?void test(int (*arr1)[5])
?{}
?//数组指针是指向数组的指针,接收数组的地址(&arr[0])
?//使用arr1接收二维数组的地址(第一行,一维数组的地址)
?//为解引用前,表示一行的地址(类型为int* [5]),解引用后表示类型为int [5]的数组的地址
??
?void test(int** arr1)//错误用法
?{}
?//二级指针是指向整数的指针的指针
?//arr1接收的是二维数组的地址
?//二维数组的地址与二维数组第一行的地址,二维数组第一个元素的地址相同,终究只是一个地址
?//这个地址所对应的空间存储的是首元素的值,解引用这个地址,得到准确数值而不是另一个地址
?//无法再次解引用,故不能使用二级指针
??
?int main()
?{
? int arr[3][5] = { 0 };
? test(arr);
? return 0;
?}
?数组指针的内存原理
🍌2.3一级指针传参
?#include <stdio.h>
?void print(int *p, int sz)
?{
? ? ?int i = 0;
? ? ?for(i=0; i<sz; i++)
? ? {
? ? ? ? ?printf("%d\n", *(p+i));
? ? }
?}
?int main()
?{
? ? ?int arr[10] = {1,2,3,4,5,6,7,8,9};
? ? ?int *p = arr;
? ? ?int sz = sizeof(arr)/sizeof(arr[0]);
? ? ?//一级指针p,传给函数
? ? ?print(p, sz);
? ? ?return 0;
?}
?思考
当一个函数的参数部分为一级指针的时候,函数能接收什么参数 ?
?//1
?int a=0;
?test(&a);
??
?//2
?int* ptr=&a;
?test(ptr);
??
?//3
?int arr[10];
?test(arr);
🍌2.4二级指针传参
?#include <stdio.h>
?void test(int** ptr)
?{
? printf("num = %d\n", **ptr);
?}
?int main()
?{
? ? ?int n = 10;
? ? ?int*p = &n;
? ? ?int **pp = &p;
? ? ?test(pp);
? ? ?test(&p);
? ? ?return 0;
?}
?思考:
当函数的参数为二级指针的时候,可以接收什么参数?
?int a =0;
?int* p=&a;
?int** pp = &p;
??
?//1
?test(pp);
??
?//2
?test(&p);
??
?//3.指针数组
?int* arr[10];
?test(arr);
🍎3.函数指针
void Add(int x,int y)
{
return x + y;
}
int main()
{
int arr[10] = { 0 };
printf("%p\n", arr);
printf("%p\n", &arr);
printf("%p\n", Add);
printf("%p\n", &Add);
//Add和&Add都是函数的地址
return 0;
}
🍌参考数组指针
int arr[10] = {0};
int (*p)[10] = &arr;
void add(int a,int b);
void (*p)(int,int) = add;
//void (*p)(int,int) = &add;
🍌列1:
?int Add(int x, int y)
?{
? return x + y;
?}
??
?int main()
?{
? int (*p)(int, int) = Add;
? int a = p(1, 2);
? ? ?//int a = (*p)(1,2);
? ? ?//也是可以的
? ? ?//&Add和Add是相同的地址
??
? printf("%d", a);
??
? return 0;
?}
🍌列2:
?void text(char (*p)[5])
?{
? for (int i = 0; i < 5; i++)
? {
? printf("%c ", *(*p + i));
? }
? printf("\n");
?}
??
?int main()
?{
? char arr[5] = { '1','2','3','4','7'};
? char(*p1)[5] = &arr;
??
? void (*p)(char(*)[5]) = text;
? p(p1);
? ? ?
? ? ?return 0;
?}
🍌分析代码
?代码1:
?(*(void (*)() )0)();
?代码2:
?void ( *signal( int,void(*)(int) ) )(int);//声明函数
表示函数signal( int,void(*)(int) )的指向int返回值为void
-
上述代码是一次函数声明 -
声明的函数为:signal -
signal函数的第一个参数是int类型 -
signal函数的第二个参数是一个函数指针类型,该函数指针指向的函数参数是int,返回类型是void -
signal函数的返回类型也是一个函数指针类型,该函数指针指向的函数参数是int,返回类型是void
?改写函数
?typedef void (*flat1)();
?typedef void (*flat2)(int);
??
?(*(flat1)0)();
?flat2 signal(int,flat2);
🍎4.函数指针数组
?//函数指针
?int (*p)(int,int);
??
?//函数指针数组
?int (*pfArr)(int,int);
??
?int* p;//整形指针
?int* arr;//整形指针数组
🍌应用:
?案例1:
#include <stdio.h>
?int add(int a, int b)
?{
? return a + b;
?}
?int sub(int a, int b)
?{
? return a - b;
?}
?int mul(int a, int b)
?{
? return a * b;
?}
?int div(int a, int b)
?{
? return a / b;
?}
?int main()
?{
? int x, y;
? int input = 1;
? int ret = 0;
? do
? {
? printf("*************************\n");
? printf(" 1:add 2:sub \n");
? printf(" 3:mul 4:div \n");
? printf("*************************\n");
? printf("请选择:");
? scanf("%d", &input);
? switch (input)
? {
? case 1:
? printf("输入操作数:");
? scanf("%d %d", &x, &y);
? ret = add(x, y);
? printf("ret = %d\n", ret);
? break;
? case 2:
? printf("输入操作数:");
? scanf("%d %d", &x, &y);
? ret = sub(x, y);
? printf("ret = %d\n", ret);
? break;
? case 3:
? printf("输入操作数:");
? scanf("%d %d", &x, &y);
? ret = mul(x, y);
? printf("ret = %d\n", ret);
? break;
? case 4:
? printf("输入操作数:");
? scanf("%d %d", &x, &y);
? ret = div(x, y);
? printf("ret = %d\n", ret);
? break;
? case 0:
? printf("退出程序\n");
? break;
? default:
? printf("选择错误\n");
? break;
? }
? } while (input);
? return 0;
?}
?案例2:
#include <stdio.h>
?int add(int a, int b)
?{
? return a + b;
?}
?int sub(int a, int b)
?{
? return a - b;
?}
?int mul(int a, int b)
?{
? return a * b;
?}
?int div(int a, int b)
?{
? return a / b;
?}
?int main()
?{
? int x, y;
? int input = 1;
? int ret = 0;
? int(*p[5])(int x, int y) = { 0, add, sub, mul, div }; //转移表
? while (input)
? {
? printf("*************************\n");
? printf(" 1:add 2:sub \n");
? printf(" 3:mul 4:div \n");
? printf("*************************\n");
? printf("请选择:");
? scanf("%d", &input);
? if ((input <= 4 && input >= 1))
? {
? printf("输入操作数:");
? scanf("%d %d", &x, &y);
? ret = (*p[input])(x, y);
? }
? else
? printf("输入有误\n");
? printf("ret = %d\n", ret);
? }
? return 0;
?}
🍎5.指向函数指针数组的指针
?//函数指针
?int (*pf)(int,int);
??
?//函数指针数组
?int (*pfArr[4])(int,int);
??
?//指向函数指针数组的指针
?int (*(*ptr)[4])(int,int) = &pfArr;
🍎6.回调函数
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个 函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。
回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
🍌qsort函数
?使用qsort函数
?typedef struct s
?{
? char name[20];
? int age;
?}s;
??
?int int_cmp(const void* p1, const void* p2)
?{
? return (*(int*)p2 - *(int*)p1);
?}
?int double_cmp(const void* p1, const void* p2)
?{
? return (*(double*)p2 - *(double*)p1);
?}
?int char_cmp(const void* p1, const void* p2)
?{
? return (*(char*)p2 - *(char*)p1);
?}
?int struct_age_cmp(const void* p1, const void* p2)
?{
? return (*(s*)p1).age - (*(s*)p2).age;
?}
??
?void int_print(void* arr, int num)
?{
? for (int i = 0; i < num; i++)
? {
? printf("%d ", *((int*)arr+i));
? }
? printf("\n");
?}
?void double_print(void* arr, int num)
?{
? for (int i = 0; i < num; i++)
? {
? printf("%.2f ", *((double*)arr + i));
? }
? printf("\n");
?}
?void char_print(void* arr, int num)
?{
? for (int i = 0; i < num; i++)
? {
? printf("%c ", *((char*)arr + i));
? }
? printf("\n");
?}
?void struct_print(void* arr, int num)
?{
? for (int i = 0; i < num; i++)
? {
? printf("%s:%d ", ((s*)arr+i)->name,(*((s*)arr+i)).age);
? }
?}
??
?int main()
?{
? int arr1[] = { 1,2,3,4,5,6,78,9,10 };
? double arr2[] = { 1.2,2.3,2.5,8.9,4.5,6.4,7.5 };
? char arr3[] = "abcdef";
? s arr4[] = { {"zhangsan",10},{"lisi",20},{"wangwu",18} };
??
? qsort(arr1, sizeof(arr1) / sizeof(arr1[0]), sizeof(arr1[0]), int_cmp);//int类型排序
? qsort(arr2, sizeof(arr2) / sizeof(arr2[0]), sizeof(arr2[0]), double_cmp);//double类型排序
? qsort(arr3, sizeof(arr3) / sizeof(arr3[0]), sizeof(arr3[0]), char_cmp);//char类型排序
? qsort(arr4, sizeof(arr4) / sizeof(arr4[0]), sizeof(arr4[0]), struct_age_cmp);//struct类型排序
??
? int_print(arr1, sizeof(arr1) / sizeof(arr1[0]));
? double_print(arr2, sizeof(arr2) / sizeof(arr2[0]));
? char_print(arr3, sizeof(arr3) / sizeof(arr3[0]));
? struct_print(arr4, sizeof(arr4) / sizeof(arr4[0]));
??
? return 0;
?}
?实现qsort函数
?typedef struct s
?{
? char name[20];
? int age;
?}s;
??
?int cmp(void* p1,void* p2)
?{
? return (*(s*)p2).age - (*(s*)p1).age;
?}
??
?void swap(void* p1, void* p2,int size)
?{
? //因为传递的类型不明确,无法简单的通过它一个元素的空间的大小确定类型
? //强制类型转换为char*类型,并传递它一个元素空间的大小数值过来
? //通过循环一个字节,一个字节的传递数值,最终完全传递
? for (int i = 0; i < size; i++)
? {
? char temp = *((char*)p1 + i);
? *((char*)p1 + i) = *((char*)p2 + i);
? *((char*)p2 + i) = temp;
? }
?}
??
?void my_psort(void* arr4, int num, int size, int (*cmp)(void*,void*))
?{
? for (int i = 0; i < num; i++)
? {
? for (int j = 0; j < num-1-i; j++)
? {
? if (cmp((char*)arr4+j*size, (char*)arr4 + (j+1) * size) > 0)
? {
? swap((char*)arr4 + j * size, (char*)arr4 + (j + 1) * size,size);
? }
? }
? }
?}
??
?void struct_print(void* arr, int num)
?{
? for (int i = 0; i < num; i++)
? {
? printf("%s:%d ", ((s*)arr+i)->name,(*((s*)arr+i)).age);
? }
? printf("\n");
?}
??
?int main()
?{
? s arr4[] = { {"zhangsan",10},{"lisi",20},{"wangwu",18} };
??
? my_psort(arr4, sizeof(arr4) / sizeof(arr4[0]), sizeof(arr4[0]), cmp);
??
? struct_print(arr4, sizeof(arr4) / sizeof(arr4[0]));
??
? return 0;
?}
|