C++primer之函数的参数传递以及参数的类型





一:函数的基本知识

(1)      函数要素:返回类型,函数名字,形参(参数之间用逗号隔开)

(2)      函数调用机制:我们通过调用运算符来执行函数,其中运算符就是括号

(3)      当我们调用函数时,主调函数被暂停执行,被调函数开始执行,当被调函数遇到return语句时,return语句完成两项工作,1:返回return语句中的值。2:将控制权从被调函数转移到主调函数。函数的返回值用于初始化调用表达式的结果。

(4)      函数的实参和形参必须类型一致,或者实参可以通过隐式转换到形参类型

下面举个例子:

#include<iostream>
using namespace std;
int function(int a) //函数返回类型,名字,参数
{ //函数体
int c=1;
while(a!=1)
{
c=c*(a--);
}
return c; //返回值
}
int main ()
{
cout<<function(5)<<endl; //调用运算符()执行函数 return 0;
}

运行结果是:

谈到函数中的参数,他们是局部对象,既生命期就是在函数开始执行到函数结束执行期间(生命期:就是对象在程序中存在的时间),形参和定义在函数中的变量都是局部变量,同时,局部变量会隐藏外层作用域中的同名的变量。

下面举个例子:

//局部静态变量
#include<iostream>
using namespace std; int Increase()
{
static int a;
a++;
return a; }
//与局部变量的区别在于: 在函数退出时,
//这个变量始终存在,静态局部变量延长了局部变量的生命周期.
//但不能被其它 函数使用, 当再次进入该函数时, 将保存上次的结果。
//其它的特点与局部变量一样。 int main()
{
for(int i=0;i<5;i++)
cout<<"After the function,the result is "<<Increase()<<endl;;
//函数调用结束,该变量仍然存在,没有被销毁,继续累加,但是由于是局部的,只能在函数内被访问。
return 0;
}





二:参数传递

(1)      传值调用,实参通过拷贝给形参,形参和实参是两个相互独立的对象,两者之间互相不影响。

(2)      传引用调用(主推使用,好处多多):形参是引用类型,即当函数被调用时,形参就是实参的另一个名字,函数中对形参的操纵就是对实参本身的操作(够通俗吧)

(3)      指针形参,当执行指针拷贝时,以指针参数传递,指针形参:此时将复制实参的指针:形参的改变不会引起实参的改变,但是形参指向的内容可以发生变化。

文字太乏味,举个例子大家就知道了。

//三种参数传递传递
#include<iostream>
using namespace std;
int Increase1(int a) //<span style="color:#ff0000;">拷贝的值传递</span>
{
a++;
return a;
}
int Increase2( int &a) //<span style="color:#ff0000;">引用参数传递</span>
{
a++;
return a;
}
int Increase3( int *p) //<span style="color:#ff0000;">指针参数传递</span>
{
(*p)++;
return (*p);
} int main()
{
int c=5; Increase1(c);
cout<<"After the Increase1,the result is "<<c<<endl;
//以拷贝的方式进行调用,c的值不会变, Increase2(c);
cout<<"After the Increase2,the result is "<<c<<endl;
//以引用的形式进行调用,c的值发生改变。 Increase3(&c);
cout<<"After the Increase3,the result is "<<c<<endl;
//以指针参数传递,指针形参:此时将复制实参的指针:形参的改变不会引起实参的改变,但是形参指向的内容可以发生变化。
return 0;
}

运行截图是:

我们建议使用,引用类型的形参代替指针(指针还是用在函数外边好).

为什么使用引用参数呢?

我们应该避开那些拷贝传递,拷贝传递费时费力,占资源,使用引用,我们就是直接在对象上操作,不需要拷贝,指针参数也是一样。无论任何是时候,我们都尽量不适用“传值调用”。

使用引用类型的形参还有一个好处就是,我们要从一个函数中得到多个值,而不是单单一个。举个例子,有一字符串,里面有很多单词,要求,计算出第一个第一个空格(也就是第一个单词后的空格),和所有空格数量,此时要计算出两个值,则我们可以如下:

