您的位置:首页 > 编程语言 > C语言/C++

c++中函数参数传递(值传递、指针传递,引用传递)

2017-05-20 10:09 796 查看
C++中传递参数的时候,每次都会翻书再看一遍这三种传递方式。 -  -

从另一位博主那里转的这篇文章,因为基本上解决了我的全部问题,有很多测试代码,而且讲的很容易明白。@一下这位博主richerg85

[cpp] view
plain copy

BOOL GetStartEndBoxes(BOOL bRow, const SwCrsrShell& rShell,  SwTableBox *pStt,  SwTableBox *pEnd)  

{  

    SwSelBoxes aBoxes;  

    ... ...  

  

    pStt = aBoxes[0];  

    pEnd = aBoxes[aBoxes.Count() - 1];  

    return TRUE;  

}  

调用:  

       。。。 。。。      SwTableBox *pStt=0;  

      SwTableBox *pEnd=0;  

  

     if ( !GetStartEndBoxes(bRow, *this, pStt, pEnd) )  

    return FALSE;  

    传递一个指针到调用函数,希望获得更新后的值(pStt, pEnd),为什么没有获得到呢?


    概念

   首先从概念上来说一下这几种函数传参方式及区别:
   1、值传递:形参是实参的拷贝,改变函数形参的值并不会影响外部实参的值,这是最常用的一种传参方法,也是最简单的一种传参方法,只需要传递参数,返回值那是return考虑的;
   2、指针传递:指针传递参数从本质上来说也是值传递,它传递的是一个地址。【值传递过程中,被调函数的形参作为被调函数的局部变量来处理,即在函数内的栈中开辟内存空间以存放由主调函数放进来的实参的值,从而成了实参的一个副本(记住这个,函数内参数的是实参的副本)】。由于指针传递的是外部实参的地址,当被调函数的形参值发生改变时,自然外部实参值也发生改变。
   3、引用传递:被调函数的形参虽然也作为局部变量在栈中开辟了内存空间,但是栈中存放的是由主调函数放进的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中实参变量(实参和形参通过引用,合二为一,说白点就是:一个人,有两个名字那种;后面想会详细说)。因此,形参的任何改动都会直接影响到实参。



 实例    

先从简单的例子开始:
 值传递:例子略过。  
指针传递:

[cpp] view
plain copy

void swap(int *a,int *b)  

{  

    int temp;  

    temp=*a;  

    *a=*b;  

    *b=temp;  

    cout<<"a=" <<a<<" ,"<<"b="<<b<<endl;  

    cout<<"*a=" <<*a<<" ,"<<"*b="<<*b<<endl;  

    cout<<"&a=" <<&a<<" ,"<<"&b="<<&b<<endl;  

}  

(刚上大学的时候就接触过的例子,交换值)调用:

[cpp] view
plain copy

int main(){  

    int x=1;  

    int y=2;  

    cout<<"x=" <<x<<" ,"<<"y="<<y<<endl;  

    cout<<"&x=" <<&x<<" ,"<<"&y="<<&y<<endl;  

    swap(&x,&y);  

}  

一定要记住这种调用方式

[cpp] view
plain copy

swap(&x,&y);  

如指针传递的概念上所述,传地址给形参。
形如:int *a = &x;//用于指针传递,a有自己独立的内存地址,存储的内容是x的地址,*a是存x的值。
输出结果:


传入值的各变量的初始状态(地址状态):
               


从上图关系可以知道:a(b)是一个指向外部实参地址的指针,*a(*b)是指针的内容,如果改变了*a(*b)也必然导致外部实参的改变。

交换后:
       *a=2,*b=1;
       


       
这样的结果是由于a或者b指针指向x或者y的地址的缘故,因此由于*a,*b值得交换导致外部实参发生变化。

 
        思考一下,下面的操作能否实现值得变化?
        简单测试代码:
       

[cpp] view
plain copy

int change(char* name){  

    cout<<"*******CHANGE--BEFORE******"<<endl;  

    cout<<"name=" <<name<<endl;  

    cout<<"*name=" <<&name<<endl;  

    name="alter";  

    cout<<"*******CHANGE--AFTER********"<<endl;  

    cout<<"name=" <<name<<endl;  

    cout<<"*name=" <<&name<<endl;  

    return 1;  

}  

int main()  

{  

    char *str = "this is a test";  

  

    cout<<"******MAIN--BEFORE*****"<<endl;  

    cout<<"str=" <<str<<endl;  

    cout<<"*str=" <<&str<<endl;  

    change(str);  

    cout<<"*****MAIN--AFTER*****"<<endl;  

    cout<<"str=" <<str<<endl;  

    cout<<"*str=" <<&str<<endl;  

    return 1;  

}  

    执行结果:

(打印的输出的时候,有点错误,*str应该为
&str)
    从结果中发现,并未达到改变值得效果,为什么?这个测试代码和本文开始的疑问是一样的,那就进一步分析:
    
    传入值的各变量的初始状态(地址状态):
     


   执行赋值操作

[cpp] view
plain copy

name="alter";  

    系统首先需要给字符串“alter”分配内存空间(地址),然后指针才指向其地址。
    

 
 

 所以*str并没有发生变化,因此最后打印出来的仍是“this is a test”,这也解释了我开始时的迷惑!


另一种成功传递参数的指针调用方法----指针的指针:
  

[cpp] view
plain copy

void my_malloc(void** p, int size)  

{  

    *p = malloc(sizeof(int)*size);  

}  

int main()  

{  

    int *a;  

    my_malloc(&a , 10);  

    return 1;  

}  

执行结果:

(有些参数没有用,只是为了打印出来看看)
当我们没有执行到给*p分配空间的时候:



执行malloc(size) 后的图如下:

 


   赋值给*p后:由于p指向&a即a的地址,*p则指向a的地址里的值,现在又要把分配的内存指向*p,所以,a的值即为新分配的内存!(这个比较难转圈)
   
    


    然后,我们就给指针a 分配内存成功了。
     3、引用传递:
     

[cpp] view
plain copy

void swapref(int &a,int &b)  

{  

    cout << "******************before swapref:******************"<<endl;  

    cout<<"a=" <<a<<" ,"<<"b="<<b<<endl;  

    cout<<"&a=" <<&a<<" ,"<<"&b="<<&b<<endl;  

    int temp;  

    temp=a;  

    a=b;  

    b=temp;  

    cout << "******************after swapref:******************"<<endl;  

    cout<<"a=" <<a<<" ,"<<"b="<<b<<endl;  

    cout<<"&a=" <<&a<<" ,"<<"&b="<<&b<<endl;  

}  

int main(){  

    int x=1;  

    int y=2;  

    cout<<"******MAIN--BEFORE*****"<<endl;  

    cout<<"x=" <<x<<" ,"<<"y="<<y<<endl;  

    cout<<"&x=" <<&x<<" ,"<<"&y="<<&y<<endl;  

    //swap(&x,&y);  

    swapref(x, y);  

    cout<<"*****MAIN--AFTER*****"<<endl;  

    cout<<"x=" <<x<<" ,"<<"y="<<y<<endl;  

    cout<<"&x=" <<&x<<" ,"<<"&y="<<&y<<endl;  

}  

一定要记住这种调用方式

[cpp] view
plain copy

swapref(x, y);  

形如:int &a=x; //用于引用传递,可以理解为a就是x,x就是a,只不过名字不一样
执行结果:


    这个具体就不分析了,记住引用传递实参和形参是一样的,只是名字不同而已。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