C++ 二级指针的理解

来源:互联网 发布:软件项目管理方法 编辑:程序博客网 时间:2024/06/09 18:04

二级指针是指向指针的指针。
首先我们先来看一段代码

#include "stdafx.h"#include <iostream>using namespace std;int main(){    int i=3;    int ** p = (int**)&i;     //定义一个二级指针p,指向i    int *q = &i;    cout<<"hello"<<endl;    cout<<"*p = "<<(int)*p<<endl<<"&i = "<<&i<<endl;    cout << "*q = " << *q << endl;    cout << (int*)i << endl;    //cout << **p << endl;      return 0;} 

在上面代码中,

int ** p = (int**)&i;

要说明一点就是,这里的指针p和&i的关系,实际上是p始终指向i,不管前面定义了多少个*比如int***p = (int***)&i,指向i的还是p,*p等于i)也就是说,定义的* 只是返回类型。

而*p等于i,如果尝试这么做

cout << **p << endl;

这里就是将i的值当成 指针,然后去寻找这个值所指向的那个地方,其实是很危险的,因为我们知道*p指向内存的哪里,所以最好不要尝试这么做。

再来说一个例子,关于定义一个指向函数指针的指针的二级指针。
我们通常通过 typedef 关键字来帮助我们实现指向函数指针的指针。比如通过以下的方法:

typedef int func(int);typedef func* func_ptr;typedef func_ptr* func_ptr_ptr;func_ptr_ptr p;

这个方法很实用,但是现在,我们需要从二级指针的角度出发,来帮助我们完成这个定义。
首先我们来看一下最初的定义:

int a;

这定义了一个整型。

int *p;

这定义了一个指向整数的指针。那么这个指针怎么变成整数呢?很简单,只需要 *p 就可以了。我们惊奇的发现,定义时和使用时的形式是一模一样的。这不是个巧合,是语言设计者有意为之的。

int *p 的意思就是让 *p 为整形。那么 p 自然是指向整数的指针了。
再来看一个的例子。

int (*p)(int);

这个p是什么我们不知道,但我们知道 (*p)(int) 是个整数,所以, *p 是个 返回整数的函数。而p就是指向这种函数的指针啦。那么如何定义函数指针的指针呢?简单点说,就是加个 * 就行了。假如不幸的是,我们一开始加错了地方,变成了:

int *(*p)(int);

我们来用我们的脑袋检验一下(你需要熟悉运算符优先级(这里又有一个口诀:小括号的运算级最高)): *(*p)(int) 是个整数,所以 (*p)(int) 是个整数的指针。 所以 *p 是个函数,返回一个整数指针,所以p是个函数指针。
那么我们,将*挪一下地方。
int (**p)(int);
再来检验一下:(**p)(int)是个整数。 **p 是个函数,返回一个整数。于是 *p 是个函数的指针。 p 是个函数指针的指针。
有的时候,有的人会直接这样定义函数的指针的指针:

int **p(int);

他还振振有词:这很显然呀。我们来看看他错在哪里:小括号的优先级最高,当你写下这个语句的时候: **p(int)实际上是先执行 p(int) 的,所以,这个定义就是 **p(int) 是个整数,所以 *p(int) 就是整数的指针,而p(int) 就是指针的指针,所以p就是函数的指针(实际上最后一步是个语法糖。不过我们这里就不追究啦)

当然也可以这样理解,从变量名开始,顺时针螺旋阅读类型。

int(*((*ptr(int,int))))(int);

先从ptr 是……开始:

从ptr开始,向右阅读,遇到(int,int),说明ptr是一个函数,接受参数(int,int)。

ptr 是 一个函数 接受(int,int) 返回……

然后转到左边,遇到*,代表ptr的返回值是个指针。

ptr 是 一个函数 接受(int,int) 返回 一个指针,指向……

目前的情况大概是:

int(*((ptr)))(int);

去掉两对括号后:

int(*ptr)(int);

右边遇到),再到左边,遇到了*,代表这又是个指针。现在我们有:

ptr 是 一个函数 接受(int,int) 返回 一个指针,指向 一个指针 指向……

再向右,遇到(int),代表接下来是一个函数。现在有:

ptr 是 一个函数 接受(int,int) 返回 一个指针,指向 一个指针 指向 一个函数 接受(int) 返回……

再转一圈,遇到最后的int。完整的ptr的类型是:

ptr 是 一个函数 接受(int,int) 返回 一个指针,指向 一个指针 指向 一个函数 接受(int) 返回int或者可以换一个语序:

ptr 是 一个接受(int,int)返回(一个指向(一个指向(一个接受(int)返回int的函数)的指针)的指针)的函数。

构造一段代码来测试一下这个结果:

int foo(int){return 0;} //一个接受(int)返回int的函数decltype(&foo) address_of_foo=&foo; //一个指向(一个接受(int)返回int的函数)的指针int(*((*ptr(int,int))))(int) { //一个接受(int,int) 返回(一个指向(一个指向(一个接受(int)返回int的函数)的指针)的指针)的函数    return &address_of_foo; //一个指向(一个指向(一个接受(int)返回int的函数)的指针)的指针}

那么怎么才能把这个转换成一般人能读懂的代码呢,其实加一个alias就可以大大增强可读性:
using FuncType = int(int);
FuncType** ptr2(int,int);
简单易懂。

int(*p)(int) //p是一个指针,接收一个int,返回一个整型int* p(int)    //p是一个函数,接收一个int,返回一个指针,指向int(返回int型指针)

其中部分内容来源于https://www.zhihu.com/question/38955439/answer/79101717
作者:王霄池
来源:知乎

https://www.zhihu.com/question/65116993/answer/227939489
作者:Harry Nu
来源:知乎

原创粉丝点击