关于我们

质量为本、客户为根、勇于拼搏、务实创新

< 返回新闻公共列表

带你深入了解c语言指针后续

发布时间:2023-06-26 23:00:48

一、函数指针


1.1 函数指针的创建


函数指针,顾名思义,就一个指向函数的指针.


那么


整形指针是接收整形的地址;


字符指针是接收字符的地址.


数组指针是接收数组的地址


函数有地址吗?函数名又可以代表什么?


示例:自定义一个加法函数,观察函数的地址


//函数指针 #includeint add(int a,int b)//自定义一个加法函数 {  return a + b; } int main() {  int a = 2, b = 3;  int c=add(a, b);  printf("%d\n", c);//确认一下函数是否正确  printf("%p\n", &add);//取出函数的地址  printf("%p\n", add);//用数组名打印  return 0; }

   


运行结果:(在不同环境下地址会不一样,这里采用的是vs x86环境)


5


00E61023


00E61023


不难发现,函数名也可以代表函数的地址.


那么函数指针该怎么写呢?


以数组指针为例:


数组指针示例:写一个指向 int arr[10] 数组的数组指针;


第一步: (*p) //先确定是一个指针 第二步: (*p)[10] //确定指向的是一个有10个元素的数组 第三步: int(*p)[10] //确定该数组元素为int型 第四步: int(*p)[10]=&arr;//将数组的地址赋值给数组指针 //或者int(*p)[10]=arr;

   


示例2:


函数指针:指向int add(int a,int b)


第一步: (*p) //先确定是一个指针 第二步: (*p)(int,int) //确定指向的函数有两个参数 第三步: int (*p)(int,int) //确定该函数的返回类型 第四步: int (*p)(int,int)=&add;//将函数的地址赋值给函数指针 //等价于:int (*p)(int,int)=add;

   


1.2 函数指针应用


那么函数指针有什么用吗?


当然是用来调用函数了.


同样以数组指针为例:


使用数组指针访问数组.


int main() {  int arr[10] = { 1,2,3,4,5 };  int(*p)[10] = arr;   for (int i = 0; i < 5; i++)  {  printf("%d ", ( * p)[i]);  }  printf("\n");  return 0; }

   


使用函数指针调用函数


#includeint add(int a,int b) {  return a + b; } int main() {  int a = 2, b = 3;  int(*p1)(int, int) = &add;  int(*p2)(int, int) = add;  int ret1=add(a,b);  int ret2=(*p1)(a, b);//写法一  int ret3=p1(a, b);//写法2  printf("ret1=%d\nret2=%d\nret3=%d",ret1,ret2,ret3);  return 0; }

   


运行结果:都能完成函数的调用


ret1=5


ret2=5


ret3=5


二、函数指针数组


函数指针数组实质用于存放函数指针的数组.


即数组的成员都是函数指针.


写法:以数组成员都是指向类似int add(int,int)的函数指针为例


1.先写出函数指针 (int) (*p)(int,int) 2.改成数组 (int) (*p[10])(int,int)//函数指针数组

   


题目:使用c语言制作简单的计算器.


要求,可以进行加减乘除运算.


//简易计算器 #includevoid menu()//菜单 {  printf("作者:初阶牛\n");  printf(" 欢迎使用计算器:\n");  printf("+-------------------------------+\n");  printf("| 1.add 2.sub |\n");  printf("| 3.mul 4.div |\n");  printf("| 0.退出 |\n");  printf("+-------------------------------+\n"); } 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=0, y=0;  int input = 1;  int ret = 0;  do  {  menu();//打印菜单  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; }

   


对于上面的代码,我们可以使用函数指针来简化.


感受一下函数的指针的魅力吧!


#includevoid menu() {  printf("作者:初阶牛\n");  printf(" 欢迎使用计算器:\n");  printf("+-------------------------------+\n");  printf("| 1.add 2.sub |\n");  printf("| 3.mul 4.div |\n");  printf("| 0.退出 |\n");  printf("+-------------------------------+\n"); } 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 = 0, y = 0;  int input = 1;  int ret = 0;  int(*arr[5])(int, int)={0,add,sub,mul,div};//使用函数指针数组  do  {  menu();  scanf("%d", &input);  if (input > 0 && input < 5)  {  printf("输入两个操作数:");  scanf("%d %d", &x, &y);  ret=arr[input](x,y);//利用数组下标调用相应的函数  printf("ret = %d\n", ret);  }  else if (input == 0)  {  printf("退出计算器\n");  break;  }  else  {  printf("很遗憾,并没有这个选项:\n");  break;  }  } while (input);  return 0; }

   


三、函数指针数组指针


函数指针数组指针:


指向一个数组.该数组的成员都是函数指针.


写法:


1.先写出函数指针 char* (*p)(const int, double, char*); 2.改成函数指针数组 char* (*pp[3])(const int, double, char*); 3.最后写成函数指针数组指针  char* (*(*ppp)[3])(const int, double, char*);

   


可以通过函数指针p调用函数,


也可以通过函数指针数组的元素,pp[0]调用函数.


最后,可以通过(*ppp)找到函数指针数组,(*ppp)[0]调用函数.


示例:


char* test(const int a, double b, char* c) {  char* ret = "AAABBBCCCDDD\n";  return ret; } #includeint main() {  //函数指针  char* (*p)(const int, double, char*)=test;  //函数指针数组  char* (*pp[3])(const int, double, char*);  pp[0] = test;  //函数指针数组指针  char* (*(*ppp)[3])(const int, double, char*)=&pp;  printf("%s", test(0,0,0));  printf("%s", p(0, 0, 0));  printf("%s", pp[0](0, 0, 0));  printf("%s", (*ppp)[0](0, 0, 0));  return; }

   


四、回调函数


回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。


大家还记得冒泡排序吗?


但是冒泡排序只能排序整形,而qsort函数,内部采用快速排序,可以排序各种类型的数据,接下来展示qsort排序部分类型的方法.


示例:qsort函数部分应用


分别将元素比较方法int_cmp和char_cmp的指针(地址) 传给 qsot函数.由qsort函数调用这些比较函数.


#include#includeint int_cmp(void* e1, void* e2)//整形元素排序方法 {  return *(int*)e1 - *(int*)e2; } int char_cmp(void* e1, void* e2)//字符型元素排序方法 {  return (*(char*)e1) - (*(char*)e2); } int main() {  int arr1[10] = { 4,5,1,8,9,2,10,3,7,6 };  char arr2[] = "fbadegc";  int sz1 = sizeof(arr1) / sizeof(arr1[0]);  int sz2 = sizeof(arr2) / sizeof(arr2[0]);  qsort(arr1,sz1,sizeof(arr1[0]),int_cmp);  for (int i=0; i < sz1; i++)  {  printf("%d ", arr1[i]);  }  printf("\n");  qsort(arr2, sz2, sizeof(arr2[0]), char_cmp);  for (int i = 0; i < sz2; i++)  {  printf("%c ", arr2[i]);  }  printf("%s", arr2);  return 0; }

   


运行结果:


1 2 3 4 5 6 7 8 9 10


a b c d e f g


/template/Home/leiyu/PC/Static