要修改变量的值,需要使用变量类型的指针作为参数或者变量的引用。如果变量是一般类型的变量,例如int,则需要使用int 类型的指针类型int *作为参数或者int的引用类型int&。但是如果变量类型是指针类型,例如char*,那么需要使用该类型的指针,即指向指针的指针类型 char* *,或者该类型的引用类型char*&。

首先要清楚  不管是指针还是值传入函数后都会创建一个副本,函数结束后值内容不能传出来是因为值的副本,而传入的值并没被修改,指针能传出来是因为我们修改的是指针指向的内容而不是指针指向的地址。

我们既然要举例子 就找一个比较经典的实用例子。

在我们进行内存管理的时候,如果想创建一个分配空间的函数,函数中调用了malloc方法申请一块内存区域。

先将一个错误的例子,如下:

void GetMemory1(char *p,int num)

{
    p=malloc(sizeof(int)*num);

return;

}

void Test1()

{

char *p=NULL;

GetMemory(p);

}

上述例子 是很普通的 将一个指针作为参数来申请一个动态内存空间,可是这个程序是错误的。

错误的原因:

由于其中的*p实际上是Test1中p的一个副本,编译器总是要为函数的每个参数制作临时副本。在本例中,p申请了新的内存,只是把p所指向的内存地址改变了,但是Test1中p丝毫未变。因为函数GetMemory1没有返回值,因此Test1中p并不指向申请的那段内存。

因为malloc的工作机制是在堆中寻找一块可用内存区,返回指向被分配内存的指针。

所以这时p指向了这个申请的内存的地址。由于在指针作为传入参数的时候会在函数体中创建一个副本指针_p

_p指针和p指针的联系就是他们指向同一个内存区域,但是malloc的函数使得_p指向了另外一个内存区域,而这个内存区域并没有座位传出参数传给p,

所以p并没有发生任何改变,仍然为NULL。

如何才能解决上述问题呢?

使用下述办法可以解决问题:

void GetMemory2(char **p,int num)

{
   * p=malloc(sizeof(int)*num);

return;

}

void Test2()

{

char *p=NULL;

GetMemory(&p);

}

下面开始分析GetMemory2()和 Test2()的原理:

char **p 可以进行拆分(从左向右拆分)  char*    *p  ,所以可以认为*p是一个char *的指针(注意这里不是p而是*p)。那么p的内容就是一个指向char*的指针的地址,换句话来说p是指向这个char*指针的指针。

从test2可以看出 p是一个char*的指针, &p则是这个char*指针的地址,换句话来说 &p是指向这个char*p的指针的指针,与GetMemory2()定义相符。所以在调用时候要使用&p而不是p。

在GetMemory2()中  *p=malloc(sizeof(int)*num);

其中*p保存了 这个分配的内存的地址,那么p就是指向这个分配的内存地址的指针。

其实在为什么要用指针的指针的道理很简单:

因为VC内部机制是将函数的传入参数都做一个副本,如果我们传入的用来获取malloc分配内存地址的副本变化了,而我们的参数并不会同步,除非使用函数返回值的方式才能传出去。

所以我们就要找一个不变的可以并能用来获取malloc内存地址的参数,

如果能够创建另外一个指针A,这个指针指向GetMemory1(char * p,int ...)中的传入参数指针p,那么 就算*p的内容变了,而p的地址没变,我们仍然可以通过这个指针A来对应得到p的地址并获得*p所指向的分配的内存地址,没错这个指针A就是本文想要讲的指向(char *)指针的指针(char **)。

于是我们创建了一个char *的指针*p(注意这里不是char *的指针p),这个p作为传入参数,在进入函数后,系统会为该指针创建一个副本_p,我们让*_p指向malloc分配的内存的地址(注意这里是*_p而不是_p),_p作为指向这个分配的内存地址指针的指针,这样在分配过程中_p并没有变化。

另外注意在void Test2()中的char *p 的p是指向的是malloc分配的内存的地址,通过GetMemory2()函数后&p作为传入参数没有变化被返回回来,依据&p将p指针指向了真正分配的内存空间。

最后还要注意一个要点,void Test2()中 GetMemory(&p);和void GetMemory2(char **p,int num)这个函数的定义,很容易有一个迷惑,在使用处的变量和定义处的变量是如何一一对应的。

下面来做解释:

不对应关系:其实这两个p不是一个p,&p中的p是一个char *的指针,而char**p中的p却是指向char *指针的指针。

对应关系:其实这个对应关系就是 在void Test2()调用的时候传入参数&p是指向char *指针的指针,GetMemory2()定义中的char **p也是指向char*指针的指针,所以说 在调用时候传入的参数和在定义时候使用的传入参数必须是匹配的。

如果看了上面的文字还是比较混乱的话就用一句话来总结下重点:

