【fishing-pan:https://blog.csdn.net/u013921430转载请注明出处】

前言

这些天又在复习C++,温故知新,每次看书都会发现一些之前被自己忽视掉的知识点,所以,学习是不能止步的!

作为一种编程语言,C++最重要的两个部分就是函数和变量,这两者之间进行沟通便是通过参数传递,而参数传递有很多需要注意的细节,今天就来讲讲参数传递的问题。

      总的来说,参数传递的过程,就是初始化函数形参的过程。

按值传递

按值传递是最直接也是最容易理解的参数传递方式,其形式如下;

void fun(int x,int y){...表达式;}    //定义;
fun(a,b);                           //调用

当进行调用的时候,将参数的值通过拷贝赋值给形参,形参的值在函数体内进行各种计算时,并不影响函数外实参的值,形参值的改变与实参无关;

传值过程是这样的;

int y = b; int x = a;

下面这个例子就说明了这点;

#include<iostream>using namespace std;
void swap(int, int);
void main()
{int a(5), b(10);swap(a, b);cout <<"a="<< a << " , "<<"b=" << b << endl;system("pause");return;
}void swap(int x, int y)
{int temp;temp = x; x = y; y = temp;cout << "按值传参" << endl;cout <<"x="<< x << " , " <<"y="<< y<<endl;
}

虽然a与b的值被传递进入了swap(),在swap内,形参的值进行交换,但是外部a与b的值并没有交换。

        注:形参的建立是自右往左的,也就是先建立y,再建立x,而函数结束时,删除的顺序与之相反。

按地址传递(指针形参)

按地址传递是用变量的地址初始化形参,这时候的形参是一个指针,其形式如下;

void fun(int* x,int* y){...表达式;}    //定义;
fun(&a,&b);                           //调用;

在传参过程中,形参初始化的操作如下;

int *y = &b; int *x= &a;

这时候重新定义swap()函数,会发现a,b的值被修改了,因为,函数通过指针修改了指针指向的对象的值,这就修改了a,b本身。

#include<iostream>using namespace std;
void swap1(int*, int*);
void main()
{int a(5), b(10);swap1(&a, &b);cout <<"a="<< a << " , "<<"b=" << b << endl;system("pause");return;
}void swap1(int* x, int* y)
{int temp;temp = *x; *x = *y; *y = temp;cout << "按地址传参" << endl;cout << "*x=" << *x << " , " << "*y=" << *y << endl;
}

按引用传递

众所周知,对于引用的操作就是对对象本身的操作,引用是被引用对象本身的一个“别名”,按引用传递参数与引用类似,形参成为了实参的一个“别名”,它的形式如下;

void fun(int &x,int &y){...表达式;}    //定义;
fun(a,b);                           //调用;

形参初始化的操作如下;

int &y = b; int &x= a;

可以想见,当按引用传值时,在函数中修改形参的值时,实参的值也被修改了,事实也正是如此。

#include<iostream>using namespace std;
void swap2(int&, int&);
void main()
{int a(5), b(10);swap2(a, b);cout <<"a="<< a << " , "<<"b=" << b << endl;system("pause");return;
}
void swap2(int& x, int& y)
{int temp;temp = x; x = y; y = temp;cout << "按引用传参" << endl;cout << "x=" << x << " , " << "y=" << y << endl;
}

优势

避免进行拷贝操作

虽然在我们的例子中都用的是简单的int类型,但是在实际使用中,常常需要传递很大的容器对象,或者是大的类类型对象,这些时候需要调用拷贝构造函数进行传参,效率低下,通过引用可以很好的避免这一点,大大地节约计算时间和计算资源。

用于返回信息

      我们知道,一个函数一次只能返回一个值,当需要通过函数知道多个变量的信息是,仅仅有返回值是不够的,引用形参为我们提供了很好的渠道,通过引用可以获得函数计算后的各个值,甚至不需要接收函数的返回值。

