函数何时值传递,何时指针,何时引用传递总结

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了函数何时值传递,何时指针,何时引用传递总结相关的知识,希望对你有一定的参考价值。

编程中定义函数,一般三种传递方法,看是简单。想灵活合理选择,还须要大量的编程经验和技巧。

故在这里特意总结一下这三种传递的方法。

根本差别: 函数值传递不改变变量值,假设想改变变量值,须要返回值,然后用变量接收一下这个返回值。

 而指针传递和引用传递都能够在函数内改变变量值。不须要通过返回值的形式改变。

应用场合: 当想通过这个函数。改变好几个变量的值,多个变量都通过函数返回值来改变变量值方式费时费力。所以这样的场合就比較适合使用指针和引用。

指针传递须要开内存。假设忘记释放的话,可能导致内存泄露。

浪费大量内存。

所以引用传递更好一些。

引用传递的性质象指针传递,书写形式象值传递,

理由:假设仅仅须要借用一下别名,就不是必需用指针,.

void changeVar(int &myVar,int newValue);  // 引用传递

这个函数第一个输入的參数不是一个指针,它是那个将被传递给这个函数的原始变量的一个别名。

changeVar()函数里对这个參数变量进行的不论什么操作都将反映在changeVar()函数外的那个原始变量身上。这意味着changeVar()函数与原来的一样。

void changeVar(int myVar,int newValue){  //值传递。没有返回值,起不到改变变量的作用

  myVar=newValue;

}

这使得这个函数更easy被调用----仅仅须要提供一个变量名;

int main(){

int myNum=20;

changeVar(myNum,90);  // 引用和值传递写法一样, 可见引用传递简单,这也是c++新添加的功能,表现了c++的强大

}

这比值传參语法上更简单了。

引用传递”方式把參数值传递给一个函数是C++的新增功能,这能够让函数的调用语法更加简单清晰。

提示:1.在定义函数时。还能够让它以引用传递方式而不是以值传递方式返回: int &myFuntion();

           2.除了能够改变有关变量的值,引用传递方式的还有一个优点是它的开销相对要小一些:由于不须要在函数里创建暂时变量来容纳那些值。程序的内存占用量当然会小一些。

           3.假设想获得引用传递方式带来的性能改善,但不想改变某个变量的值,能够把对应的输入參数定义为一个常量:

 void myFunc(const int &myNum);

