一、形参与实参
什么是形参?什么是实参?参考定义如下:
1、形参即形式参数,在函数定义中,在整个函数体内都可以使用,离开该函数则不能使用。
2、实参即实际参数,实参出现在主调函数中,进入被调函数后,实参变量也不能使用。
简单来说,形参就是在函数定义时函数名后面括号内定义的变量,实参就是函数以外定义的变量。形参在函数被调用完结束之后便会被释放,实参则会维持原有的值不变,这里注意的是,在定义函数的时候会把实参的值赋值给形参,并不是实参本身进入函数参与。而且,函数在运行过程中,无论形参做怎样的运算,都不会影响实参的值。也就是说形参是以实参的值为参考单独在内存单元里开辟了一个新的空间来存储实参的值,这就是所谓的“值传递”。我用一个图大概解释一下。
函数的内容省略一下,可以看出形参就是对实参做的一个“复制”。然后把形参带入到函数中做运算。这就引出了学C语言时大家都遇到的通过函数来交换两数值的问题。我们先来看一段程序:
void swap1(int a, int b)
{
int c;
c = a;
a = b;
b = c;
}
int main()
{
int a=1;
int b=2;
swap1(a,b);
printf("a=%d\nb=%d",a,b);
return 0;
}
有了刚才的知识储备显然只是形参a和形参b的值在函数内部做了交换,但是实参a和b的值并未做任何变化。那怎么做才能让实参的值也做交换呢,想一下,既然传的变量本身不能改变,那如果传递的是个内存地址,然后我们通过改变地址指向的内存空间的值。这样,实参和形参代表着同样一块内存地址,利用指针来改变地址存储的数据,这样实参代表的地址本身虽然不会发生变化,但是这个地址里的数据已经悄悄地被改变了。我们看这段代码:
void swap2(int* a, int* b)
{
int c;
c = *a;
a = *b;
b = *c;
}
int main()
{
int a=1;
int b=2;
swap2(&a,&b);
printf("a=%d\nb=%d",a,b);
return 0;
}
这里我们传递的是实参a和b的地址,便成功的绕开了“实参本身不会发生变化”的阻碍。在内存中实际的过程是这样的:
这里地址都是我方便理解瞎编的,就很明显看出这个函数实际上操控的是最上方存放数值1和2的两个变量的值。通过这两个例子便对函数形参问题有了深入的理解。我们接下来再看一段代码是我在海康威视一年的校招笔试题里看到的:
void swap3(int* a, int* b)
{
int* c;
c = a;
a = b;
b = c;
}
int main()
{
int a=1;
int b=2;
swap3(&a,&b);
printf("a=%d\nb=%d",a,b);
return 0;
}
仔细想想是不是也很明了,形参与实参代表的是变量的地址,在函数里操控的是指针值也就是变量的地址,和形参的类型是一致的,也就是说最终不但变量的地址没有变,变量的值也没做任何变化,仍然交换失败。具体原因也已经说过了,为了验证我们的想法,于是我又验证了如下代码:
void test(int *p)//测试函数调用形参与实参的本质:值传递
{
printf("p=%p.\n&p=%p.\n",p,&p);
}
int main()
{
int a = 2;
int *x = &a;
printf("p=%p.\n&p=%p.\n", x, &x);
test(x);
return 0;
}
结果如下:
验证成功。
所以说所谓的地址传递只是值传递制造出来的假象,函数的形参与实参之间实质上就是值传递。
二、结语
最近在重新学习一些C语言的知识,便记录下自己的一些理解,本人编程基本功很不扎实,正在努力寻求进步中,有错误的地方希望得到批评指正~