函数参数的操作实际就是堆栈操作: 函数名也是个地址,它把参数一个一个压入栈中,返回时再一个一个弹出栈中,这也就是为什么函数返回后函数中的数据不可用的原因。
函数的参数是怎么分配的:
一个参数在栈中有一个地址,如果是值传递这个地址的值就是实参的值,如果是址传递,这个地址的值就是实参的地址
函数参数传递分为址传递和值传递:
址传递---把实参的地址传递到函数中,这样在函数里做的操作就是对实参原形的操作.
值传递---把实参的值拷贝刀参数的存储区中,函数不会访问当前调用的实参,函数处理的值是它本地的拷贝,这些拷贝被存储在运行栈中,因此改变这些值不会影响实参的值。
swap的三种实现方法:
1.
void pswap(int *v1, int *v2){
int tmp=*v1;
*v1=*v2;
*v2=tmp;
}
调用的时候pswap(&v1, &v2);
2.
void rswap(int &v1, int &v2){
int tmp=v1;
v1=v2;
v2=tmp;
}
调用的时候rswap(v1,v2);
3.
void ptrswap(int *&v1, int *&v2){
int *tmp=v2;
v2=v1;
v1=tmp;
}
调用的时候 ptrswap(v1, v2);
引用和指针参数:
相同:都允许函数修改实参指向的对象,都允许有效地向函数传递大型类对象。
不同:引用必须被初始化为指向一个对象,一旦初始化了,它就不能再指向其他对象;指针可以指向一系列不同的对象也可以什么都不指向。因为指针的这种特点,函数在确定指针实际指向一个有效的对象之前不能安全地解引用一个指针,例如
class X;
void manip(X *px){
//在解引用指针之前确信它非0
if(px!=0)
//解引用指针
}
对于引用参数,函数不需要保证它指向一个对象,例如
class Type{};
void operater(const Type& p1, const Type& p2);
int main(){
Type obj1;
//设置obj1为某个值
Type obj2=operate(obj1, 0);//错误:引用参数的实参不能为0
}
数组作函数参数:数组被传递为指针,下列三个声明等价
void putValues(int* );
void putValues(int[]);
void putValues(int[10]);数组长度不是参数类型的一部分,编译器检查实参类型时不检查数组长度。
可以分为如下三种情况:(这三种情况的结果相同,只是所采用的调用机制不同)
1. 形参和实参都用数组
调用函数的实参用数组名,被调用函数的形参用数组,这种调用的机制是形参和实参共用内存中的同一个数组。因此,在被调用函数中改变了数组中某个无素的值,对调用函数该数组的该元素值也被改变,因为它们是共用同一个数组。
函数定义 void test(Class c[]){
......c[i].......
}
调用的时候 test(c);
2. 形参和实参都用对应数组的指针
在C++中,数组名被规定为是一个指针,该指针便是指向该数组的首元素的指针,国为它的值是该数组首元素的地址值,因此,数组名是一个常量指针。实际中,形参和实参一个用指针,另一个用数组也是可以的。在使用指针时可以用数组名,也可以用另外定义的指向数组的指针。
3. 实参用数组名形参用引用
如何对数组类型使用引用方式,这里先做如下说明:先用类型定义语句定义一个int型的数组类型,如下所示:
typedef int array[8];
然后,使用array来定义数组和引用。
示例:
#include <iostream.h>
typedef int array[8];
int a[8] = {1, 3, 5, 7, 9, 11, 13};
void fun(array &b, int n) {
for(int i=0; i<n-1; i++)
b[7]+=b[i];
}
void main()
{
int m=8;
fun(a, m);
cout<<a[7]<<endl;
}
该程序中,在fun()函数中,使用了引用作形参,调用时所对应的实参应该是一个数组名,这里的引用是给数组起个别名。在fun()函数中对数组b的操作,就相当于b所引用数组a的操作。在C++中,常用这种调用方式。