1,VC的函数机制传入的参数都是会创建一个副本 不管是指针还是值;如果是值A则直接创建另外一个值B,值B拥有和A相同的值;如果是传入参指针C创建另外一个指针的副本D,那么D所指向的地址是和C相同的地址。

2,第1条总结可知指针传参比值传参的多出的功能是可以通过修改指针D所指向的地址的内容来讲函数的运算结果告知指针C,因为C和D指向相同的地址。

3,第2跳总结的指针C和D所共用的指向地址可以是值类型,也可以是另外一个指针的地址(也就是上面所讲的**)。

首先要清楚 不管是指针还是值传入函数后都会创建一个副本,函数结束后值内容不能传出来是因为值的副本,而传入的值并没被修改,指针能传出来是因为我们修改的是指针指向的内容而不是指针指向的地址。

我们既然要举例子 就找一个比较经典的实用例子。

在我们进行内存管理的时候,如果想创建一个分配空间的函数,函数中调用了malloc方法申请一块内存区域。

先将一个错误的例子,如下:

void GetMemory1(char *p,int num)

{
p=malloc(sizeof(int)*num);

return;

}

void Test1()

{

char *p=NULL;

GetMemory(p);

}

上述例子 是很普通的 将一个指针作为参数来申请一个动态内存空间,可是这个程序是错误的。

因为malloc的工作机制是在堆中寻找一块可用内存区,返回指向被分配内存的指针。

所以这时p指向了这个申请的内存的地址。由于在指针作为传入参数的时候会在函数体中创建一个副本指针_p

_p指针和p指针的联系就是他们指向同一个内存区域,但是malloc的函数使得_p指向了另外一个内存区域,而这个内存区域并没有座位传出参数传给p,

所以p并没有发生任何改变,仍然为NULL。

如何才能解决上述问题呢?

使用下述办法可以解决问题:

void GetMemory2(char **p,int num)

{
* p=malloc(sizeof(int)*num);

return;

}

void Test2()

{

char *p=NULL;

GetMemory(&p);

}

下面开始分析GetMemory2()和 Test2()的原理:

char **p 可以进行拆分(从左向右拆分) char* *p ,所以可以认为*p是一个char *的指针(注意这里不是p而是*p)。那么p的内容就是一个指向char*的指针的地址,换句话来说p是指向这个char*指针的指针。

从test2可以看出 p是一个char*的指针, &p则是这个char*指针的地址,换句话来说 &p是指向这个char*p的指针的指针,与GetMemory2()定义相符。所以在调用时候要使用&p而不是p。

在GetMemory2()中 *p=malloc(sizeof(int)*num);

其中*p保存了 这个分配的内存的地址,那么p就是指向这个分配的内存地址的指针。

其实在为什么要用指针的指针的道理很简单:

因为VC内部机制是将函数的传入参数都做一个副本,如果我们传入的用来获取malloc分配内存地址的副本变化了,而我们的参数并不会同步,除非使用函数返回值的方式才能传出去。

所以我们就要找一个不变的可以并能用来获取malloc内存地址的参数,

如果能够创建另外一个指针A,这个指针指向GetMemory1(char * p,int ...)中的传入参数指针p,那么 就算*p的内容变了,而p的地址没变,我们仍然可以通过这个指针A来对应得到p的地址并获得*p所指向的分配的内存地址,没错这个指针A就是本文想要讲的指向(char *)指针的指针(char **)。

于是我们创建了一个char *的指针*p(注意这里不是char *的指针p),这个p作为传入参数,在进入函数后,系统会为该指针创建一个副本_p,我们让*_p指向malloc分配的内存的地址(注意这里是*_p而不是_p),_p作为指向这个分配的内存地址指针的指针,这样在分配过程中_p并没有变化。

另外注意在void Test2()中的char *p 的p是指向的是malloc分配的内存的地址,通过GetMemory2()函数后&p作为传入参数没有变化被返回回来,依据&p将p指针指向了真正分配的内存空间。

最后还要注意一个要点,void Test2()中 GetMemory(&p);和void GetMemory2(char **p,int num)这个函数的定义,很容易有一个迷惑,在使用处的变量和定义处的变量是如何一一对应的。

下面来做解释:

不对应关系:其实这两个p不是一个p,&p中的p是一个char *的指针,而char**p中的p却是指向char *指针的指针。

对应关系:其实这个对应关系就是 在void Test2()调用的时候传入参数&p是指向char *指针的指针,GetMemory2()定义中的char **p也是指向char*指针的指针,所以说 在调用时候传入的参数和在定义时候使用的传入参数必须是匹配的。

