注册 | 登录 忘记密码? 51cto首页 | 博客 | 论坛 | 招聘
热点文章 用了十年的QQ号,第二次被..
 帮助

C语言专题——数组与指针


2007-04-10 22:29:44
 标签:C语言 语言 专题   [推送到技术圈]

C语言专题——数组与指针

什么时候数组与指针相同

所有作为函数参数的数组名总是可以通过编译器转换为指针。
在其他所有情况下,数组的声明就是数组,指针的声明就是指针,两者不能混淆。

但在语句或表达式中引用时,数组总是可以写成指针的形式,两者可以互换。

然而,数组和指针在编译器处理时是不同的,在运行时的表示形式也是不一样的。
对编译器而言,一个数组就是一个地址,一个指针就是一个地址的地址,你应该根据情况做出选择。
 
为什么会发生混淆

当人们学习编程时,一开始总是把所有的代码都放到一个函数里。
随着水平的进步,他们把代码分别放在几个函数中。
在水平继续提高后,他们最终学会了如何用几个文件来构造一个程序。

什么时候数组和指针是相同的?C语言标准对此作了如下说明:
规则1 表达式中的数组名(与声明不同)被编译器当作一个指向该数组第一个元素的指针。
规则2 下标总是与指针的偏移量相同。
规则3 在函数参数的声明中,数组名被编译器当作指向该数组的第一个元素的指针。
 
规则1:“表达式中的数组名”就是指针

规则1和2合在一起理解,就是对数组下标的引用总是可以写成“一个指向数组的起始地址的指针加上偏移量。”
(个人认为,表述为“一个指向该数组第一个元素的指针加上偏移量”更明确。)

对数组的引用如a[i]在编译时总是被编译器改写成*(a+i)的形式。
C语言标准要求编译器必须具备这个概念性的行为。
于是,a[6]和6[a]都是正确的。

编译器自动把下标值的步长调整到数组元素的大小。
这就是为什么指针总是有类型限制,每个指针只能指向一种类型的原因,
因为编译器需要知道对指针进行解除引用操作时应取几个字节,以及每个下标的步长应取几个字节。
 
规则2:C语言把数组下标作为指针的偏移量

事实上,下标范围检测被认为并不值得加入到C语言中。

数组下标是定义在指针的基础上的,所以优化器常常可以把它转换为更有效率的指针表达式,
并生成相同的机器指令。

C语言把数组下标改写成指针偏移量的根本原因是指针和偏移量是底层硬件所使用的基本模型。
 
为什么C语言把数组形参当作指针

之所以要把传递给函数的数组参数转换为指针是出于效率的考虑,
这个理由常常也是对违反软件工程做法的辩解。

我们倾向于始终把参数定义为指针,因为这是编译器内部所使用的形式。
但从另一方面,有些人觉得int table[]比int *table更能表达程序员的意图。
 
数组片段的下标

向函数传递数组前面一个位置的地址(a[-1]),这样就可以使数组下标从1到N,而不是从0到N-1。
不幸的是,这个手段完全为标准所不容,所以你千万不要告诉别人是我告诉了你这个方法。
 
C语言的多维数组
 
但所有其他语言都把这称为“数组的数组”

C语言里有一种别的语言称为数组的数组的形式,但C语言称它为多维数组。
C语言中的数组就是一维数组,而这个数组的元素可以是另一个数组。

编译器在编译时会把carrot[i][j]解析为*(*(carrot+i)+j)的形式。
 
如何分解多维数组

在“数组的数组的数组”中的每一个单独的数组都可以看作是一个指针。
这是因为在表达式中的数组名被编译器当作“指向数组第一个元素的指针”。
 
内存中数组是如何布局的

在C语言的多维数组中,最右边的下标是最先变化的,这个约定称为“行主序”。
 
如何对数组进行初始化

只能够在数组声明时对它进行整体的初始化。
之所以存在这个限制,并没有过硬的理由。

在IEEE754标准浮点数实现中,0.0和0的位模式是完全一样的。

初始化二维字符串数组:
char vegetables[][9] =
{
 "beet",
 "barley",
 "basil",
 "broccoli",
 "beanes"
};

一种有用的方法是建立指针数组,字符串常量可以数组初始化值:
char *vegetables[] =
{
 "beet",
 "barley",
 "basil",
 "broccoli",
 "beanes"
};
 
source: 《Expert C Programming》




    文章评论
 
 

发表评论

昵   称:
验证码:  点击图片可刷新验证码  博客过2级,无需填写验证码
内   容: