以下文章转载自: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. windows下vscode修复c++找不到头文件

    因为原博客太长将部分内容分开 vscode找不到头文件的问题是由于windows下vscode默认的编译器是微软的MSVC(vs使用的编译器)的头文件路径 如果你没有安装vs肯定会因为找不到头文件而报 ...

  2. js 格式化时间日期函数小结

    下面是脚本之家为大家整理的一些格式化时间日期的函数代码,需要的朋友可以参考下. 代码如下: Date.prototype.format = function(format){ var o = { &q ...

  3. WPF系列学习

    1:WPF最小化到系统托盘 2:WPF程序单例运行 3:WPF中三种异常捕获:UI线程异常.非UI线程异常.Task线程异常 在窗体放一个按钮在单击事件执行如下代码来模拟. private void ...

  4. ALGO-149_蓝桥杯_算法训练_5-2求指数

    AC代码: #include <stdio.h> int main(void) { int n,m,sum; int i,j; scanf("%d %d",&n ...

  5. PureMVC剖析

    http://www.cnblogs.com/skynet/archive/2013/01/29/2881244.html http://hi.baidu.com/mmforever/item/408 ...

  6. Ubuntu 16.04安装Pycharm2017.1.1

    安装pycharm 1.到官网下载安装包. 2.到下载目录下进行解压. 3.运行解压后的文件夹中的bin目录下的pycharm.sh文件. cd pycharm-community-2017.1.1/ ...

  7. 【原创】虚拟机上实现绑定固定IP扩主机容器互访

    Docker绑定固定IP/跨主机容器互访 https://blog.csdn.net/qq_34021712/article/details/75948566 服务器IP   容器分配网段   启动容 ...

  8. pos省纸的妙招

  9. [UE4 ]Is Locally Controlled的局限性

    一.在有机器人的游戏中,就不能使用IsLocallyControlled判断.而是要使用这个方法: 二.因为机器人也是属于本地控制的角色.所以不能使用IsLocallyControlled判断是否是本 ...

  10. linux 为什么要关闭selinux

    一般安装linux课程时都把SELinux与iptables安排在后面,使初学者配置linux服务器时不成功,却没有头绪,那是因为在RedHat linux操作系统中默认开启了防火墙,SELinux也 ...