通过这样定义的函数,能够把详细的參数直接传递给它:myFunc(7);


 
int script_orientation(VOID *dic, unsigned char *im, int w, int h,
                               RECT roi, int &script_id,  // NOLINT
                               int &orient_id,  // NOLINT
                               float &conf) {  // NOLINT
函数调用

 
 const char* model_file = "model.txt";
 void* model = CNN_Init(model_file);
cv::Mat image = cv::imread(path, 0);
    int script_id, orient_id;

script_orientation(model, image.data, image.cols, image.rows, roi,
                               script_id, orient_id, confidence);
这里须要script_id, orient_id 两个返回值, 所以这两个定义为应用较好。 调用时就不须要再去定义变量接收 这两个 script_id, orient_id 两个返回值


以下写一个函数,从函数中把我须要的两个值传出来,因为传出来的值比較多,所以不考虑用return来返回。须要通过參数把改动后的值拉出来供我使用,非常当然的就想到了用指针,可是值就是传不出来。使我对原有的大脑中指针的思维产生混沌感。今天一上午才把函数传递又走了一遍。才明确当中道理(道行还是非常浅),如今整理例如以下:

    我之前写的方法部分代码,相信好多人都是这么写的:
    
[cpp] view plain copy
  1. BOOL GetStartEndBoxes(BOOL bRow, const SwCrsrShell& rShell,  SwTableBox *pStt,  SwTableBox *pEnd)  
  2. {  
  3.     SwSelBoxes aBoxes;  
  4.     ... ...  
  5.   
  6.     pStt = aBoxes[0];  
  7.     pEnd = aBoxes[aBoxes.Count() - 1];  
  8.     return TRUE;  
  9. }  
  10. 调用:  
  11.        。。。 。。

    。      SwTableBox *pStt=0;  

  12.       SwTableBox *pEnd=0;  
  13.   
  14.      if ( !GetStartEndBoxes(bRow, *this, pStt, pEnd) )  
  15.     return FALSE;  

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

    概念

   首先从概念上来说一下这几种函数传參方式及差别:
   1、值传递:形參是实參的拷贝,改变函数形參的值并不会影响外部实參的值,这是最经常使用的一种传參方法。也是最简单的一种传參方法,仅仅须要传递參数,返回值那是return考虑的;
   2、指针传递:指针传递參数从本质上来说也是值传递。它传递的是一个地址。【值传递过程中,被调函数的形參作为被调函数的局部变量来处理。即在函数内的栈中开辟内存空间以存放由主调函数放进来的实參的值。从而成了实參的一个副本(记住这个,函数内參数的是实參的副本)】。因为指针传递的是外部实參的地址,当被调函数的形參值发生改变时。自然外部实參值也发生改变。

   3、引用传递:被调函数的形參尽管也作为局部变量在栈中开辟了内存空间,可是栈中存放的是由主调函数放进的实參变量的地址。被调函数对形參的不论什么操作都被处理成间接寻址。即通过栈中存放的地址訪问主调函数中实參变量(实參和形參通过引用,合二为一,说白点就是:一个人,有两个名字那种;后面想会具体说)。因此。形參的不论什么修改都会直接影响到实參。

   实例    

先从简单的样例開始:
  1.  值传递:样例略过。  
  2. 指针传递:
[cpp] view plain copy
  1. void swap(int *a,int *b)  
  2. {  
  3.     int temp;  
  4.     temp=*a;  
  5.     *a=*b;  
  6.     *b=temp;  
  7.     cout<<"a=" <<a<<" ,"<<"b="<<b<<endl;  
  8.     cout<<"*a=" <<*a<<" ,"<<"*b="<<*b<<endl;  
  9.     cout<<"&a=" <<&a<<" ,"<<"&b="<<&b<<endl;  
  10. }  
(刚上大学的时候就接触过的样例,交换值)调用:
[cpp] view plain copy
  1. int main(){  
  2.     int x=1;  
  3.     int y=2;  
  4.     cout<<"x=" <<x<<" ,"<<"y="<<y<<endl;  
  5.     cout<<"&x=" <<&x<<" ,"<<"&y="<<&y<<endl;  
  6.     swap(&x,&y);  
  7. }  
一定要记住这样的调用方式
[cpp] view plain copy
  1. 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
  1. int change(char* name){  
  2.     cout<<"*******CHANGE--BEFORE******"<<endl;  
  3.     cout<<"name=" <<name<<endl;  
  4.     cout<<"*name=" <<&name<<endl;  
  5.     name="alter";  
  6.     cout<<"*******CHANGE--AFTER********"<<endl;  
  7.     cout<<"name=" <<name<<endl;  
  8.     cout<<"*name=" <<&name<<endl;  
  9.     return 1;  
  10. }  
  11. int main()  
  12. {  
  13.     char *str = "this is a test";  
  14.   
  15.     cout<<"******MAIN--BEFORE*****"<<endl;  
  16.     cout<<"str=" <<str<<endl;  
  17.     cout<<"*str=" <<&str<<endl;  
  18.     change(str);  
  19.     cout<<"*****MAIN--AFTER*****"<<endl;  
  20.     cout<<"str=" <<str<<endl;  
  21.     cout<<"*str=" <<&str<<endl;  
  22.     return 1;  
  23. }  
    运行结果:技术分享(打印的输出的时候。有点错误,*str应该为 &str)
    从结果中发现,并未达到改变值得效果。为什么?这个測试代码和本文開始的疑问是一样的,那就进一步分析:
    
    传入值的各变量的初始状态(地址状态):
     技术分享
   运行赋值操作
[cpp] view plain copy
  1. name="alter";  
    系统首先须要给字符串“alter”分配内存空间(地址)。然后指针才指向其地址。
    技术分享   
 所以*str并没有发生变化,因此最后打印出来的仍是“this is a test”,这也解释了我開始时的迷惑!

技术分享

还有一种成功传递參数的指针调用方法----指针的指针:
  
[cpp] view plain copy
  1. void my_malloc(void** p, int size)  
  2. {  
  3.     *p = malloc(sizeof(int)*size);  
  4. }  
  5. int main()  
  6. {  
  7.     int *a;  
  8.     my_malloc(&a , 10);  
  9.     return 1;  
  10. }  
运行结果:技术分享(有些參数没实用,仅仅是为了打印出来看看)
当我们没有运行到给*p分配空间的时候:
技术分享
运行malloc(size) 后的图例如以下
 技术分享
   赋值给*p后:因为p指向&a即a的地址,*p则指向a的地址里的值,如今又要把分配的内存指向*p,所以。a的值即为新分配的内存!(这个比較难转圈技术分享
   
    技术分享
    然后,我们就给指针a 分配内存成功了。

     3、引用传递:
     
[cpp] view plain copy
  1. void swapref(int &a,int &b)  
  2. {  
  3.     cout << "******************before swapref:******************"<<endl;  
  4.     cout<<"a=" <<a<<" ,"<<"b="<<b<<endl;  
  5.     cout<<"&a=" <<&a<<" ,"<<"&b="<<&b<<endl;  
  6.     int temp;  
  7.     temp=a;  
  8.     a=b;  
  9.     b=temp;  
  10.     cout << "******************after swapref:******************"<<endl;  
  11.     cout<<"a=" <<a<<" ,"<<"b="<<b<<endl;  
  12.     cout<<"&a=" <<&a<<" ,"<<"&b="<<&b<<endl;  
  13. }  
  14. int main(){  
  15.     int x=1;  
  16.     int y=2;  
  17.     cout<<"******MAIN--BEFORE*****"<<endl;  
  18.     cout<<"x=" <<x<<" ,"<<"y="<<y<<endl;  
  19.     cout<<"&x=" <<&x<<" ,"<<"&y="<<&y<<endl;  
  20.     //swap(&x,&y);  
  21.     swapref(x, y);  
  22.     cout<<"*****MAIN--AFTER*****"<<endl;  
  23.     cout<<"x=" <<x<<" ,"<<"y="<<y<<endl;  
  24.     cout<<"&x=" <<&x<<" ,"<<"&y="<<&y<<endl;  
  25. }  
一定要记住这样的调用方式
[cpp] view plain copy
  1. swapref(x, y);  
形如:int &a=x; //用于引用传递,能够理解为a就是x,x就是a,仅仅只是名字不一样
运行结果:技术分享
    这个详细就不分析了,记住引用传递实參和形參是一样的,仅仅是名字不同而已。


总结:
       本文重点还是在參数传指针方面,指针确实令人头疼。今天遇到了。会出错,弄明确以后,等过段时间,又忘了。又遇到错误。再来看,这样不断重复,希望能不断的提升。对指针的认识不断的加深!
















以上是关于函数何时值传递,何时指针,何时引用传递总结的主要内容,如果未能解决你的问题,请参考以下文章

PHP 中的数组是作为值复制还是作为对新变量的引用,以及何时传递给函数?

在c / c ++中何时通过引用传递以及何时通过值传递[重复]

python如何决定何时按值传递参数以及何时按引用传递参数? [复制]

何时重载按引用传递(左值和右值)优于按值传递?

何时在 PHP 中通过引用传递

何时使用缺失值与 NULL 值在 R 中传递未定义的函数参数,为啥?