最近在看C primer plus中文第六版,看到指针与多维数组的部分,发现在10.7节中解释双重解引用时,最后有一句“地址的地址或指针的指针就是双重间接的例子”,这句话本身没有错误,但是放到多维数组这里,难免就会让人以为,多维数组其实也是指针的指针,但是这种想法是错误的。(我个人觉得这里可能是属于翻译问题,我看的版本还有其他几处句子本身没有错误,但是跟上下文联系起来就是怎么读都不通顺——当然也可能是我见识太少。)
为了简单起见,我们就用二级指针和二维数组为例,详细说明一下二级指针和二维数组的区别。(在百度百科中,把二级指针分了两类,一类是普通二级指针,一类是指向数组的二级指针,在这里我们讨论的实际上就是这二者之间的区别,本文中的二级指针就是普通二级指针,二维数组就是所谓指向数组的指针)。
首先来明确一下概念,所谓数组就是内存中存储相同元素的连续存储单元;而指针则指向一个内存地址,是一种存储着带有类型描述信息的内存地址的变量。注意,这是两种完全不同的东西,数组是连续的内存单元,而指针只是一个标量变量,只占用一个存储单元。
但是这两者是有着密切的关系的,在C语言中使用数组并不是直接使用整块的内存空间,而是使用一个指针来代表它,这个指针指向数组的首元素,通过对这个指针的解引用、进行加减等操作,我们可以方便地使用数组。而正是因为使用数组就是在变相的使用指针,所以二维数组与二级指针十分容易混淆。
但是指针与数组终归是两种不同的东西,二维数组与二级指针也必然有很大区别。
我们来看一下那个被用来代表数组的指针,它就是数组名,你可以把它理解为指针,因为它的值确实是指向某种类型的某个内存地址,但是它是特殊的:
首先它是常量,不能像普通变量一样被修改;
其次,它是用来代表整个数组的,这一点与普通指针变量截然不同。
下面讨论二维数组与二级指针。
如果我们对普通指针p1取地址,我们会得到这个指针本身的地址,我们把这个地址赋值给另一个指针p2,那么p2指向的变量就是被我们取地址的p1,所以p2就是一个二级指针,因为p2所指向的变量仍然是一个指针。所以说二级指针指向的是一个指针。
而二维数组是用二维数组名这个指针来表示的,二维数组名指向二维数组的首元素(一个一维数组),而这个首元素同样用一个指针来表示。那么二维数组就相当于二级指针吗?
假设二维数组与普通二级指针没有区别的话,那么二维数组名指向的同样应该是一个指针,而这个指针指向的是一个作为二维数组首元素的一维数组。按照这个假设,我们对二维数组名解引用应该得到一个一维数组的指针,那么事实的确如此吗?是的,而且那个指针所指向的一维数组正是二维数组的首元素。看起来,这个假设是正确的,二维数组与二级指针完全没有区别,这篇文章的写作完全没有意义。但是如果你确实这么认为那就大错特错了。
我们解引用出来的看似是一个指针,然而它真的是一个普通指针吗?不是,那是一个数组名,是作为首元素的一维数组的数组名,它并不是一个普通的指针变量,它代表的是整个数组。也就是说,二维数组名真正所指向的并不是指针,而是指向了一个数组!要知道二维数组的首元素可是一个数组,不是一个指针。这意味着上面的假设其实是错误的,二维数组和二级指针是完全不同的两种东西。
在C语言中我们使用特殊的指针即数组名来表示数组,当这样使用一个指针,它就具有了完全不同的意义,它不再是代表一个单独的指针变量,而是意味着存储了那个数组的一整块内存。所以你如果对数组名取地址,你所得到的值并不是存储数组名本身的变量的地址,而是数组名所指向的地址,这个值是与数组名本身的值相同的,它们的不同之处在于,数组名所指向的类型是数组元素的类型,而取数组名地址所指向的类型是这个数组本身的类型。
数组名本身的地址,是无法通过取数组名的地址得到的,到目前为止我也不知道怎么得到它,不过貌似得到了也没什么用。
二维数组和二级指针的区别有一个直观的体现:
通过对比我们可以发现二级指针的值和二级指针指向的指针的值是不一样的,而二维数组名和解引用它得到的二维数组首元素(一个一维数组名)的值是一样的。这是由于一级指针本身的地址和一级指针所指向的地址是不一样的,而二维数组中两个数组名所指向的数组虽然不一样但是数组的起始地址是一样的。这说明,二维数组名实际上指向的是数组,而不是一个单纯地指针。
综上,二维数组其实是数组的数组,也就是连续内存单元的连续内存单元,纵横坐标足够大的话,可以占用非常大的空间;二级指针就是一个普通的指针变量,占用一个普通指针大小的存储空间,只不过可以通过这个指针找到另一个指向其他东西的指针。我们解引用二级指针得到的是一个普通指针,而解引用二维数组名得到的是一个特殊的代表数组的指针。
通过二维数组名的双重解引用取值,确实用到了两层指针,但是用到的这两层指针是代表数组的指针,更准确的说这种行为是通过两个指针检索两层数组取值,而不是什么地址的地址或指针的指针。
本人只是初学,学到这一部分有感而发,如有错误,欢迎指正,不胜感谢。