以下文章转载自:http://www.jb51.net/article/108390.htm

函数中参数的传递

这里说的传递当然是指 实参是如何传递给形参的啦

还挺复杂的~~~~~~~~⊙﹏⊙b汗,这里讲述了4种参数传递的情况和注意事项:

1.非引用形参

这是最普通,也是最简单的形参传递了。

参数传递,即是使用实参副本(注意啊,是副本,不是实参本身)来初始化形参;

因此,在函数体内对形参的修改不会影响实参的值。

如果形参是指针类型的,那么函数体内是否可以修改指针所指向的对象的值呢?

如果您产生这样的疑问,表示您很有想法~~~

答案是~~~需要分情况讨论。

如果函数的形参是非const类型的指针,则函数可以通过指针实现赋值,修改指针所指向对象的值。

所以,如果需要保护指针指向的值,则形参需定义为指向const对象的指针(注意了,这里的指针依然是非const型的,只是其指向的对象是const型的):

1
2
3
4
5
6
7
void use_ptr(const int *p)
 
{
 
     //use_ptr这个函数可以读指针p所指向的对象,但是不可以修改该对象的值
 
}

const形参

如果函数使用的是非引用非const形参,则既可以给该它传递const实参,也可传递非const实参。

如果函数使用的是非引用const形参,也是既可以给该它传递const实参,也可传递非const实参。那么这两者的差别是什么呢?对于后者,函数连实参的局部副本都不可以改变了。下面是第二种情况的一个例子: void fcn(const int i) {}

复制实参的局限性:复制实参不是在所有的情况下都适合,不是一复制实参的情况如下:

1.当需要在函数中修改实参的值时

2.当需要以大型对象作为实参传递时。对实际的应用而言,复制对象所付出的时间和存储空间代价往往过大

3.当没有办法实现对象的复制时

对于上述几种情况,有效的解决办法是将形参定义为引用或指针类型。

(终于说完这个最简单的传递方式了,╮(╯▽╰)╭)

2.引用形参

引用形参的用法:

1.让函数修改实参的值

2.向主调函数返回额外的结果(本来return就可以返回一个值给主调函数,而且引用参数可以改变实参的值,所以相当于返回了额外的结果)

3.利用const引用避免复制(当向函数传递大型对象时,需要使用引用来提高效率,如果使用引用形参的唯一目的是避免复制实参,则应将形参定义为const引用)

这是一个不适宜复制实参的例子,该函数希望交换两个实参的值

1
2
3
4
5
6
7
8
9
10
11
void swap (int v1,int v2)
 
{
 
  int tmp=v1;
 
  v2=v1;
 
  v1=tmp;
 
}

这个例子期望改变实参本身的值,但是swap无法影响实参本身,执行swap时,指示交换了其实参的局部副本,对实参根本没有改变。解决的方法是:将形参定义为引用类型。

1
2
3
4
5
6
7
8
9
10
11
void swap (int &v1,int &v2)
 
{
 
      int tmp=v1;
 
      v2=v1;
 
      v1=tmp;
 
}

当调用swap(i,j)时,i和j的值才真正实现了交换。

更灵活的指向const的引用

应该将不需要修改的引用形参定义为const引用。普通的非const引用形参在使用时不大灵活。非const引用形参既不能用const对象初始化,也不能用字面值或者产生右值的表达式实参初始化。(如果函数的形参是非const引用形参,表示在函数体内可能会修改该形参值,即会修改实参的值,因此不可以用const对象来做实参传递给这样的函数,所以不灵活。)

传递指向指针的引用

如果想编写一个与前面交换两个整数的swap类似的函数,实现两个指针的交换。已知需用*定义指针,用&定义引用,问题在于,如何将这两个操作符结合起来一获得指向指针的引用。

1
2
3
4
5
6
7
8
9
//交换两个指向整形的指针的值
 
void ptrswap(int *&v1,int *&v2)
 
{
       int=*tmp=v2;
       v2=v1;
       v1=tmp;
 }

形参int *&v1的定义,应该从右至左的理解:v1是一个引用,与指向int型对象的指针相关联。也就是说,v1只是传递ptrswap函数的任意指针的别名。

3.vector和其他容器类型的形参

由于复制vector会使得效率降低,多以如果形参是vector的话,我们常常将该形参声明为引用,避免复制。另一种方法在C++中更为常用,就是通过传递指向容器中需要处理的元素的迭代器来传递容器。

4.数组形参

由于数组是不可以复制的,所以不可以定义使用数组类型形参的函数。如果函数需要使用数组作为形参,那么就要通过操纵指向数组中元素的指针来处理数组。

以下定义都是正确的:

1
2
3
void printValues(int*){}
void printValues(int[]){}
void printValues(int[10]){}

注意了,虽然不能直接传递数组,但是函数的形参可以写成数组的形式。上面三种定义是等价的,形参类洗个都是int*。

通常,将数组形参直接定义为指针要比使用数组语法定义更好。这样就明确地表示,函数操纵的是指向数组元素的指针,而不是数组本身。由于忽略了数组长度,形参定义中如果包含了数组长度则特别容易引起误解。

对于非引用型形参来说,编译器检查数组形参关联的实参时,它只会检查实参是不是指针、指针的形参和数组元素的类型是否匹配,而不会检查数组的长度,所以即使实参数组的长度与形参不匹配时,编译也可以通过,但是在调用时会出错。

但是对于引用型形参来说,编译器还会检查是西安数组的大小与形参的大小是否匹配,所以如果实参数组的长度与形参不匹配,编译时就会报错。

如何确保函数的操作不超出数组实参的边界?

方法有三:

1.在数组本身放置一个标记来检测数组的结束。C风格字符串就是采用这个方法的一个例子,它是一个字符数组,并且以空字符null作为结束的标记。处理C风格字符串的程序就是使用这个标记停止数组元素的处理。

