下面我们通过一个例题来看一下传值调用和传址调用分别是怎么回事。
我会详细的讲讲为什么通过函数的传值调用,交换不了main函数里的两个数,以及我们可以通过什么方法解决这个问题。
悄悄告诉你们:我以前只知道通过函数的传值调用交换不了main函数里的两个数,但是一直不知道为什么不行。如果你现在也有这个疑惑,不妨端好小板凳,坐下,听我详细给你讲讲其中的原理吧。
目录
例题:交换两个变量
例题:
“写一个函数可以交换两个整形变量的内容”
一、不通过写外部函数来交换
首先,如果不通过写外部函数来交换两个数的值,是这样的:
#include<stdio.h>
int main()
{
int a = 10;
int b = 20;
int c = 0;
printf("交换前:a=%d b=%d\n", a, b);
c = a;
a = b;
b = c;
printf("交换后:a=%d b=%d\n", a, b);
return 0;
}
输出
交换前:a=10 b=20
交换后:a=20 b=10
但现在,我们需要通过写一个外部函数来交换a和b,
二、试图通过函数传值调用来交换两个数
按上面的思路,我们就写出了以下代码:
#include<stdio.h>
void Swap(int x, int y)
{
int z = 0;
z = x;
x = y;
y = z;
}
int main()
{
int a = 10;
int b = 20;
printf("交换前:a=%d b=%d\n", a, b);
//函数
Swap(a, b);
printf("交换后:a=%d b=%d\n", a, b);
return 0;
}
但我们运行一下
发现运行结果是这样的:
交换前:a=10 b=20
交换后:a=10 b=20
a和b的值并没有改变。
这是为什么呢?
传值调用原理
其实,
实参a和b,传给形参x,y的时候,形参将是实参的一份临时拷贝,
改变形参变量x,y,是不会影响实参a和b的。(实参和形参的概念和总结放在文章最后面,有需要,可以先看)
详细点,我们来看看,原理是这样的:
我们创建了一个a和一个b,a中放有值10,b中放有值20;
然后通过函数Swap传参,创建变量x和变量y,x中得到a的10,y中得到b的20.
然后,通过变量z,来交换x和y的值。
我们要知道,x,y分别是一个独立的内存空间,x、y的值变化,根本就不会影响到a和b。
所以a和b的值根本不会交换。
#那么我们怎么解决以上问题呢?
三、通过函数传址调用来交换两个数(正解)
我们从上面的例子可以看到,从空间的角度上来说,实参和形参之间并没有建立联系,以上方式形参是改变不了实参的。所以下面我们就需要给它们来建立联系。
我们通过一个指针变量pa来获得a的地址。
int a = 10;
int* pa = &a;
通过pa来改变a的值
*pa = 20;//将pa指向的地址中的值(即a中存的值)改为20
这样,pa中存了a的地址,这样一来,pa和a就建立了联系。可以通过pa找到a的地址,进而改变a的值。
#include<stdio.h>
int main()
{
int a = 10;
int* pa = &a;
*pa = 20;
printf("%d\n", a);
return 0;
}
运行一下,得到
20
可以看到确实改变了a的值。按照这个思路,我们把a和b的地址传给Swap函数
Swap(&a, &b);
那么我们外面的Swap函数的参数就应该是指针变量,因为Swap(&a, &b)这个里面传的是地址,地址应该放到指针变量里面去,
Swap(int* px, int* py)
{
}
指针px里面存a的地址,py里面存b的地址
通过变量z来交换px所指向地址中的值(即a的值)和py所指向地址中的值(即b的值)
void Swap(int* px, int* py)
{
int z = 0;
z = *px;//*px相当于是a
*px = *py;//*py相当于是b
*py = z;
}
整个代码就是这个样子
#include<stdio.h>
void Swap(int* px, int* py)
{
int z = 0;
z = *px;
*px = *py;
*py = z;
}
int main()
{
int a = 10;
int b = 20;
printf("交换前:a=%d b=%d\n", a, b);
//函数
Swap(&a, &b);
printf("交换后:a=%d b=%d\n", a, b);
return 0;
}
如果这里还没懂,别慌,我们画一个图来看看它的原理吧:
传址调用原理
最开始,我们创建了一个变量a和b,它们的值分别是10和20.
a和b在内存中开辟空间,假设,a这块空间的起始地址为0x0012ff40
b这块空间的起始地址为0x0012ff48;
然后我们通过Swap函数传参,a的地址(0x0012ff40)传给px,b的地址(0x0012ff48)传给py,此时px中放的就是a的地址
通过px和py找到a和b的地址,从而交换a和b的值。
把传值调用和传址调用放一起来看看。
函数的参数的概念
下面我们再来看一下函数的参数的概念:
函数的参数
1 实际参数(实参):
真实传给函数的参数,叫实参。实参可以是:常量、变量、表达式、函数等。
无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。
2 形式参数(形参):
形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内存单元),所以叫形式参数。
形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有效。
上面Swap1和Swap2函数中的参数x,y,px,py都是形式参数。在main函数中传给Swap1的a,b和传给Swap2函数的&a,&b是实际参数。
由于我的能力有限,如有错误,欢迎指正!
如果这篇文章对你有帮助,记得点赞和关注哦!
我最近在总结相关内容,可以关注我,查看我的更多文章。
毕竟,我们要一起学习,一起进步!