函数指针数组和函数指针数组的指针以及回调函数

函数指针数组和函数指针数组的指针

先写一段代码引出函数指针数组和函数指针数组的指针
int test(const char* str,int num)
{

}
int main()
{
int (*pf)(const char * str,int num) = test;//见详解1
int (*arr[5])(const char *,int);//存放函数指针的数组,见详解2
int ( * ( * p)[5])(const  char * , int) = &arr;//见详解3
}

详解1:
pf = test ,把地址放到pf中去,pf现在是一个函数指针,所以要写成(*pf),
指向了函数,第一个参数是const char * str,第二个参数是int num,所以写成(* pf) ( const char * , int num) = test;
返回类型是int型,所以写成int (* pf)(const char * str ,int num ) = test;这个时候pf是一个指针,指向了test
详解2:要把pf存到一个数组中去,假设数组有5个元素。
写一个数组arr[5],每个元素都是函数指针类型,按照语法习惯,我们可能会写成这样int ( * )(const char * ,int ) arr[5];但其实应该写成这样,符合书写习惯int ( * arr[5]) (const char * , int);
详解3:arr 是一个数组,&arr 取出的是函数指针数组的地址
p = &arr,p是一个指针,这个指针能够指向一个数组,这个数组是一个指向函数指针数组的指针,所以给p得加一个 * ,
(p)指向的是一个数组,数组有5个元素,所以写成(*p)[5] = &arr;数组的每个元素是个指针,指针前得加一个 ,所以写成(* (*p)[5]) = &arr;
这个指针又指向的是这个函数,函数的参数是
(const char * , int ) ,返回类型是int 型,最终写成int ( * ( * p )[5])(const char * , int) = &arr;

规律:
函数指针:int (*p) (int , int );
函数指针数组:int (*p[5])(int , int );(只需要给p后面加上[ ]就变成函数指针数组)
函数指针数组的指针:int (*(*p)[5])(int , int );(将函数指针数组的p改成(*p)即可)

函数指针的应用

计算器

void menu()
{
printf("************************\n");
printf("****1. add  2. sub *****\n");
printf("****3. mul  4. div *****\n"); 
printf("****0.    exit     *****\n");
printf("************************\n");
}
enum CALC  
     {
         EXIT,
         ADD,
         SUB,
         MUL,
         DIV
     }
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 ret = 0;
int  x = 0;
int  y = 0;
do
{
menu();
printf("请选择:>");
scanf("%d",&input);
printf("请输入两个操作数:>");
scanf("%d%d",&x ,&y );
switch(input)
{
case ADD:
ret = Add(x , y);
break;
case SUB:
   ret = Subx , y);
break;
case MUL:
   ret = Mul(x , y);
break;
case DIV:
   ret = Div(x , y);
break;
case EXIT:
printf("退出\n");
break;
default:
printf("选择错误\n");
break;
}
 printf("ret = %d\n",ret);
}
    while(input)
}

上述代码比较繁琐,四种计算尚且能一一列举,若是计算比较多的话,就很麻烦了,在这里就运用了函数指针数组来简化代码

void menu()
{
printf("************************\n");
printf("****1. add  2. sub *****\n");
printf("****3. mul  4. div *****\n"); 
printf("****0.    exit     *****\n");
printf("************************\n");
}
enum CALC  
     {
         EXIT,
         ADD,
         SUB,
         MUL,
         DIV,
     }
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 (*pfun[5])(int , int) = {0, Add, Sub, Mul, Div};//函数指针的数组
int input = 0;
int ret = 0;
int  x = 0;
int  y = 0;
do
{
menu();
printf("请选择:>");
scanf("%d",&input);

printf("请输入两个操作数:>");
scanf("%d%d",&x ,&y );
ret =  pfun [ input ] (x , y);

     printf("ret = %d\n",ret);
}
    while(input)
}

