关于函数传参

本文详细介绍了函数传参的三种主要方式:值传递、地址传递和全局变量。值传递中,实参的值复制给形参,形参的改变不会影响实参。地址传递允许在被调函数中改变实参的值,通过指针传递。全局变量在所有函数中可见,但使用需谨慎,因其可能导致错误。文章通过实例代码和示意图清晰解释了每种传参方式的工作原理。
摘要由CSDN通过智能技术生成

1.函数传参的三种主要形式

首先要知道函数形参和实参的特点

1.形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元,因此形参只有在函数内部有效,调用结束返回主调函数后则不能再使用该形参变量。

2.实参可以是变量、常量、表达式、函数等。无论实参是何种类型的量,在进行函数调用时,他们都必须具有确定的值,以便把这些值传送给形参。因此应该先用赋值、输入等办法获得确定值。

3.实参和形参在数量上、类型上、顺序上应严格一致,否则会发生类型不匹配的错误。

1.1复制传参(值传递)

       形神只是将实参的值复制保存了一份,在被调函数中无论如何改变形参,都不影响主调函数中实参的值。

       我们来看下面一段代码:

int my_add_ten(int x, int y)
{
    printf("func : &x = %p, &y = %p\n", &x, &y);
    x = x * 10;
    y = y * 10;
    int temp = x+y;
    printf("func : x = %d, y = %d\n", x, y);//100 200
    return temp;
}

      被调函数的功能是将主调函数传递过来的参数放大10倍,并将放大后的值相加返回给主调函数,我们在参数放大之前先打印一下被调函数中形参的地址。

      接下来是主调函数部分

int main(int argc, const char *argv[])
{
    int x = 10;
    int y = 20;
    printf("main : &x = %p, &y = %p\n", &x, &y);//和上面子函数中xy的地址不一样
    printf("main 前 : x = %d, y = %d\n", x, y);//10 20
    int ret = my_add_ten(x, y);
    printf("ret = %d\n", ret);  //300
    printf("main 后 : x = %d, y = %d\n", x, y);//10 20

return 0;
}

 主调函数中,在定义x,y后我们亦首先打印变量的地址,代码的执行结果如下:

可以看到主调函数中实参x,y和被调函数中的形参x,y并不是同一个变量,因为二者的地址并不一致,当主调函数调用被调函数后,实参x,y的值复制给形参x,y,示意图如下;

 

        对形参x,y无论进行何种操作,并不会影响实参x,y的值。如果我们想改变实参的值,我们需要将实参的地址传递给被调函数,也就是我们所说的地址传参,这将在下面得到验证。

1.2地址传参(地址传递)

       如果想在被调函数中改变实参的值,我们需要将实参的地址传递过来,于此同时,在被调函数中的形参部分,我们应当用一个指针来接实参的地址,代码如下:

void my_add(int x, int y, int *z)
{
    printf("my_add : z = %p\n", z);
    *z = x+y;
    printf("my_add : z = %d\n", *z);//30
}

在被调函数my_add中我们一共定义了三个变量:两个普通的整形变量x,y和一个整形指针变量z,z用来保存实参中的地址。接下来是主调函数部分:

int main(int argc, const char *argv[])
{
    int a = 10;
    int b = 20;
    int ret = 0;
    printf("main : &ret = %p\n", &ret);
    my_add(a, b, &ret);
    printf("ret = %d\n", ret); //30
    return 0;
}

 注意,在调用函数时必须注意形参和实参的类型必须严格一致,因此在对应形参指针的位置上我们传递的是变量ret的地址

可以看到z中保存到的是变量ret的地址,当我们对指针取*操作时,我们便可以操作地址所对应的变量,示意图如下(图中的地址并不是实际值,仅作参考使用):

 

 当形参是指针时,也不一定时地址传递,有可能是值传递,看下面一段代码:

#include <stdio.h>

int m = 10;
int n = 20;

//功能:改变指针指向
void my_chage1(int* q) 
{
	printf("my_chage1前 q=%p\n", q);
	q = &n;
	printf("my_chage1后 q=%p\n", q);
}

int main(int argc, const char* argv[])
{
	printf("m_add=%p\n",&m);
	printf("n_add=%p\n",&n);
	int* p = &m;
	printf("*p = %d\n", *p);//10
	my_chage1(p);
	printf("*p = %d\n", *p);//10
	return 0;
}

函数执行的结果如下:

       我们将实参指针p中所存地址赋值给形参指针q,可以看到在my_chagel函数被调用后,形参指针q的指向改为指向变量n的地址,但是我们对p取*操作时,p的值依旧没有改变,这是为什么呢?原因是因为实参指针p将m的地址传递给形参指针q,执行*q = &n操作后,q指向了n,p中所存m的地址并没有发生改变,也就时前文所提到的被调函数中无论如何改变形参,都不影响主调函数中实参的值。示意图如下(图中的地址并不是实际值,仅作参考使用):

 

 如果想通过形参指针q改变实参指针p的指向,那我们需要将实参指针p的地址传递到形参q,为了接受指针的地址,我们必须要用二级指针,看下面一段代码:

#include <stdio.h>

int m = 10;
int n = 20;

void my_chage2(int** q)
{
	*q = &n;
}
	
int main(int argc, const char* argv[])
{
	printf("m_add=%p\n",&m);
	printf("n_add=%p\n",&n);

	int* p = &m;
	printf("*p = %d\n", *p);//10
	my_chage2(&p);
	printf("*p = %d\n", *p);//20
	printf("p = %p  &n = %p\n", p, &n);//一样的
	return 0;
}

 代码的执行结果如下:可以看到指针p所指向的地址正是变量n的地址

 

 示意图如下(图中的地址并不是实际值,仅作参考使用):

 1.3全局传参

       全局变量就是在函数体外说明的变量,它们在程序中的每个函数里都是可见的。实际上,全局变量也是一种静态型变量。使用全局变量传递数据的先后顺序的不同会影响计算结果,应用顺序不当,会导致错误,这种方式尽量少用。 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前进的小电灯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值