函数指针
是指向函数的指针,存放函数地址。
#include<stdio.h>
int ADD(int x, int y)
{
int z = 0;
z = x + y;
return z;
}
int main()
{
int a = 10;
int b = 20;
printf("%p\n", &ADD);
printf("%p\n", ADD);
return 0;
}
00007FF6789113CF 00007FF6789113CF
两个打印的结果是一样的,都指向了同一个地址,可见 &函数名和函数名都是函数的地址。
整形指针 是 int* p, int 是数据类型,* 号表示p 是一个指针
数组指针 是 int (*p) [5] int [5] 是数组的类型,* 号同样表示p 是一个指针。
所以当指针指向函数的时候 ,我们只需要有函数的类型 ,和?* 号就可以了。
以int ADD(int x,int y) 为例子,指向这个函数的指针就可以这么写了
int (*pa)(int,int) =ADD;
第一个int 是函数的返回值,* 号表示pa 是一个指针,( )表示的指向函数的指针,这个括号里面的两个 int,int 是函数的参数类型。
#include<stdio.h>
int ADD(int x, int y)
{
int z = 0;
z = x + y;
return z;
}
int main()
{
int a = 10;
int b = 20;
int (*pa)(int, int) = ADD;
printf("%d\n",(*pa)(a,b));
return 0;
}
?打印的结果:30
?使用函数的指针去调用函数。
printf("%d\n",(*pa)(a,b));?
函数调用的这句也可以写成:printf("%d\n",pa(a,b)); ADD 函数名本身也是一个地址,pa 指向的就是函数的地址,直接调用pa 就调用这个函数地址就直接调到函数。
void(*signal(int,void(*)int))(int); //1
typedef void(*pfun_i)(int); //2
pfun_i signal(int,pfuni);
//1?
首先* 号和signal 并没有括号()括起来,()的优先级比* 高,所以先确定 signal 是过一个函数名,(int,void(*)int) 是这个函数的参数部分,把函数名和参数部分去掉剩下的就是,返回参数
void(*? ?)(int) 是这个函数的返回参数。
//2
上面函数的第二个参数类型和返回类型都是void(* )int,可以给这个类型自定义的名字让这个函数阅读起来比较简单一些。
在重定以时是这么定义的 typedef void(*pfun_i)(int) ,而不是?typedef void(*)(int)?pfun_i,因为这个类型在使用的时候不是void(*)(int)?p, 而是这么使用?void(*p)(int)。?
函数指针数组
存放函数指针的数组。
int ADD(int x, int y)
{
return x+y;
}
int MUL(int x, int y)
{
return x * y;
}
int SUB(int x, int y)
{
return x - y;
}
int DIV(int x, int y)
{
return x / y;
}
int main()
{
int(*parr[4])(int, int) = { ADD,MUL,SUB,DIV };
return 0;
}
?去掉函数名,剩下的返回值与函数参数就构成函数类型,这个四个函数的类型是一样的都是
int? ?(int,int)。类型一样的元素是可以使用数组来存储的。
? int(*parr[4])(int, int) = { ADD,MUL,SUB,DIV }; *号的优先级比[ ]优先级低所以这是个数组,把数组名去掉剩下的是数组类型
int(* [4])(int,int) 两部分 一是数组元素的个数[4] ,是4个元素,二是元素的类型 int(* )(int,int)指向函数的指针,函数指针
所以parr 就是一个函数指针数组啦。
#include<stdio.h>
int ADD(int x, int y)
{
return x+y;
}
int MUL(int x, int y)
{
return x * y;
}
int SUB(int x, int y)
{
return x - y;
}
int DIV(int x, int y)
{
return x / y;
}
int main()
{
int(*parr[4])(int, int) = { ADD,MUL,SUB,DIV };
int i = 0;
for ( i = 0; i < 4; i++)
{
printf("%d\n", parr[i](6, 3));
}
return 0;
}
结果:
9 18 3 2
通过下标访问数组,传参,就是分别访问数组中的每个函数。?
指向函数指针数组的指针
指向函数指针数组的指针是一个指针?,该指针指向一个数组,数组的元素都是函数指针。
int main()
{
int(*pfArr[4])(int, int);
int(*(*ppfArr)[4])(int, int) = &pfArr;
return 0;
}
?数组的类型是去掉数组名
int arr[10] 去掉数组名 arr 剩下的元素类型,数组元素个数int [10] 就是数组类型了
int a = 10;
int* p = &a;
使用类型、*来定义指针变量。
? ? int(*pf)(int,int)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//函数指针
? ? int(*pfArr[4])(int, int);? ? ? ? ? ? ? ? ? ? ? ? //函数指针数组 ?? ?int(*(*ppfArr)[4])(int, int) = &pfArr;? ? //指向函数指针数组的指针
?去掉数组名pfArr,?? int(* [4])(int, int) 就是函数指针数组的类型,int(* (*) [4])(int, int)类型与*号就组成了 指向函数指针数组的指针。
回调函数
回调函数就是通过函数指针调用的函数。
#include<stdio.h>
int ADD(int x, int y)
{
return x+y;
}
int MUL(int x, int y)
{
return x * y;
}
int SUB(int x, int y)
{
return x - y;
}
int DIV(int x, int y)
{
return x / y;
}
void Calc(int(*pf)(int, int))
{
int x = 6;
int y = 2;
printf("%d\n", pf(x, y));
}
int main()
{
Calc(ADD);
Calc(MUL);
Calc(SUB);
Calc(DIV);
return 0;
}
结果:
?8 ?12 ?4 ?3
Calc 以函数指针作为参数类型,调用时转递函数名,在内部使用函数指针调用到具体的函数。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct Stu
{
char name[20];
int age;
};
int cmp_stu_by_age(const void* p1, const void* p2)
{
return ((struct Stu *)p1)->age - ((struct Stu*)p2)->age;
}
int cmp_stu_by_name(const void* p1, const void* p2)
{
return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
}
int main()
{
struct Stu s[3] = { {"zhansan",20},{"lisi",10},{"wangwu",30}};
int sz = sizeof(s) / sizeof(s[0]);
qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);
return 0;
}
使用到了库函数qsort, 函数的详细介绍与用法可以查看官方的文档
qsort - C++ Reference (cplusplus.com)
void qsort (void* base, size_t num, size_t size,
int (*compar)(const void*,const void*));
base 要排序的数组的第一个对象
num? 要排序的数组的元素个数
size? ?元素的大小,单位时字节
第四个参数是一个函数指针,这个函数实现比较功能。p1 < p2 ,返回值<0。p1 =p2,返回0。p1 >p2,返回值>0。
void* 表示无具体类型的指针,可以用来接收任意转递的过来的指针类型。指针类型表明了指针在解引用是的可影响的范围,void*因为是无具体类型的,所以也就不能解引用了。
函数参数在使用之前需要先转成实际的指针类型。
我们并没有直接调用比较函数的功能,而是将这个函数的地址传给了库函数,在库函数在做比较的时候,会回调回来到这个函数,再根据这个函数的结果,给我们转递的数组做好排序。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct Stu
{
char name[20];
int age;
};
int cmp_stu_by_age(const void* p1, const void* p2)
{
return ((struct Stu *)p1)->age - ((struct Stu*)p2)->age;
}
int cmp_stu_by_name(const void* p1, const void* p2)
{
return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
}
void Swap(char* buff1, char* buff2, int width)
{
int i = 0;
for ( i = 0; i < width; i++)
{
char temp = *buff1;
*buff1 = *buff2;
*buff2 = temp;
buff1++;
buff2++;
}
}
/**
*base: Pointer for the first element of target array
*size: numbers of the tartet array
*width: how much bytes for each element of this array
*cmp: perform to compare two element of this array
*/
void bubble_sort(void* base, int size, int width, int (*cmp)(void* e1, void* e2))
{
int i = 0;
for ( i = 0; i < size; i++)
{
int j = 0;
for ( j = 0; j < size-1-i; j++)
{
if (cmp((char*)base + (j)*width, (char*)base + (j + 1)*width) > 0)
{
Swap((char*)base + (j)*width, (char*)base + (j + 1)*width,width);
}
}
}
}
int main()
{
struct Stu s[3] = { {"zhansan",20},{"lisi",10},{"wangwu",30}};
int sz = sizeof(s) / sizeof(s[0]);
bubble_sort(s, sz, sizeof(s[0]), cmp_stu_by_age);
return 0;
}
?
参考qsort 库函数实现了一个冒泡排序的方法。?
文章是基于比特鹏哥C语言学习视频的学习笔记,仅用于学习。请勿转载,请勿商用。?
|