C++ 解疑(**与引用)

目录

 

1.C++ 值传递、指针传递、引用传递详解

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并没有变化。

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值