C语言参数传递
前言
最近复习Block相关知识,其中有个问题:block中为什么不能改变(这里值重新复制)被截获的自动变量,这个问题涉及到C语言参数传递,所以回头看了一下,并做了一些整理。
下面是C语言的几种参数传递方式:值传递、引用传递、指针传递、指针引用传递。
PS:为方便表述,以下内容的图片对内存的描述作了简化,如int类型是4个字节,指针类型是8个字节,这里统一用相同大小的一个格子表示。
1. 值传递
代码:
void func(int p)
{
printf("\n-----------func start-----------");
printf("\n&p : %x", &p);
printf("\np : %x", p);
p = 0xff;
printf("\n-----------func end-----------\n");
}
void test()
{
int a = 0x10;
printf("\n&a : %x", &a);
printf("\na : %x", a);
func(a);
printf("\na : %x", a);
}
输出:
&a : efbfde3c
a : 10
-----------func start-----------
&p : efbfde1c
p : 10
-----------func end-----------
a : 10
通过上面的代码及输出可知,变量a的地址为efbfde3c
,值为10
;通过调用func(a)
,通过输出可知:变量p的地址为efbfde1c
,值为10
。也就是说参数传递只把变量a的值传递给了变量p,此时变量a与变量p是值相同的两个不同变量,在内存不同的两个地址中,所以对变量p赋值只是修改了变量p的值,并不能修改变量a的值,如下图所示。总结一句话就是:值传递不传递变量本身,只传递变量的值。
2.引用传递
代码:
void func(int &p)
{
printf("\n-----------func start-----------");
printf("\n&p : %x", &p);
printf("\np : %x", p);
p = 0xff;
printf("\n-----------func end-----------\n");
}
void test()
{
int a = 0x10;
printf("&a : %x", &a);
printf("\na : %x\n", a);
func(a);
printf("\na : %x", a);
}
输出:
&a : efbfde2c
a : 10
-----------func start-----------
&p : efbfde2c
p : 10
-----------func end-----------
a : ff
与值传递不同,func的参数是int &p
,表示引用传递。如输出所示,通过引用传递,变量a的地址与变量p是相同的,也就是说引用传递把a的地址传给了变量p,所以对变量p进行赋值之后,变量a的值也改变了,因为变量a与变量p实际是同一个变量。如下图所示:
3. 指针传递
代码:
void func(int *p)
{
printf("\n-----------func start-----------");
printf("\n&p : %x", &p);
printf("\n*p : %x", *p);
printf("\np : %x", p);
*p = 0xff;
printf("\n-----------func end-----------\n");
}
void test()
{
int a = 0x10;
printf("&a : %x", &a);
printf("\na : %x\n", a);
func(&a);
printf("\na : %x", a);
}
输出:
&a : efbfde2c
a : 10
-----------func start-----------
&p : efbfde08
*p : 10
p : efbfde2c
-----------func end-----------
a : ff
指针传递,顾名思义,int *p
表明p是一个指针变量,调用func(&a)
是把变量a的内存地址传递过去赋值给指针变量p,此时指针变量p的值是变量a的内存地址,故可看到输出p为efbfde2c
(变量a的内存地址)。*p
是对指针p的值(即变量a的内存地址)进行取值,相当于*&a
,所以对*p
进行赋值也就改变了变量a的值。如下图所示:
4. 指针引用传递
代码:
void func(int *&p)
{
printf("\n-----------func start-----------");
printf("\n&p : %x", &p);
printf("\n*p : %x", *p);
printf("\np : %x", p);
*p = 0xff;
printf("\n-----------func end-----------\n");
}
void test()
{
int a = 0x10;
printf("&a : %x", &a);
printf("\na : %x\n", a);
int *b = &a;
printf("\n&b : %x", &b);
printf("\n*b : %x", *b);
printf("\nb : %x", b);
func(b);
printf("\na : %x", a);
}
输出:
&a : efbfde2c
a : 10
&b : efbfde20
*b : 10
b : efbfde2c
-----------func start-----------
&p : efbfde20
*p : 10
p : efbfde2c
-----------func end-----------
a : ff
其实理解了前面的,这里也就明了了。首先把变量a
的地址即&a
赋值给指针变量b,指针变量b的值就是efbfde2c
(后面的的输出证明了这一点)。然后调用
func(b)
,这里跟前面的引用传递一样道理,指针变量p实质是是指针变量b,而指针变量b的值又是变量a的内存地址,所以*p
等同于*b
,对其进行赋值相当于对变量a进行赋值(a = 0xff
)。可见下图: