您的位置:首页 > 编程语言 > C语言/C++

【转】C++函数——指针和引用类型的参数传递

2012-10-12 16:03 751 查看
普通的函数形参:

void fun(int v1,int v2)
{
cout<<v1<<"\t"<<v2<<endl;
}

这就是一个最基本的带有两个普通形参的void型函数,在函数的()中定义的两个变量就是函数的形参。在调用函数时,编译器用实参对形参初始化并运行程序,需要指出的是形参只是实参的副本,这一过程中形参的可以重新赋值,而实参的值不会相应发生变化,可以举个例子:

void fun(int v1,int v2)
{
int num=v1;v1=v2;v2=num;
cout<<v1<<"\t"<<v2<<endl;
}
int main()
{
int num1=10;int num2=20;
fun(num1,num2);
cout<<num1<<"\t"<<num2<<endl;
return 0;
}

运行结果:

20 10

10 20

这个例子证明了对形参的重新赋值不会改变实参的值,这就是最基本的函数参数传递,这里不再做详细讨论,下面我想说的是指针的形参是指针类型和引用类型的情况。

一.指针形参的传递(非引用形参的传递)

函数的参数可以是指针,它与普通类型的形参一样,形参的任何改变只作用于形参局部副本,也就说是当对形参重新赋值时,函数的实参不会发生变化

void fun(int *p,int *q)
{
cout<<*p<<"\t"<<*q<<endl;
int num=*p;
*p=*q;*q=num;
cout<<*p<<"\t"<<*q<<endl;
p=0;q=0;
cout<<p<<"\t"<<q<<endl;
}
int main()
{
int num1=10;int num2=20;
int *ptr1=&num1;int *ptr2=&num2;
cout<<num1<<"\t"<<num2<<endl;
cout<<ptr1<<"\t"<<ptr2<<endl;
fun(ptr1,ptr2);
cout<<num1<<"\t"<<num2<<endl;
cout<<ptr1<<"\t"<<ptr2<<endl;
return 0;
}

运行结果:

10 20

0x22ff74 0x22ff70

10 20

0 0

20 10

0x22ff74 0x22ff70

这是在我机器上运行的结果,当然了,你运行的是时候可以能得到的地址值是不一样的,因为他在内存中分配的空间不同,得到的结果当然不会相同,不过这个不关键。我们来看,由于函数为指针类型的形参,为了容易理解,我们在调用函数之前先输出num1,num2以及指针ptr1,ptr2的值以便比较。我们来看函数部分,我通过中间量交换了*p与*q的值并输出他们两个值,然后又将两个形参赋值为0,并输出其值,然后调用函数之后,我又输出了num1,num2以及实参ptr1,ptr2的值。

从运行结果中我们发现,与普通形参调用不同的是num1与num2的值发生了变化,相同的是实参没有变化,而且形参的一切操作都没有改变实参的值(函数中我将形参重新赋值了,形参发生了变化,但从运行结果中可以看出,实参没有发生变化)。

我们来总结一下,调用形参为指针类型的函数时,实参必须是指针(或者是取地址操作后的对象如&num1,&num2),在编译时,函数的形参用主调函数所给的实参初始化。以本例解释也就是说,编译时系统将p初始化为ptr1的副本,它内部存储的地址与ptr1存储的地址相同,也就是说*p与*ptr1指向的是同一个对象,因此当对*p和*q交换值时实际上是交换了它们所指向的对象的值,也就是交换了num1和num2的值。继而我将p和q赋值为0,目的是改变形参,输出他们的值以便与比较。然后在调用完函数之后,我在主调函数中输出了实参ptr1和ptr2的值,以及num1和num2的值,通过运行结果,我们就发现了我们的推断都是正确的!那就是:任何对非引用形参的操作都不会改变实参的值,即使是指针类型的形参!

值得提出的是,指针形参的操作固然有好处,但如果我们不想改变实参所指对象的值,那又该怎么办呢?这时我们需要const关键字。我们先这样,你可以将上面程序的函数形参定义为const类型运行并看报错,你会发现*p=*q;*q=num;操作是不合法的,这是因为const关键字的作用!大家都知道,当定义指针指向const类型对象或者定义const类型对象的引用时需要在指针前加const,即const
int a=1;const int *p=a
; const int& b=a;但如果我们这样int a=1;const int *p=a; const int& b=a;会产生什么结果呢?(大家知道的是const int *与int *const 是不同的,这里不做详细解释,可以参考本blog知识点文章——“学习标准C++Primer过程中发现的几个需要注意的问题”)首先const int *p=a; const int& b=a;此操作使得程序不能通过*p或者b来修改a的值(当然了,a的值仍然是可以改变的,例如直接赋值或者通过其他指针或者引用),根据这一现象,我们在函数的形参上加const,就确保了函数中所有改变指针所指对象值的操作都是非法的,这样就实现了这一功能。

可以参考如下程序:

void fun(const int *p,const int *q)
{
cout<<*p<<"\t"<<*q<<endl;
p=0;q=0;
cout<<p<<"\t"<<q<<endl;
}
int main()
{
int num1=10;int num2=20;
int *ptr1=&num1;int *ptr2=&num2;
fun(ptr1,ptr2);
cout<<ptr1<<"\t"<<ptr2<<endl;
return 0;
}

运行结果:

10 20

0 0

0x22ff74 0x22ff70

二.引用参数的传递

1.普通类型的引用参数

还是先解释下什么是引用参数吧!这里我们还是沿用上篇文章的例子吧!

oid fun(int& a,int &b)
{
cout<<"这是实参传递给a b的值 \t<<"<<a<<">>\t<<"<<b<<">>"<<endl;
int num=a;
a=b;b=num;
cout<<"这是函数操作后的a b值 \t<<"<<a<<">>\t<<"<<b<<">>"<<endl;
}
int main()
{
int num1=10;int num2=20;
cout<<"这是调用前的num1和num2\t<<"<<num1<<">>\t<<"<<num2<<">>"<<endl;
fun(num1,num2);
cout<<"这是调用后的num1和num2\t<<"<<num1<<">>\t<<"<<num2<<">>"<<endl;
return 0;
}

运行结果:

这是调用前的num1和num2 <<10>> <<20>>

这是实参传递给a b的值 <<10>> <<20>>

这是函数操作后的a b值 <<20>> <<10>>

这是调用后的num1和num2 <<20>> <<10>>

这是一个简单的函数形参为引用的典型例子。我先解释一下这个函数的运行,与前面不同的是我加了汉字解释,这样更容易区分,为了方便比较结果我先打印了数值num1和num2的值,然后调用函数,先打印实参传递过来的值,直接操作参数,对其值进行交换,然后再输出操作后参数的值,最后在主调函数中打印调用函数后实参的值,这是程序的运行过程,我们比较结果不难发现,引用形参的函数与普通形参或者指针形参函数的不同在于函数引用形参调用后,它修改了实参的值!!!

2.const类型的引用参数

有时候程序并不需要它本有的特性,有时候我们的代码并不需要修改实参的值,这时候难道就不能用引用类型的的形参吗?其实到这里都能想到了,正如指针所具有的特性一样,指针类型形参的特点是能改变其所指对象的值,而我们加了const就改变这点,那么在这里加const有没有同样的效果呢??我们不妨用个例子来说明一下。

void fun(const int& a,const int &b)
{
cout<<"这是实参传递给a b的值 \t<<"<<a<<">>\t<<"<<b<<">>"<<endl;
int num=a;
a=b;b=num;
cout<<"这是函数操作后的a b值 \t<<"<<a<<">>\t<<"<<b<<">>"<<endl;
}
int main()
{
int num1=10;int num2=20;
cout<<"这是调用前的num1和num2\t<<"<<num1<<">>\t<<"<<num2<<">>"<<endl;
fun(num1,num2);
cout<<"这是调用前的num1和num2\t<<"<<num1<<">>\t<<"<<num2<<">>"<<endl;
return 0;
}

系统报错:

lab.cpp: In function `void fun(const int&, const int&)':

lab.cpp:10: error: assignment of read-only reference `a'

lab.cpp:10: error: assignment of read-only reference `b'

这个例子我只把上面程序函数的形参加了const关键字,我们看一下报错啊,先声明一下啊,我英语四级成绩刚够线,六级也不准备考了,我的意思是说编程工具报错的英语虽然不容易看懂,但是当你多次编译的时候就能才出它的意思了,我们来猜一下,第一行,在函数void fun(const int&, const int&)'中,第二行:错误,a是只读类型的指针。第三行:b是只读类型的指针。这并不是说加了const之后a和b的值都不能改变了,这是值得提出的,const关键字在此处的作用是把引用定义为只读的,也就是说,引用所指向的对象的值不能改变!但是由于引用只能在定义时初始化,a和b的值也是不能改变的,但这不是const的作用。

最后 我觉得有必要提出的是:传递指向指针的引用。

void fun(int* &a,int* &b)
{
cout<<"这是实参传递给a b的值 \t<<"<<a<<">>\t<<"<<b<<">>"<<endl;
cout<<"这是实参传递给*a*b的值\t<<"<<*a<<">>\t<<"<<*b<<">>"<<endl;
int *num=a;
a=b;b=num;
cout<<"这是函数操作后的a b值 \t<<"<<a<<">>\t<<"<<b<<">>"<<endl;
cout<<"这是函数操作后的*a*b值\t<<"<<*a<<">>\t<<"<<*b<<">>"<<endl;
}
int main()
{
int num1=10;int num2=20;
int *ptr1=&num1;int *ptr2=&num2;
cout<<"这是调用前的num1和num2\t<<"<<num1<<">>\t<<"<<num2<<">>"<<endl;
fun(ptr1,ptr2);
cout<<"这是调用前的num1和num2\t<<"<<num1<<">>\t<<"<<num2<<">>"<<endl;
return 0;
}




这里我不再对程序作解释,大家可以按上面的方式理解一下程序,我想告诉大家的是这虽然是形参的一种特殊形式,但这完全可以看作是对指针对象的引用,也就是说把指针当做实参传递给函数,函数中通过对形参的换值,把实参指针存储的地址做了交换,从而交换了指针所指的空间,继而*ptr1*ptr2的值发生了变化,而num1和num2的值没有变化!!

注:后面的内容作者表达的有点乱,但总体来说值得看看,理清了一些关系。当然,函数部分还有很多值得我们探讨的内容,可以自己再进行总结。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