C语言学习笔记:为什么&相当于升级而*相当于降级?

最近一直在学习北京大学李戈老师在Coursera上的MOOC课程《计算概论A》。在课程的后半部分讲到了C语言的指针运算符&*在数组中的应用。课程中李戈老师通过分析讲解和引用C语言规范文档清晰地讲清楚了这两个运算符的含义,并给出了三条非常重要的结论:

1. 数组名相当于指向数组第一个元素的指针;

2. &E相当于把E的管辖范围上升了一个级别;

3. *E相当于把E的管辖范围下降了一个级别。

利用这三条结论,我们可以非常方便且准确地分析指针运算符在数组中应用时的含义,因此这三条结论十分重要。这三条结论不仅值得花时间记下来,也值得花时间真正搞清楚为什么是这样的,这样才不至于死记硬背。在这里,我根据李戈老师的讲解,用中文将此处知识整理一下,便于学习和复习。

两条事实


由于多维数组实质上就是嵌套(nested)数组,所谓的“多维”不过是基于这样一个事实:数组也可以作为数组之中的元素。

&运算符只能用在实体(就是变量)前面,*运算符只能用在指针前面。

什么是“表达式E的管辖范围(级别)”?


上述结论中涉及到了这样一个概念:“表达式E的管辖范围”,也就是“表达式E的级别”。那么,什么是所谓的“管辖范围”和“级别”呢?

以整型二维数组a[i][j]为例。以下表达式的“管辖范围”(“级别”)依次降低:

&a 指针,指向整个二维数组a
a 指针,指向二维数组a的第一个元素(一维数组a[0]
*a 指针,指向二维数组a的第一个元素(一维数组a[0])中的第一个元素(int变量 a[0][0]
*a[0] int变量,就是a[0][0]

其中前三者(都是指针)存储的值都是该二维数组a的第一行的首个元素的起始地址,但区别在于所指的“范围”不同。当对它们进行+1运算的时候,跨过的范围是不同的。

通俗地说,指针化的程度越高,表示的范围越大,级别越高。

为什么&表示升级?


首先,当&用在多维数组中最基本的元素(而不是数组名,如本例中的a[0][0])前面的时候,情况是最简单的:整个表达式表示指向这个元素的指针。

而当&用在一个数组名前面的时候,由于&运算符只能用在实体(变量)前面,而根据结论1,一个数组的名字(如本例中二维数组的名字a和一维数组的名字a[0])实质上就是指向该数组第一个元素的指针,因此在&后接一个数组名(如本例中的&a&a[0])实质上是在&后接了一个指针。这个时候怎么处理呢?C语言的规范文档中规定:此时整个表达式是一个指针,并且表示指向整个该数组的指针(在本例中,&a就是指向整个二维数组a的指针,&a[0]就是指向整个一维数组a[0]的指针)。这样,数组名在前面加上&运算符后,就由原先“指向该数组的第一个元素的指针”升级为“指向该数组整体的指针”,这样就完成了对&运算符后接的表达式的“升级”。这就是结论2的含义。

为什么*表示降级?


*运算符的情况比较简单一些,因为*只能用在指针前面,而根据结论1,数组名是指针化的。通俗地说,通过结论1,实体(变量)能变成指针,而指针不能变成实体(变量),因此*运算符不存在像上述&运算符那样的人为规定。所以*运算符就表示指针的实体化。而对于数组而言,指针实体化后所变成的那个实体(变量)如果仍然是数组名(如在本例中,*a变成a[0]),则根据结论1,*运算符将a(表示指向a[0]的指针)本身又降了一级,整个表达式表示a[0](表示指向a[0][0]的指针),从而完成了对*运算符后接的表达式的“降级”。这就是结论3的含义。




评论

此博客中的热门博文

安装 Windows 7 家庭高级版以及一些设置

重拾博客