数组形参

与普通变量一样,数组也可以作为函数的形参。但是在《【C++】细说C++中的数组之“静态”数组》中我们提到过,数组是不允许被拷贝的,因此我们不能以传值的形式使用数组形参,所以改换成传地址的方式向函数传递数组实参的信息。

当且仅当用于函数头或者函数原型时,int *arr与int arr[]是含义相同的,他们都意味着arr是一个指针。所以下面三者是等价的;

int* multi(int a[],int m);
int* multi(int *a,int m);
int* multi(int a[10],int m);

将数组作为形参时,其实是将数组首元素的地址,包含元素的种类,以及元素的数目提交给了函数,有了这些信息后,函数就可以使用数组的信息了。但是,也有一些问题需要注意,当我们有一个数组时,可以获得数组的大小(利用sizeof()函数),但是当它转化成指针后,我们没法获得它的大小,所以常常显示地向函数传递数组的大小;

#include<iostream>
using namespace std;int* multi(int a[], int, int);
void main()
{int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };int *arr1 = multi(arr,10,10);cout << arr1[3]<<endl;system("pause");return;
}
int* multi(int a[],int len,int m)
{for (int i = 0; i < len;i++){a[i] *= m;}return a;
}

数组引用形参

变量可以定义成数组的引用,形参也同样可以,

int* multi(int (&a)[10],int m);
//注:&a两端的括号不能少,因为[]的优先级更高;C++也不允许引用的数组。其次,必须给定数组的大小,这在一定程度上限制了函数的使用。

多维数组作为形参

与数组一样,多维数组也可以作为形参传递给函数,与一维数组一样,传递的也是数组首元素的地址。因为处理的是数组的数组,所以首元素本身是一个数组,指针指向的是一个数组,因此第二维的数组的大小不能被省略。

int* multi(int (*a)[10],int m);//注:*a两端的括号不能掉,因为[]的优先级更高如果失去了括号,那么int *a[10]表示的是包含十个int类型指针的数组。而前者表示a是一个指针,指向含有十个元素的数组。

带默认值的形参

很多情况下都要用到默认值的形参,例如OpenCV中的很多函数都使用了默认形参,这样使得函数更加灵活好用。
当函数提供了形参的默认值,形参就不是必须要从实参获得值,那么在函数调用时,也不是必须提供与形参数一致的实参。
       形参与实参匹配是从左到右的,第一个形参与第一个实参匹配,第二个形参与第二个实参匹配。因此,指定默认值的形参必须放在形参列表的最右侧,或者说,在带默认值的形参的右边,不允许出现无默认值的形参;

int add(int x = 10, int y = 20){...表达式;}add();
add(a);
add(a, b);float f1(float a,float b=1,float c,float d=0);    //错误
float f1(float a,float b,float c=1,float d=0);    //正确

这里也只是简单的列举了一下C++中形参和参数传递的内容,还有很多复杂的内容需要在项目实践中去了解,但是万变不离其宗,这些东西是我们必须掌握的。

已完。。

