通过例题“交换两个变量”,来看一下“传值调用”和“传址调用”分别是怎么回事。(附函数形参、实参的概念)

下面我们通过一个例题来看一下传值调用传址调用分别是怎么回事。
我会详细的讲讲为什么通过函数的传值调用,交换不了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是实际参数。

由于我的能力有限,如有错误,欢迎指正!
如果这篇文章对你有帮助,记得点赞关注哦!
我最近在总结相关内容,可以关注我,查看我的更多文章。

毕竟,我们要一起学习,一起进步!
请添加图片描述

猜你喜欢

转载自blog.csdn.net/m0_53558236/article/details/119597225