进阶指针大全(下篇)---函数指针和回调函数

简介: 进阶指针大全(下篇)---函数指针和回调函数

前言


`在上篇,我们已经讲了指针和数组的深入关系,现在讲讲指针和函数的深入关系。


一、函数指针


什么是函数指针?例如数组指针,是指向数组的指针。那么函数指针则是 指向函数的指针,或许有人说指针存储的是地址,那么函数也有地址嘛?我们先来看一段代码:


5aef5bcc185b4548b5f5fc3807e54a43.png


从图中我们可以发现,输出的是两个地址,且是函数test的地址,那么指针存储的是地址,那么指针也能存储函数。

那存储的方法是什么呢?举个例子吧


函数是: int Text(int x,int y);

则定义函数指针: int (*p)(int ,int);

并且需要初始化指针:p=Text;

指针的使用: p(2,3);


由此看见函数指针的定义方法是: ret (*p)(args, …);

注:ret为函数的返回值类型,p是函数指针 ,(args,…)则是函数的形参列表,就相当于把函数名换成了指针


二、函数指针数组


数组是一个存放相同类型数据的存储空间,那函数指针数组,很明显是存放函数指针的数组。而函数指针则是存放的是函数地址,所以函数指针数组存放的是函数的地址

那又如何定义呢?


在进阶指针的上部里,我们可以看见 指针数组:int* arr[10] arr先和[]结合,为整形数组,而类型是int*,所以存放的是整形指针。

同理把函数指针存放入数组,例如:返回值类型 (p[长度])(形参,形参…) ,可以说是直接在函数指针的指针后面写[长度 ]


2.1代码实现

敲个代码促进理解

//函数指针数组,与函数相同的返回值类型,相同的形参列表
void (*p[4])(int, int) = { NULL,text1,text2,text3};
void text1(int x, int y)
{
  printf("hehe\n");
}
void text2(int x, int y)
{
  printf("hehe\n");
}
void text3(int x, int y)
{
  printf("hehe\n");
}
int main()
{
  int a = 0;
  scanf("%d", &a);  //当a=1时,调用text1
  p[a](2, 3);     //当a=2时,调用text2........
}


三、指向函数指针数组的指针


顾名思义,指针指向一个数组,数组里是存放着函数的地址 。


函数指针数组:void (* *p[4])(int, int) = { NULL,text1,text2,text3};

则指针是:int( * (*ppf)[5])(int,int)=&p;


四、回调函数


回调函数:通过函数指针调用的函数,而具体例子则是使用库函数中的快排函数qsort

简单的说就是:调用一个函数A,传参里有函数B,而接收的是函数指针,然后在A函数里通过函数指针再调用函数B


4.1代码实现:


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;
}
void cale(int(*p)(int, int))
{
  int x = 0;
  int y = 0;
  printf("请输入2个数");
  scanf("%d %d", &x, &y);
  printf("%d\n",p(x, y)); //函数指针再调用对应的函数
}
int main()
{
  cale(add);
  //调用cale函数 传add函数,int(*p)(int, int)接收   
  cale(sub);
  cale(mul);
  return 0;
}



现在解释一下快排函数qsort,存在标准库函数里,头文件是<stdlib.h>

void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )(const void *elem1, const void *elem2 ) );


void *base接收的是首地址,size_t num接收的是字节大小,size_t width接收的是元素的大小,int (__cdecl *compare )(const void *elem1, const void *elem2 ) 这个很明显接收的是函数。


用途:排列元素顺序。

我们可以使用 冒泡排序 的方法来实现qsort函数,对qsort进行一个深入了解


4.2冒泡排序实现qsort代码:


int cmp_int(const void* e1, const void* e2)
{
  return *(int*)e1 - *(int*)e2;
}
void swap(char* q, char* w, int width)
{
  int i = 0;
  for (i = 0; i < width; i++)
  {
    char trm = *q;
    *q = *w;
    *w = trm;
    q++;
    w++;
  }
}
void bubblesort(void* base, size_t a, size_t width, int(*p)(const void* e1, const void* e2))
{
  for (size_t i = 0; i < a - 1; i++)
  {
    for (size_t j = 0; j < a - i - 1; j++)
    {
      if (p((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
      {
        swap((char*)base + j * width, (char*)base + width * (j + 1), width);
      }
    }
  }
}
int main()
{
  int arr[] = { 3,2,4,8,1,6,9,7,5,41 };
  int a = sizeof(arr) / sizeof(arr[0]);
  //实现qsort函数
  bubblesort(arr, a, sizeof(arr[0]), cmp_int);
  for (int i = 0; i < a; i++)
  {
    printf("%d ", arr[i]);
  }
}

而如果使用qsort函数则更为简便,比较大小之后,会自动帮你排序


4.3qsort快排代码:


int cmp_int(const void* e1, const void* e2)
{
  return *(int*)e1 - *(int*)e2;
     //当大于0;则e1
}
void Text2()
{
  int arr[] = { 3,2,4,8,1,6,9,7,5,41 };
  int a = sizeof(arr) / sizeof(arr[0]);
  qsort(arr, a, sizeof(arr[0]), cmp_int);
  for (int i = 0; i < a; i++)
  {
    printf("%d ", arr[i]);
  }
}
int main()
{
  Text2();
}


在qsort中的com_int函数传递2个参数去比较时,需要传递的是地址,比较之后确定位置。

如果返回值 < 0,则表示 s1 小于 s2。 元素不互换

如果返回值 > 0,则表示 s1 大于 s2。 元素互换

如果返回值 = 0,则表示 s1 等于 s2。 元素不互换

而比较完后,会自动传递下一位元素与下下一位元素比较


数组和函数与指针的深层关系介绍完了,若有不懂,评论区留言或者私聊我哦。

目录
相关文章
|
6月前
|
C语言
指针进阶(C语言终)
指针进阶(C语言终)
|
2月前
|
C++
指针中的回调函数与qsort的深度理解与模拟
本文详细介绍了回调函数的概念及其在计算器简化中的应用,以及C++标准库函数qsort的原理和使用示例,包括冒泡排序的模拟实现。
21 1
|
2月前
魔法指针 之 函数指针 回调函数
魔法指针 之 函数指针 回调函数
17 0
|
2月前
|
存储
一篇文章了解区分指针数组,数组指针,函数指针,链表。
一篇文章了解区分指针数组,数组指针,函数指针,链表。
20 0
|
4月前
|
存储 程序员 C语言
指针的高级应用:指针数组、数组指针、函数指针等。
指针的高级应用:指针数组、数组指针、函数指针等。
146 0
|
6月前
|
C语言
指针进阶(回调函数)(C语言)
指针进阶(回调函数)(C语言)
|
6月前
|
存储 C语言 C++
指针进阶(函数指针)(C语言)
指针进阶(函数指针)(C语言)
|
6月前
|
Java 程序员 Linux
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
52 0
|
6月前
|
C语言
C语言中的函数指针、指针函数与函数回调
C语言中的函数指针、指针函数与函数回调
|
25天前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
87 13