欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

}

答案

  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;
}
相关标签: c++