一、函数
实际项目中,要实现的功能不是仅靠一些基本语句就可以实现的,通常需要将这些大的功能进行分解,分步骤完成。例如:要实现一个学生信息管理系统, 一个学生信息管理系统至少包括学生信息的 添加、查询、删除、修改等功能, 这些功能要求就是对该系统的初步分解, 然后以查询功能为例对其继续分解, 查询 功能可以再次分解为由以下几个功能组成的模块:
- 获取用户查询信息;
- 到数据库查询该学生信息;
- 按照一定格式输出查询结果。
如果感觉该功能实现起来还是比较困难那么就继续分解, 直到可以顺利实现。这些功能分解后的实现就是依靠函数, 函数在广义上理解为具有具体功能的一个模块, 在函数实现后, 通过对函数的调用来使用这个功能。
1.函数声明
函数声明也叫函数原型,包括返回类型、函数名、参数列表以及最后的一个分号。C++在处理函数调用之前,必须先看到该函数的声明或者定义。如果一个函数在不同源文件中被调用,那么每个源文件中都必须有声明。如果函数没有返回值,那么返回类型必须是void,如果什么都不写,默认返回类型是int。要避免不写返回类型
2.函数定义
函数包括返回类型、函数名、形参列表、花括号括起来的函数体。如果函数返回类型是void,return语句可有可无,如果有的话不要带任何参数。如果函数返回类型不是void,那么至少要有一个return,并且return后必须带一个值。函数定义在一个程序中只能出现一次,但是函数原型可以有多个。
函数定义的格式为:
返回值类型 函数名(参数列表)
{
函数体
}
例1:
int max(int a, int b) //函数头
{//函数体
if(a>=b)
return a;
else
return b;
}
二、函数的调用
在任何的一个C++程序中, 都有一个被称为主函数的函数 - main(),该函数又被称为C++程序的入口函数,该函数的作用是告诉程序应该从这里开始执行指令, 也就是说,,任何一个C++程序都是从 main() 函数处开始执行, 直到执行过程中遇到程序的结束指令。
C++中的函数之间可以互相调用,即:
main()函数可以调用任何函数,也包括自身;
自定义的函数可以调用其他自定义的函数或者库函数,自定义函数同样也可以调用main()函数。
函数调用做了如下两件事:
- 用对应的实参初始化函数的形参,并将控制权转移给被调用的函数;
- 主调函数的执行被挂起,被调函数开始执行。
每次调用函数时,该函数的所有形参都会被重新创建,此时将会用实参来初始化对应的形参。
注:形参的初始化与变量初始化一样:如果形参是非引用类型,则复制实参的值;如果形参为引用类型,则它是实参的一个别名。
1. 非引用形参
- 非引用类型的形参是通过复制对应的实参来实现初始化(实参副本来初始化形参)。
- 非引用类型的形参实际上是对应实参的局部副本,对非引用类型的形参的修改仅仅改变了局部副本的值,一旦函数执行结束,这些局部变量的值也就随之没有了。
例2:
void swap(int v1 , int v2)
{
int temp = v2;
v2 = v1;
v1 = temp;
}
如果有函数调用swap(i, j),则i和j不受影响,只交换了副本的值。
2. 指针形参
当函数形参是指针时,此时将复制实参指针。与非引用形参一样,该类形参的任何改变也仅作用域局部副本。如果函数将新指针值赋给形参,主调函数的实参指针的值依然不会改变。
例3:
void add(int *p)
{
*p+=1;
p+=1;
}
上例中:使用指针做为函数的形参,同样指针的值(指针的地址)不会因为p+=1而受到影响,但是指针指向的地址的值(*p)将会改变。所以要想修改实参的值,可以使用这种方法。
注意:
复制实参并不是适合所有情况,不适合采用复制实参的情况有:
- 当需要在函数中修改实参的值时;
- 当需要以大型对象作为实参传递时;
- 当没有办法实现对象的复制时。
3. 引用形参
对于例1要实现的交换两个数的功能,需要将两个形参定义为引用类型才可以,即:
例4:
void swap(int &v1 , int &v2)
{
int temp = v2;
v2 = v1;
v1 = temp;
}
每次被调用时,引用形参被创建并与相应的实参关联。当调用swap(i, j)时,形参v1只是实参对象i的另一个名字,而v2也只是实参对象j的另一个名字,对v1或v2的任何修改,实际上就是对i或j的修改。
4.传递指向指针的引用
例5:
//修改指针指向的地址,而地址的值不变 void fun(int *&v1,int *&v2) { int *p=v2; v2=v1; v1=p; } //交换指针指向地址的值 void fun1(int *&v1,int *&v2) { int p=*v2; *v2=*v1; *v1=p; } int main() { int i=1; int j=2; int *v1=&i; int *v2=&j; cout<<"i="<<i<<" "<<"j="<<j<<endl;//1,2 fun(v1,v2); cout<<"*v1="<<*v1<<" "<<"*v2="<<*v2<<endl;//2,1 cout<<"i="<<i<<" "<<"j="<<j<<endl;//1,2 注意这里只是指针指向的地址交换,而i和j的值没变 fun1(v1,v2); cout<<"i="<<i<<" "<<"j="<<j<<endl;//2,1 这里函数交换的是指针指向地址的值 system("PAUSE"); return 0; }
上例中:
int *&v1就是一个指向指针的引用,从右至左理解:v1是一个引用,与指向int类型对象的指针相关联,v1只是一个传递进函数的指针别名。