C中的数组作函数参数被译为指针

来源:互联网 发布:three.js 全景视频 编辑:程序博客网 时间:2024/05/17 09:03

不管是全局还是局部的数组变量,系统读会为其分配指定的连续的内存空间。

数组作函数参数时,函数运行时系统并未给形参数组分配设定的内存栈空间。而是将数组代表的一片连续地址空间的首地址传递给函数的数组参数。对指针的理解稍多即可明白。

 

1 一维数组作为函数形参

1.1误写程序

 

Figure1:计算通过函数参数传递的数组大小程序

 

写此程序的目标是想用sizeof来计算未知数组的大小。哈哈,经验证len的值为1int类型在此系统中占4个字节)。

 

1.2程序分析

一维数组作为函数参数是传址的方式即只是将生存期更大的数组的首地址传进了子函数内。接收地址的只需是一个地址变量即可,如果函数形参为数组并且未其单独分配内存空间则有以下问题:

  • 分配数组栈空间:调用print函数将main内的a传递给print时,为print函数内的a分配跟main函数内的a相同大小的内存空间。
  • print函数内修改关于a的任何元素都只是在修改运行print函数时重新分配的一段内存空间里的数据。达不到能修改main函数内a数组元素的目的。

 

故而,根据函数运行结果,一维数组作为函数形参时不可能是数组而只能是地址。其实,在C语言中,有这样一个规则:C编译器将函数形参中的一维数组编译成一个指向实参数组首地址的指针。如此,无论为函数数组形参下标填写多少的数字都是无效的。故而,a[]作为函数形参最为清爽。

 

2 二维数组作为函数参数

跟一维数组类似,二维数组作函数参数运行时系统也不会为此形参数组分配空间。我想编译器会将函数的二维数组形参编译成一个二级指针,此二级指针指向实参数组的首地址[ 设想错误委屈 ]。那为什么要求申明在函数参数中的二维参数形式的外围必须要申明大小呢。哈哈,这一点当然是不符合编译器的规则才会被编译不过。这是有道理的:

 

2.1使用一维数组时

int a[]={1, 2, 3};

void print(int a[])

{

         ….

}

print(a);

定义a数组时,系统自动确定a的维数为3,确定数组为a[3]。编译器将print内的int a[]编译为指向int数组的指针。调用print函数时,除了操作a的地址(而此地址又是常量,不具有操作性)后,其它的操作如访问数组内容都是访问的外部定义的a[3]地址中的内容。

 

2.2使用二维数组时

int a[][3]={1, 2, 3, 4, 5, 6};

void print(int a[][3])

{

         ….

}

print(a);

 C语言中有规定,二维数组的外围大小一定要申明。不然编译就不会通过。这是有道理的,因为二维数组的数组名其实是一个二级指针(存的是地址的地址),a指向a[0]a[0]是数组第一行的首地址),则a+1就是a[1](数组的第二行地址)。如果还没有这个概念可以再去理解理解指针。二维数组的第一下标表示行首地址,第二个下标表示每行的元素个数。

 

上述程序中定义a[][3]经赋值后后a就变为a[2][3]正因为声明了每行元素的维数,再对数组赋值时编译器才能确定二维数组一共有几行

 

而对于具二维数组类型形参的函数来说,要不要规定二维数组每行数组的大小其实没必要,因为被编译器始终会将其编译成一个指向实参数组首行的地址。但事实证明,这是编译不过的。我想这只是编译器对定义二维数组的一个约束及对传参对应的一个约束(虽然一维数组的维数可以随便写)。

 

最近读到《C深度剖析》一书时,说到关于多维数组作函数参数时的话:在C语言中,当一维数组作为函数参数的时候,编译器总是把它解析成一个指向其首元素首地址的指针。这条规则并不是递归的,也就是数只有一维数组才是如此,当数组超过一维时,将第一位改写为指向数组首元素首地址的指针之后,后面的再也不可改写。如a[3][4][5]作函数参数时可被写作a[][4][5]。                                                                         [2013-11-11]

 

笔记有点拗口。

C Note Over。

原创粉丝点击