函数的参数。每次调用函数的时候,都会重新创建函数的所有形参。然后用传递的实参初始化对应的形参。函数结束后,形参自动释放(非动态申请的内存)。。
函数的形参分为两类:
1、非引用形参。
void exchange(int a,int b) { int temp=a; a=b; b=temp; }
该exchange函数的目的是交换a 和 b的值,但是不能实现,函数结束后a、b的值不变。
普通的非引用形参通过复制对应的实参进行初始化,函数不会修改实参的值。
(1)要特别说一下非引用指针形参。
函数的形参可以是指针,此时将复制实参指针。也就是说,对形参的任何操作不会影响实参指针的值(说明:指针的值指的是指针里边存放的地址,而不是指针所指的对象的值)。
void test(int *p) { p=0;//修改形参指针的值,对实参无影响 *p=0;//修改形参指针所指对象的值,则,实参指针所指对象的值发生改变。 }
如果需要保护实参指针所指对象的值,参考下边的const形参。
(2)形参为const类型。
要区别,const类型形参和指向const类型的指针形参。
指针形参是指向const还是非const类型(注意:是指向const类型,而不是说指针是const类型(const指针))直接影响函数所使用的实参。既可以用指向const类型也可以用非const类型的指针实参调用形参为指向const类型的函数,即,可以用int *,也可以用const int*类型的实参去调用test2函数,而只能将int *类型的实参传递给test1函数。
void test1(int *p);
void test2(const int *p);
这是由于指针的初始化规则,即不能将const对象的地址赋给指向非const对象的指针。因为指向非const队形的指针所指向的对象大内容可以改变,而const对象的值不能改变,所以会导致编译时的错误。
const类型的形参(包括const指针,不再赘述):
不管是不是从const类型的形参的函数,可以将const和非const类型的实参传递进去。即,可以将int 和const int类型的实参传递给func1和func2.这是因为函数不可能更改实参的值,函数操作的始终只是实参的局部副本。
void func1(int p);
void func2(const int p);//或者是void func(int *const p);----const指针。
在c语言中,具有const形参或非const形参的函数并无区别。
2、引用类型形参。。那么形参是实参的别名儿,另一个名字。对形参的所有操作都会同样反映到实参上边。
void exchange(int a,int b) { int temp=a; a=b; b=temp; }
相比于非引用类型形参的exchange函数,这个函数就能实现两个数的交换。
(1)使用引用类型返回额外的信息。
函数只能有一个返回值,而有些函数不只要求一个返回值,这时就可以利用将某个形参设置为引用类型,因为引用类型传递给函数的是实参本身(有点儿不恰当,但就是这个意思),所以可以对这个引用参数进行操作,函数调用结束后即相当于返回个一个值。
(2)使用引用形参可以避免复制。
在给函数传递某些大型对象或者某些不能复制的对象时候,如果用非引用类型的形参,效率就太低了,此时我们可以用引用类型形参,避免参数的复制。
使用引用形参的唯一目的是避免复制实参,则应该将形参定义为const引用。
如前所述,如果函数具有非const引用的形参,就不能通过const对象对其进行调用。而此时,也不能将右值(只能放在“=”的右边,即常量)或者需要进行强制转换的对象传递给它。即,非const引用的形参只能和完全同类型的非const对象相关联。eg:
int find_char(string &s,char c) { int i=0; while(i!=s.size() && s[i]!=c) { ++i; } return i; }
这个函数带来的问题是不能通过字符串字面值来调用该函数。
int num=find_char("HelloWorld",'l');
"HelloWorld"需要被转换为string对象,但是上述调用会导致编译失败。。所以最好将不需要修改的引用形参定义为const引用,普通的非const引用形参在使用时不太灵活,既不能用const对象初始化,也不能用右值或者需要类型转换的对象初始化。
(3)传递指向指针的引用
需要修改指针的值(不再赘述),就可以将指针形参设置为引用类型。
[主要参考C++ primer。。。。]