再再论指针.doc

上传人:hw****26 文档编号:3967782 上传时间:2019-09-05 格式:DOC 页数:30 大小:132.50KB
下载 相关 举报
再再论指针.doc_第1页
第1页 / 共30页
再再论指针.doc_第2页
第2页 / 共30页
再再论指针.doc_第3页
第3页 / 共30页
再再论指针.doc_第4页
第4页 / 共30页
再再论指针.doc_第5页
第5页 / 共30页
点击查看更多>>
资源描述

1、再再论指针1再再论指针篇首语 指针是 C 语言规范里面一项核心内容,指针具有与生俱来的优势,利用指针可以写出许多短小精悍、效率极高的代码,它是 C 语言一把无可替代的利器,凭着这把利器,C 语言与其它高级语言相比至少在效率方面高人一筹。但是,由于指针的原理与使用方式跟人们通常的思维习惯有较大的差别,造成了指针比 C 语言其它概念难理解得多,这使得对指针认识不足成为了一种在 C 程序员中普遍存在的现象,这种不足必然导致程序员在指针的使用过程中不断遭受挫折,挫折多了,指针俨然变成一道无法逾越的难关,恐惧感也就油然而生了。在恐惧感面前,某些程序员甚至产生了要避免使用指针的念头,这是非常不可取的。指针

2、是如此犀利,正是它才使得 C 语言威猛无比,如果就这样把它放弃了,那么 C 语言就算是白学了。我们应当让指针成为你手中那把砍掉索伦手指上魔戒的举世无双的纳西尔圣剑,而不是成为你心中永远的魔戒。本文的目的,是希望通过跟各位朋友一起讨论关于指针的几个关键概念及常见问题,以加深对指针的理解。因此,本文并不是讲述形如 int *p、struct int i;float j; *p 等这些东西是什么的文章,阅读本文的朋友最好对指针已经具有一定的使用经验,正因如此,笔者才给文章起名叫再再论指针。笔者不敢奢望能够完全解开你心中的魔结,但如果通过阅读本文,能够让你在日后的指针使用过程中减少失误,那笔者就心满意

3、足了。本文将讨论如下十个主题,读者最好按主题的顺序一个一个地阅读,当然,如果你只对其中某个或某几个主题感兴趣,只看那几个也未尝不可。当你阅读本文后:如果你有不同的意见,欢迎你在评论里留下自己的见解,笔者很乐意跟你一起讨论,共同进步。如果你觉得我说的全都是废话,那么恭喜你,你的指针已经毕业了。如果你有太多不明白的地方,那么我介绍你先找一些关于数组与指针的读物看看,笔者推荐你阅读一本叫C 与指针的书,看完后再回来继续思考你的问题。再再论指针2第一章 什么是数组名? -一个让你吃惊的事实!数组是指针的基础,多数人就是从数组的学习开始指针的旅程的。下面我节选一些在各种论坛和文章里经常见到的关于数组的文

4、字:“一维数组是一级指针”“二维数组是二级指针”“数组名可以作为指针使用”“数组名就是.的常量指针”“数组名就是.的指针常量”.这些文字看起来非常熟悉吧?类似的文字还有许多,或许你就是经常说这些话的人呢。不过非常遗憾,这些文字都是错误的,实际上数组名永远都不会是指针!这个结论也许会让你震惊,但它的确是事实。数组名、指针、地址这几个概念虽然是基础中的基础,但它们恰恰是被混淆和滥用得最多的概念,把数组名说成指针,是一个概念性的错误,实质是混淆了指针与地址两个概念的本质。俗话说得好:浅水淹死人。因此,在讨论数组之前,有必要先回过头来澄清一下什么是指针,什么是地址,什么是数组名。 指针是 C 语言具有

5、低级语言特征的最直接的证据。在汇编语言里面,指针的概念随处可见。比如 SP,SP 寄存器又叫堆栈指针,它的值是地址,由于 SP保存的是地址,并且 SP 的值是不断变化的,因此可以看作一个变量,而且是一个地址变量。地址也是 C 语言指针的值,C 语言的指针跟 SP 这样的寄存器虽然不完全一样,但原理却是相通的。C 语言的指针也是一种地址变量,C89 明确规定,指针是一个保存对象地址的变量。这里要注意的是,指针跟地址概念的不同,指针是一种地址变量,通常也叫指针变量,统称指针。而地址则是地址变量的值。 看到这里,也许你会觉得,这么简单的东西还用你来说吗?的确,对于 p与我们可以用一个整数变量 int

6、 n 作实参来调用 fun,就是 fun(n);当然,也正如大家所熟悉的那样,可以用一个整数常量例如 10 来做实参,就是 fun(10);那么,按照第二个疑问的看法,由于形参是一个整数变量,而 10 可以作为实参传递给 i,岂不就说明 10 是一个整数变量吗?这显然是谬误。实际上,对于形参 i 来说,用来声明 i 的类型说明符 int,所起的作用是用来说明需要传递给i 一个整数,并非要求实参也是一个整数变量,i 真正所期望的,只是一个整数,仅此而已,至于实参是什么,跟 i 没有任何关系,它才不管呢,只要能正确给i 传递一个整数就 OK 了。当形参是指针的时候,所发生的事情跟这个是相同的。指针

7、形参并没有要求实参也是一个指针,它需要的是一个地址,谁能给予它一个地址?显然指针、地址常量和符号地址常量都能满足这个要求,而数组名作为符号地址常量正是指针形参所需要的地址,这个过程就跟把一个整数赋值给一个整数变量一样简单!在后面的章节中,笔者将严格地使用地址这一概念,该是地址时就用地址,该是指针时就用指针,以免象其它教材那样给读者一个错误的暗示。再再论指针5第二章 再一次吃惊 -数组的数组与多维数组的区别看见这个题目,也许有些人就会嘀咕了:难道两者不是一样的吗?C 语言的多维数组不就是数组的数组吗?不!两者是有区别的,而且还不小呢。首先看看两者的共同点:1。内存映象一样。2。数组引用方式一样,

8、都是“数组名下标下标.”。3。数组名都是数组的首地址,都是一个符号地址常量、一个右值。由于两者的共同点主要反映在外部表现形式上,因此,从外部看来,数组的数组跟多维数组似乎是一样的,这造成了 C 程序员对两者的区别长期以来模糊不清。但实际上,c 语言限于本身的语言特性,实现的并非真正的多维数组,而是数组的数组。数组的数组与多维数组的主要区别,就在于数组的数组各维之间的内在关系是一种鲜明的层级关系。上一维把下一维看作下一级数组,也就是数组嵌套。数组引用时需要层层解析,直到最后一维。举个例,对于数组:int a789;如果要访问元素 a456,首先就要计算第一维元素 4 的地址,也就是a+4,由于是

9、数组的数组,元素 4 的值代表了一个数组,因此元素 4 的值就是它所代表的那个数组的首地址,我们用一个符号 address1 代表它,也就是address1=*(a+4),接着计算第二维,显然元素 5 的地址是 address1+5,其值也是一个数组的首地址,用 address2 表示它,就是 address2=*(address1+5),最后一维,由于已经到达了具体的元素,因此这个元素的地址是 address2+6,其值*(address2+6)是一个整数,把 address1 和 address2 分别代入相应表达式,就成了:*(*(*(a+4)+5)+6);这就是我们熟知的运算符的等价表

10、达式。 而真正的多维数组并没有这么多“束缚”,相比之下简单得多,由于各维之间不是这种复杂的层级关系,元素 a456的偏移量可以这样直接获得:(4*8*9+5*9+6)*sizeof(int),再加上数组的首地址 a 就是元素 a456的地址了。但是,c 语言的数组能够这样用首地址加上(4*8*9+5*9+6)*sizeof(int)的形式来访问元素吗?显然是不行的。归根到底就在于 C 语言的再再论指针6地址数据类型不但有类型,还具有级别。就是这种层级关系造成了 C 语言只能用数组的数组当作多维数组。如果 C 语言非得要实现真正的多维数组,那么地址与指针的概念就得重新改写了。再再论指针7第三章

11、数组的解剖学这一章我们来讨论一下数组的内涵,对数组的内部构造进行一次解剖,看看里面究竟隐藏了什么秘密。 有了前面两章对数组名和 C 语言数组本质的澄清,再来理解这一章的内容,就容易多了。在下面的叙述中,笔者会用到一个运算符 sizeof,由于在不同的编译器和编译模式下,对一个地址进行 sizeof 运算的结果有可能是不同的,为了方便讨论,我都假设地址长度为 4 个字节。多数教材在讲述数组的时候,都是把重点放在外部表现形式上,很少涉及数组的内部,只告诉你如何做,却忽视了为什么要这样做。在解释的过程中,还会列出各种各样的表达式,例如:a、a+1、a0、a00、(p+1)2这样就是合法的,因为 p+

12、1 的结果仍然是一个指针。要注意的是,虽然后缀表达式是一个“指向某类型的指针”,但不要被这里所说的指针一词搞混了,上面的规定不能反过来使用。还是以上面的例子为例,我们可以 pi这样使用 p,这是符合上述规定的,但并不能因为指针 p 能够以pi这种形式使用就认为 p 是一个数组,这就错误了,不能反过来应用上述规则。最后说一下编译器对这个声明的形式跟人们所熟悉的 int *p 的形式大相庭径,初学者通常会感到迷惑,不理解的地方大致有四个:1。为什么会以这种形式声明?2。(*p)应该如何理解?3。为什么必须把第二维显式地声明?4。为什么忽略第一维?下面我们就一起逐个讨论这四个问题:1。这种形式是 C

13、 标准的声明语法规定的,由于本章不是对标准的解释,只是对标准的应用,因此笔者尽量以简洁的方式解释这个声明,详细的讨论将在第七章进行。C 标准的声明包含了两部分:声明:声明说明符 初始化声明符表 opt (opt 的意思是可选)在声明说明符里面有一项类型说明符,int 就是这种类型说明符。而初始化声明符表里面的其中一种形式,就是:直接声明符 常量表达式 opt(*p)9就是这种直接声明符加的形式。2。p 左边的*在这里不是取值运算符,而是一个声明符,它指出 p 是一个指针。而()括号是不能去掉的,如果去掉了,由于运算符优先级比*高,p 就会先跟结合,这样 p 就变成了一个指针数组,而不是指向数组的指针。题外话:

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 实用文档资料库 > 策划方案

Copyright © 2018-2021 Wenke99.com All rights reserved

工信部备案号浙ICP备20026746号-2  

公安局备案号:浙公网安备33038302330469号

本站为C2C交文档易平台,即用户上传的文档直接卖给下载用户,本站只是网络服务中间平台,所有原创文档下载所得归上传人所有,若您发现上传作品侵犯了您的权利,请立刻联系网站客服并提供证据,平台将在3个工作日内予以改正。