准备花三天时间来好好谢谢c++函数的调用和返回。当然这里参照网络的,还有一些书,来进行笔记。本章节分为
1、声明参数和返回类型
函数是由返回类型,函数名,和函数名后边括号内的形式参数列表组成的。例如 :
voidf(int a);//函数的声明, 不会返回值 void
int g(int b,int c){return a*b;}//函数的定义
函数的定义包括大括号,以及在内部要执行的一些动作。函数返回类型为void时候,表示什么也不做。
在函数声明和定义中,你可以为参数命名也可以不命名,完全取决你需要。
如下面的函数 int my_find(vector<string> vs,string s,int hint);//有参数名字的
也可以这么声明 int my_find(vector<string> ,string ,int ); //无参数的。
但是,有参数命名的我们看了好看,习惯这么写。
当然我们在定义一个函数的时候是要写形参参数的。
//查找s在vs中
int my_find(vector<string> vs,string s,int hint) { if(hint<0||vs.size()<hint) hint=0; for(int i=hint;i<vs.size();i++) { if(vs[i]==s) return i; if(0<hint) { for(int i=0;i<vs.size();i++) if(vs[i]==s) return i; } } return -1; }
从这个函数我们发现,这个int对我们的使用,让我们的这个函数产生了复杂的效果,我们并不想用它,但是,我们又不打算更改这个函数的声明方式。所以这个时候我们也可以这么写
int my_find(vector<string> vs ,string s,int ) { for(int i=0;i<vs.size();i++) { if(vs[i]==s) retrun i; retrun -1; } }
2、返回一个值
我们可以用return 返回一个值
T Fun() { V v; return v; }
T t=Fun();
这段代码我们可以看到,我们利用函数Fun()来初始化了值,也就是说 返回值可以作为变量初始化的一种形式。如果函数声明要返回一个值,那么函数体内一定要有个return 返回一个值,否则编译时就会报错;
double my_abs(int x) { if (x<0) return -x; else if (x>0) return x; }
尤其注意点的就是我们再利用vs,vc编程到时候返回值,是有所不同的。vs一般都是返回一个int值,
上例子中,当我们x=0时,就会报错了。没有返回值
3、传值参数与引用参数
这一节,以及下一节都是我要重点要讲述的内容,因为它涉及了引用,在C++中,引用的使用是关系到了c++程序的效率等问题。
想函数传递参数是最简单的方式是,将参数的值拷贝一份,传递给函数,一个函数的f()的参数实际是函数的局部变量如下变得的例子就一目了然了
#include "stdafx.h" #include <vector> #include <iostream> using namespace std; int func(int x) { return x+1; } int _tmain(int argc, _TCHAR* argv[]) { int x1=2; cout<<func(x1)<<endl; cout<<"x1="<<x1<<endl; int x2=8; cout<<func(x2)<<endl; cout<<"x2="<<x2<<endl; }
我们发现x1,x2的值并没有改变, 说明参数是通过拷贝一份的值传给他的。
如图
![](http://hi.csdn.net/attachment/201108/27/0_1314437390ea8y.gif)
直接就是拷贝值。
![](http://hi.csdn.net/attachment/201108/27/0_1314437409YbYx.gif)
4、传常量引用参数
当我们传的值是一个比较小的数字,或者字符,这时候,拷贝的代价并不大,占用的系统资源就比较少,但是当我们传递一个表的数据,一个图像等等大容量的数据呢?如果再拷贝的话,就会对系统资源造成极大浪费。而且对效率也是问题,
例如下边例子
void print(vector<double> v) { cout<<"{"; for(int i=0;i<v.size();i++) { cout<<v[i]; if(i!=v.size()-1) cout<<","; } cout<<"}\n"; } void f(int x) { vector<double> vd1(10); vector<double> vd2(10000000); vector<double> vd3(x); print(vd1); print(vd2); print(vd3); }
从以上例子可以看出,一个double如果按照八字节算,第一个是80,第二个八百万。如果x很大呢?这就会造成极大了浪费。
这个时候我们就开始使用下边对函数print改一下
void print(const vector<double> &v) { cout<<"{"; for(int i=0;i<v.size();i++) { cout<<v[i]; if(i!=v.size()-1) cout<<","; } cout<<"}\n"; } 首先看一下例子 void init(vector<double> & v) { for(int i=0;i<v.size();i++) v[i]=i; }
引用了,引用其实就是一个变量的别名机制,给他起个名字,操作的时候就是对本身进行操作。
这时候我们就希望能够修改v值,进行初始化。引用允许我们对一个对象起一个新名字,例如int& 是对一个整形对象的一个引用,因此,我们可以利用以下代码:int i=7;
int & ii=i; ii=10; cout<<ii<< " "<<i<<endl; //此时输出的是 10 10
通过实例可以看书,任何对引用进行修改的,就是对对象本身修改的。
应用的一个用途就是作为简写形式,例如以下形式,
vector<vector<double> > v;当我们多次使用某个向量时v[g(x)][f(x)]的时候,我们当然不愿意写这么表达式,所以我们可以这么写 double val=v[g(x)][f(x)];
但是当我们不仅需要对其读取值,还要对其进行写值的时候,这时候引用就派上用场了,我们可以如下声明,double& val=v[g(x)][f(x)],下面就会有一个经典的例子。
就是交换数的例子,上源代码
void swap1(int a,int b) { int temp=a; a=b; b=temp; } void swap2(int& a,int& b) { int temp=a; a=b; b=temp; } int _tmain(int argc, _TCHAR* argv[]) { int x=2; int y=3; swap1(x,y); cout<<"x="<<x<<endl; cout<<"y="<<y<<endl; int m=4; int n=5; swap2(m,n); cout<<"m="<<m<<endl; cout<<"n="<<n<<endl; }
输出的结果为:
如图
![](http://hi.csdn.net/attachment/201108/27/0_1314437425zz3t.gif)
就可以看出,利用引用才能进行对值的交换。
这时候大家注意上一个例子的参数列表,多出了个const,因为我们的引用是直接对对象本身操作的,如果你怕在调用的时候对对象不小心的修改,那么你就对这个参数进行const修饰,当你不小心对其修改了,那么编译器就会报出错误的。
5、传值和传引用的比较
我们如何在传值参数,传引用参数和传常量应用参数中选择呢?
下面我们有如下原则:
- 使用传值方式是是传的很小的参数,对象。
- 使用传常量引用方式传递你不需要修改的大对象
- 让函数返回一个值,而不是修改通过引用参数传递来的对象
- 只有迫不得已的时候才使用传引用方式。
当我们看到函数参数是以一个非常量引用参数传过来的参数,那我们必须假设该函数要进行对其修改。
考虑如下代码
int incr1(int x) {retrun x+1;} void incr2(int &x){ x++;} int m=2; m=incr1(m); incr2(m);
这时候你会想到,效果一样,为什么还需要引用呢,但是一下情况你要知道:
- 用于操作容器
- 用于改变多个对象的函数
下面使用一个函数说明一下void larger(vector<double> v1,vector<double> v2) { if(v1.size()!=v2.size()) error ("different size"); for(int i=0;i<v1.size();i++) { if(v1[i]<v2[2]) swap(v1[i],v2[2]); } }
先讲这些,如果有什么漏洞希望大家指出了。
先讲这些,如果有什么漏洞希望大家指出了。