【C++】函数的形参相关推荐

  1. 【C 语言】文件操作 ( 配置文件读写 | 读取配置文件 | 函数接口形参 | 读取配置文件的逐行遍历操作 | 读取一行文本 | 查找字符 | 删除字符串前后空格 )

    文章目录 一.函数接口形参 二.读取配置文件的逐行遍历操作 1.读取配置文件的逐行遍历操作 2.读取一行数据 3.查找字符 4.删除字符串前后的空格 5.完整代码示例 一.函数接口形参 函数作用 : ...

  2. 函数默认形参与占位参数

    一.默认参数 1.默认参数的基本概念 默认参数就是我们可以给函数的形参设定一个初始值. 我们调用函数的时候,如果我们传了实参,那么就用我们传的实参,如果我们没有传实参的话,就用函数形参的初始值. in ...

  3. c/c++教程 - 2.3 函数的提高 函数的形参列表默认值 占位参数 函数重载

    3. 函数的提高 目录 3. 函数的提高 3.1 函数的默认参数 3.2 函数占位参数 3.3 函数重载 (重要) 相关教程 3.1 函数的默认参数 C++中,函数的形参列表中的形参是可以有默认值的. ...

  4. 函数指针和指针函数:超详解——函数指针形参

    函数指针: 函数指针 的本质是一个指针,该指针的地址指向了一个函数,所以它是指向函数的指针. int (*test)() 指向的是函数而非对象.和其它指针一样,函数指针指向某种特定类型.函数的类型由它 ...

  5. 函数的形参(普通形参、指针形参、引用形参)

    以一些代码段为例: 1.普通形参 int n=10; add1(n);void add1(int v1) { v1+=1;//对实参无影响 } 这是最普通的形参方式,形参仅仅为实参的一个副本,对形参的 ...

  6. python中形参和return语句_Python-return语句-函数的形参定义

    return语句 语法: return [表达式] [ ]可以省略 作用: 用于函数中,结束当前函数的执行,返回到调用该函数的地方,同时返回一个对象的引用关系 说明: 1.return语句后跟的表达式 ...

  7. 函数的实参 函数的形参 闭包 js

    函数的实参和形参 可选形参 if(a === undefined) a = []; 等价于 a = a || []; 这两句是完全等价的,只不过后者需要提前声明a而已 如果参数没有传入,其余的填充un ...

  8. Python基础语法-三种函数特殊形参定义以及使用方式

    函数的基础定义和使用 函数使用必须在函数声明之后. 注意形参的作用域只限于函数体内部 每个函数在python中都有返回值,如果不写默认返回None. def func1(str1):print(str ...

  9. Angular前端事件处理函数的形参名必须为某个硬编码值的怪事

    Angular通过ng-click directive注册event handler,经过测试发现形参名必须为$index, 改成其他任意值都不工作.不工作的意思是点击之后,instead of ex ...

最新文章

  1. 硬件加速器为人工智能应用服务
  2. Centos 6启动流程详解
  3. python绘图颜色代码_python matplotlib-颜色代码+ve和-ve值在绘图中
  4. 二项式反演[bzoj3622]已经没有什么好害怕的了
  5. 检测Maven依赖中介
  6. 自动产生fsm代码的工具_代码自动生成工具
  7. 3.3亿人都在用小程序,中国首次定义的互联网标准又有新进展
  8. 文末送书 | 自动机器学习(AutoML):方法、系统与挑战
  9. Java发送GET/POST请求
  10. android 透明度_Android智能视图翻转器
  11. web开发人员必备的提高开发水平的20个参考手册
  12. fork()和多线程
  13. D-tale功能的探索
  14. uiswitch样式_iOS - UISwitch 、UISegmentedControl
  15. SNDACode介绍
  16. webstorm,idea 右键菜单管理
  17. 【Matlab图像隐写】DCT数字水印嵌入与提取【含GUI源码 943期】
  18. Java实现桐桐的数学难题
  19. ​5.10.4 操作查询之​追加查询
  20. 逆向知识之CS辅助/外挂专题.2.实现CS1.6无限夜视仪.无限闪光烟雾高爆弹.

热门文章

  1. javascript访问frame,iframe框架和href的定向
  2. ubuntu14.04修改limits.conf后链接限制仍然不生效
  3. 行为设计模式 - 状态设计模式
  4. docker 守护进程
  5. java 课后习题 键入日期输入星期几
  6. C#LeetCode刷题之#345-反转字符串中的元音字母​​​​​​​(Reverse Vowels of a String)
  7. C#LeetCode刷题之#598-范围求和 II​​​​​​​(Range Addition II)
  8. 面向对象设计原则之1-单一职责原则
  9. lodash和debounce
  10. 常用系统级加压工具简介