接着指针2,继续学习指针!
三、数组参数、指针参数(此处不细讲,只看两个问题理解一下就好)
1.当一个函数的参数部分为一级指针时,函数能接受什么参数?
1)对应的类型的一级指针 2)对应类型的一维数组名
如:void f(int *a,int n) ; void f(int a[],int n);
2.当函数的参数为二级指针时,可以接收什么参数?
1)应用于二维数组: void f(int a[][n],int n,int m) 对于二维数组做参数一定要先指定列数!
2)普通二级指针:void f(int **p){} int a=0; int *p=&a; f(&p);
//此处只能传入普通二级指针,不能传入二维数组 原因:由于二维数组要先确定长度问题,因此不能像一维数组那样直接用
数组名代替一级指针当参数
四、函数指针
1.函数指针:是指向函数的指针变量。因此“函数指针”本身首先应是指针变量,只不过该指针变量指向函数。
函数指针有两个用途:调用函数和做函数的参数。
2.函数指针的声明方法为:
返回值类型 ( * 指针变量名) ([形参列表]);
如:void (*pfun)(int,int); //声明了一个无返回值类型,带两个int 类型参数的函数指针。pfun是一个指针
注:区别于指针函数: void *pfun(int,int);//这是一个函数声明语句 pfun是函数名。
编码示例:
#include <stdio.h>
int max(int a,int b);
int min(int a,int b);
int main()
{
int a=3,b=8;
int (*pfun)(int,int);//定义函数指针变量
int res;
pfun=max;
res=pfun(a,b);
printf("max:%d\n",res);
pfun=min;
res=pfun(a,b);
printf("min:%d\n",res);
return 0;
}
int max(int a,int b)
{
return a>b? a:b;
}
int min(int a,int b)
{
return a<b? a:b;
}
总结:函数指针能代替相应类型的函数名工作。
补充:函数名就相当于每个函数的入口地址。所以当函数指针指向函数时就相当于找到了打开函数的钥匙,所以可以用函数指针进入函数。
五、函数指针数组、函数指针数组的指针
1.函数指针数组:存放函数地址的数组。即数组元素全为函数指针的数组。
如:int (*parr[10])();//该数组可存放10个int类型,无参函数的地址
用途:当要操作多个函数时可考虑用函数指针数组。
示例:转移表(计数器的实现)
#include <stdio.h>
int add(int x,int y);//加
int sub(int x,int y);//减
int mul(int x,int y);//乘
int div(int x,int y);//除
void show();//菜单显示
void calc(int input,int x,int y,int (*p[5])(int,int));//计算器!
int main()
{
int x=0,y=0;
int input=1;
//定义一个函数指针数组 p
int (*p[5])(int,int)={0,add,sub,mul,div};//转移表
calc(input,x,y,p);
return 0;
}
void calc(int input,int x,int y,int (*p[5])(int,int))
{
int result=0;
while(input)
{
show();
printf( "请选择:" );
scanf( "%d", &input);
if(input==0)
{
printf("停止计算!\n");
break;
}
if(input>=1&&input<5)
{
printf("请输入操作数:\n");
scanf("%d %d",&x,&y);
result=p[input](x,y);
printf("result=%d\n",result);
}
}
}
void show()
{
printf( "*****************\n" );
printf( "*0:close *\n");
printf( "*1:+ 2:-*\n" );
printf( "*3:* 4:/*\n" );
printf( "*****************\n" );
}
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;
}
2.函数指针数组的指针:是一个指针,指向函数指针数组。即数组元素全为函数指针的数组。
如: void (*(*ppfunArr)[5]) (int,int); //就是定义了一个指针,这个指针指向的是一个长度为5的数组,而这个数组中存储都是 无参带两个int类型参数的函数的指针(地址)。可能看起来比较绕一些!下面,我将计算器用函数指针数组的指针 来实现一下。其实改动的地方不多。
重点理解:函数指针数组 是数组! 而函数指针数组的指针是指针变量的概念! 类似之前讲过的 数组 和数组指针!只是在这 里类型不仅是平常我们见的基本类型。此处类型可以看成是函数!
#include "stdafx.h"
int add(int x,int y);
int sub(int x,int y);
int mul(int x,int y);
int div(int x,int y);
void show();
//改1:void calc(int input,int x,int y,int (*p[5])(int,int))
void calc(int input,int x,int y,int (*(*pparr)[5])(int,int));//将参数 函数指针 改为函数指针参数的指针
int main()
{
int x=0,y=0;
int input=1;
//定义一个函数指针数组
int (*p[5])(int,int)={0,add,sub,mul,div};//转移表
//定义一个函数指针数组指针
int (*(*pparr)[5])(int,int)=&p;
calc(input,x,y,pparr);
return 0;
}
void calc(int input,int x,int y,int(*(*pparr)[5])(int,int))
{
int result=0;
while(input)
{
show();
printf( "请选择:" );
scanf( "%d", &input);
if(input==0)
{
printf("停止计算!\n");
break;
}
if(input>=1&&input<5)
{
printf("请输入操作数:\n");
scanf("%d %d",&x,&y);
//改2:result=p[input](x,y);
//将数组名改为指针变量 p[i](x,y)==(*pparr)[i](x,y)
result=(*pparr)[input](x,y);
printf("result=%d\n",result);
}
}
}
void show()
{
printf( "*****************\n" );
printf( "*0:close *\n");
printf( "*1:+ 2:-*\n" );
printf( "*3:* 4:/*\n" );
printf( "*****************\n" );
}
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;
}
总结:在我看来,凡是指向数组的指针,加上*后都可以代替数组名来使用。
不管是之前讲过的 数组和数组指针 还是在这里讲的 函数指针数组和函数指针数组的指针其实本质上是一样的东西,只是由后者的类型变复杂了,所以理解起来会困难一些!
学习完这一次课的内容,给我最深的感悟就是,所有复杂的东西都是从最原始的逐渐添加枝叶变成的大树。遇到大问题的时候就
将其一步步简化为小的问题去逐个理解吸收。只有理解完了小的,最后才能拼成一个完整的知识体系。就如本章内容,其实最根
本的东西还是数组,指针的问题。
补充:
回调函数:
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为 参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这 是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条 件发生时由另外的一方调用的,用于对该事件或条件进行响应。
编码示例: 简单选择排序,用回调函数实现
#include <stdio.h>
void sort(int *a,int n,bool (*pFun)(int,int));
void output(int *a,int n);
//升序
bool less(int x,int y);
//降序
bool greater(int x,int y);
int main(int argc, char* argv[])
{
int a[5]={2,1,4,5,3};
output(a,5);
printf("升序:\n");
sort(a,5,less);
output(a,5);
pirntf("降序\n");
sort(a,5,greater);
output(a,5);
return 0;
}
//不用回调函数时:只能单独进行升序或是降序排列 void sort(int *a,int n);
//用函数指针做参数,实现函数调用
void sort(int *a,int n,bool (*pFun)(int,int))//1.加一个参数,传递比较方法
{
int k;int tmp;
for(int i=0;i<n;i++)
{
k=i;
for(int j=i+1;j<n;j++)
{
//if(a[j]>a[k])||if(a[j]<a[k])
if(pFun(a[j],a[k]))//2.调用函数实现比较操作
k=j;
}
if(k!=i)
{
tmp=a[k];a[k]=a[i];a[i]=tmp;
}
}
}
void output(int *a,int n)
{
printf("\n");
for(int i=0;i<n;i++)
{
printf("%d ",a[i]);
}
printf("\n");
}
bool less(int x,int y)
{
return x<y;
}
bool greater(int x,int y)
{
return x>y;
}
用了回调函数后就可以将降序和升序的选择,作为一个函数指针 的参数传入排序函数中。
如果感兴趣,可以先自己写好普通的排序,再在自己的代码上改成与上面类似的回调函数。毕竟看十遍不如自己敲一遍!
以上内容是全由个人对现阶段所学知识进行的总结整理,如果有任何问题欢迎指出!谢谢。