C++ 二级指针、函数指针与数组复合类型的问题分析
程序员文章站
2022-07-07 11:38:28
...
简介
这是今年笔试时遇到的一道问答题,笔试过后查了好久的资料并经过@Wuhanstudio 大神的帮助才弄懂。。
问题
以下几个 a 的含义分别是什么?
int main(){
float (**a)[10]; // 1
double (*a)[10]; // 2
double (*a[10])(); // 3
long (*a)(int); // 4
int (*(*a)(int, int))(int); // 5
}
答案
- a 是一个二级指针。它指向
float[10] *
的一级指针对象。float[10]*
这个一级指针对象,指向一个float[10]
数组。 - a 是一个指向 ”有 10 个 double 元素的数组” 的指针
- a 是数组名。数组有10个元素,每个元素的类型是函数指针,double (*pf)(),返回类型 double,无参数。
- a 是函数指针。这个函数的参数是一个 int,返回值是 long
- a 是函数指针。指向的函数参数列表是两个 int,返回值是一个函数指针(参数int,返回int)。分析:从内向外看,a 是指针。因为有参数,所以是函数指针。再往外看,返回值是指针,这个指针带参数,所以返回的是函数指针。等价写法:auto
解析
问题 1
子问题
理解这个式子要先理解两个子问题:
- 对于
*ptr[0] = 0;
,问:* 与 [] 的结合次序?答:因为 [] 的优先级更高,所以结合次序是:*(ptr[0]) = 0
。 -
int (*ptr)[10];
和int *ptr[10];
中,ptr 分别代表什么?答案是:第一个式子中,ptr 是一个指向 ”有 10 个元素的数组” 的指针;第二个式子中,ptr 是一个有 10 个元素的数组的名字,是一个数组名。
针对 2 号子问题示例(这实际上是问题 2 的解答):
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
int (*ptr)[10] = nullptr; // a pointer to an array of 10 ints.
//ptr[0] = 1; // Array is not assignable
// *ptr[0] = 5; // 指针为随机值,不可使用
//
// cout << *ptr[0] << endl;
// exit code 11
// Under Linux and most other Unix variants, the signal number 11 indicates a segmentation fault, as remarked by Kerrek SB.
int array[10];
ptr = &array;
*ptr[0] = 5;
cout << *ptr[0] << endl; // 5
int *ptr2[10]; // an array of 10 pointers.
ptr2[0] = &*ptr[0];
cout << ptr2[0] << endl; // 地址值
cout << *ptr2[0] << endl; // 5
cout << *(ptr2[0]) << endl; // 5 上一条语句的等价表达
cout << *ptr2 << endl; // 对于一维数组 ptr2 = *ptr2,与 ptr2[0] 的地址相同
cout << (*ptr2)[0] << endl; // 所以依旧是 5
// cout << (**ptr2)[0] << endl;
return 0;
}
问题本身
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
float (**a)[10];
// 错误:可能的理解 1: a 是一级指针。a 是指向一个有 10 个 float 一级指针数组的首元素
// 错误:可能的理解 2: a 是数组名。a 是 10 个 float 二级指针的首元素
// 正确理解:a 是一个二级指针。它指向 float[10] * 的一级指针对象。
// float[10]* 这个一级指针对象,指向一个 float[10] 数组。
float num[10] = {5.0, 6.0};
float (*ptr)[10] = # // ptr 是指向 num 数组的一级指针
a = &ptr; // a 是指向 ptr 的指针,也就是二级指针
cout << **a[0] << endl; // 5
cout << (**a)[0] << endl; // 5
cout << **(a[0]) << endl; // 5
cout << **a[1] << endl; // 3.02777e+14
cout << (**a)[1] << endl; // 6 注:正确的使用方法,解引用两次再下标运算
cout << **(a[1]) << endl; // 3.02777e+14
return 0;
}
问题 3
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void PrintType(const char *str){
string type_name(str);
string command = "echo " + type_name + "| c++filt";
system(command.c_str());
}
double func1() {
cout << "Hello from func1" << endl;
}
int main()
{
double (*a[10])(); // a 是数组名。数组有10个元素,每个元素的类型是函数指针,double (*pf)(),返回类型 double,无参数。
cout << typeid(a).name() << endl; // A10_PFdvE
PrintType(typeid(a).name()); // double (* [10])()
a[0] = func1;
a[0]();
return 0;
}
问题 4
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
long func1(int a) {
cout << "Hello from func1, param: " << a << endl;
}
int main()
{
long (*a)(int);
a = func1;
a(5); // Hello from func1, param: 5
return 0;
}
问题 5
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
using PF = int(*)(int);
//typedef int (*PF)(int);
PF func1(int a, int b) {
cout << "Hello from func1, param: " << endl;
cout << "a: " << a << endl;
cout << "b: " << b << endl;
}
typedef decltype(func1) *PF2;
void CallFunction(PF2 f){
f(7, 8);
}
int main()
{
int (*(*a)(int, int))(int);
a = func1;
a(5, 6);
CallFunction(a);
return 0;
}
// question 5 @Wuhanstudio(http://wuhanstudio.cc) 提供的示例
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// for simplicity
typedef int (*myfunction)(int);
// function which "a" points to
// (*(*a)(int,int))(int);
myfunction select(int a,int b);
int debug(int c);
int release(int c);
int main()
{
// "a" is exactly what's in question 5
int (*(*a)(int,int))(int);
a = select;
string type_name = typeid(a).name();
cout << type_name << endl;
string command = "echo " + type_name + "| c++filt";
system(command.c_str());
// "b" is what "a" returns, which depends on two params for "a"
// if a(0,0) --> debug
// if a(1,1) --> release
int (*b)(int);
printf("\n");
// If a(0,0), then return "b" (debug)
printf("-- Let's try (0+0=0) then debug --\n");
b = (*a)(0,0);
int ret = (*b)(666);
printf("[Return Value %d]\n",ret);
printf("\n");
// If a(1,1), then return "b" (release)
printf("-- Let's try (1+1=2) then release --\n");
b = (*a)(1,1);
ret = (*b)(666);
printf("[Return Value %d]\n",ret);
return 0;
}
myfunction select(int a,int b)
{
if((a+b)==0)
return &debug;
else
return &release;
}
int debug(int c)
{
printf("Debug: %d\n",c);
return 0;
}
int release(int c)
{
printf("Release: %d\n",c);
return 1;
}