#include<iostream>
using namespace std;
#include <string>
int find_char(<span style="color:#ff0000;">const string s,int &a</span>)
{
cout<<"the string is "<<s<<endl;
decltype(s.size()) i=0; //i 的类型个s.size 一样
i=s.find(' ',0); //从索引0开始找第一个为空格的,返回索引,失败返回-1
for(auto b=s.begin();b!=s.end();b++) //使用C++迭代器查找string中总的空格数
{
if(*b==' ')
<span style="color:#ff0000;">a++; //这个引用参数虽然没有输出,但是我们仍然可以得到它,这就是引用的好处</span>
}
return i;
}
int main()
{
string s="Zheng zhengzhou university software institute";
int k=0;
cout<<"the blank characters of first index is "<<find_char(s,k)<<endl;
cout<<"the sum of black characters have "<<k<<endl; //引用形参,形参改变,实参也跟着改变。
return 0; //<span style="color:#ff0000;">实现了一个返回值,却可以得到两个有用的参数</span> }

三:初始化时忽略形参的const特性

我们使用实参初始化形参时,可以忽略形参的顶层const,通俗一点来说,当形参是const类型,实参是否是const 类型都一样。反之也成立(当实参是常量类型,形参是否是常量类型都一样),只是当形参是常量类型,函数中不允许改编实参。

例子如下:

//实参初始化形参时,可以忽略形参是否是const类型
#include<iostream>
using namespace std; int add1(const int &a)
{
cout<<a<<endl;
return 1;
} int add2(int a,int b)
{
cout<<"After the add2,the result is "<<a+b<<endl;
return 1;
}
int main()
{
const int a=9;
int b=10;
add1(a); //形参是常量,实参是非常量,只要在程序中不改变形参的值即可:
add1(b); //使用const实参初始化const形参肯定是没有问题的。 const int c=11;
const int d=12;
add2(c,d); //形参是非常量,实参是常量。 return 0;
}

上面的例子告诉我们,尽量使用常量的引用,当在函数中不改变参数时,我们设置为常量。把函数不会改变的形参定义成普通的引用是一种常见的错误,这么做带给函数的调用者一种误导,既函数可以修改它的实参值,使用引用而非常量引用也会极大地限制所能接受的实参类型,例如,我们不能把const 对象,传给普通的引用形参。





四:形参是数组

当形参是数组时候,若形参是:a[10],a,a[],这三种形式都一样,原理是:数组会被转换成指针,我们外函数传递数组,其实就是为数组传递数组的首元素的指针。

例如一下程序:

#include<iostream>   //显式的传入一个数组大小的参数
using namespace std;
int print(const char *a,int b) //数组作为形参的,传递的其实是手首元素指针,其中参数1也可以写成:a[],a[10]
{
for(int i=0;i<b;i++)
cout<<a[i]<<endl;
return 0;
} int main()
{
char a[]="helloworld";
//重载函数,编译器根据参数的类型个数判断调用哪个
print(a,10); //其实有11个元素,最后一个元素为空 return 0;
}

五:函数的返回类型

(1)      存在返回值,返回值类型与函数返回类型一致,或者可以隐式转换,返回值通过return 返回到主调函数中。其中,一个返回引用的的函数可以充当左值,其原理和变量可以充当左值是一样的。

(2)      没有返回值,既renturn ;即可,也可以没有这句话,函数会自动隐式添加这句话。

举个例子

<span style="font-size:18px;">//返回类型是引用可以当左值
#include<iostream>
using namespace std;
int& function(int &a)
{
cout<<"Before the change,the a is"<<a<<endl;
return a;
}
int main()
{
int a=4;
function(a)=50;
cout<<"after the change,the a is"<<a<<endl;
return 0;
}</span>

第一遍看C++primer,以后还得多看,多想,多练。暂且到这吧

C++函数的参数传递机制以及参数的类型选择的更多相关文章

  1. 深入剖析C/C++函数的参数传递机制

    2014-07-29 20:16 深入剖析C/C++函数的参数传递机制    C语言的函数入口参数,可以使用值传递和指针传递方式,C++又多了引用(reference)传递方式.引用传递方式在使用上类 ...

  2. 图说函数模板右值引用参数(T&&)类型推导规则(C++11)

    见下图: 规律总结: 只要我们传递一个基本类型是A④的左值,那么,传递后,T的类型就是A&,形参在函数体中的类型就是A&. 只要我们传递一个基本类型是A的右值,那么,传递后,T的类型就 ...

  3. C#中的函数(三)参数传递及返回值

    接前面二篇,继续开始新的研究 前面忘了说什么是主调函数与被调函数 主调函数:执行调用其它函数语句所在的函数 被调函数:被其它函数所调用的函数 简单说就是一个是发起调用者,另一个是被调用者 写个小例子说 ...

  4. Python学习笔记7-把函数当参数传递、指定可变参数

    把函数当参数传递 # 函数参数传递 # 面向对象编程就是把对象传来传去 # 面向函数编程就是把函数传来传去 def mytest(num): return num * 2 # # 不光可以传递变量,还 ...

  5. Python 函数参数传递机制.

    learning python,5e中讲到.Python的函数参数传递机制是对象引用. Arguments are passed by assignment (object reference). I ...

  6. Python中函数的参数传递与可变长参数

    转自旭东的博客原文 Python中函数的参数传递与可变长参数 Python中传递参数有以下几种类型: (1)像C++一样的默认缺省函数 (2)根据参数名传参数 (3)可变长度参数 示例如下: (1)默 ...

  7. C/C++的参数传递机制

    近来公司招人较多,由此面试了非常多的C++程序员.面试时,我都会问到参数传递的相关问题,尤其侧重指针.因为指针毕竟是C/C++最重要的一个优势(在某种情况下也可以说是劣势).但其结果是,1/3的人基本 ...

  8. python中的*和**参数传递机制

    python的参数传递机制具有值传递(int.float等值数据类型)和引用传递(以字典.列表等非值对象数据类型为代表)两种基本机制以及方便的关键字传递特性(直接使用函数的形参名指定实参的传递目标,如 ...

  9. 我的Java开发学习之旅------>Java语言中方法的参数传递机制

    实参:如果声明方法时包含来了形参声明,则调用方法时必须给这些形参指定参数值,调用方法时传给形参的参数值也被称为实参. Java的实参值是如何传入方法?这是由Java方法的参数传递机制来控制的,Java ...

随机推荐

  1. leetcode 104

    104. Maximum Depth of Binary Tree Given a binary tree, find its maximum depth. The maximum depth is ...

  2. javaSE第十天

    第十天    57 1. 形式参数和返回值的问题(理解)    57 (1)形式参数:    57 (2)返回值类型:    57 (3)链式编程    57 2. 包(理解)    57 (1)其实 ...

  3. SE11

        自省数据及表存储 2014年4月6日 21:37     类似JAVA反射的特性 SAP提供自省数据的机制 这样可以保证程序的灵活性和动态性     1.使用OO中的cl_abap_typed ...

  4. Unable to add App ID because the '10' App ID limit in '7' days has been exceeded.

    Unable to add App ID because the '10' App ID limit in '7' days has been exceeded. 官方的原因是对bundle iden ...

  5. Dockpanel的控件加载问题

    1. 正确加载模式:panel.ControlContainer.Controls.Add(control); 如果用panel.Controls.Add(control);则可能出现模块发生位移问题 ...

  6. WPF—TreeView无限极绑定集合形成树结构

    1.如图所示:绑定树效果图 2.前台Xaml代码: <Window x:Class="WpfTest.MainWindow" xmlns="http://schem ...

  7. shopnc二次开发(一)

    ---恢复内容开始--- 以前没有怎么接触过shopnc,感觉界面挺漂亮的,不过后来自己需要开发一个电商系统,就顺便参考了下,感觉构架垃圾的一塌糊涂.不过平时做这个系统二次开发的业务比较多,所以简单的 ...

  8. AMD平台下在Windows虚拟机中安装Mac10.8.6【Written By KillerLegend】

    我的电脑CPU是AMD,以前在虚拟机中装过Windows操作系统,感觉很简单,这几天想体验一下苹果系统,未来也可能会从事Mac相关软件开发,于是从早上便兴致勃勃的开始了--于是悲剧也开始了,上网各种查 ...

  9. Delphi CxGrid 汇总(4)

    1.     CxGrid汇总功能 ① OptionsView-Footer设置为True,显示页脚   ② CxGrid的Summary选项卡定义要汇总的列和字段名及汇总方式,Footer选项卡定义 ...

  10. 用VBA计算WPS 表格ET EXCEL中的行数和列数的多重方法

    用VBA计算WPS 表格ET EXCEL中的行数和列数 每种方法中上面的是Excel的行数,下面的是Excel的列数. 方法1: ActiveSheet.UsedRange.Rows.Count Ac ...