第六章 函数
6.1 函数基础
函数的形参列表
不带形参的函数,两种定义方法
void f1(){} //隐式定义
void f2(void){} //显式定义
6.2 参数传递
6.2.1 传值参数
指针形参
指针的行为和其他非引用类型一样。当执行指针拷贝操作时,拷贝的是指针的值。拷贝之后,两个指针是不同的指针。因为指针使我们可以间接的访问它所指的对象,所以通过指针可以修改它所指对象的值。
//Q:了解指针形参
void reset(int *p){
*p = 50;
cout << "形参p的值:" << p << endl;
p = 0;
cout << "p=0执行后,形参p的值:" << p << endl;
}
void e1(){
int i = 42;
cout << "i的初始值:" << i << endl;
int *q = &i;
cout << "实参q的值:" << q << endl;
reset(q);
cout << "函数运行过后i的值:" << i << endl;
cout << "函数运行过后实参q的值:" << q << endl;
}
以前很长一段时间都把指针形参等同于引用形参,这是错误的。要注意区分指针形参和引用形参的区别。指针形参还是值传递,引用形参是引用传递。
6.2.2 传引用参数
使用引用避免拷贝
拷贝大的类类型对象或者容器对象比较低效,甚至有的类类型根本不支持拷贝。当某种类型不支持拷贝操作时,函数只能通过引用形参(指针形参不行吗?)访问该类型的对象。
如果函数无需改变引用形参的值,最好声明为常量引用***(const type &i)***。
使用引用参数返回额外信息
想让函数返回多个值,引用形参为我们一次返回多个结果提供了有效的途径。下面总结一下返回多个值的方法。
- 定义一个新的数据类型,比如XX类。返回这个类,这个类里面有你要的那些值
- 返回的是某个对象,还想返回其他东西,则形参定义引用,然后通过引用改变外面那个值(实参),最后在函数外使用实参即可得到。
- 返回类型void,全部使用指针或者引用来完成
6.2.3 const形参和实参
①
void fcn(const int i){} //fcn能读取i,但不能像i写值
void fcn(int i){} //错误,重复定义fcn(int)
上述代码看起来好像是重载,但是利用实参初始化形参时,如果形参有顶层const,传给它的常量对象或者非常量对象都是可以的。那么,当主调函数在调用fcn的时候,用的实参都是非常量对象,那编译器就无法区分到底应该调用哪一个fcn了,因为两个都可以匹配。
6.2.4 数组形参
//一维
void print(const int*);
void print(const int[]);
void print(const int[10]);
void print(int (&arr)[10]); //数组引用形参
对于多维数组来说,数组的第二维(以及后面所有维度)的大小都是数组类型的一部分,不能省略。
//多维
void print(int (*matrix)[10],int rowSize); //第二维是10个int的数组,其实这么看*(matrix[10])更好理解
void print(int matrix[][10],int rowSize);
6.2.5 main:处理命令行选项
prog -d -o ofile data0
int main(int argc,char *argv[]){}
int main(int argc,char **argv){}
当实参传给main函数之后,argv的第一个元素指向程序的名字或者一个空字符串,接下来的元素依次传递命令行提供的实参。最后一个指针之后的元素值保证为0。
如上面命令行,argc为5。
argv[0] = "prog"; //argv[0]保存程序的名字,而非用户输入
argv[1] = "-d";
argv[2] = "-o";
argv[3] = "ofile";
argv[4] =