swap函数中体现出的c语言函数的值传递机制(形参中int * &是什么意思)
目前初学C语言,对于深层内存机制了解不是十分透彻,只是将自己的理解方式简单记录一下。
我们知道交换两个变量的数值非常简单,只需要一个中间变量swap
void main(){
int a=3, b=5,swap;
swap = a;
a = b;
b = swap;
}
这样就完成了a和b两个变量的数值交换,但是当我们把这段代码原封不动的搬进一个函数swap里好像又不是这么回事了。
无法达到预想目的swap函数
void swap(int x, int y){
int swap;
swap = x;
x = y;
y = swap;
}
void main(){
int a=3, b=5;
printf("交换前:a=%d,b=%d\n",a,b);
swap(a,b);
printf("交换后:a=%d,b=%d\n",a,b);
}
交换前a=3,b=5
交换后a=3,b=5
请按任意键继续. . .
这时我们惊奇的发现明明一模一样的代码搬进了函数里但是变量a与b却并没有按照预想中的一样交换数值。 那么这段代码在内存中是什么样子的呢
刚刚进入swap函数时: 每个函数都有一个独立的变量空间,当执行到swap(a,b)时,swap中定义的形参x、y只是拿到了a、b两个变量中存储的值的复制品,它们甚至不知道a、b的存在,这两组变量是完全独立互不影响的。
当函数执行完之后: 当一个函数执行完毕时也就是它的变量空间销毁的时刻,因为main函数执行完毕意味着程序的结束,所以main中的变量一直伴随着程序存在。
图片上是swap函数刚刚执行完毕即将销毁变量空间时里面的变量值,我们可以看到事实上在swap的变量空间中已经完成了交换,但是功能的完成也意味着自己的销毁,无法影响a、b的值也无法展示出来,只能默默的毁灭。
能够成功完成使命的swap函数
通过上面的例子我们知道形参是无法影响实参的值的,因为它们在两个空间中,注定不能相遇。但是好在C语言有指针的存在。 这里我决定先画出来原理再写代码。
指针是通过存储变量地址来指向变量,那么即使*x、*y拿到的是地址的复制品也不影响它们存在的期间指向a、b的事实,那么现在实际上有两个指针(*a,*x)指向a,两个指针(*b,*y)指向b,这两个指针地位是一样的,都可以直接读取和修改a、b的值,所以我们就可以通过这点来改变a、b的值。
实际代码如下:
void swap(int *num1, int* num2){
int swap;
swap = *num1;
*num1 = *num2;
*num2 = swap;
}
void main(){
int a=3, b=5;
int *c=&a, *d=&b
printf("交换前a=%d,b=%d\n",a,b);
swap(c,d);
printf("交换后a=%d,b=%d\n",a,b);
}
交换前a=3,b=5
交换后a=5,b=3
请按任意键继续. . .
在调用swap函数时我们没有直接传入a、b,而是传入了&a、&b(即a、b的地址,亦即最左侧的那栏c、d) 下面是swap刚执行完即将销毁时各个变量的值:
我们可以看到在swap函数中我们没有改变x和y的值,而是通过*x 和 *y直接修改了它们指向的a、b变量中存储的值。也就达到了交换值的目的。
现在我们也就不难发现另一种写法中的错误了:
又一种错误写法
void swap(int *num1, int *num2){
int *swap;
swap = num1;
num1 = num2;
num2 = swap;
}
void main(){
int a=3, b=5;
int *c=&a, *d=&b
printf("交换前a=%d,b=%d\n",a,b);
swap(c,d);
printf("交换后a=%d,b=%d\n",a,b);
}
交换前a=3,b=5
交换后a=3,b=5
请按任意键继续. . .
在这个swap函数中刚开始执行时内存结构和正确的情况是相同的,我们直接来看一下执行结束时的结果:
我们可以看到swap函数中只是交换了x、y中存储的地址值,也就是改变了x、y指向的变量的值,main函数的变量空间还是没有任何改变。
最后再看看(int * &)是什么意思
这个语法是C++中的引用类型,但不知道为什么C语言也可以用,我们直接来看看代码和最后的结果。
void swap(int* &num1, int* &num2){
int * temp;
temp = num1;
num1 = num2;
num2 = temp;
}
void main(){
int a =3,b = 5;
int *c=&a, *d=&b;
printf("交换前a=%d,b=%d\n",a,b);
swap3(c,d);
printf("交换后a=%d,b=%d\n",a,b);
}
交换前a=3,b=5
交换后a=5,b=3
请按任意键继续. . .
和刚刚的代码效果一样啊,那这多加的一个&有什么用呢?看看内存结构就一目了然了。
其实效果很简单,就是让实参与形参同步变化。实质上是将实参这个空间直接给形参,即形参和实参公用一个空间(或者说是给实参空间又起了一个别名)。这个加了&的就叫引用变量。实际内存中就是这样的: 这样就可以实现形参与实参的同步改变了,因为它们实际上是一个人的两个名字,叫哪个说的都是同一个人。在swap函数结束时销毁掉的也只是x、y这两个名字,而不是那个人。
这样的话是不是就有一个大胆的想法,交换函数哪儿还用这么麻烦还要用指针,这个想法还真没问题。
利用引用变量来直接完成swap函数
void swap4(int & x,int & y){
int temp;
temp = x;
x = y;
y = temp;
}
void main(){
int a=3, b=5;
printf("交换前:a=%d,b=%d\n",a,b);
swap(a,b);
printf("交换后:a=%d,b=%d\n",a,b);
}
交换前a=3,b=5
交换后a=5,b=3
请按任意键继续. . .
但是引用变量在C语言中使用好像和C语言文件的后缀有关系,.cpp文件可以成功编译。不管怎样我们最终的目的并不是单纯的写一个可以实现值交换的函数,而是理解C语言函数的值传递机制。
|