1. 形参问题
形参——形式化的参数,这种解释很抽象。
在任何编程语言中,任何变量都是某个特定的存储空间的一段而已,这一段具体有多大,由变量的类型决定,如 int 型,则为4 Byte。
在进行函数/方法的调用时,函数的实参是存在于存储空间某个具体位置的一段指定空间的,而任何函数或方法都会被程序控制器开辟一个栈空间(stack),这个空间也是一段存储位置,有时候为了效率起见,它存在于计算机的ram或是CPU高速寄存器中。
调用的过程,实际上就是从实参的存储空间复制值到形参栈空间的过程。如下:
- 实际上,几乎在所有的编程语言中,形参在函数未被调用之前都是没有分配存储空间的。
形参存的存储空间,存在于函数的栈空间中,因此,在函数未被调用之前,栈空间实际上是不存在的,也就是说,形参在未被调用之前,没有被分配存储空间。
- 形参的生命周期
- 代码实例
#include "stdio.h" void f(int x){ x=99; return; } int main(void){ int x=10; printf("before callback, x=%d\n",x); f(x); printf("after callback, x=%d\n",x); return 0; }
- 结果
可见,实际上在调用中对实际参数并未形成影响。调用中的处理都是对实参的“被复制的那一份”进行的操作。
2. 在C语言中,当有多个函数的返回值时,不能用普通的 return 的方式实现。需要通过传回地址的形式进行,即地址/指针传递。
- 数组作为参数的函数调用方式是地址传递!
- 一维数组的数组名表示数组中0下标元素的地址。不管数组元素中第0个元素为什么类型,数组名都表示一个地址,不能看成整型。
- 地址传递中,形参和实参将指向相同的地址空间。虽然在这种传递方式中,函数调用过程仍然在一个栈空间中进行,但因为其操作中会对地址空间所指向的变量进行操作,因此实际上改变了传入参数的值。
在上述的形参实参传递过程中,形参和实参都指向相同的内存空间(即实参的数组本身),只不过传递过程中,只是告知了函数该实参的首个元素的地址,因此在用数组名作为参数时还需指定数组长度。
- 数组为形参时,实际上数组变量是一个指针变量。在函数调用完成后,指针变量被销毁,但指针变量所指向的内存空间(也就是实参数组的空间)依然存在,不会也无法被销毁。
在调用中,需要注意几点:
- 形参实参必须为相同的数组类型
- 在主调和被调函数中需分别定义数组
- 在编译过程中对形参的数组大小不做检查,因此可以不指定大小,形如“void fun(int [])”是合法的
- 如果在形参中指定了数组的大小,则必须在传入实参时注意其大小,因为我们通常假定,对形参的处理中,是按照这个形参中给出的大小来计算的。
- [请注意:]当然,如果在形参中按"void fun(int a[10])"的方式定义被调函数,却在函数内使用了a[10]、a[11],那么,如果实参中的对应a[10]、a[11]合法时,也不会出错!
- 代码实例
#include "stdio.h" void change(int a[],int n){ int i,j,temp; for(i=0,j=n-i-1;i
结果

显然,传入的参数为 b[10],结果在对形参 a[10] 的处理中,将实参数组 b[10] 进行了操作!
3. 如果在函数调用中参数列表不是数组形式或指针,那么几遍主调函数传入了数组的某个元素,仍然是值传递而非地址传递。如:
#include "stdio.h"
void change2(int x){
x+=1000;;
return;
}
void p(int a[],int n){
for(int i=0;i
结果如下:

可见,第三个元素也即是 b[2] 本身没有在函数调用过程中被更改。
4.多维数组在函数参数列表中,必须指明第一维之后的所有维的大小!第一维是可以忽略的。如下定义方式都是合法且等价的。
void f(int a[5][10]);
void f(int a[][10]);
而如下方式则是非法的:
void f(int a[5][]);
void f(int a[][]);