C语言中的参数传递机制详解

2020-01-06 17:11:25王旭

由此我们看到,数组作为参数与指针作为参数并没有什么区别,因为编译器会自动将形参中的数组名转换为一个指针。所以,以下面代码中的两个函数签名是等效的:


void func(int arr[]){
 
}
void func(int * p){
 
}
 

实际上,如果我们同时定义了它们,编译器会报“redefinition”错误而无法编译。

此外需要注意的是,虽然我们可以将形参声明成一个数组,但在编译器看来它只是一个指针而已,因此形参中有关数组长度的信息会被自动忽略,在实际调用时实参数组的长度与形参指定的数组长度没有任何关系,而且在函数内也无法通过 sizeof(arr)/sizeof(arr[0]) 得到数组的长度。


//形参arr的指定长度5无意义,会被编译器忽略,未防止误解建议不写
void arrArg(int arr[5]){
 // sizeof(arr)是指针类型的大小而非数组大小,因此len不是数组长度 
 int len = sizeof(arr)/ sizeof(arr[0]);
}
 

自定义类型参数

数组这种“组合”类型在作为参数传递时被解析为指针方式传递,那么当结构体(struct)、共同体(union)以及枚举类型作为参数传递时是否也是如此呢?

枚举类型本质上是int,所以当形参被声明为枚举类型时,在编译器看来就是int型,以下面代码中的两个函数签名是等效的,编译器会报“redefinition”错误:


enum week{ Mon, Tues, Wed, Thurs, Fri, Sat, Sun };
 
void func(enum weekday){}
 
void func(int i){}
 

下面是结构体和共同体分别作为参数时的示例:


#include <stdio.h>
 
struct Date{
  int year;
  int month;
  int day;
};
 
void changeStruct(struct Datedate){
  printf("形参date的地址:%#xn", &date);
  date.year ++;
  date.month = 12;
  date.day = 31;
  printf("形参date的值:%d-%d-%dn",date.year,date.month,date.day);
}
 
union Data{
  int i;
  float f;
  double d;
};
 
void changeUnion(unionDatadata ){
  printf("形参data的地址:%#xn", &data);
  printf("形参data的值,d.i:%d, d.f:%f, d.d:%fn",data.i,data.f,data.d);
  data.d = 2017.4;
  printf("函数调用后,形参data的值,d.i:%d, d.f:%f, d.d:%fn",data.i,data.f,data.d);
}
 
int main(){
  printf("结构体参数传递示例:n");
  struct Datedate = {2017,4,2};
  printf("实参date的地址:%#xn", &date);
  printf("实参date的值:%d-%d-%dn",date.year,date.month,date.day);
  changeStruct(date);
  printf("函数调用后,实参date的值:%d-%d-%dn",date.year,date.month,date.day);
 
  printf("共用体参数传递示例:n");
  unionDatadata={.i=2017};
  printf("实参data的地址:%#xn", &data);
  printf("实参data的值,d.i:%d, d.f:%f, d.d:%fn",data.i,data.f,data.d);
  changeUnion(data);
  printf("函数调用后,实参data的值,d.i:%d, d.f:%f, d.d:%fn",data.i,data.f,data.d);
 
  return 0;
}