你知道C语言函数调用的2种方式吗?传值调用 && 传址调用

这篇具有很好参考价值的文章主要介绍了你知道C语言函数调用的2种方式吗?传值调用 && 传址调用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

你知道C语言函数调用的2种方式吗?传值调用 && 传址调用

区别

  1. 传值调用,即通过传递变量的值来调用函数。
  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 = %p\n", &x, &y);
	int tmp = x;
	x = y;
	y = tmp;
}

int main()
{
	int a = 3, b = 5;
	printf("&a = %p, &b = %p\n", &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. 传址调用适用于需要修改函数外部变量的场景。

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

总结

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

感谢大家的阅读!文章来源地址https://www.toymoban.com/news/detail-427022.html

到了这里,关于你知道C语言函数调用的2种方式吗?传值调用 && 传址调用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C语言中这么骚的退出程序方式你知道几个?

    在本篇文章当中主要给大家介绍C语言当中一些不常用的特性,比如在 main 函数之前和之后设置我们想要执行的函数,以及各种花式退出程序的方式。 通常我们在写C程序的时候都是从 main 函数开始写,因此我们可能没人有关心过这个问题,事实上是main函数不是程序第一个执行

    2024年02月06日
    浏览(40)
  • Stable Diffusion你需要知道的算法原理;ChatGPT新增函数调用;Adobe Illustrator引入AI工具Firefly;

    🦉 AI新闻 🚀 OpenAI更新ChatGPT,新增函数调用、4倍上下文长度、更低的嵌入成本 摘要 :OpenAI在官网发布了ChatGPT的更新细节,包括新增函数调用、GPT-4和GPT-3.5-Turbo的升级、降低成本等。其中,新增函数调用能力使得模型能够直接支持Agent或Plugin,并且能够更可靠地从模型中获

    2024年02月16日
    浏览(33)
  • Lua调用函数的方式汇总

    在Lua脚本语言中,调用函数是一种基本的操作,它允许代码执行在函数定义中封装的操作。Lua 提供了几种灵活的方式来调用函数,以适应不同的场景和需求。以下是Lua中调用函数的几种常见方式: 1. 基本函数调用 最简单的调用方式是使用函数名后跟括号,并在括号内传递参

    2024年04月28日
    浏览(33)
  • JS函数的4种调用方式

    函数可以声明定义,也可以是一个表达式, 函数使用 function 定义 函数被定义时,函数内部的代码不会执行 函数被调用时,函数内部的代码才会执行 函数有四种调用方式 ,每种方式的不同在于this的初始化。 (this是保留,this指函数执行时的当前对象,this的值

    2024年02月05日
    浏览(33)
  • MySQL用的在溜,不知道业务如何设计也白搭!!!

    作者: 博学谷狂野架构师 GitHub: GitHub地址 (有我精心准备的130本电子书PDF) 只分享干货、不吹水,让我们一起加油!😄 范式设计 范式概述 第一范式: 当关系模式R的所有属性都不能在分解为更基本的数据单位时,称R是满足第一范式的,简记为1NF。满足第一范式是关系模式

    2023年04月27日
    浏览(50)
  • C语言 调用函数

    1.函数调用的形式 函数调用的一般形式: 函数名(实参表列) 如果时调用无参函数,则“实参表列”可以没有,但括号不可以省略。如果实参表列包含多个实参,各参数之间用逗号隔开。 按函数调用在程序中出现的形式和位置来分,有以下3种函数调用的方式: (1)函数调

    2024年02月06日
    浏览(35)
  • C语言 函数的嵌套调用

    C语言的函数定义是互相平行、独立的,也就是说,在定义函数时,一个函数内不能再定义另一个函数,即不能嵌套定义,但可以嵌套调用函数,即,在调用一个函数的过程中,又调用另一个函数。 如下图所示:表示的是两层嵌套(连main一共三层函数)。 其执行过程时: ①

    2024年02月06日
    浏览(36)
  • 在C语言中调用汇编语言的函数

    在C语言中调用汇编文件中的函数,要做的主要工作有两个: 一是在C语言中声明函数原型,并加extern; 二是在汇编中用EXPORT导出函数名,并用该函数名作为汇编代码段的标识,最后用mov pc, lr返回。然后,就可以在C语言中使用该函数了。 从C语言的角度,并不知道该函

    2024年02月14日
    浏览(38)
  • QT JS交互、调用JS、传值

            本文详细的介绍了 QT JS交互、调用JS、传值 的各种操作,包括QT向JS传递String字符串、包括QT向JS传递Int数字、包括QT向JS传递List数组,同时也接收JS向QT返回的List数组、JS向QT返回的Json、JS向QT返回的数字、JS向QT返回的字符串。 本文作者原创,未经允许禁止转载。

    2024年02月05日
    浏览(33)
  • 5.5 汇编语言:函数调用约定

    函数是任何一门高级语言中必须要存在的,使用函数式编程可以让程序可读性更高,充分发挥了模块化设计思想的精髓,今天我将带大家一起来探索函数的实现机理,探索编译器到底是如何对函数这个进行实现的,并使用汇编语言模拟实现函数编程中的参数传递调用规

    2024年02月12日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包