

免费预览已结束,剩余9页可下载查看
下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
个人收集整理-ZQC语言声明、指针、数组、函数、typedef等等的一通“超级扯”关于语言声明、指针、数组、函数、等等的一通“超级扯”按:在论坛上,有坛友这样提议: (*)();应该被写作: (*)() ;才是“严谨”、“合乎逻辑”的。对此,我来说说吧 关键字的意思是“关于类型的定义”。为什么要有“类型”这个观念?我们都知道,在计算机的内部,一切数据和功能性代码(比如函数、命令、指令等)都是以、组成的有序排列来进行存储和运算等处理的。所以,我们总是会这麽说:“计算机只认得二进制”。在编程语境中,当我们写下: ;的时候,实际上是在告诉编译器这位老:请您为我的程序在存储器中预留一块地方,这块地方不论将来会存储什么样的东东,您一律把那些东东视作“整数”来处理。老根据自己所在的计算机架构或操作系统环境,确定个“整数”需要在存储器里面占有多大的地盘。而我们经常使用的架构或环境,决定了,这块地盘的大小,通常是即。而“”这个符号,是我们的程序用来称呼那块地盘的代号。也就是说,在我们的程序中,将来凡是用到了“”这个符号,就是在告诉老:我是让您在那块地盘上做些什么,如读取那里的数据(当作为右值),或向那里刷入什么数据(当作为左值)。当然,这所有的处理,均是把那块地盘上既有的数据或将要刷入的数据,作为“整数”来看待。以上这一切,就叫做“定义性声明( )”,我们可以根据不致引起歧义的某种习惯,简称它为“定义”或“声明”。(严格地说,变量的定义与声明,两个概念之间,有一些微妙的联系与区别,在此不再赘述。)语言采用了不同于其他语言的规则,来让程序员进行这种声明工作。作为比较,我们可以观察在语言中,类似的工作,是如何进行的:;就这个简单的例子看来,我们除了看到语言似乎利用了一种更加接近人类语言习惯的规则(语序以及冒号)之外,与还是大同小异的,但是,后面所讲到的例子,就会把这种特性上的差异,扩大地展现出来。此外,我们也不难意识到,的这个规则,会跟基于对象()的某些思路,有一些“暗合”的地方,比如说:当我们利用 . .;来定义一个类之后,我们可以利用 ;来将这个类实例化出来一个具体的对象,即 。我们已经了解到,其实是对与其他具有相同“结构”的实例们的一种抽象。那么,我们可以反过来推: ;就可以用“变量其实是这个类的一个实例化”这样的思路,来揣度(仅仅是一种类比性思维)语言中声明变量的这件事情。以上这些,都是比较容易理解的。但是语言不会就这麽轻易地放过我们。在语言编程语境中,把一个“符号”的“类型”或“性质”表达出来,有远比“类型名 变量名”更为复杂的方式。比如: ;在这个例子中,引入了方括号。围绕符号“”的事情就复杂了一层。方括号紧跟在符号“”的右边,说明符号“”是用来称呼一段连续分布在存储器中的多个数据,俗称“数组”。而这一段数据中的单位数据,即每个元素的“类型”是,且所有元素均被视为类型,概莫能外!“类型名 变量名”的简单做法,已经失效了。在中,我们不能用 ;或 ;这样的写法来声明一个元素均为类型的数组。但是,在语言的规则里,就可以这麽写: : () ;在语言的“侄子”语言中,用“”来声明一个数组:();而在语言中,即没有关键字,也没有用来声明数组的符号,甚至语言本身都不会对数组元素的下标是否越界做出令程序员知晓正误的判断 这一切,不得不让我狗胆包天地,下了这个狂妄的断言:“在语言中,压根儿就没有数组这个东东!”(哎哟一只鞋子袭来!)不那么狂了,把话说回来:在语言中,通过引入方括号,来声明一个数组。注意,这个方括号对,与用“数组名下标”的写法来指明具体某个元素这种方法里的方括号对,是完全不同的。在指明(术语叫“引用”)数组中某个元素的时候,也是用方括号对。这里的方括号对,叫做“取下标操作符”。其实“取下标操作符”是一种被包装起来的指针运算符,即一种存储器上的偏移量运算,所以,我们可以大胆猜测:在语言中,这种利用方括号对来引用数组中某个元素的做法,应该是承袭于某些更加低级的(更加接近计算机存储机制底层的)语言。这是语言承袭老语言的一方面,那么,语言在其内部扩展的一方面,就是把方括号对,作为数组声明的一个符号。当“*”这个邪恶的星号,被语言引进来了之后,关于声明的事情,就变得更加复杂和诡异了。比如: *;我们如果把星号看成一个“读取指针所指向的存储器某个位置上的数据”的符号,又顽固地抱持着以“类型名 变量名”来解读声明的这种思路的时候,上面这行语句,就彻底无解了 详述如下:如果星号与先结合构成一个意群,那么,该语句的意思就是:读取指针变量所指向的位置上的数据,然后这个数据数组完全说不通了!如果与方括号对先结合构成一个意群,那么,该语句的意思就是:一个名叫的数组成为一个指针,该指针指向一个类型为的数据可是,一个数组(即多个元素组成的序列)能成为一个指针吗?这同样也是不可想象的事情。乱猜是没有结果的。我们必须用语言自己的规定,来解读和运用这种写法。合乎语言规定的思路是:符号先与紧跟其后的方括号对结合,显明了是指代一个数组。而数组的每一个元素,都是一个指针变量,这些指针变量乃均为指向某些类型的数据之用。根据上述思路,该行语句可写为:* ;即与星号先结合,构成一个意群,我们且以代之。那么,该行语句即恒等变换为: ;与“* ;”比较,解读思路是一致的,即,一切放在“”顶头的东东,均指明了数组里每个元素的类型。(不妨强迫自己这样记住:数组是没有类型的,数组只是一段连续分布在存储器中的数据而已,而这些单位数据即元素,是有类型的。)当我们讨论到这里,就可以把关于的概念自然地引入了。我在上面说到,可以与星号先结合构成一个意群,且可以用这个新符号代表它,那么,关键字就可以登场了: * ; ;在这里,不妨这样理解的用途,它把“*”打了包,取名为“”(即所谓“别名”),注意,这个别名不是变量名,而是类型名。由于“”是一个类型名,所以,“”可以被用来声明该类型的变量(或者由一群该类型的变量构成的数组)。我们依然可以用“类 对象(实例化)”的类比性思路,来理解这个过程:在第一行里,“*”是一个抽象,“”是该抽象的一个实例化;在第二行里,“”是一个抽象,“”这个数组里的每个元素,分别都是该抽象的一个实例化(一共有个实例化)。之所以,我们依然可以用“类 对象”这个类比性思路,必须有一个前提,那就是:“ ”中的与之间不是(由到的)单射关系,而是可以是“一对多”的。也就是说: * ; * ; ; ;是正确的。既然,我们可以用“类 对象”的类比性思路,来理解,如同理解“数据类型名 变量名”一样,那么,为什么下面这样写就是错误的呢?* ; ;在上面的第一行代码中, 是“*”这个类型抽象的一个实例化出来的变量。而只有用了关键字,才能让“*”这个类型抽象实例化出来一个类型,而后者又是实例化的变量的一个抽象。接下来,我们回到“ *;”这个例子。上面说了,由于把星号、方括号引入了对于符号的声明,使得语言的声明方法,变得特别复杂,甚至非常晦涩。我们之所以感到“ *;”这样的声明很复杂,可能有以下几点原因:第一,我们对声明的客体,即“我们到底是为谁而声明?”这个问题,回答起来,不是那么有底气。第二,即便是知道了我们为谁而声明,我们也不知道这个东东的“性质”到底是个啥?整数?字符?指针(又是指向另外某一个谁的)?还是函数?我们必须要做出明确的解答:对于第一个原因中的问题,答案是:声明的客体,是该声明中出现的唯一的一个“不明确”的符号。所谓“明确的”,就是已经被定义 、声明、初始化的。比如在 *;里面,其中的一定是被事先定义 、声明、初始化了的。“”是关键字,星号和方括号以及句尾的分号均是语言的保留部分。那么,唯一的一个“不明确”的符号,就是“”。所以,我们可以放心大胆地认定:整个语句的声明客体是符号“”,即我们是为“”而声明。对于第二个原因中的问题,就是难点了。符号“”是被其他的“已明确的”符号、星号、方括号、各种关键字所层层包围或粘黏起来的,而不像语言中的那么明显(符号被清晰地放在冒号的左边)。 这就是语言的特色了: 一个符号的“性质”,由它所出现的位置,即它的处境、它被什么样的东东(按什么样的次序)所包围或粘黏,来决定!根据我很浅薄的观察和很笨拙的思考,得出一些结论,希望能对大家有所帮助:()在声明中,符号出现在方括号的左边,符号的性质一定是:指代一个数组,即作为数组名。()在声明中,符号出现在圆括号的左边,符号的性质一定是:指代一个函数,即作为函数名。()在声明中,符号出现在星号的右边,符号的性质一定是:它跟右边所构成的整体的其中之元素(在情况()下)或返回值(在情况()下)是指针,且指针所指向的数据之类型,一定由星号左边的关键字来确定。本教程由深圳天荷伞业的整理 专业从事雨伞、太阳伞、礼品伞、高尔夫伞、发光伞、广告伞等产品的专业雨伞厂 我们的网站是() 有您的支持我们会更专注。根据以上结论所确定的原则,我们就不难解读“ *;”。既然可以根据上述的原则,来解读“数据类型名 变量名或混杂的东西”这种声明,也就可以利用这些原则,来解读语句。我们可以把 * ; ;改写成: * ; ;上下两段代码,是完全等效的!请看, 在 语句中,“”这个符号被夹在了星号与方括号当中,但是这个符号的意义完全没有失真。这就是语言的声明规则以及的用法,所体现出的它的特色。你说它晦涩也好,说它变态也好,甚至说它有缺陷、有陷阱也好 但是,它保持了高度的逻辑性、可理喻性,以及由此带来的高度的可扩展性。我在上面,曾经说过“在计算机的内部,一切数据和功能性代码(比如函数、命令、指令等)都是以、组成的有序排列来进行存储和运算等处理的。”所有前面所讲述的,都是关于数据,即变量、由连续存储的变量所构成的数组,它们在存储器中的存在形态,均是和构成的序列。由于这些序列在存储器中都有确定的位置,所以,指针这个机制的存在,就有了确定性的基础,也就是说,语言可以允许我们利用指针,来操控(指代、指向、引用、解引用、读取、刷入)这些分布在存储器中各个位置上的数据。那么,功能性代码,也是如此。我们的程序赖以运行的最基本结构函数,也是以和所构成的序列,于存储器中存在的。而我们又知道“计算机只认得二进制”,那么,从这个角度上说,不论是数据,还是函数,在计算机内部那头看来,都是一样的东西,计算机本身是“无法区分”数据和函数的 这就是黑客的基本原理之一。也就是说,我们同样也可以利用指针,来操控(指代、指向、引用、解引用、读取、刷入)函数。所以,在语言中,存在着这麽一些指针变量,它们所指向的,是某个函数,更具体地说,它们分别指向了某些函数可以被切入运行的那个“入口”。接下来,我们要注意到一个事实。在语言中,对于函数的声明,并没有用到一个类似于“”这样的关键字。 ();上面的这种写法,是中的。而且,在中,这样的写法,实际上,是在显式地为“”这个类,实例化出一个名叫的对象!也就是说, 在中,一切函数,均是“”这个类实例化出来的对象。那么,在语言中,是怎么声明函数的呢?在语言中的函数,与数学上的函数一样,有三个要素:定义域(输入)、对应法则(加工处理输入用以将来输出)、值域(输出)。具体地说,在语言的函数的三要素中:输入部分,即是函数的参数; 对应法则,即是函数体所实现的功能;输出部分,即是函数的返回值。对于参数部分,必须确定一个或多个参数中每个参数的数据类型;对于返回值部分,返回值只能是以一个整体的单元而存在,那么就必须确定该单元的数据类型;对于函数体部分,在声明中,则不必和盘托出,在声明之后,自然须要写明(定义)。所以,对于函数的声明,只要包含了关于对于参数部分的声明、对于返回值部分的声明,当然还有声明的客体,即函数名,就完备了。上述三者,必须按次写出,如下:返回值类型 函数名(关于参数的声明);函数体即实现函数内在功能的部分,属于函数的定义,不在函数声明的范围之内。上述这个声明的规范,在 中,叫做“函数原型”。再援引之前的例子,* ;当这里的数组,是由一个函数的返回值来确定的时候,比如是由这个函数的返回值来确定,那么,代码就应该是:* ();但是,很遗憾,上面这种写法是错误的。逻辑上并没有错,只是语言中有一条硬性的规定:函数不能返回一个数组,即函数的返回值,不能是一个数组。上面的写法,会使得编译器报错:: 不过,语言允许函数返回一个指向任何数据类型的变量或数据结构的指针。那么,指针当然可以被用来指向一个数组。所以,我们若想利用函数的返回值来确定一个数组,可以令函数返回一个指向该数组的指针 用这种“迂回曲折”的方式,来实现我们的意图。也就是:* (*();根据之前已经提到的原则: 后面紧跟圆括号,那么首先圆括号结合,这个符号一定是用来指代函数,即作为函数名;后来,这个函数整体的左边紧贴着星号,意思是,该函数的返回值,是一个指针;这个指针作为一个整体被夹在一个圆括号里面,后面又紧跟着一个方括号,那么,该整体是用来确定(其实不是直接确定,而是“指向”)一个数组,由于是利用指针指向数组,而不是直接确定数组,所以,这样做的话,跟用数组名符号(如上面的“”)来指代数组,还是有一些微妙的区别。顺别说一句,在这个函数的定义里,按照我们例子的意图,返回语句必须是: ;如果写成“ ;”,也可以编译通过,但是老会骂一声,之后运行结果无异。我们之前一开始介绍函数的时候,提到了,可以用指针来操控函数,也就是说,我们可以用一个指针,来指向某个函数。那么,现在我们用这个指针变量来指向这个函数。既然是声明指针变量,那么它左边所紧贴的,一定是星号。于是,代码就应该是:* (*(*)();如果要解读的话,还是老规矩:在这个符号所在的圆括号里面,该符号右边无东东,那么直接先跟左边的星号结合,表示该符号所指代的,一定是一个指针。然后,整个这个圆括号就跟之前的 这个函数名等效。显然,在这一切的例子中,这个函数,是没有参数的 在原型中,最好写成()以警醒自己。现在,我们有这麽一个函数叫,它跟干的事情差不多,但是它有一个参数,其类型为。类似上面的,是指向函数的一个指针变量。那么,关于这个函数的代码,如下:* (*(*)();如果函数的参数,不是一个类型的数据,而是一个指向类型的数据的指针的话,代码就应该是这样的:* (*(*)( *);怎么样?如果再让、什么的关键字穿插其中的话,那么,上述代码,假若作为考试题(考察 到底是个什么性质的东东)的话,也算是一道很厉害的难题了。(其实遇到、关键字,也不要怕!规则也非常简单:()如果它们的左边没有星号的话,那么它们就跟紧邻的关键字结合;()如果它们的左边紧贴星号的话,那么它们就立即先与星号结合了再说,表示星号(再)右边的符号所指代的指针,是“坚贞不屈”的。)之前还提到:在语言中,一个符号的“性质”,由它所出现的位置,即它的处境、它被什么样的东东(按什么样的次序)所包围或粘黏,来决定 那么,这个 被一层层的星号、圆括号、方括号、关键字等等所围绕和粘黏,但是,由于这些星号、圆括号、方括号、关键字等等是按着某种“次序”排列的,所以,的“性质”,就在这种“次序”的存在方式中,得到了确定,而永远不会失真和发生歧义。所以,我们可以把抽象出来,用来“打包”,代码如下: * (*(*)( *);这也就是:作为一切跟指针具有相同性质的指针的一个抽象。如果要将这个抽象实例化的话,就这样写: ; 函数的指针。如果我们在此前,已经把“ *”用打包为“”的话,那么,上述声明就可以分解地写为: * ; * (*(*)();上述两行代码,实际上是对应了下面这个最初的复杂的声明:* (*(*)( *); 合乎规范的声明。现在,我们要把“ *”类型抽离出来,我们只抽离“ *”它一个,那么,按照那位坛友的设想,可以写作: * (*(*)() ;但是,恐怕连那位坛友也肯定同意:这样写没有任何意义!因为“”到底是什么?没有任何合理的信息。所以,只能通过“ * ;”把“”定义出来。那么,在“ * ;”之后,我们就可以这样声明:* (*(*)();现在,我们想要把“”抽离出来,那么,按照那位坛友的设想,可以写作: * (*(*)() ;那位坛友一定会说“”必然是第三个星号要修饰的东东,这是按照那位坛友所发明的新规则;我说,我也可以发明一个新规则,即可以重新定义已经被定义过的类型。在合乎语言固有规范的情况下,加上我的这个“新发明”,不会发生冲突(总是对最早被定义的符号没有被定义的符号视为无穷久远按照最后一次的定义为准);但是
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 人力资源社会保障部劳动合同示范文本(终稿)2篇
- 奶茶店用工协议书7篇
- 二手房协议书范本6篇
- 赡养子女协议书6篇
- 租赁物业场地合同范本
- 珍爱网婚介合同范本
- 人参采购合同范本
- 班班通维修合同范本
- 中日合资协议合同范本
- 出售农村别墅合同范本
- 建立隐患闭环管理制度
- 《多样的美术门类》教学课件-2024-2025学年赣美版(2024)初中美术七年级上册
- T/CECS 10026-2019绿色建材评价建筑门窗及配件
- 企业往来款协议书
- 2025山东中考:生物高频考点
- DB65T 4815-2024 清洗消毒中心内畜禽及其产品运输车辆消毒技术规范
- 《儿童癫痫护理指南》课件
- 数学三年级上册二 观察物体1 看一看(一)教学设计
- 2025-2030中国PEM水电解槽行业现状调查与发展前景规划研究研究报告
- 2025年中国人保财险全系统黑龙江分公司招聘笔试参考题库含答案解析
- 施工阶段全过程造价咨询管理办法
评论
0/150
提交评论