从一道面试题谈谈数组与指针的差别

如果遇到的面试多了,大抵会被问到这样一个问题:数组和指针有什么区别?这也是一道非常基础但不乏精华的题目,所能得到的答案也可谓是五花八门,但不外乎如下几类:概念复述,具体使用,能否改变。

概念复述:数组是内存中长度确定的连续单元排列,而指针则是包含了单个单元地址的特殊单元。

简单而又直接,直接列出概念,前者是一群单元,而后者是一个单元。但这显然不是一个完整的答案。

具体使用:在全局下,数组与指针的长度不同,而对于函数而言,数组不能被传入函数,会被替换成一个指针。

类似的答案还有很多,无非在强调数组和指针在使用(引用元素)上的种种差别。然而本质上可以归纳为下列一句话:

数组在应用元素时直接对数组地址符号的值作偏移,而指针在引用元素时则先读取指针单元中的地址的值,再按该值进行寻址。

这里我为了突出两个值的差别,叙述的比较拗口,其实这个答案的要素在于数组和指针的符号对于编译器而言是两个不同的东西,如果写成代码,事情其实很明了:


       int a[10];

       int* b = a;

       cout << "a = " << a<< "   &a = "<< &a << "  sizeof(a) = " << sizeof(a) << endl;

       cout << "b = " << b<< "   &b = "<< &b << "  sizeof(b) = " << sizeof(b) << endl;

数组和指针

上述的代码昭示了几个信息 数组的(首地址)值等于其取地址的结果,而指针不然;数组与指针长度是不一样的,前者是所声明数组的长度,后者则仅仅是一个指针的大小。

回到刚才的讨论:所有的符号都会被编译器放在一张符号表中,这张表也会标注其相关的类别,对于数组,编译器直接在出现这个符号的地方用那个地址去作替换,并完成相关的寻址和偏移工作,因此会有a == &a。而对于指针,则会先读取存放在指针这个地址的单元的“值”,并把该值作为一个待寻地址,对其进行寻址。简而言之,数组是地址符号,指针是存值单元,指针多了一次读取的步骤。而这样的差异,则造成了数组与指针在所有使用细节上的不同。

能否改变:数组不能改变,指针可以改变。

这个切入点在我看来可以说有些刁钻了,因为一般而言,不会有人会觉得数组本身(地址)有什么修改的意义,因而这样的角度有些刻意为之。然而要较真地去剖析,不得不承认事实确实如此。从这个角度切入的人一般会认同一种观点,即数组与指针在本质上没有差别——均为指针,不过数组多了一个const限定。因此如下的代码是不合法的:


Int a[10];

++ a;

编译器给出的解释为:表达式必须是能修改的左值。这恰也符合试图修改const的情况。

由此来看,上述的观点完全成立,但是考虑到第二个角度,这个观点又明显相悖,这里我不打算深究数组的本质,毕竟要不要把数组理解为指针确实是个因人而异的话题,这里我选择文字上做一个妥协,在最终的叙述上作一点修正:数组是一个const地址符号,而指针则是一个非const的存址单元。

抽象观念:数组是一个元素内在关联的线性表,而指针是一个独立的迭代器

一般而言,如果能系统地从上述角度去表述这些差异,再画上一两张好看的图示,可以说是非常完整了,然而我在阅读Andrew Koenig / Barbara Moo的《C++沉思录》时,作者提出了这样一种观点——数组(或者索引)本身提供了特殊的抽象含义,那些偏移本身就具有其意义,即使数组消失了也是如此。而指针的价值在于通过指针,便提供了额外的对象信息,能够用来构造出更通用的程序。

上述的区别可以说相当的特立独行了,我认为作者在此处不是从语法或实现上,而是更多地从算法或抽象观念的角度上来理解问题,看起来有些抽象,其实这个观念是很直观的,要说明这个问题,请直接读一读如下的代码吧:


a[2] = 3;

*(a + 2) = 3;

两句代码实现了一样的功能,但却给了人不一样的感觉。对于第一句,我们会说:给a的第二个元素赋值3;而对于第二句,除非我们明白地知道a是一个数组,否则我们往往会说:给a后面的第二个单元赋值3。这个表述上的差异正如作者所言,索引本身具有含义,它表征了各元素的内在联系,数组的长度情况,以及数组作为一个整体而存在等诸多概念。而指针则更加独立,即使它被放入一个指针,也往往被割裂而存在。

至于说指针提供了对象信息,我认为有些晦涩了。对此我的理解是提供索引来进行元素访问时解引用过程默认发生了,而指针则需要手动解引用,显然解引用后的对象便被限定了类型,而指针则可以通过多态等手段有着更多发挥空间。这个解释也有些刻意为之了,希望日后能悟到新的见解吧。

总而言之,数组与指针的差异:可以从概念复述,具体使用,能否改变和抽象观念四个方面来思考。有的观点有些过于刁钻,但这也表明了C++的魅力所在——多去思考,便能窥见新天地。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。