C++第七章__传递字符串__返回字符串_传递结构__传递结构的地址和返回结构地址__函数和string对象__函数与array对象__ 递归函数(简单应用)__递归调用(复杂)__函数指针_子函数中调用子函数__创建指向函数的指针_函数指针数组之*pd[3]
目录:
- 传递字符串
- 返回字符串
- 传递结构
- 传递结构的地址和返回结构地址
- 函数和string对象
- 函数与array对象
- 递归函数(简单应用)
- 递归调用(复杂)
- 函数指针
- 子函数中调用子函数
- 创建指向函数的指针
- 函数指针数组之*pd[3]
字符串数组作为函数参数(传递字符串)
注意:01)用while循环字符串数组时,结束的条件,在子函数中
02)指针字符串作为函数参数时,声明时注意要加const
03)字符串数组作为函数参数时,直接将字符串数组的名字写入子函数的括号内作为子函数的实参即可 如:recurs(str,20);//其中str是一个字符串数组
04)用字符串数组作为形参的子函数声明的时候,就必须写全了 如:void subdivide(char ar[], int low, int high, int level); //声明一个递归函数
1 #include <iostream> 2 3 unsigned int c_in_str(const char* str, char ch); //不能修改str指针的值 4 5 int main() 6 { 7 using namespace std; 8 char mmm[15] = "minimum"; //声明一个字符串数组 9 const char* wail = "ululate"; //声明一个指针数组 10 11 unsigned int ms = c_in_str(mmm, 'm'); //函数调用 12 unsigned int us = c_in_str(wail, 'u'); 13 14 cout << ms << " m characters in" << mmm << endl; 15 cout << us << " u characters in" << wail << endl; 16 17 system("pause"); 18 return 0; 19 } 20 unsigned int c_in_str(const char* str, char ch) 21 { 22 unsigned int count = 0; 23 while (*str) //str传入的是一个字符串数组,只要不是空字符,*str就是非零值 24 { //字符串数组以空字符'\0'结束,如果到了最后,则推出while循环 25 if (*str == ch) //如果查找到对应的字符,则进入if语句 26 count++; 27 str++; //str指向下一个字符 28 } 29 return count; 30 }
执行结果为:
子函数返回字符串的方法:返回该字符串的地址(返回字符串)
注意:01)声明一个用来盛放字符串地址的指针的时候,要用new来为其分配内存空间
02)注意字符串最后一个元素是空字符'\0',所以这里是要单独加紧字符串中去的
03)既然子函数返回的是一个字符串指针,那么在主函数中也是要定义一个字符串指针来接收此字符串指针的
1 #include <iostream> 2 3 char* buildstr(char ch, int n); //声明一个返回字符串地址的函数 4 5 int main() 6 { 7 using namespace std; 8 char ch; 9 int times; 10 char* str; 11 12 cout << "请输入一个字符:"; 13 cin >> ch; 14 cout << "请输入一个数字:"; 15 cin >> times; 16 17 str = buildstr(ch, times); 18 cout << "函数调用之后的指针数组为:" << str << endl; 19 delete[] str; //释放new创建的内存 20 21 system("pause"); 22 return 0; 23 24 } 25 26 char* buildstr(char ch, int n) 27 { 28 char* str = new char[n + 1]; //为空字符占一个位置 29 str[n] = '\0'; //因为字符串的序号是从0开始排序的,所以最后一个位置的序号是n 30 for (n = n - 1; n >= 0; n--) //书上用的是 while(n-- >0) 31 { 32 str[n] = ch; //重复的将ch赋值给指针数组 33 } 34 return str; 35 }
执行结果为:
结构做为子函数的参数(传递结构)
注意:01)cin接收正确的输入之后可以返回一个值,该值随后会被转换为true或者是false,
如果输入正确,则转换为true.否则转换为false,因此可以作为while循环是 否结束的判断条件。
02) 自己定义的新的结构类型可以去定义子函数、变量等。
1 #include <iostream> 2 #include <cmath> 3 4 using namespace std; 5 struct polar //定义新结构类型,可以用该结构类型去定义子函数、变量和子函数中的参数 6 { 7 double distance; 8 double angle; 9 }; 10 struct rect //垂直坐标系 11 { 12 double x; 13 double y; 14 }; 15 16 polar rect_to_polar(rect xypos); //声明返回值为polar型的子函数,该函数的参数为rect型结构 17 void show_polar(polar dapos); //声明一个无返回值的子函数,该函数的参数为polar型结构 18 19 int main() 20 { 21 rect rplace; //用新的结构类型rect去定义一个结构rplace 22 polar pplace; //用新的结构类型polar去定义一个结构rplace 23 24 cout << "请输入直角坐标系的x和y值:"; 25 while (cin >> rplace.x >> rplace.y) //由于结构中的x和y都是double型变量,所以输入除数字以为的都会退出循环 26 { 27 pplace = rect_to_polar(rplace); //将在主函数中定义的结构作为子函数的参数 28 show_polar(pplace); //再将返回的结构传入show_polar()子函数中去 29 cout << "请再次输入垂直坐标系中的x和y的值(按除数字以外的字符退出该程序):"; 30 } 31 cout << "程序执行完毕" << endl; 32 system("pause"); 33 return 0; 34 } 35 36 polar rect_to_polar(rect xypos) 37 { 38 polar polar_return; 39 polar_return.distance = sqrt(xypos.x * xypos.x + xypos.y * xypos.y); //sqrt()求根号 40 //polar_return.angle = atan2(xypos.x, xypos.y); //atan2()求坐标x和y的角度 41 polar_return.angle = atan2(xypos.y, xypos.x); //这样求出的角度才对 42 43 return polar_return; //返回结构 44 } 45 void show_polar(polar dapos) //polar新结构类型定义的函数参数dapos 46 { 47 const double rad_to_deg = 57.29577951; //即 180°/Π 48 49 cout << "您输入的点和原点之间的距离是:" << dapos.distance << endl; 50 cout << "您输入的点和x正半轴之间的角度是:" << dapos.angle * rad_to_deg << endl; 51 }
执行结果:
传递结构的地址和返回结构地址(并不使用返回值,而是对指针进行操作)
/*
01)调用函数时,将结构的地址(&pplace)传递给子函数
02)将形参声明为指向polar的指针,即polar*型。(由于子函数不应该修改结构,因此这里使用了const修饰符)
03)由于形参声明为指向polar的指针,因此使用间接成员运算符(->)
*/
void rect_to_polar(const rect* pxy,polar* pda);
//第一个指向rect的指针存储直角坐标系的数据
//第二个指针指向存储角坐标系的数据
//该子函数的目的是要将直角坐标系的数据转换为角坐标系的数据,因此要将直角坐标系的数据设置为const
//且该子函数没有返回值,是修改pda指向的存储区域,在主函数中可以直接使用传给pda的那个结构
//使用指针,使函数能够对原始指针进行操作
1 #include <iostream> 2 #include <cmath> 3 4 using namespace std; 5 struct polar //定义新结构类型,可以用该结构类型去定义子函数、变量和子函数中的参数 6 { 7 double distance; 8 double angle; 9 }; 10 struct rect //垂直坐标系 11 { 12 double x; 13 double y; 14 }; 15 16 void rect_to_polar(const rect* pxy,polar* pda); 17 //第一个指向rect的指针存储直角坐标系的数据 18 //第二个指针指向存储角坐标系的数据 19 //该子函数的目的是要将直角坐标系的数据转换为角坐标系的数据,因此要将直角坐标系的数据设置为const 20 //且该子函数没有返回值,是修改pda指向的存储区域,在主函数中可以直接使用传给pda的那个结构 21 //使用指针,使函数能够对原始指针进行操作 22 23 void show_polar(const polar* pda); //声明一个无返回值的子函数,该函数的参数为polar型结构 24 25 int main() 26 { 27 28 rect rplace; //用新的结构类型rect去定义一个结构rplace 29 polar pplace; //用新的结构类型polar去定义一个结构rplace 30 31 cout << "请输入直角坐标系的x和y值:"; 32 while (cin >> rplace.x >> rplace.y) //由于结构中的x和y都是double型变量,所以输入除数字以为的都会退出循环 33 { 34 rect_to_polar(&rplace, &pplace); //传入两个结构的地址进去,在主函数中可以直接使用pplace结构 35 //&rplace是对rplace结构中的数据进行使用,然后存储在&pplace处; 36 //所以在主函数中可以直接使用pplace结构 37 show_polar(&pplace); //再将返回的结构传入show_polar()子函数中去 38 cout << "请再次输入垂直坐标系中的x和y的值(按除数字以外的字符退出该程序):"; 39 } 40 cout << "程序执行完毕" << endl; 41 system("pause"); 42 return 0; 43 } 44 45 void rect_to_polar(const rect* pxy, polar* pda) 46 { 47 pda->distance= sqrt(pxy->x * pxy->x + pxy->y * pxy->y); //sqrt()求根号 48 //polar_return.angle = atan2(xypos.x, xypos.y); //atan2()求坐标x和y的角度 49 pda->angle = atan2(pxy->y, pxy->x); //这样求出的角度才对 50 51 } 52 void show_polar(const polar* pda) //polar新结构类型定义的函数参数dapos 53 { 54 const double rad_to_deg = 57.29577951; //即 180°/Π 55 56 cout << "您输入的点和原点之间的距离是:" << pda->distance << endl; //使用间接成员运算符修改结构中的值 57 cout << "您输入的点和x正半轴之间的角度是:" << pda->angle * rad_to_deg << endl; 58 }
执行结构和上一个的执行结果是一样的,只不过使用指针的话,效率会更高一些,因为传递的是地址,如果不使用指针的话,传递的是数据
函数和string对象
01)定义了一个string数组,定义方法和定义常规数组是一样的
02)传递string类字符串只在子函数中写string类字符串的名字就可以
03)如果需要在子函数中去读string类字符串中字符的多少,也可以在子函数的参数中加入一个数字
04)使用size()来计算string类字符串中字符的多少 如str2是一个string类字符串 str2.size()返回str2中字符的多少
05)使用strlen来计算char类字符串数组中字符的多少 如str1是一个char类字符串数组 strlen(str1)返回str1中字符的多少
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 const int SIZE = 5; 6 7 void show(const string str[], int size); //声明一个子函数,参数为一个string对象和传入的string对象的大小 8 9 int main() 10 { 11 string list[SIZE]; //定义一个string数组,数组名为list,包含五个元素 12 cout << "请输入五个字符串:"<<endl; 13 for (int n = 0; n < SIZE; n++) 14 getline(cin, list[n]); 15 show(list, SIZE); 16 17 const string str2 = "haijing"; 18 char str3[] = "haijing"; 19 cout << "使用strlen来计算char类字符串数组中字符的多少:" << strlen(str3) << endl; 20 cout << "使用size来计算string类字符串中字符的多少:" << str2.size() << endl; 21 22 system("pause"); 23 return 0; 24 } 25 void show(const string str[], int size) 26 { 27 for (int i = 0; i < size; i++) 28 cout << "您输入的五个string对象分别为:" <<str[i]<< endl; 29 }
执行结果:
函数与array对象
01)要使用array对象,需要包含头文件array
02)名称array位于名称空间std中
03)使用一个array对象来存储一年四个极度的开支: std::array<double,4> expenses;
04)如果要在主函数中来显示expenses的内容,则调用方法为: show(expenses);
05)如果子函数中要修改expenses,则需要将该对象的地址传递给函数,在主函数调用方法为: fill(&expenses);
06)声明函数的方法:
void show(std::array<double,4> da);//因为expenses的类型为array<double,4>,因此要在函数声明中指定这种类型
void fill(std::array<double,4>* pa);//因为要传入的是一个地址,所以这里要声明的是指针
07)array<double,4> a3={3.14,2.72,1.62,1.41}; //创建一个array对象a3,其中4是不可省略的,使用a3的方法和使用数组一样 以前的知识点
1 #include <iostream> 2 #include <array> 3 #include <string> //刚刚没有加这个头文件,导致"没有与这次额错做书匹配的<<运算符"错误出现 4 5 //using std::string; //这样去声明也可以 6 //using std::array; 7 using namespace std; 8 9 const int Size = 4; 10 const array<string, 4> Seasons = { "Spring","Summar","Fall","Winter" }; //声明并初始化一个静态的array对象Seasons 11 void fill(array<double, Size>* pa); //声明一个参数为array<double, Size>指针的子函数,声明为指针以便于修改pa对于的array对象 12 void show(array<double, Size> da); //声明一个参数为array<double, Size>的子函数,由于不需要修改da对于的array对象,不必使用指针 13 14 int main() 15 { 16 array<double, Size> expenses; //声明一个array对象expenses,包含Size个元素 17 fill(&expenses); //传入expenses的地址进去,以便于修改expenses内的元素的值 18 show(expenses); //只是显示一下,所以只要传入expenses的原数据就好了 19 20 system("pause"); 21 return 0; 22 } 23 24 void fill(array<double, Size>* pa) 25 { 26 for (int i = 0; i < Size; i++) 27 { 28 cout << "请输入" << Seasons[i] << "的开支:"; //Seasons为全局array对象 29 cin >> (*pa)[i]; //(*pa)就代表了expenses这个array对象,(*pa)[i]就等价于expenses[i] 30 } 31 } 32 void show(array<double, Size> da) 33 { 34 double total = 0.0; 35 for (int i = 0; i < Size; i++) 36 { 37 cout << Seasons[i]<< "季度的开支为:" << da[i] <<"$"<< endl; //Seasons为全局array对象 38 total = total + da[i]; //将传入的array对象中的数据进行累加 39 } 40 cout << "一年中总的开支为:" << total << "$" << endl; 41 }
执行结果:
递归函数(简单应用)
void recurs(argumentlist)
{
statments1;
if(test)
recurs(argumentlist);
statment2;
}
/*
01)只要if语句为true,每个recurs调用都将执行statments1,然后再调用recurs,而不会执行tatments2
02)当if语句为false时,当前调用将执行statment2,当前调用结束后(执行完statment2后),程序控制权将返回
给调用它的recurs(),而该recurs()将执行statment2部分,然后结束,并将程序控制权
返回给前一个调用,以此类推;
因此如果recurs()进行了5次递归调用,则第一个statments1部分将会按函数调用顺序执行5次
然后statments2部分将以与函数调用相反的顺序执行5次,进入5层递归后,程序将沿进入的路径返回
*/
1 #include <iostream> 2 3 using namespace std; 4 5 void recurs(int n); //声明一个递归函数 6 7 int main() 8 { 9 int i = 4; 10 recurs(4); //调用递归函数 11 12 system("pause"); 13 return 0; 14 } 15 void recurs(int n) 16 { 17 cout << "递归正向开始,n=" << n << "(n at " << &n << ")" << endl; 18 if (n > 0) 19 { 20 n = n - 1; 21 recurs(n); //此处也可以直接用recurs(n-1)代替,此时n的值也会被改变 22 } 23 cout << "递归正向结束后,反向开始,n=" << n << "(n at " << &n << ")" << endl; 24 }
执行结果:
递归调用(复杂)
1 #include <iostream> 2 3 const int Len = 66; 4 const int Dives = 6; 5 void subdivide(char ar[], int low, int high, int level); //声明一个递归函数 6 7 int main() 8 { 9 char ruler[Len]; //声明一个字符串数组 10 ruler[Len - 1] = '\0'; //设置ruler数组最后一个元素为空字符,否则ruler不是字符串数组 11 for (int i = 1; i < Len - 2; i++) //ruler[1]数组中第二个元素 12 ruler[i] = ' '; //首先设置ruler数组中第二个元素到倒数第二个元素之间为空格 13 int max = Len - 2; //因为数组是从0开始排序,Len-1对应最后一个元素(\0),则真正的有值的应该是从Len-2向左开始的 14 int min = 0; 15 ruler[min] = ruler[max] = '|'; 16 std::cout<< ruler << std::endl; 17 18 for (int i = 1; i <= Dives; i++) 19 { 20 subdivide(ruler, min, max, i); 21 std::cout<< ruler << std::endl; //显示字符串数组中的竖杠和空格 22 for (int j = i; j < Len - 2; j++) 23 ruler[j] = ' '; //显示完了之后将ruler中的'|'全部设置为空格 24 } 25 26 std::cout << std::endl;//为了显示的更清楚 27 system("pause"); 28 return 0; 29 } 30 31 void subdivide(char ar[], int low, int high, int level) 32 { 33 if (level == 0) 34 return; 35 int mid = (high + low) / 2; //求出中间数,即使high+low是奇数 36 ar[mid] = '|'; //设置中间的字符串为竖杠 37 subdivide(ar, low, mid, level - 1); 38 subdivide(ar, mid, high, level - 1); 39 40 }
执行结果:
函数指针(在子函数中调用另外一个子函数,当然不用函数指针,直接在子函数中调用另外一个子函数也是可以的)
/*
01)与数据项类似,函数也有地址。函数的地址是存储其机器语言代码的内存的开始地址
02)获取函数的地址:只要使用函数名(后面不跟参数即可),类如think()是一个函数,则think就是该函数的地址
03)process(think);//process()调用使得process()函数能够在其内部调用think()函数
04)thought(think()); //thought()调用先调用think()函数,然后将think()函数的返回值传递给thought()函数
05)指针函数声明方法:double pam(int); //声明一个普通函数,返回值为double类型,参数为int类型
double (*pf)(int); //pf指向一个函数,返回一个double值,其中(*pf)括号不可少
pf = pam; //将普通函数的地址赋给指针pf
注意:pam的返回值类型、参数类型 和 pf的返回值类型、参数类型必须是完全一样的,否则编译器会报错
06)double (*pf)(int); //pf指向一个函数,返回一个double值
double* pf(int); //声明一个函数pf,返回值为一个指针(地址),该指针指向一个double值
07)例:void estimate(int lines,double (*pf)(int)); //声明estimate()函数,该函数的第二个参数为一个函数指针
//它指向的函数接收一个int参数,并返回一个double值
estimate(50,pam); //主函数中调用方法,其中pam是函数pam()的地址
08)使用指针来调用函数:
double pam(int);
double (*pf)(int);
pf = pam;
double x = pam(4); //使用函数名字掉头函数pam()
double y = (*pf)(5); //使用函数指针调用函数pam()
double z = pf(6); //这样调用c++也是允许的
这是由于一种学派认为,由于pf是函数指针,而*pf是函数,因此应将(*pf)()用作函数调用;
另一种学派认为,由于函数名(比如pam)是指向该函数(pam())的指针,指向函数的指针(pf)的行为应该与函数命相似
因此应将pf()用作函数调用
c++进行了折中,两种方法都用
*/
1 #include <iostream>
2
3 using namespace std;
4
5 double betsy(int lns);
6 double pam(int lns);
7 void estimate(int lines, double (*pf)(int)); //声明一个普通函数estimate(),其中一个参数为指针函数,该指针函数的返回值为double类型,接收参数为int类型
8
9 int main()
10 {
11 int code;
12 cout << "请输入您的代码的行数:";
13 cin >> code;
14 cout << "Here is Betsy's estimate: " << endl;
15 estimate(code, betsy); //将函数betsy()的地址betsy传递给estimate()函数
16 cout << "Here is Pam's estimate: " << endl;
17 estimate(code, pam); //将函数pam()的地址pam传递给estimate()函数
18
19 system("pause");
20 return 0;
21 }
22 double betsy(int lns)
23 {
24 return 0.05*lns;
25 }
26 double pam(int lns)
27 {
28 return 0.03*lns + 0.0004*lns*lns;
29 }
30 void estimate(int lines, double(*pf)(int))
31 {
32 cout << lines << " lines will take ";
33 cout << (*pf)(lines) << " hour(s)" << endl; //在主函数调用estimate(code, betsy);时,(*pf)(lines)将会调用betsy()函数,
34 //注意(*pf)就等价于betsy,lines作为参数传入betsy()函数
35 }
执行结果:
子函数中调用子函数
1 #include <iostream>
2
3 using namespace std;
4
5 void show00(char str1[]); //两个子函数的声明
6 void show01(char str2[]);
7
8 int main()
9 {
10 char str1[] = "haijing00"; //这里定义的字符串变量类型必须和子函数中形参的类型是一致的,不能是string类型
11 show00(str1); //在主函数中调用子函数
12
13 system("pause");
14 return 0;
15 }
16
17 void show00(char str1[])
18 {
19 cout << str1 << endl;
20
21 char str2[] = "我是在子函数中调用的一个子函数";
22 show01(str2); //在子函数中调用子函数
23
24 }
25 void show01(char str2[])
26 {
27 cout << str2<<endl;
28 }
执行结果:
函数指针的深入 :创建指向函数的指针
/*
01) const double* f1(const double ar[], int n); //返回值为double* 函数名字为f1
const double* f1(const double [], int ); //返回值为double* 函数名字为f2
const double* f1(const double* , int n); //返回值为double* 函数名字为f3 这三个声明是等价的
//但是在函数定义时,是不允许这么做的,函数声明是允许这么做的
I 参数列别(形参)中的const double ar[]与const double* ar的含义完全相同
II在函数原型(函数声明)中,可以省略标识符,因此const double ar[]可以简化为const double []
而const double* ar可以简化为const double*,因此上述所有函数特征标的含义都相同
02)函数定义必须提供标识符,因此需要使用const double ar[]或const double* ar
03)现在要声明一个指针p1,指向这三个函数(f1、f2和f3)之一,则只需将目标函数原型中的函数名替换为(*p1)即可
那么可以任选一个f1、f2或f3用*p1替换下来,则声明为:const double* (*p1)(const double* , int);
解析:一种学派认为:因为指针p1为地址,所以*p1就是该指针所指向的东西f1,所以*p1和f1是等价的
另一种学派认为:因为函数名f1就是函数f1()的地址,且指针p1指向了该函数,也是该函数的地址,所以p1是和f1等价的
04)可以在声明的同时进行初始化:const double* (*p1)(const double* , int) = f1; //声明一个指针p1,并使p1指向函数f1()
调用方法为:(1)学派一:(*p1)(av,3),该句等价于f1(av,3),因为f1函数返回的是一个地址,所以(*p1)(av,3)返回
的也是一个地址
(2)根据函数指针中的知识,我们知道函数指针调用(*p1)(av,3)和p1(av,3)是等价的,都是返回一个
地址,为查看实际存储的值,需要对其进行解除引用,如表达式:*(*p1)(av,3)
(3)学派二:p1(av,3); 该句等价于f1(av,3),且返回的是一个地址,所以*p1(av,3)表示的是该地址处的值
05)厉害的来了:const double* (*p1)(const double* , int) = f1;该句可以用 auto p1 = f1; 代替!
所表示的意思是完全一样的
*/
1 #include <iostream> 2 3 using namespace std; 4 5 //声明返回值为地址的函数 6 const double* f1(const double ar[], int n); //返回值为double* 函数名字为f1 7 const double* f2(const double[], int); 8 const double* f3(const double*, int); 9 10 int main() 11 { 12 double av[3] = { 112.3,1542.6,227.9 }; //声明并初始化一个数组 13 14 const double* (*p1)(const double*, int) = f1; //声明一个指针p1,使p1指向函数f1。该句可用auto p1=f1;代替 15 auto p2 = f2; //声明一个指针p2,使p2指向函数f2 16 17 cout << "(*p1)(av,3): " << (*p1)(av, 3) << "; " << "*(*p1)(av,3): " << *(*p1)(av, 3) << endl; //该学派认为*p1和f1等价 18 cout << "p1(av,3): " << p1(av, 3) << "; " << "*p1(av,3): " << *p1(av, 3) << endl; //该学派认为p1就是f1是等价的 19 //在指针函数中可知, 20 //一种学派认为: 21 //由于p1指向的是f1函数,且f1是一个返回值为地址(double*)的函数,而p1是指向f1的指针,所以*p1就和f1等价 22 //所以(*p1)(av,3)就等价于f1(av,3),自然是要返回一个地址,要获取该地址的值,对该地址解除引用就好了 23 //另一种学派是这么认为的: 24 //他们认为函数的名字(比如f1)就是一个地址,那么也就是指向该函数f1()的指针,而p1也是指向该函数f()的指针 25 //所以他们认为p1的行为应该和函数名f1是一样的,故直接用p1(av,3)去调用函数f1() 26 //但是如果f1函数的返回值不是地址,而是值,那么函数指针好像就没有多大的意义了***** 27 28 cout << "(*p2)(av,3): " << (*p2)(av, 3) << "; " << "*(*p2)(av,3)" << *(*p2)(av, 3) << endl; //该学派认为*p1和f1等价 29 cout << "p2(av,3): " << p2(av, 3) << "; " << "*p2(av,3)" << *p2(av, 3) << endl; //该学派认为p1就是f1是等价的 30 31 system("pause"); 32 return 0; 33 } 34 35 const double* f1(const double ar[], int n) 36 { 37 return ar; //返回ar数组中的第一个数的地址 38 } 39 const double* f2(const double ar [], int n) //函数定义的时候必须写上标识符 ar 和 n 40 { 41 return ar+1; //返回ar数组中的第二个数的地址 42 } 43 const double* f3(const double* ar, int n) //函数定义的时候必须写上标识符 ar 和 n 44 { 45 return ar+2; //返回ar数组中的第三个数的地址 46 } 47 48 创建一个指针,使该指针指向一个函数
执行结果为:
*pd[3]和(*pd)[3]
函数指针数组之*pd[3] 锚点为12
/*
01) 假设pa是指向三个函数的数组,要声明这样的数组,首先要使用pa[3]
运算符[]比*的优先级的高,因此*pa[3]表明pa是一个包含三个指针的数组
所以函数指针数组的声明方法为:const double* (*pa[3])(const double*, int);
该声明表示数组指针pa指向的函数的返回值为地址(double*指针),其余的为形参
02) 初始化方法:const double* (*pa[3])(const double*, int) = {f1,f2,f3};
其中f1,f2,f3为返回值为地址的函数,pa[0]是一个指针,指向f1()
pa[1]是一个指针,指向f2()
pa[2]是一个指针,指向f3()
03) auto只能用于单值初始化,而不能用于列表初始化。
但是声明数组pa后,声明同类型的数组pa就可以用auto了
比如:auto pb = pa; //将pb声明为和pa同类型的函数指针数组,
04) 由于数组名是指向第一个元素的指针,所以pa和pb都是指向函数指针(或函数地址f1)的指针
const double* (*pa[3])(const double*, int) = {f1,f2,f3}; //创建一个数组pa,该数组内包含了
// 三个指针pa[0]、pa[1]、pa[2]分别指向f1、f2、f3
解析:由于pa是数组名,所以pa指向数组中第一个元素f1,而f1也是一个地址(函数f1()的地址)
所以pa是指向函数指针的指针,换句话说也就是pa是一个指针,它指向函数指针f1,
也就是说pa和f1是等价的
05)调用方法:
(01)学派一:pa[0]是一个指针,它指向函数指针f1,所以*pa和f1是等价的
(对一个指针解除引用后就是指向的东西),所以调用方法为: (*pa[0])(av,3);
该句返回的是一个地址,获取该地址的方法为 *(*pa[0])(av,3);
(02) 学派二:认为pa[0]是一个指针,它指向函数指针f1,也就是说pa和f1是等价的
所以调用方法为:pa[0](av,3); 该句返回的是一个地址
获取该地址的方法为 *pa[0](av,3);
06) *pd[3]; //[]的优先级比*高,所以c++编译器会认为该句的意思为: 创建创建一个数组,
//该数组包含了三个指针(三个函数地址)
(*pd)[3]; //创建一个指针,该指针指向一个包含3个元素的数组
*/
1 #include <iostream> 2 3 using namespace std; 4 5 //声明返回值为地址的函数 6 const double* f1(const double ar[], int n); //返回值为double* 函数名字为f1 7 const double* f2(const double[], int); 8 const double* f3(const double*, int); 9 10 int main() 11 { 12 double av[3] = { 112.3,1542.6,227.9 }; //声明并初始化一个数组 13 14 const double* (*pa[3])(const double*, int) = {f1,f2,f3}; //声明一个数组pa[3],该数组包含3个指针(函数地址)f1,f2,f3, 15 //且pa[0]、pa[1]、pa[2]分别指向f1、f2、f3 16 auto pb = pa; //创建和pa同类型的数组pb,pb也包含了三个指针元素 17 18 for (int i = 0; i < 3; i++) 19 { 20 cout << "pa第一种方法显示地址: " << "(*pa[" << i << "])(av, 3): " << (*pa[0])(av, 3) << endl; //显示地址 21 cout << "pa第一种方法显示值: " << "*(*pa[" << i << "])(av, 3): " << *(*pa[i])(av, 3) << endl; //显示值 22 23 cout << "pa第二种方法显示地址:" << "pa[" << i << "](av,3): " << pa[i](av, 3) << endl; 24 cout << "pa第二种方法显示值:" << "*pa[" << i << "](av, 3): " << *pa[i](av, 3)<< endl; 25 } 26 cout << endl; 27 cout << endl; 28 for (int i = 0; i < 3; i++) 29 { 30 cout << "pb第一种方法显示地址: " << "(*pb[" << i << "])(av, 3): " << (*pb[0])(av, 3) << endl; //显示地址 31 cout << "pb第一种方法显示值: " << "*(*pb[" << i << "])(av, 3): " << *(*pb[i])(av, 3) << endl; //显示值 32 33 cout << "pb第二种方法显示地址:" << "pb[" << i << "](av,3): " << pb[i](av, 3) << endl; 34 cout << "pb第二种方法显示值:" << "*pb[" << i << "](av, 3): " << *pb[i](av, 3)<< endl; 35 } 36 system("pause"); 37 return 0; 38 } 39 40 const double* f1(const double ar[], int n) 41 { 42 return ar; //返回ar数组中的第一个数的地址 43 } 44 const double* f2(const double ar [], int n) //函数定义的时候必须写上标识符 ar 和 n 45 { 46 return ar+1; //返回ar数组中的第二个数的地址 47 } 48 const double* f3(const double* ar, int n) //函数定义的时候必须写上标识符 ar 和 n 49 { 50 return ar+2; //返回ar数组中的第三个数的地址 51 }
执行结果为: