C++ 二级指针、函数指针与数组复合类型的问题分析

简介

这是今年笔试时遇到的一道问答题,笔试过后查了好久的资料并经过@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

}

答案

  1. a 是一个二级指针。它指向 float[10] * 的一级指针对象。 float[10]* 这个一级指针对象,指向一个 float[10] 数组。
  2. a 是一个指向 ”有 10 个 double 元素的数组” 的指针
  3. a 是数组名。数组有10个元素,每个元素的类型是函数指针,double (*pf)(),返回类型 double,无参数。
  4. a 是函数指针。这个函数的参数是一个 int,返回值是 long
  5. a 是函数指针。指向的函数参数列表是两个 int,返回值是一个函数指针(参数int,返回int)。分析:从内向外看,a 是指针。因为有参数,所以是函数指针。再往外看,返回值是指针,这个指针带参数,所以返回的是函数指针。等价写法:auto

解析

问题 1

子问题

理解这个式子要先理解两个子问题:

  1. 对于*ptr[0] = 0;,问:* 与 [] 的结合次序?答:因为 [] 的优先级更高,所以结合次序是:*(ptr[0]) = 0
  2. 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] = &num; // 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;
}

猜你喜欢

转载自blog.csdn.net/u013614126/article/details/77803950