将 printf(“请输入两个操作数:>”);
scanf(“%d%d”,&x ,&y );
ret = pfun [ input ] (x , y);
封装成一个函数,过滤掉一些非法的值

  void menu()
{
printf("************************\n");
printf("****1. add  2. sub *****\n");
printf("****3. mul  4. div *****\n"); 
printf("****0.    exit     *****\n");
printf("************************\n");
}
enum CALC  
     {
         EXIT,
         ADD,
         SUB,
         MUL,
         DIV,
     }
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 (*pfun)(int, int))
    {
    int ret = 0;
    int x = 0;
    int y = 0;
     printf("请输入两个操作数:>");
     scanf("%d%d",&x ,&y );
     ret =  pfun  (x , y);
     printf("ret = %d\n",ret);
    }
int main()
{
 int (*pfun[5])(int , int) = {0, Add, Sub, Mul, Div};//函数指针的数组:转移表

int input = 0;
int ret = 0;
int  x = 0;
int  y = 0;
do
{
menu();
printf("请选择:>");
scanf("%d",&input);
if(input >= 1 && input <= 4)
calc(pfun[input]);
else
printf("非法\n");
}
    while(input)
}

函数指针的数组的用途:转移表

回调函数

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

struct Stu
{
char name[20];
int  age;
};
void print_arr(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
    printf("%d ", arr[i]);
}
printf("\n");
}
int cmp_stu(const void * e1, const void * e2)
{
return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}

void print_stu(struct Stu arr[],int sz)
 {
 int  i = 0;
 for (i = 0; i < sz; i++)
 {
     printf("name = %s age = %d\n",arr[i].name,arr[i].age);
 }
 }
 int main()
  {
int arr[] = { 1, 6, 3, 8, 9, 4, 2, 5, 7, 0 };
struct Stu s[3] = { { "zhangsan", 20 }, { "lisi", 15 }, { "wangwu", 50 } };
int sz1 = sizeof(arr) / sizeof(arr[0]);
int i = 0;
//qsort(arr, sz, sizeof(arr[0]), cmp_int);
//print_arr(arr, sz1);       //打印整型
int sz2 = sizeof(s) / sizeof(s[0]);
qsort(s, sz2, sizeof(s[0]), cmp_stu);
print_stu(s, sz2);   //打印浮点型

system("pause");
return 0;
}
模拟实现qsort
 struct Stu
 {
char name[20];
int  age;
 };
void print_arr(int arr[], int sz)
 {
int i = 0;
for (i = 0; i < sz; i++)
{
    printf("%d ", arr[i]);
}
printf("\n");
}
int cmp_stu_age(const void * e1, const void * e2)
{
assert(e1 && e2);
return (((struct Stu*)e1)->age - ((struct Stu*)e2)->age);
}

void print_stu(struct Stu arr[], int sz)
{

  int  i = 0;
     for (i = 0; i < sz; i++)
{
    printf("name = %s age = %d\n", arr[i].name, arr[i].age);
}
}
void Swap(char *buf1, char *buf2, int width)
{
int i = 0;
assert(buf1 && buf2);
for (i = 0; i < width; i++)
{
    char tmp = *buf1;
    *buf1 = *buf2;
    *buf2 = tmp;
    buf1++;
    buf2++;
}
void bubble_sort( void *base,int sz,int width,int (*cmp)(const void*e1,const void *e2))
{
int i = 0;
int j = 0;
assert(base && cmp);
for (i = 0; i < sz - 1; i++)
{
    for (j = 0; j < sz - i - 1; j++)
    {
        if (cmp((char*)base+width*j ,(char*)base+width*(j+1))>0)
        {
            //交换
            Swap((char*)base + width*j, (char*)base + width*(j + 1),width);
        }
    }
}
}
int main()
{
int arr[] = { 1, 6, 3, 8, 9, 4, 2, 5, 7, 0 };
struct Stu s[3] = { { "zhangsan", 20 }, { "lisi", 15 }, { "wangwu", 50 } };
int sz1 = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, sz1, sizeof(arr[0]), cmp_int);
//int sz2 = sizeof(s) / sizeof(s[0]);
//bubble_sort(s, sz2, sizeof(s[0]), cmp_stu_age);
print_arr(arr, sz1);
//print_stu(s, sz2);
system("pause");
return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值