这一章我们来讨论一下数组的内涵,对数组的内部构造进行一次解剖,看看里面究竟隐藏了什么秘密。 有了前面两章对数组名和C语言数组本质的澄清,再来理解这一章的内容,就容易多了。
在下面的叙述中,笔者会用到一个运算符sizeof,由于在不同的编译器和编译模式下,对一个地址进行sizeof运算的结果有可能是不同的,为了方便讨论,我都假设地址长度为4个字节。
多数教材在讲述数组的时候,都是把重点放在外部表现形式上,很少涉及数组的内部,只告诉你如何做,却忽视了为什么要这样做。在解释的过程中,还会列出各种各样的表达式,例如:a、a+1、a[0]、a[0][0]、&a[0]、&a[0][0]、*(a+1)等等,让人眼花缭乱。但实际上真正能够用来描述数组内部构造的表达式只有其中的几个。
上一章讲到,C语言的数组实现并非真正的多维数组,而是数组嵌套,访问某个元素的时候,需要逐层向下解析。仍然以上一章的例子数组int a[7][8][9]来说,第一维元素0的值a[0]是a[0]所代表的那个数组的首地址,这个表达式在C语言的数组里面具有特殊的意义,之所以特殊,不仅仅在于它所代表的东西与一般的地址不同,而且类型也并非一般的地址类型,它的类型叫做数组类型,数组类型这个名称在绝大多数教材中是从来没有出现过的,在C89标准中,也仅仅出现在介绍数组定义的那一段。具有数组类型的地址跟一般类型地址的主要区别,在于长度不一样,对一个一般类型的地址进行sizeof运算,结果是4个字节,而a[0]由于代表了一个数组,sizeof(a[0])的结果是整个数组的长度8x9xsizeof(int),并非4个字节。具有数组类型的地址跟数组名一样都是一个符号地址常量,因此它必定是一个右值。数组类型在数组的定义与引用中具有非常重要的作用,它可以用来识别一个标识符或表达式是否真正的数组, 一个真正数组的数组名,是一个具有数组类型的符号地址常量,它的长度,是整个数组的长度,并非一般地址的长度,如果一个标识符不具备数组类型,那它就不是一个真正的数组。 在后面的章节里,还会再次使用这个概念。
与a[0]类似的数组类型地址还有a[0][0],a[0][0]是a[0]的下一层数组,因此sizeof(a[0][0])的结果是9xsizeof(int)。类似地,对于一个三维数组:
a[i][j][k]
a、a[x]、a[x][y](其中x、y大于等于0而小于i、j)都是具有数组类型的地址常量,而且都是一个右值。这一点要牢牢记住。正是由这些特殊类型的地址构成了整个数组。
以上结论对于n维数组同样适用。
接下来跟各位一起讨论一下跟数组有关的各种表达式的意义及其类型:
&a[0][0][0]:
&a[0][0][0]仅仅是一个地址,它的意义,仅仅表示元素a[0][0][0]的地址,sizeof(&a[0][0][0])的结果是4。不少人把它说成是数组a的首地址,这是错误的,这是对数组首地址概念的滥用。 真正能代表数组a的数组首地址只有a本身,a与&a[0][0][0]的意义根本就是两回事,真正的数组首地址是具有数组类型的地址,sizeof(a)结果是ixjxkxsizeof(int),而不是4,只不过由于a[0][0][0]位置特殊,恰好是数组a的第一个元素,所以它们的地址值才相同。 而对于a[0]和a[0][0],它们是在数组a内部a[0]和a[0][0]所代表的那个数组的首地址,它们的地址值也是由于位置“特殊”,因此才跟a和&a[0][0][0]一样。这一点一定要区分清楚了。
a+i:
可能有些人会对a+i感到迷惑,数组的首地址加上一个整数是什么呢?它是第一维元素i的地址,sizeof(a+i)为4。
a[i]+j:
跟上面的类似,a[i]+j是a[i]所代表的那个数组的元素j的地址,sizeof(a[i]+j)的结果也为4。
&a:
对数组名取地址在C标准里面是未定义的。这个表达式曾经引起过争论,焦点在于对一个右值取地址的合法性。C89规定&运算符的操作数必须具有具体的内存空间,换言之就是一个左值,但数组名却是一个右值,按照&运算符的要求,这是非法行为。因此,早期的编译器通常规定&a是非法的。但不知道什么原因,现在的编译器都把&a人为地定义成一个比a高一级而地址值跟a一样的地址,但作为比a高一级的地址,有一个行为却非常怪诞,sizeof(&a)的结果跟sizeof(a)相同,这也是人为的痕迹。笔者倾向于把&a定义为非法,应该维护&运算符的权威性,而不是在规定对某个右值取地址为非法的同时,又允许对另一个右值取地址,这是互相矛盾的。
&a[i]和&a[i][j]:
跟&a一样,也是未定义的,同样不符合&运算符的规则。由于a[i]是a[i][j]的上一层数组,有些人可能会想当然地以为:a[i]=&a[i][j],错也,实际上,由于a[i][j]=*(a[i]+j),因此&a[i][j]=&*(a[i]+j),结果是a[i]+j。对于sizeof(&a[i])和sizeof(&a[i][j]),由于是未定义的,因此有些编译器规定其值跟sizeof(a[i])和sizeof(a[i][j])相同,有些编译器却规定为4,就是一个地址的长度。
发表评论
-
《再再论指针》后记
2011-03-02 11:25 650在这篇后记中,笔者将对三个问题进行补充: 一、 ... -
再再论指针----篇首语
2011-03-02 11:24 563指针是C语言规范 ... -
第十章 围绕p()与(*p)()的争论
2011-03-02 11:23 685对于一个函数: void func(void) ... -
第九章 指针与const
2011-03-02 11:22 664const一词是英文constan ... -
第八章 右左法则----复杂指针解析
2011-03-02 11:22 641上一章费那么多唇舌讨论C语言的声明,其实目的都是为了这一 ... -
第七章 C语言声明详解
2011-03-02 11:21 675人们常说,C语言的 ... -
第六章 “另类”数组
2011-03-02 11:20 772动态数组与字符串常量可算是两种“另类”数组。 ... -
第五章 指向数组的指针
2011-03-02 11:19 1069讲到第五章了,数组两个字还离不开我们的左右,数组的内容 ... -
第四章 [ ]运算符的本质
2011-03-02 11:18 725数组是存在于人们头 ... -
第二章 再一次吃惊----数组的数组与多维数组的区别
2011-03-02 11:17 494看见这个题目,也许有些人就会嘀咕了:难道两者不是一样的 ... -
第一章 什么是数组名?----一个让你吃惊的事实!
2011-03-02 11:15 708数组是指针的基础,多数人就是从数组的学习开始指针的旅程的 ... -
图书推荐
2011-02-19 19:04 793图书收藏夹 ...
相关推荐
系统解剖学习题及答案.pdf系统解剖学习题及答案.pdf系统解剖学习题及答案.pdf系统解剖学习题及答案.pdf系统解剖学习题及答案.pdf系统解剖学习题及答案.pdf
第一章动物解剖学组织学及胚胎学.doc
《系统解剖学》学习指导及习题集.doc
腧穴解剖学填空题.doc
人体解剖学习题集(含答案)
解剖学、生理学、药理学、病理学合称三理一剖,是现代医学的基础。本系列视频的主讲人凌树才教授是浙江大学医学院解剖学教研室主任,中国解剖学会神经解剖学专业委员会委员,中国解剖学会临床解剖学专业委员会委员,...
局部解剖学-第三章胸部.ppt
人体解剖学第三章-呼吸系统.ppt
山东大学《局部解剖学》期末复习资料总结(有点老
手术局部解剖学[第三章头部]山东大学期末考试知识点复习.pdf
动物解剖学全真模拟试题,动物解剖学全真模拟试题,动物解剖学全真模拟试题
(期末复习)2816人体解剖学与组织胚胎学复习资料.pdf
中山大学大学生《临床解剖学》期末复习资料
人体解剖学第七章脉管系统-静脉系统.ppt
解剖学图谱
人体解剖学女性生殖系统学习教案.pptx
神经解剖学习图片汇总
神经系统解剖学PPT学习教案.pptx
病理解剖学简答题.pdf
系统解剖学多套试卷及参考答案