1.函数的定义:
函数主要包括:返回类型、函数名、形参表、函数体几个部分组成。
2.函数参数的传递:
(1)非引用型形参:参数是通过复制对应的实参实现初始化。当用实参副本初始化形参时,函数并没有访问调用所传递的实参本身,因此不会修改实参的本身。如:int gcd(int v1,int v2)
{
while(v2){
int temp=v2;
v2=v1%v2;
v1=temp;
}
return v1;
}
循环体虽然修改了v1,v2的值,但这些变化仅限于局部参数,而对调用gcd函数使用的实参没有任何的影响。
(2)指针形参:函数的形参可以是指针,此时将复制实参指针。与其他的非引用类型的形参一样,该类形参的任何改变也仅作用于局部副本。如果函数将新指针值赋给形参,主调函数使用的实参指针的值没有改变。如:void reset(int *ip){}
(3)const形参:在调用函数时,如果使用非引用的非const形参,则既可以给该函数传递const实参也可以传递非const的实参。
如果将形参定义为非引用的const类型:void fcn(const int i){} 则在函数中,不可以改变实参的局部副本(意思就是说因为形参是const类型的,在函数体中不能改变这个形参的值)。由于实参仍然是以副本的形式传递的,因此传递给fcn的既可以是const对象也可以是非const对象。
以上三种都是采用复制实参的形式传递参数的,存在一定的局限性:1.当需要在函数中修改实在的时候,2.但需要以大型对象作为实参传递时,对实际的应用而言,复制操作所付出的时间和存储空间代价往往过大,3.当没有办法实现对象的复制时。这三种情况下不宜采用复制实参的形式。
(4)引用形参:与所有引用一样,引用形参直接关联到其所绑定的对象,而并非是这些对象的副本。定义引用时,必须用与该引用绑定的对象初始化该引用。通过引用形参可以修改实参的值。如 void swap(int &v1,int &v2 ){}
《1》使用引用形参返回额外的信息:由于函数只能返回单个值,而有些时候,函数有不止一个的内容需要返回。我们可以定义一个引用型的形参来返回相应的值。如:vector<int>::const_iterator find_val(vector<int>::const_iterator beg,vector<int>::const_iterator end,int val,vector<int>::size_type &occur){},在函数体中通过改变occur的值,相应的实参的值也随之改变,从而达到返回参数的目的。
《2》利用const引用避免复制:在想函数传递大型对象时,需要使用引用形参,这是引用形参适用的另一种情况。如: bool isshorter(const string &s1 ,const string &s2){},此种方式形参只是引用实参并不能修改实参。
《3》对于非const引用形参只能与完全同类型的非const对象关联。应该将不修改相应实参的形参定义为const引用。
《4》传递指向指针的引用:void ptswap(int *&v1 ,int *&v2){},形参int *&v1的定义应该从右至左理解,v1是一个引用。与指向int型对象的指针相关联。注意:指针的引用关联的是指针,改变的也是指针。而指针指向的值并没有改变。
《5》数组形参:其数组形参的定义方式:void printvalue(int *){},void printvalue(int []){},void printvalue(int [10]){}.虽然形参的表示方式不同,但是可以将使用数组语法定义的形参看做指向数组元素类型的指针。在这种情况下,编译器会忽略数组的长度。如:void printvalue(int ia[10]){}.这时候数组长度10编译器会忽略。
通过引用传递数组:void printvalue(int (&ia)[10]){},此时数组的长度10也是形参的一部分。
<6>传递给函数的数组的处理:有三种常见的编程技巧确保函数的操作不超过数组实参的边界。
1.在数组本身放置一个编辑来检测数组的结束。如C风格字符串采用这种方式。
2.传递指向数组第一个和最后一个元素的下一个位置的指针。如:void printvalue(const int *beg,const int *end){},int j[2]={0,1}; printvalue(j,j+2);
3.将第二个形参定义为表示数组的长度。void printvalue(const int ia[] ,size_t size ){}。
(后续)