很多初学c语言或者对c语言不是很熟悉的时候,对c语言之间的传参总是不太懂(包括我),或者说是半知不解;有时候容易搞混传参时该传递的是地址还是数据
下面从传数据和传地址的区别分开讲述;我们先了解一下一个函数中的什么数据都存放在什么地方的,什么时候它需要传地址,什么时候只需要传递数据,并且什么三时候会被释放掉:
如图是c语言的内存分布图
(1)当我们在一个函数内申请一个变量时
(calloc,malloc等函数申请的内存空间和static修饰的变量除外)
,它是存放在栈空间的数据,在当前函数退出时,该数据所拥有的内存空间也会被释放掉,因此我们在定义变量时要考虑该变量是否要被其他函数频繁调用等问题
(2) 在Linux下我们可以使用
readelf -S 文件名
进行查看某个文件它的数据都有存放什么地方,图中框起来的是存储在段中的三种数据
函数传递数据的情况分为两种:
一、我们不需要改变本身函数中该变量的值,当这种情况下,我们传参的时候只需要把这个数据传递过去,
测试代码:
/*
测试:函数传参传递数据的情况
*/
#include <stdio.h>
void func(int a,int b)
{
a = 20;
b = 30;
//打印一下输出结果
printf("func_a:%d\n",a);
printf("func_a地址:%p",&a);//打印一下a的地址
printf("func_b:%d\n",b);
printf("func_b地址:%p",&b);//打印一下b的地址
printf("func_a+b:%d\n",a+b);
return ;
}
int main()
{
int a = 10;
int b = 20;
//调用func这个函数,并传递两个参数的数据过去
func(a,b);
printf("main_a:%d\n",a);
printf("main_a地址:%p",&a);//打印一下a的地址
printf("main_b:%d\n",b);
printf("main_b地址:%p",&b);//打印一下b的地址
printf("main_a+b:%d\n",a+b);
return 0;
}
运行结果:
(注:地址不同,代表变量不同)
(1)void func(int a,int b)里的int a和int b只是用于定义然后接收传进来的参数(形参),因此main函数中的a和b的地址与func函数中a和b的地址不一致
(2) 当代码执行到main函数里面的
func(a,b);
时其实只是相当于main函数的a和b赋值给func函数的a和b中
(3)main函数与func函数中定义的a和b其实是没有关系的,只是变量名相同,只是为了传参时方便易辨别
(4)因为main函数的a和b没有改变,改变的只是func里面的a和b,因此mian函数里面的运行a依旧是10,b依旧是20;并没有任何变化
(5)func中的a和b因为是只是一个函数内的普通变量,并非static修饰的变量也不是全局变量,因此是存放在
栈
里面的数据,存放在栈的数据的特点是:在函数执行结束后会被释放
如图是代码的图解:
二、函数传递地址的问题;当把变量的地址传递过去后,如果在其他函数修改了这个地址里面的值的时候,那么它原来的值就已经改变了的(除了const修饰的变量不可修改里面的值)
测试代码:
/*
测试:函数传参传递地址的情况
*/
#include <stdio.h>
//如果形参变量加了const修饰后只可读,不可修改它地址所在的数据,编译时会报错
//void func(const int *a,const int *b)
void func(int *a,int *b)
{
*a = 20;
*b = 30;
//打印一下
printf("func_a:%d\n",*a);
printf("func_a地址为:%p\n",a);//打印a的地址
printf("func_b:%d\n",*b);
printf("func_b地址为:%p\n",b);//打印b的地址
printf("func_a+b:%d\n",*a+*b);
return ;
}
int main()
{
int a = 10;
int b = 20;
//调用func这个函数,并把变量的地址传递过去
func(&a,&b);
printf("main_a:%d\n",a);
printf("main_a地址为:%p\n",&a);//打印a的地址
printf("main_b:%d\n",b);
printf("main_b地址为:%p\n",&b);//打印b的地址
printf("main_a+b:%d\n",a+b);
return 0;
}
运行结果:
(注:两个函数中的a和b的地址其实是一样的)
(1)当这个函数把数据的地址传递过去的时候函数的变量需要使用指针接收,因为接收的是一个地址,mian’与func之间的参数传递可看作:
int *a = &a; int *b = &b;
(2)func接收的a和b变量的地址,因此当在func函数中修改了a和b变量地址所在的数据时,其实是修改mian函数中a和b的值;
(3)例如我们可以假设main函数中a和b的地址分别为0x1000和0x1004(一个int类型数据占4个字节),当我们func(&a,&b);其实只是传递这两个地址过去而已,然后func函数中只是把0x1000和0x1004这两个内存地址中的数据修改为20和30
(4)因为main函数传递给func函数的是地址,因此func函数在打印时需要解引用取它地址里面的数据
下面是关于这个代码的图解:
总结:
(1)函数传参时传递的是数据的话,其实只是相当于这个函数的值赋值到另一个函数
(2)函数传参时传递的是地址的话,这个时候是把变量的地址传递过去,并不是数据的地址传递过去,然后接收的函数需要对变量所在的地址修改里面值的话是需要解引用该地址后才能修改和读取里面的数据
(3)函数传参传地址时,在其他函数通过修改该地址的数据后,它这个地址的值就已经改变了,并不会因为函数执行完销毁,因为是对地址操作,销毁的只是一个存放有变量地址的指针
================================================
这些都是关于我个人对函数传参的一些理解,包括图也都是自己画的;如果有什么地方写错或者画错了麻烦告知一下,真的非常感谢
版权声明:本文为takashi77原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。