函数的定义
求两个int型的最大公约数
int gcd(int v1,int v2)
{
while (v2)
{
int temp = v2;
v2 = v1 % v2;
v1 = temp;
}
return v1;
}
1、函数调用
函数名(实参);
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
int gcd(int v1,int v2);
int main()
{
cout<<"enter two numbers:\n";
int i,j;
cin>>i>>j;
cout<<gcd(i,j)<<endl;
system("pause");
return 0;
}
int gcd(int v1,int v2)
{
int temp;
while(v2)
{
temp=v2;
v2=v1%v2;
v1=temp;
}
return v1;
}
函数在定义或者声明时,没有显式指定返回类型是不合法的。
如果两个参数具有相同的类型,则其类型必须重复声明:
int manip(int i,j) //error
{
//......
}
int manip(int i,int j) //ok
{
//......
}
参数表中不能出现同名的参数。
2、参数传递
每次调用函数时,都会重新创建该函数的所有形参,此时所传递的实参将初始化对应的形参。
形参的初始化与变量的初始化一样:如果形参具有非引用类型,则复制实参的值;如果形参为引用类型,则它只是实参的别名。
2.1、非引用形参
普通的非引用类型的参数通过复制对应的实参实现初始化。当用实参副本初始化形参时,函数并没有访问调用所传递的实参本身,因此不会修改实参的值。
int gcd(int v1,int v2)
{
int temp;
while(v2)
{
temp=v2;
v2=v1%v2;
v1=temp;
}
return v1;
}
While循环虽然修改了v1和v2的值,但这些仅局限于局部参数,而对调用gcd函数使用的实参没有任何影响。于是调用
gcd(i,j);则i与j的值不受gcd内执行的赋值操作的影响。
1、指针形参
函数的形参可以是指针,此时将复制实参指针。与其他非引用类型的形参一样,该类形参的任何改变也仅作用于局部副本。如果函数将新指针值赋给形参,主调函数使用的实参指针的值没有改变。
如果函数形参是非const类型的指针,则函数可通过指针实现赋值,修改指针所指向对象的值。
#include <iostream>
using namespace std;
void reset(int *ip)
{
*ip = 0; // changes the value of the object to which ip points
ip = 0; // changes only the local value of ip; the argument is unchanged
}
int main()
{
int i = 42;
int *p = &i;
cout << "i: " << *p << '\n'; // prints i: 42
reset(p); // changes *p but not p
cout << "i: " << *p << endl; // ok: prints i: 0
}
如果需要保护指针所指向对象的值,则形参需定义为const对象的指针:
void use_ptr(const int *p)
{
}
我们既可以用int*也可以用const int*类型的实参调用use_ptr函数;但仅能用int*类型的实参传递给reset函数。这个差别来源于指针的初始化规则。可以将指向const对象的指针初始化为指向非const对象,但不可以让指向非const对象的指针指向const对象。
2、const形参
如果函数使用非引用的非const形参,则即可给该函数传递const实参也可传递非const实参。例如可以传递两个int型const对象调用gcd函数
const int i=3,j=6;
int k=gcd(i,j);
如果形参定义为非引用的const类型:
void fcn(const int i)
{ }
则在函数中,不可以改变实参的局部副本。由于实参仍然是以副本形式传递,因此传递给fcn的既可以是const对象也可以是非const对象。
3、复制实参的局限性
复制实参并不是在所有的情况下都适合,不适宜复制实参的情况包括:
• 当需要在函数中修改实参的值时。
• 当需要以大型对象作为实参传递时。对实际的应用而言,复制对象所付出的时间和存储空间代价往往过大。
• 当没有办法实现对象的复制时。
对于上述几种情况,有效的解决办法是将形参定义为引用或指针类型。
2.2、引用形参
交换两个实参的值:
#include <iostream>
using namespace std;
void swap(int v1, int v2)
{
int tmp = v2;
v2 = v1; // assigns new value to local copy of the argument
v1 = tmp;
} // local objects v1 and v2 no longer exist
int main()
{
int i = 10;
int j = 20;
cout << "Before swap():\ti: "
<< i << "\tj: " << j << endl;
swap(i, j);
cout << "After swap():\ti: "
<< i << "\tj: " << j << endl;
system("pause");
return 0;
}
结果显示如下,两个实参的值并未交换,执行swap函数只是交换了实参的局部副本。
为了交换实参的值,需要将形参定义为引用类型
void swap(int &v1, int &v2)
{
int tmp = v2;
v2 = v1;
v1 = tmp;
}
引用形参直接关联到其所绑定的对象,而并非这些对象的副本。因此,当调用swap
swap(i, j);
形参v1只是对象i的另一个名字,而v2则是对象j的另一个名字。对v1的任何修改实际上也是对i的修改。
如果使用引用形参的唯一目的是避免复制实参,则应将形参定义为const引用。
如果函数具有非const引用形参,则不能用const对象进行调用,因为此函数可以修改传递进来的对象,这就违背了实参的const特性。