你知道C语言函数调用常用的2种方式吗

本篇博客会讲解C语言函数调用的2种方式,分别是:传值调用和传址调用。这2种函数调用方式有什么区别呢?为什么会有不同的效果呢?分别有哪些用途呢?下面我会一一展开。

区别

传值调用,即通过传递变量的值来调用函数。

传址调用,即通过传递变量的地址来调用函数。

比如,假设有2个变量a和b,对于变量a和b来说test(a, b)就是传值调用,test(&a, &b)就是传址调用。

原理

这时你可能很好奇:这2种调用方式的原理是什么呢?其实非常简单。

先举个传值调用的例子:

// 函数定义
int Add(int x, int y)
{
	return x + y;
}
// 调用
int a = 3, b = 5;
int sum = Add(a, b);

在上面的代码中,我们分别把a和b的值传递给了Add函数中的x和y。此时,我们称:a和b是“实际参数”,简称实参;x和y是“形式参数”,简称形参。传值调用的方式,会把实参的值传递给形参,也就是说,把a中的3传递给x,此时x就是3,把b中的5传递给y,此时y就是5。在Add函数内部,把x+y的值带回来,也就返回3+5的值,即返回8,再把返回值赋值给sum,sum就是8。

再举个传址调用的例子:

// 函数定义
int Add(int* p1, int* p2)
{
	return *p1 + *p2;
}
// 调用
int a = 3, b = 5;
int sum = Add(&a, &b);

以上就是典型的传址调用,但是很显然在这个场景下,我们只想“求和”,使用传址调用有点多此一举,但是还是分析一下原理:我们把a和b的地址传给了p1和p2,此时p1存储了a的地址,p2存储了b的地址,p1就指向了a,p2就指向了b。我们想在Add函数内部求和,就要先对p1解引用,拿到a的值,再对p2解引用,拿到b的值,再把拿到的a和b的值加起来返回,此时sum就被赋值为函数的返回值,即8。

以上只是非常粗略的带大家了解了传值调用和传址调用的区别。下面用一个经典的例子进行更加深入的讲解。这个例子就是:写一个函数,交换2个整数的值。

使用传值调用的方式,写出来的函数如下:

// 定义
void Swap(int x, int y)
{
	int tmp = x;
	x = y;
	y = tmp;
}

// 调用
int a = 3, b = 5;
Swap(a, b);

下面我通过调试的方式,来带大家看一下这个程序会如何执行。

你知道C语言函数调用常用的2种方式吗

代码即将执行Swap(a, b);,此时a的值是3,b的值是5。接下来执行这条语句:

你知道C语言函数调用常用的2种方式吗

代码来到第17行,此时a和b的值并没有交换?到底发生了啥?

重新开始调试,这次我进入到Swap函数内部看一眼。

你知道C语言函数调用常用的2种方式吗

按照前面的分析,此时x和y拿到了a和b的值,接下来进行交换:

你知道C语言函数调用常用的2种方式吗

代码执行到第10行,此时可以发现,x和y其实已经交换了,但是a和b并没有变化?这又是为什么呢?

此时再回到main函数,发现a和b的值并没有被交换。

你知道C语言函数调用常用的2种方式吗

发现这个问题后,我们可以干一件事,使用下面的代码,把a、b、x、y的地址打印出来:

#include <stdio.h>
void Swap(int x, int y)
{
	printf("&x = %p, &y = %pn", &x, &y);
	int tmp = x;
	x = y;
	y = tmp;
}
int main()
{
	int a = 3, b = 5;
	printf("&a = %p, &b = %pn", &a, &b);
	Swap(a, b);
	return 0;
}

输出结果如下:

你知道C语言函数调用常用的2种方式吗

可以发现,当把a的值传递给x,把b的值传递给y时,x和y,a和b已经是不同的空间了,此时相当于,内存中有4个变量,分别是a、b、x、y,由于值传递,x的值和a相同,y的值和b相同,此时交换了x和y,对a和b的值并没有影响!所以函数调用结束后,a和b的值并没有交换。

这时,我们就可以总结:当我们使用传值调用,实参的值传递给形参后,形参只是实参的一份临时拷贝,改变形参的值并不影响实参的值!

那Swap函数的正确实现形式是怎样的呢?相信聪明的你已经想到了,使用传址调用就行了嘛!

// 定义
void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
// 调用
int a = 3, b = 5;
Swap(&a, &b);

为什么以上的代码就能实现“交换”的效果呢?这就是传址调用的神奇之处!

分析一下:把a的地址传递给p1,把b的地址传递给p2,此时p1就指向了a,p2就指向了b,这时再对p1和p2解引用,就能把a和b的值给修改了!

我们还是通过调试来观察一下细节:

你知道C语言函数调用常用的2种方式吗

进入到函数内部:

你知道C语言函数调用常用的2种方式吗

再回到main函数:

你知道C语言函数调用常用的2种方式吗

成功交换了a和b的值!

用途

根据以上的讲解,可以总结一下传值调用和传址调用的用途:

  • 传值调用适用于不需要修改函数外部变量的场景。
  • 传址调用适用于需要修改函数外部变量的场景。

这是因为,传值调用时,形参是实参的一份临时拷贝,改变形参并不影响实参,所以在函数内部没有能力改变外面的变量的值;传址调用就不一样了,形参保存了函数外部变量的地址,就可以通过解引用的方式,修改函数外部变量的值了。

总结

1.传值调用适用于不需要修改函数外部变量的场景,因为函数内部变量和外部变量并没有建立联系,是独立的空间。

2.传址调用适用于需要修改函数外部变量的场景,因为函数内部存储了指向函数外部变量的指针,建立了联系,可以通过解引用的方式改变函数外部的变量。

以上就是你知道C语言函数调用常用的2种方式吗的详细内容,更多关于C语言函数调用的资料请关注aitechtogether.com其它相关文章!

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
扎眼的阳光的头像扎眼的阳光普通用户
上一篇 2023年5月12日
下一篇 2023年5月12日

相关推荐