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

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

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

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

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

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

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

浪费大量内存。

所以引用传递更好一些。

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

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

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. pStt = aBoxes[0];
  6. pEnd = aBoxes[aBoxes.Count() - 1];
  7. return TRUE;
  8. }
  9. 调用:
  10. 。。。 。。

    。      SwTableBox *pStt=0;

  11. SwTableBox *pEnd=0;
  12. if ( !GetStartEndBoxes(bRow, *this, pStt, pEnd) )
  13. 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的值。

输出结果:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcmljaGVyZzg1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" style="border:none; max-width:100%">

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

从上图关系能够知道:a(b)是一个指向外部实參地址的指针,*a(*b)是指针的内容,假设改变了*a(*b)也必定导致外部实參的改变。

交换后:

*a=2,*b=1;

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcmljaGVyZzg1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" style="border:none; max-width:100%">

这种结果是因为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. cout<<"******MAIN--BEFORE*****"<<endl;
  15. cout<<"str=" <<str<<endl;
  16. cout<<"*str=" <<&str<<endl;
  17. change(str);
  18. cout<<"*****MAIN--AFTER*****"<<endl;
  19. cout<<"str=" <<str<<endl;
  20. cout<<"*str=" <<&str<<endl;
  21. return 1;
  22. }

运行结果:(打印的输出的时候。有点错误,*str应该为
&str)

从结果中发现,并未达到改变值得效果。为什么?这个測试代码和本文開始的疑问是一样的,那就进一步分析:

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

运行赋值操作

[cpp] view
plain
 copy

  1. name="alter";

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



watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcmljaGVyZzg1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" style="border:none; max-width:100%">

所以*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分配空间的时候:



watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcmljaGVyZzg1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" style="border:none; max-width:100%">

运行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,仅仅只是名字不一样

运行结果:

这个详细就不分析了,记住引用传递实參和形參是一样的,仅仅是名字不同而已。

总结:

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

时间: 2024-12-19 08:38:52

函数何时值传递,何时指针,何时引用传递总结的相关文章

C++函数参数-值,指针,引用

本文转载自SurpassLi的博文:http://www.cnblogs.com/lidabo/archive/2012/05/30/2525837.html,修改了部分代码和贴图,如有侵犯版权请与我联系删除.           以“ 值传递”方式向函数传递参数 在编写个人函数的时候,你将会受到C++中的一条基本的原则的限制:在默认的情况下,变量只能以值传递的方式传递给函数.这句话的意思是:被传递到函数的只是变量的值,永远不是变量的本身. 例如: void changeValue(int or

java只有值传递,不存在引用传递

今天,我在一本面试书上看到了关于java的一个参数传递的问题: 写道 java中对象作为参数传递给一个方法,到底是值传递,还是引用传递? 我毫无疑问的回答:“引用传递!”,并且还觉得自己对java的这一特性很是熟悉! 结果发现,我错了! 答案是: 值传递!Java中只有按值传递,没有按引用传递! 回家后我就迫不及待地查询了这个问题,觉得自己对java这么基础的问题都搞错实在太丢人! 综合网上的描述,我大概了解了是怎么回事,现在整理如下,如有不对之处望大神提出! 先来看一个作为程序员都熟悉的值传递

为什么 Java 只有值传递,但 C# 既有值传递,又有引用传递,这种语言设计有哪些好处?

为什么 Java 只有值传递,但 C# 既有值传递,又有引用传递,这种语言设计有哪些好处? http://www.zhihu.com/question/20628016 Java值传递的终极解释 http://developer.51cto.com/art/201103/251163.htm

函数对象状态(Function Object State)获取 -- 引用传递和for_each()

一般情况下function object默认值传递,无法获取其状态.本文以引用传递和for_each()两种方法获取function object状态. 引用方式传递function object 以引用方式传递function object程序示例: #include <iostream> #include <list> #include <algorithm> #include <iterator> using namespace std; templa

值传递,指针传递;引用传递(c++独有)本质

要理解值传递.指针传递和引用传递的区别,主要要理解函数的实参和形参,函数的作用域(自动变量.栈),内存的布局以及指针和引用的特点.这里主要总结三种参数传递方式使用的主要场合. 值传递:只给函数提供输入值,需要复制开销,大对象很少使用值传递. 指针传递:可以改变指针指向内容的值,但是不能改变指针本身,无需复制开销.如果需要改变指针本身,可以使用二重指针或者指针引用. 引用传递:除了提供输入值外,还返回操作结果,无需复制开销. #include<stdlib.h> //值传递,函数体内变量n是参数

C++函数传递指向指针的指针的应用

传递指向指针的引用假设我们想编写一个与前面交换两个整数的 swap 类似的函数,实现两个指针的交换.已知需用 * 定义指针,用 & 定义引用.现在,问题在于如何将这两个操作符结合起来以获得指向指针的引用.这里给出一个例子: // swap values of two pointers to int void ptrswap(int *&v1, int *&v2) { int *tmp = v2; v2 = v1; v1 = tmp; } 形参 int *&v1 的定义应从右

參数传递(引用,指针,值传递)C++11

C++中,函数的參数传递方式有值传递.地址传递.传地址有指针和引用方式. 在函数參数中,传地址的理由有: 1.使被调函数能够改动主调函数中的数据对象: 2.传地址能够降低数据拷贝,提高程序运行速度. 那么,何时使用值传递,何时使用地址传递(指针和引用)? 以下是一些写代码时会遇到的一些情况 被调函数使用參数对象时,不会改动数据对象 假设要传入函数的数据对象较小,比方是内建数据类型或小规模的结构体,那么使用值传递: 假设数据对象是数组,那么使用指针(这也是你唯一的选择).指针加入const修饰:

Android For JNI(三)——C的指针,指针变量,指针常见错误,值传递,引用传递,返回多个值

Android For JNI(三)--C的指针,指针变量,指针常见错误,值传递,引用传递,返回多个值 C中比较难的这一块,大概就是指针了,所以大家还是多翻阅一下资料,当然,如果只是想了解一下,看本篇也就够了,不过我也尽量陈述的很详细 一.指针 要说指针,其实通俗易懂的话来说,他应该是保存内存地址的一个变量,我们来看一下小例子 #include <stdio.h> #include <stdlib.h> main(){ //int 变量 int i ; i = 5; //打印i的值

参数传递(引用,指针,值传递)C++11

C++中,函数的参数传递方式有值传递.地址传递.传地址有指针和引用方式. 在函数参数中,传地址的理由有: 1.使被调函数可以修改主调函数中的数据对象: 2.传地址可以减少数据拷贝,提高程序执行速度. 那么,何时使用值传递,何时使用地址传递(指针和引用)? 下面是一些写代码时会遇到的一些情况 被调函数使用参数对象时,不会修改数据对象 如果要传入函数的数据对象较小,比如是内建数据类型或小规模的结构体,那么使用值传递: 如果数据对象是数组,那么使用指针(这也是你唯一的选择).指针添加const修饰:

[转]Python中函数的值传递和引用传递

首先还是应该科普下函数参数传递机制,传值和传引用是什么意思? 函数参数传递机制问题在本质上是调用函数(过程)和被调用函数(过程)在调用发生时进行通信的方法问题.基本的参数传递机制有两种:值传递和引用传递. 值传递(passl-by-value)过程中,被调函数的形式参数作为被调函数的局部变量处理,即在堆栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本.值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值. 引用传递(pass-