C++函数的传入参数是指针的指针(**)的详解相关推荐

  1. mysql存储过程或函数中传入参数与表字段名相同引发的悲剧

    真实案例.如下的一个存储过程: create procedure Apple(in user_id int) begin delete from users where user_id = user_ ...

  2. MATLAB 将 n 美分转换成 25、10、5 和 1 美分的硬币总共有多少种转换方法?编写一个函数,传入参数 n,输出转换的种类

    将 n 美分转换成 25.10.5 和 1 美分的硬币总共有多少种转换方法?编写一个函数,传入参数 n,输出转换的种类. clc clear n=input('n=');%输入n美分. num=0; ...

  3. 转 常量指针和指针常量的区别详解

    传送门 常量指针和指针常量的区别详解 在C/C++中关键字const用来定义一个只读的变量或者对象,有如下优点     (1)便于类型检查,如函数的函数 fun(const int a) a的值不允许 ...

  4. pandas新字段(数据列)生成、使用np.where或者apply lambda函数结合if else生成新的字段,详解及实战

    pandas新字段(数据列)生成.使用np.where或者apply lambda函数结合if else生成新的字段,详解及实战 pandas apply用法: pandas apply方法的作用原理 ...

  5. C语言中指针与数组的区别,C语言 指针与数组的详解及区别

    C语言 指针与数组的详解及对比 通俗理解数组指针和指针数组 数组指针: eg:int( *arr)[10]; 数组指针通俗理解就是这个数组作为指针,指向某一个变量. 指针数组: eg:int*arr[ ...

  6. WiFi无线网络参数 802.11a/b/g/n 详解

    转载自:WiFi无线网络参数 802.11a/b/g/n 详解 如转载侵犯您的版权,请联系:2378264731@qq.com 802.11a/b/g/n,其实指的是无线网络协议,细分为802.11a ...

  7. torch.randn()参数size与输出张量形状详解

    torch.randn()参数size与输出张量形状详解 torch.randn(*size, *, out=None, dtype=None, layout=torch.strided, devic ...

  8. Linux系统与网络、磁盘参数和日志监控等命令详解二

    创作人QQ:851301776,邮箱:lfr890207@163.com, 欢迎大家一起技术交流,本博客主要是自己学习的心得体会,只为每天进步一点点! 个人座右铭: 1.没有横空出世,只要厚积一定发. ...

  9. python url解码_对python中url参数编码与解码的实例详解

    一.简介 在python中url,对于中文等非ascii码字符,需要进行参数的编码与解码. 二.关键代码 1.url编码 对字符串编码用urllib.parse包下的quote(string, saf ...

最新文章

  1. 使用Python,OpenCV实现简单的场景边界/拍摄转换检测器
  2. Hessian矩阵在XGBoost算法的应用小结
  3. magento2 所需要php 扩展,Magento2如何通过Composer安装插件扩展
  4. mathtype运行时错误48_在office中无法使用MathType该怎么办?
  5. rip协议中周期性广播路由信息的报文_技术实操||距离矢量路由协议-RIP
  6. 安装wps导致 application/kset 上传文件类型报错解决办法
  7. ruby推送示例_Ruby直到示例循环
  8. 一起谈.NET技术,Silverlight 应用整合
  9. datagridview 筛选_【Excel】如何用通配符快速筛选到所需信息
  10. SARIF在应用过程中对深层次需求的实现
  11. 用一道面试题考察对闭包的理解
  12. tidb 企业_TiDB,日均千万级数据存储方案选型
  13. 沪江前端由H5页面引起的一场前端数据结构讨论
  14. 好用的格式化SQL工具SQL Prompt
  15. 通过设置关联菜单建立excel记账本
  16. 三星note3官方固件rom包android4.4.2,三星N9005/Note3最新官方4.4.2系统刷机包官方root版本稳定纯净...
  17. SU插件|TopoShaper生成地形 免费下载及介绍(SketchUp草图大师必备)!
  18. 基于python实现的线性回归基础
  19. Linux条件变量(pthread_cond)示例
  20. Linux如何检测栈溢出,Linux环境下栈溢出实验(一) 改变程序流程

热门文章

  1. python学习-注释、语法、整数、浮点数初步接触
  2. alter在mysql_MySQL中ALTER用法小结
  3. 位域 内存 字节序_C语言中的位域、字节序、比特序、大小端(转)
  4. mysql 开启innodb win版本_MySQL安装与启动——Windows系统下
  5. 码支付如何对接网站_支付宝当面付门店码如何做?
  6. 微型计算机原理课程设计计算器,微机原理课程设计简易计算器的设计.docx
  7. python 二次平滑_时序分析 指数平滑
  8. centos系统php环境配置,CentOS 6.4系统下编译安装LNMP和配置PHP环境具体步骤
  9. HDLBits答案(18)_Verilog有限状态机(5)
  10. 电路常识性概念(1)-输入、输出阻抗