目录
声明:本文由笔者在阅读《c++ primer plus》自学第七章函数指针部分后撰写。
声明:本文由笔者在阅读《c++ primer plus》自学第七章函数指针部分后撰写。
函数指针初了解:
显然,被定义的函数在编程中与被定义的变量类似,也有其存储的相应地址,而指向存储一个函数的地址的指针自然也就是函数指针了,并且一个函数的地址可以由函数名来表示。通过函数指针也可以实现函数的调用,且很多时候能够带来好处。
#include <iostream>
using namespace std;
double f1(double a,double b){
return a+b;
}//函数原型及函数定义
int main(){
double (*p1)(double a,double b);
p1=f1;//f1为函数名,函数名本身就可以表示一个函数的地址
cout<<(*p1)(12.2,3.6)<<endl;//函数指针的调用方法之一
return 0;
}
以上代码便是一种最简单的定义函数指针的方法,从中可以看出函数的地址可以用函数名本身来表示,而我们需要做的便是定义好一个符合该函数类型的指针p1,就可以通过p1=f1来实现让p1指向对应的函数f1了。
而学习过程中很容易便发现了,每次编写一大串的函数类型着实很麻烦,而学习了相关内容后就可以发现,可以通过自动类型推断auto或者typedef来简化过程,下面放一段用auto的代码:
#include <iostream>
using namespace std;
const double* f1(const double* ,int );
int main(){
double s1[10]={1,2,3,4};
auto p1=f1;
for(int i=0;i<5;i++){
cout<<(*p1)(s1,i)<<'\t'<<':'<<'\t'<<*(*p1)(s1,i)<<endl;
}
cout<<"另一种编程方法,输出结果相同:"<<endl;
for(int i=0;i<5;i++){
cout<<p1(s1,i)<<'\t'<<':'<<'\t'<<*p1(s1,i)<<endl;// \t为制表符
}
//应当注意:这种等价只针对于函数指针有效!
return 0;
}
const double* f1(const double* p1,int a){
return p1+a;//返回的是指针
}
这里采用的是先定义函数原型,在main函数之后给出完整函数定义的方式。可以看到通过auto p1 = f1,编译器自动识别了f1为函数名也即函数地址,故将p1定义为指针,指向函数f1,实现了快速且方便的定义。
同时这里还展示出了函数指针的两种调用方式,一种是符合逻辑上的先用(*p1)来找到对应函数,再调用,也即"(*p1)(此处放参数)"的方法,另一种则是直接把p1当成函数f1来使用,而不必再额外添加*号。
函数指针数组
类比其他的指针,函数指针显然也可以采用数组来存储,也就是所谓的函数指针数组,这里的函数指针数组基本可以完全类比其他普通类型的指针数组。
再看写的第二个程序:
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <cmath>
using namespace std;
// 函数指针数组
const double *f1(const double *, int);
const double *f2(const double *, int);
const double *f3(const double *, int);
int main()
{
cout<<"New Start\n";
double ar[10] = {11.5, 223.3, 423.32, 35.234, 87.34,137.842,654.134,13.445,23.75};
const double *(*pa[10])(const double *, int);
pa[0] = f1;
pa[1] = f2;
pa[2] = f3;
for(int i=0;i<3;i++){
printf("第%d个函数对应的输出:",i+1);
for(int j=0;j<5;j++){
cout<<(*pa[i])(ar,j)<<'\t'<<*(*pa[i])(ar,j)<<endl;//事实上,很多时候()时候可以省略的,写成如同**pa的形式即可。
}
}
//下面采用auto来简化编写程序的过程。
auto pb=pa;//pb指向pa数组,pb+i可理解为pa[i];
for(int i=0;i<3;i++){
printf("第%d个函数对应的输出:",i+1);
for(int j=0;j<5;j++){
cout<<(*(pb[i]))(ar,j)<<'\t'<<*(*(pb[i]))(ar,j)<<endl;//事实上,很多时候()时候可以省略的,写成如同**pa的形式即可。
}//pb[i]<==>pb+i;
}
return 0;
}
const double *f1(const double *ar, int r)
{
return ar + r;
}
const double *f2(const double *ar, int r)
{
return ar + r+1;
}
const double *f3(const double *ar, int r)
{
return ar + r + 2;
}
//这里图省事就直接开了个大小为10的数组,不过自然也懒得去写10个函数把这个数组填满,强迫症请见谅……
pa数组也就是存储函数指针的数组。自然的,pa[i]也就表示pa+i。这些都是与其他类型的指针相同的。
而定义函数指针类型的数组时,同样的也需要交代清楚类型,也即这一行
const double *(*pa[10])(const double *, int);
前面的const double *表示了函数的返回类型,后面的(const double *,int)则表示了函数所需的参数,这些一起描述了函数的类型。 而中间的*pa[10]则表示该类型的指针数组。就如同int表示类型时,定义方法为int *pa[10]。
同样的也可以采用auto简化定义方式,见上面的代码中pb有关实现。
提到了类型的概念,就比较方便理解typedef在这里的作用了,见下面采用typedef的代码:(在第二个程序的基础上略加修改得到)
//本篇采用typedef来简化类型定义的编辑
#include <iostream>
using namespace std;
typedef const double* (*p_fun/*这里*p_fun表示p_fun是指针类型*/) (const double *,int);//函数指针类型定义,即创建了一种p_fun类型,为函数指针类型
const double* f1(const double* ,int );
int main(){
double s1[10]={1,2,3,4};
p_fun p1=f1;
for(int i=0;i<5;i++){
cout<<(*p1)(s1,i)<<'\t'<<':'<<'\t'<<*(*p1)(s1,i)<<endl;
}
cout<<"另一种编程方法,输出结果相同:"<<endl;
for(int i=0;i<5;i++){
cout<<p1(s1,i)<<'\t'<<':'<<'\t'<<*p1(s1,i)<<endl;// \t为制表符
}
//应当注意:这种等价只针对于函数指针有效!
return 0;
}
const double* f1(const double* p1,int a){
return p1+a;//返回的是指针
}
结尾
以上便是我在浅略学习这一部分的code内容了,剩下的还有一些小的部分没有具体敲出相应代码来实现,例如指针的指针等,函数名的地址等,总之它们大体都类似于其他类型的指针与地址的处理方式,不再一一展开。
本文属于笔者的自学记录与总结,如有不足欢迎评论指点。