❥关于C++之函数与指针
Posted itzyjr
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了❥关于C++之函数与指针相关的知识,希望对你有一定的参考价值。
执行到函数调用指令时,程序将在函数调用后立即存储该指令的内存地址,并将函数参数复制到堆栈(为此保留的内存块),跳到标记函数起点的内存单元,执行完函数代码(也许还需将返回值放入到寄存器中),然后跳回到地址被保存的指令处。这与阅读文章时停下来看脚注,并在阅读完脚注后返回到以前阅读的地方类似。
与数据项相似,函数也有地址。函数的地址是存储其机器语言代码的内存的开始地址。
double pam(int); // 函数原型
double (*pf)(int); // 声明函数指针(参数为int型,返回值为double型)
pf = pam; // 函数名就是函数的地址,这时pf就是指向函数pam()的指针(参数、返回值类型都匹配)
double x = pam(4); // 用函数名调用
double x = (*pf)(5); // 使用函数指针调用
为何pam和(*pf)等价呢?由于pf是函数指针,那*pf是函数,因此可将(*pf)( )用作函数调用。
#include <iostream>
using namespace std;
double betsy(int);
double pam(int);
void estimate(int lines, double (*pf)(int));
int main()
int code;
cout << "How many lines of code do you need? ";
cin >> code;
cout << "Here's Betsy's estimate:\\n";
estimate(code, betsy);
cout << "Here's Pam's estimate:\\n";
estimate(code, pam);
return 0;
double betsy(int lns) return 0.05 * lns;
double pam(int lns) return 0.03 * lns + 0.0004 * lns * lns;
void estimate(int lines, double (*pf)(int))
cout << lines << " lines will take ";
cout << (*pf)(lines) << " hour(s)\\n";
How many lines of code do you need? |100<Enter>
Here's Betsy's estimate:
100 lines will take 5 hour(s)
Here's Pam's estimate:
100 lines will take 7 hour(s)
可以看到,调用相同的estimate()函数,有不同的效果,这都是函数指针的功劳,它可以按需实现不同的功能。
下面看一个稍复杂点的示例:
#include <iostream>
const double* f1(const double ar[], int n);
const double* f2(const double[], int);
const double* f3(const double*, int);
int main()
using namespace std;
double av[3] = 1112.3, 1542.6, 2227.9 ;
typedef const double* (*p_fun)(const double*, int); // 创建类型别名
p_fun p1 = f1;
auto p2 = f2; // C++0x automatic type deduction
cout << "Using pointers to functions:\\n";
cout << " Address Value\\n";
cout << (*p1)(av, 3) << ": " << *(*p1)(av, 3) << endl;
cout << p2(av, 3) << ": " << *p2(av, 3) << endl;
p_fun pa[3] = f1,f2,f3 ;
auto pb = pa;
cout << "\\nUsing an array of pointers to functions:\\n";
cout << " Address Value\\n";
for (int i = 0; i < 3; i++)
cout << pa[i](av, 3) << ": " << *pa[i](av, 3) << endl;// 运算符优先级:[] > () > *
cout << "\\nUsing a pointer to a pointer to a function:\\n";
cout << " Address Value\\n";
for (int i = 0; i < 3; i++)
cout << pb[i](av, 3) << ": " << *pb[i](av, 3) << endl;
cout << "\\nUsing pointers to an array of pointers:\\n";
cout << " Address Value\\n";
auto pc = &pa; // easy way to declare pc
cout << (*pc)[0](av, 3) << ": " << *(*pc)[0](av, 3) << endl;
p_fun (*pd)[3] = &pa;// slightly harder way to declare pd(1)
const double* (*(*pd)[3])(const double *, int) = &pa;// hard way to declare pd(2)
const double* pdb = (*pd)[1](av, 3);
cout << pdb << ": " << *pdb << endl;
cout << (*(*pd)[2])(av, 3) << ": " << *(*(*pd)[2])(av, 3) << endl;
return 0;
const double* f1(const double* ar, int n) return ar;
const double* f2(const double ar[], int n) return ar + 1;
const double* f3(const double ar[], int n) return ar + 2;
Using pointers to functions:
Address Value
006FFC0C: 1112.3
006FFC14: 1542.6
Using an array of pointers to functions:
Address Value
006FFC0C: 1112.3
006FFC14: 1542.6
006FFC1C: 2227.9
Using a pointer to a pointer to a function:
Address Value
006FFC0C: 1112.3
006FFC14: 1542.6
006FFC1C: 2227.9
Using pointers to an array of pointers:
Address Value
006FFC0C: 1112.3
006FFC14: 1542.6
006FFC1C: 2227.9
代码里面最难理解的点在于如下这句代码:
p_fun pa[3] = f1,f2,f3 ;
const double* (*(*pd)[3])(const double *, int) = &pa;
首先,运算符优先级:[ ] > () > *
T (*pd)[3](K)
——pd是一个指针(函数指针),pd指向一个包含3个元素的数组,每个数组元素都是具有参数列表为K,返回类型为T特征的函数。由于函数名只可以作为指针(函数指针)使用,而不可能有其他函数名用法,所以此声明是无效的!在此只是作个比较说明而已。
T (*(*pd)[3])(K)
——pd是一个指针(函数指针),pd指向一个包含3个元素的数组,每个数组元素都是具有参数列表为K,返回类型为T特征的指针(函数指针)。第一个星号作用于pd变量,第二个星号作用于数组元素。
以上图片是去掉最外层的*(),其就不能作为函数指针数据了,在此无任何意义。
程序解读:
对于函数原型f1、f2、f3这些函数的特征标看似不同,但实际上相同。首先,在函数原型中,参数列表const double ar [ ]与const double * ar的含义完全相同。其次,在函数原型中,可以省略标识符。因此,const double ar [ ]可简化为const double [ ],而const double * ar可简化为const double *。因此,上述所有函数特征标的含义都相同。
从运行结果,可以看到,同一函数的地址是固定不变的。
可以看到auto
的强大,让程序员将主要精力放在设计而不是细节上。
注意到程序中:
p_fun pa[3] = f1,f2,f3 ;// f1、f2、f3都是函数名,也是代表着地址,都是指针变量
auto pb = pa;
cout << pa[i](av, 3);
对比:
auto pc = &pa;
cout << (*pc)[0](av, 3)
————————————
通过IDEA的提示,如下图,更直观比较pb与pc的赋值区别:
auto pb = pa;
——对于数组pa是数组首元素地址,这时pb[0]=f1, pb[1]=f2, pb[2]=f3
auto pc = &pa;
——对于数组&pa是整个数组的地址,两边加星号,则*pc=pa, (*pc)[0]=pa[0]=f1, (*pc)[1]=f2, (*pc)[2]=f3
下面这个示例,非常直观解释了以上疑惑:int arr[3] = 3, 5, 7; int (*pc)[3] = &arr; cout << arr[0] << "," << arr[1] << "," << arr[2] << endl; cout << pc[0] << "," << pc[1] << "," << pc[2] << endl; cout << *pc[0] << "," << *pc[1] << "," << *pc[2] << endl; cout << (*pc)[0] << "," << (*pc)[1] << "," << (*pc)[2];
3,5,7 0x3bc51ffafc,0x3bc51ffb08,0x3bc51ffb14 3,-987759876,59 3,5,7
arr是数组首元素地址,步长为1,所以可以直接下标访问。
pc被赋值为整个数组的地址,通过例子打印的地址也可佐证它步长为3,所以除了pc[0]外,其他下标访问的元素是无意义的。
pc指向整个数组的地址&arr,那(*pc)就恒等于arr了,这时(*pc)就是首元素地址了,可以直接用下标访问元素。
还可以看到:使用typedef
,使程序编写简单很多:
typedef const double* (*p_fun)(const double*, int);
以上是关于❥关于C++之函数与指针的主要内容,如果未能解决你的问题,请参考以下文章