目录
2. C++函数的传入参数是指针的指针(**指向地址的地址)的详解
1.C++ 值传递、指针传递、引用传递详解
#include<iostream>
using namespace std;
//值传递
void change1(int n){
cout<<"值传递--函数操作地址"<<&n<<endl; //显示的是拷贝的地址而不是源地址
n++;
}
//引用传递
void change2(int & n){
cout<<"引用传递--函数操作地址"<<&n<<endl;
n++;
}
//指针传递
void change3(int *n){
cout<<"指针传递--函数操作地址 "<<n<<endl;
*n=*n+1;
}
int main(){
int n=10;
cout<<"实参的地址"<<&n<<endl;
change1(n);
cout<<"after change1() n="<<n<<endl;
change2(n);
cout<<"after change2() n="<<n<<endl;
change3(&n); // 传入的是变量的地址
cout<<"after change3() n="<<n<<endl;
return true;
}
值传递:
形参是实参的拷贝,改变形参的值并不会影响外部实参的值。从被调用函数的角度来说,值传递是单向的(实参->形参),参数的值只能传入,不能传出。当函数内部需要修改参数,并且不希望这个改变影响调用者时,采用值传递。
指针传递:【传入变量的地址,修改地址的指向,几个*都是这个道理】
形参为指向实参地址的指针,我们改变的是指针指向的变量[也就是实参地址指向的变量],而指向实参的地址没有变,这样指针才能传递出来。
//指针传递
void change3(int *n){ // 这里形参变量是整型指针int* 变量n(实参应该传入地址)!!
cout<<"指针传递--函数操作地址 "<<n<<endl;
*n=*n+1; // 形参变量指针地址没有变,变得是指向的变量。
}
int main(){
int n=10;
// 在实参传入后,从系统栈中开辟内存,存入地址变量&n
change3(&n); // 实参 传入的是变量的地址!!
}
本质上是值传递的方式,它所传递的是一个地址值。值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,即在栈中开辟了内存空间以存放由主调函数放进来的实参的值,相当于复制了实参的一个副本。
引用传递:
形参相当于是实参的“别名”,对形参的操作其实就是对实参的操作,在引用传递过程中,形参作为局部变量在栈中也开辟了内存空间,存放实参变量的地址。
指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名。
// 如果需要函数的参数具有返回值的能力,往往是通过指针来实现的。
// 两整数变量值交换的c程序如下:
void swapint(int *a,int *b)
{
int temp;
temp=*a;
a=*b;
*b=temp;
}
// 使用引用机制后,以上程序的c++版本为:
void swapint(int &a,int &b)
{
int temp;
temp=a;
a=b;
b=temp;
}
// 调用该函数的c++方法为:swapint(x,y); c++自动把x,y的地址作为参数传递给swapint函数。
2. C++函数的传入参数是指针的指针(**指向地址的地址)的详解
如果想通过指针参数传递来改变主调函数中的相关变量,那就得使用指向指针的指针,或者指针引用。
比如,在链表中如果涉及到头结点的变化,那么是需要**,因为这里需要修改的是地址的值。
要修改变量的值,需要使用变量类型的指针作为参数或者变量的引用。如果变量是一般类型的变量,例如int,则需要使用int 类型的指针类型int *作为参数或者int的引用类型int&。
但是如果传入的参数的变量类型是指针类型,例如char*,那么需要使用该类型的指针,即指向指针的指针类型 char* *,或者该类型的引用类型char* &。
首先要清楚 :不管是传入的参数是指针还是值,都会创建一个副本,修改的是这个副本,而传入的值并没被修改。而指针之所以能传出来是因为:我们修改的是副本指针指向的内容而不是指针指向的地址。
在我们进行内存管理的时候,如果想创建一个分配空间的函数,函数中调用了malloc方法申请一块内存区域。
先将一个错误的例子,如下:
void GetMemory1(char *p,int num)
{// 直接对地址变量进行了操作,所以错误!!
p=malloc(sizeof(int)*num);//在被调函数中应该是对其指向的变量进行操作,这里直接对地址进行了操作
// 这里不能直接改成*p = 因为malloc本身返回的就是一个地址,不是变量
}
return;
}
void Test1()
{
char *p=NULL;
//在被调函数中应该是对其指向的变量进行操作
GetMemory(p);// p是地址 进入之后 创建一个 副本地址_p,_p指针和p指针的联系
// 他们指向 同一个内存区域,但是malloc的函数使得_p指向了另外一个内存区域,
// 而这个内存区域并没有座位传出参数传给p,所以p并没有发生任何改变,仍然为NULL。
}
如何才能解决上述问题呢?
void GetMemory2(char **p,int num)// **表示通过指针地址内部传递改变
{
* p=malloc(sizeof(int)*num);//
return;
}
void Test2()
// 最终目的是p指向分配的给的内存地址的start!!
{
char *p=NULL; //本身变量就是地址
GetMemory(&p);// 传入地址p的地址&p,修改地址&p的指向地址p。
}
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内存地址的参数,
于是我们创建了一个char *的指针*p(注意这里不是char *的指针p),这个p作为传入参数,在进入函数后,系统会为该指针创建一个副本_p,我们让*_p指向malloc分配的内存的地址(注意这里是*_p而不是_p),_p作为指向这个分配的内存地址指针的指针,这样在分配过程中_p并没有变化。
转载:https://blog.csdn.net/e01528/article/details/86706700