【C语言】传值调用和传址调用
今天学习C语言的时候,接触到了两个全新的概念
话不多说,就此和大家分享一下c语言中函数的传值调用和传址调用,希望有所帮助
欢迎dalao无情指正!
引子 : 交换函数
我们先来写一个简单的函数
目的是交换a和b
1 |
|
运行的结果如图
需要注意的是,这是在主函数main里面直接进行的交换程序,而我们想要的其实是一个可以在任何地方使用的交换函数
1 |
|
若想达成以上目的,我们要先把上述代码优化成以下形式。其中swap1就是我们即将要写的自定义函数
1 | void swap1(int x, int y) |
- void表示自定义函数无返回类型
这个自定义函数看起来没什么问题对吧!
但是结果却告诉我们a和b并没有被交换
这是为什么?
查错方法
这里给大家介绍一个老师教授的查错方法。虽然我估计大家都知道(小声bb)
那就是用vs编译器自带的监视器了(快捷键f10,我用的是最新的vs2019,官网即可免费下载使用)
- 左边有个很Q的黄色小箭头,告诉你正在监视那一步
- 每按一次f10代码就会往下走一行
- 当遇到swap此类函数时,按f11进入函数,f10会直接跳过函数
可以看到代码在第25行的时候,x和y已经获得了a和b的值,tmp此时为0
下一行继续,tmp变成10
再下一行,x获得y的值,x=20
然后y获得tmp里面保存的x的值,y=10
可当我们下一步跳出函数,回到主函数的时候
会发现a和b仍然是10和20,并没有发生交换
聪明的你肯定已经想到这是为什么了
函数中的x和y与主函数的a和b是独立的,x和y的变化无法影响a和b
那怎么样函数中的x和y才能影响函数外的a和b,从而达到我们交换的目的呢?
这里需要涉及一个新的大家都知道的概念
& 取地址操作符
先用一个简单的例子让大家了解&取地址操作符的作用
在我们的c语言中,每个字符都对应了一个它独自的地址
而&符号就是取出这个字符的地址
1 | int main() |
这里面的*pa获取了a的地址,在打印的时候会顺着地址找到a,显示a的结果
让我们继续
我们将上述交换函数代码的主函数改成如下形式
1 | int main() |
比较swap1和swap2,会发现swap2括号中的a和b前面都多了一个**&操作符**
这个操作符会让swap2不再读取a和b的数值,即10和20
而是会读取a和b在内存中的地址
相对应的,swap2函数也要改成如下形式
其实形式和swap1基本一样,只是x和y被替换成了**pa 与 pb
1 | void swap2(int* pa, int* pb) |
- 表明 pa和pb都是*指针变量
- pa和pb保存的是a和b的地址
这时候我们再运行代码,a和b被很好的调换了
我们的目的也达成了
实参和形参
要想了解为什么两个函数会有这样的不同
我们需要学习实参(实际参数)和形参(形式参数)
1 | void swap1(int x, int y) |
在这串代码中,a和b是实参
x、y、*pa、 *pb都是形参
可以借用另外一个代码的例子进一步给大家了解实参
1 | int get_max(int x, int y) |
在这串代码中,抛去上面的a和b
max = get_max(100,300);是我们使用这个函数的基本方式
- 这里面的100和300是实参
- 同时**300+1和get_max(3, 5)**也是实参
- 对应的函数中的x和y就是形参
当实参传给形参的时候
形参其实是实参的一份临时拷贝
对形参的改变是不会改变实参的
这样解释大家应该对实参和形参有一定的认识了
接下来就有请我们的标题人物隆重登场
传值调用,传址调用
这两个调用方式十分重要,而且两个字从读音到长相(bushi)都十分相似
所以大家一定要注意区分!
简而言之
当我们需要在函数内部操作函数外部的变量的时候→传址调用
如果我们只需要外部变量的值,不需要改变外部变量→传值调用
以上面的交换函数为例子
1 | void swap1(int x, int y)//传值调用 |
因为swap1里面的x和y是传值调用,x和y只获取了a和b的值,自然无法影响函数外面的a和b
而swap2中的*pa 和 *pb获取的是a和b的地址(址→地址)所以可以影响函数外的a和b,实现它们的交换
注:x,y,*pa , *pb 都是局部变量,它们在出了函数外之后就无法使用,也失去了使用它们的意义
结束语
本篇小博客到这里也结束啦,感谢你看到最后!
如果感觉看完之后仍有不明白的地方
可以去观看这期视频里面的讲解,swap函数的讲解在1小时17分【点我跳转】
我也是刚学C语言的小白,博文有错在所难免,请各位大佬无情指正
这篇博文虽然字不多,但依旧花了我2小时的时间,如果觉得不错就点个赞再走吧!
求求了,跪谢!