2.使用标准库规范,传递指向数组第一个和最后一个元素的下一个位置的指针。void printValues(const int *beg, const int *end){},如果定义int j[2]={0,1},在调用该函数时,printValues(j,j+2).

3.显式传递表示数组大小的形参。void printValues(const int ia[], size_t size){}

5.可变形参

C++中的省略符形参是为了编译使用了varargs的C语言程序。

1
2
void foo(parm_list,...);
void foo(...);

以上这篇老生常谈C++中实参形参的传递问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。

转载:老生常谈C++中实参形参的传递问题的更多相关文章

  1. C#形参,实参,值传递参数,引用传递参数,输出参数,参数数组的学习

    1)形参 形参顾名思义就是形式上的参数,不是实际的参数,它代替实际传入方法的值.在方法体代码中代表了值本身参与运算.形参定义于参数中,它不同于方法体内局部变量,因为是一个变量,在它的作用域内不允许存在 ...

  2. 匿名函数中undefined形参疑问(转载)

    唉,基本功不扎实,昨天在微博上问了个问题,就匿名函数中undefined形参,不知道是干什么用的. 经常看到这样的匿名函数代码: ;(function( $, window, document,und ...

  3. (转载)理解Java中的引用传递和值传递

      关于Java传参时是引用传递还是值传递,一直是一个讨论比较多的话题,有论坛说Java中只有值传递,也有些地方说引用传递和值传递都存在,比较容易让人迷惑.关于值传递和引用传递其实需要分情况看待,今天 ...

  4. Pyhton函数篇(一)之函数中的形参与实参

    1:什么是函数 函数其实就是带名字的代码块,用于完成一些具体的工作.如果我们在写一段程序的时候,需要多次用到同样的一个功能,如果每次都要重复写相同的代码,不仅会增加我们的代码量,更会让我们写出的代码让 ...

  5. java基础 - 形参和实参,值传递和引用传递

    形参和实参 形参:就是形式参数,用于定义方法的时候使用的参数,是用来接收调用者传递的参数的. 形参只有在方法被调用的时候,虚拟机才会分配内存单元,在方法调用结束之后便会释放所分配的内存单元. 因此,形 ...

  6. python 函数(实参与形参、传递参数)

    函数 什么是函数?函数是带名字的代码块,用于完成具体的工作.写出一个函数后,就可以一直调用. 定义函数,函数的基本组成: 1.1 向函数传递参数 向函数中传递任意参数,这样打印出的结果就可以根据自己的 ...

  7. Java中的形参和实参的区别以及传值调用和传引用调用

    名词解析: 1.形参:用来接收调用该方法时传递的参数.只有在被调用的时候才分配内存空间,一旦调用结束,就释放内存空间.因此仅仅在方法内有效. 2.实参:传递给被调用方法的值,预先创建并赋予确定值. 3 ...

  8. python函数中参数是如何传递的?

    python中一切皆对象,函数中参数传递的是对象的引用. 1在函数中改变变量指向的对象,即指向不同对象. 当在函数中修改传递进来的变量指向另一个对象时,实参的对象不会改变. >>> ...

  9. Java中到底是值传递还是引用传递?

    Java中到底是值传递还是引用传递? 我们先回顾一下基本概念 实参和形参 参数在编程语言中是执行程序需要的数据,这个数据一般保存在变量中.在Java中定义一个方法时,可以定义一些参数, 举个例子: p ...

随机推荐

  1. Java第10次实验(网络)

    参考资料 本次作业参考文件 正则表达式参考资料 漫画:HTTP 协议极简教程,傻瓜都能看懂! 注:主要根据实验任务书的指导完成本次实验. 第1次实验 1. 网络基础 ipconfig.ping Con ...

  2. vc++获取网页源码之使用import+智能指针包装类

    创建基于对话框的mfc应用程序 使用智能指针包装类IWinHttpRequestptr,它内部采用的是引用计数来管理对象的生命周期 代码: #import "C:\\Windows\\Sys ...

  3. 结构方程软件Lisrel 8.7 和HLM5.5

    这是我亲自使用过的软件,其中lisrel是破解版的,HLM是学生版的 下载地址:http://pan.baidu.com/s/1bnfCOrH

  4. 1.汇编指令介绍(arm)

    本文作为本人学习过程中的记录及时不时的突发奇想偶记.鄙人菜鸟一只,文中如有错误或疏漏,若读者肯不吝赐教,在下感激零涕.文章一直不断更新中 一.汇编语言 汇编语言是一种应用计算机.微处理器.微控制器或其 ...

  5. Spring-framework应用程序启动loadtime源码分析笔记(一)

    1,实例化DefaultListableBeanFactory DefaultListableBeanFactory是AnnotationConfigApplicationContext的组件,Def ...

  6. PAT 甲级 1011 World Cup Betting (20)(20 分)

    1011 World Cup Betting (20)(20 分)提问 With the 2010 FIFA World Cup running, football fans the world ov ...

  7. [转][C#]单例模式之懒加载

    private static ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().Decla ...

  8. NFS应用场景及环境搭建

    两台虚拟机,一台做服务端(server)用来存储,一台做客户端(client)用来访问. 注意,两台虚拟机都已经挂载完光盘,并配置好yum源.客户端client已经安装好lamp环境,服务端不做任何处 ...

  9. echarts饼图配置

    js引用和配置div <div id="container" style="height: 100%"></div> <scrip ...

  10. 关于daterangepicker的配置

    一开始接触daterangepicker搞得思路很乱,慢慢研究才了解一些,下面粘一个daterangepicker的基本配置,代码是来自网上某位大神的.我只是引荐过来的,加入了周和月的汉化. 在回调函 ...