`
michael-java
  • 浏览: 18883 次
  • 性别: Icon_minigender_1
  • 来自: 合肥
最近访客 更多访客>>
社区版块
存档分类
最新评论

请您先登录,才能继续操作

第一章 什么是数组名?----一个让你吃惊的事实!

阅读更多

 

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

        指针是C语言具有低级语言特征的最直接的证据。在汇编语言里面,指针的概念随处可见。比如SP,SP寄存器又叫堆栈指针,它的值是地址,由于SP保存的是地址,并且SP的值是不断变化的,因此可以看作一个变量,而且是一个地址变量。地址也是C语言指针的值,C语言的指针跟SP这样的寄存器虽然不完全一样,但原理却是相通的。C语言的指针也是一种地址变量,C89明确规定,指针是一个保存对象地址的变量。这里要注意的是,指针跟地址概念的不同,指针是一种地址变量,通常也叫指针变量,统称指针。而地址则是地址变量的值。

        看到这里,也许你会觉得,这么简单的东西还用你来说吗?的确,对于p与&p来说,99%的人都能在0.1秒内脱口而出谁是指针,谁是地址,但是,又有多少人在使用指针的过程中能够始终如一毫不动摇地遵循这两个概念呢?不少人使用指针的时候就会自觉或不自觉地把指针和地址两个概念混淆得一塌糊涂了,数组名的滥用就是一个活生生的例子。这一点甚至连一些经典著作也没能避免。

        不过也不能全怪你自己,笔者认为某些国内教材应该承担最大的责任。这些教材一开始就没有给读者好好地分清指针与地址的区别,相反还在讲述的过程中有意无意地混用这两个概念。更有甚者,甚至在书中明言指针就是地址!说这话的家伙最应该在C语言这个地图上抹掉,呵呵。两个月前我在购书中心随手翻开了某个作者主编的一本被冠以国家“十五”规划重点研究项目的书,书里就是这么写的。当时笔者就感慨:不知道又要有多少人的思想被这家伙“**”了。

        实际上,地址这个东西,本来就是一种基本数据类型,本应该在介绍整数、浮点、字符等基本类型的时候把地址显式地放在一起讨论,这样在后面介绍指针与数组的时候就能避免许多误解。可惜不少教材或者根本没有谈及,或者就算提起这个类型也用了指针类型这个字眼。这就错了,指针不是类型,真正的类型是地址,指针只是存储地址这种数据类型的变量!打个比方,对于
int i=10;
10是整数,而i是存储整数的变量,指针就好比这个i,地址就好比那个10。
指针能够进行加减法,原因并不是因为它是指针,加减法则不是属于指针这种变量的,而是地址这种数据类型的本能,正是因为地址具有加减的能力,所以才使指针作为存放地址的变量能够进行加减运算。 这跟整数变量因为整数能够进行加减乘除因而它也能进行加减乘除一个道理。


        那么数组名又应该如何理解呢?用来存放数组的区域是一块在栈中静态分配的内存(非static),而数组名是这块内存的代表,它被定义为这块内存的首地址。
这就说明了数组名是一个地址,而且,还是一个不可修改的常量,完整地说,就是一个地址常量。数组名跟枚举常量类似,都属于符号常量。数组名这个符号,就代表了那块内存的首地址。注意了!不是数组名这个符号的值是那块内存的首地址,而是数组名这个符号本身就代表了首地址这个地址值,它就是这个地址,这就是数组名属于符号常量的意义所在。由于数组名是一种符号常量,因此它是一个右值,而指针,作为变量,却是一个左值,一个右值永远都不会是左值,那么,数组名永远都不会是指针! 不管什么话,只要说数组名是一个指针的,都是错误的!就象把刚才int i=10例子中的10说成是整数变量一样,在最基本的立足点上就已经完错了。

        总之要牢牢记住,数组名是一个地址,一个符号地址常量,不是一个变量,更不是一个作为变量的指针!

        在数组名并非指针这个问题上,通常会产生两种疑问:
1。作为形参的数组,不是会被转换为指针吗?
2。如果形参是一个指针,数组名可以作为实参传递给那个指针,难道不是说明了数组名是一个指针吗?

        首先,C语言之所以把作为形参的数组看作指针,并非因为数组名可以转换为指针,而是因为当初ANSI委员会制定标准的时候,从C程序的执行效率出发,不主张参数传递时复制整个数组,而是传递数组的首地址,由被调函数根据这个首地址处理数组中的内容。那么谁能承担这种“转换”呢?这个主体必须具有地址数据类型,同时应该是一个变量,满足这两个条件的,非指针莫属了。要注意的是,这种“转换”只是一种逻辑看法上的转换,实际当中并没有发生这个过程,没有任何数组实体被转换为指针实体。另一方面,大家不要被“转换”这个字眼给蒙蔽了,转换并不意味着相同,实际上,正是因为不相同才会有转换,相同的话还转来干吗?这好比现在社会上有不少人“变性”,一个男人可以“转换”为一个女人,那是不是应该认为男人跟女人是相同的?这不是笑话么。

        第二,函数参数传递的过程,本质上是一种赋值过程。C89对函数调用是这样规定的:函数调用由一个后缀表达式(称为函数标志符,function designator)后跟由圆括号括起来的赋值表达式列表组成,在调用函数之前,函数的每个实际参数将被复制,所有的实际参数严格地按值传递。因此,形参实际上所期望得到的东西,并不是实参本身,而是实参的值或者实参所代表的值!举个例来说,对于一个函数声明:

void fun(int i);

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

        在后面的章节中,笔者将严格地使用地址这一概念,该是地址时就用地址,该是指针时就用指针,以免象其它教材那样给读者一个错误的暗示。

---------------------------------------------------------------------------------------------------------------------------------

---------------------------------------转载:没油的猪的系列文章

分享到:
评论

相关推荐

    springmybatis

    请注意,这里面有一个方法名 selectUserByID 必须与 User.xml 里面配置的 select 的id 对应() 重写测试代码 程序代码 程序代码 public static void main(String[] args) { SqlSession session = ...

    网页设计课件校内资源

    5. **第七章 数组.ppt** - 数组是存储数据的重要方式,这一章可能涵盖了数组的声明、初始化、操作和数组在实际问题中的应用。 6. **第五章 选择结构.ppt** - 选择结构(if语句、switch语句)是决定程序逻辑的关键,...

    第一章 MATLAB 基础 (2).pdf

    MATLAB 是一款由 MathWorks 公司开发的科学与工程计算软件,被广泛应用于众多领域,包括自动控制、数学运算、信号分析、计算机技术、图像处理、财务分析、航天工业等。MATLAB 在数学计算领域已成为事实上的标准,...

    你必须知道的495个C语言问题

    事实上,能够确保的只有如下几点: …… 目录第1章 声明和初始化 第2章 结构、联合和枚举第3章 表达式第4章 指针第5章 空指针第6章 数组和指针第7章 内存分配 第8章 字符和字符串 第9章 布尔表达式和...

    jQuery权威指南-源代码

    jQuery是继Prototype之后的又一个优秀JavaScript框架,深受全球开发者欢迎,已经成为Web开发领域的事实标准。jQuery以其轻巧的体积、强大的选择器、出色的DOM封装、丰富的插件支持使得广大的Web前端开发者得心应手,...

    CodeIgniter:php敏捷开发框架web快速开发详解

    第二个例子,现在让我们想象你正在用 HTML 写一个数据输入窗口,你想要一个下拉输入框。下拉框中有三个选项。代码如下: 复制代码到剪贴板HTML 代码 <option value="1">www.this.com</option> <option value="2">...

    SWI Prolog 入门级日语资料

    需要注意的是,虽然SWI-Prolog是一个特定的Prolog实现,但上述提及的知识点是大多数Prolog系统所共有的。了解这些基础概念是深入学习逻辑编程和使用SWI-Prolog的关键。对于懂日语的学习者来说,这份资料能够提供在...

    2023年C语言程序设计基本知识点.doc

    第一章 C语言基本知识 1. C源程序的框架:C源程序的框架包括编译预处理、主函数等,主函数的名字固定为main,位置不一定在最前面,可以在程序的中部或后面。 2. C语言源程序的书写规则: * C源程序是由一个主函数...

    Python二级等级考试电子教案 第11章 Python第三方库纵览.pdf

    根据提供的文件信息,以下是关于“Python二级等级考试电子教案 第11章 Python第三方库纵览”的详细知识点: 在本章中,我们首先了解了Python的第三方库生态。这些库极大地扩展了Python的使用范围和能力,涵盖了从...

    计算机二级ms

    ##### 第一章:数据结构与算法 - **算法**:算法是解决问题的一种详细步骤或一系列指令。在计算机科学中,它指的是用于处理数据、执行计算以及解决特定问题的一系列明确指令。算法的质量直接影响到程序的效率和性能...

    C语言入门经典(第4版)--源代码及课后练习答案

    1.3 编辑第一个程序 4 1.4 处理错误 5 1.5 剖析一个简单的程序 6 1.5.1 注释 6 1.5.2 预处理指令 7 1.5.3 定义main()函数 7 1.5.4 关键字 8 1.5.5 函数体 8 1.5.6 输出信息 9 1.5.7 参数 10 1.5.8 控制符...

    人工智能+专家系统+推理机设计-第六章 搜索策略.ppt

    第六章“搜索策略”主要探讨了如何在复杂的问题空间中找到有效的问题解决方案。 **基本概念** 1. **推理**:推理是根据已知规则和事实推导出新知识的过程。它分为多种类型,如演绎推理(基于逻辑规则)、归纳推理...

    北大青鸟ACCP5.0计算机单词汇总

    **第一章 基本单词** - **mouse 鼠标**:用户通过移动来控制屏幕上的光标。 - **Chinese 中文**:中国使用的语言。 - **English 英文**:国际通用的语言之一。 - **save 保存**:将文件内容存入硬盘或其他存储设备...

    c#学习笔记.txt

    很多人觉得它应该像C或者C++,但事实上它更像是java的一个clone,所以作为入门,读一下清华大学出版社出版的《Java 语言与面向对象程序设计》可能会对你有所帮助。本文假定你具备一切学习此语言所需的知识,没有也不...

    人工智能动物识别系统

    本系统主要通过结合第五章内容,以动物识别系统为例,实现一个基于规则的人工智能系统。该系统旨在通过计算机程序来模拟人类专家的决策过程,进而实现对动物特征进行识别与分类。整个实验计划用时6学时。 #### 二、...

    编写高质量代码:改善C 程序的150个建议

    #### 三、第一章:从C继承而来的 这一章首先强调了C和C++之间的密切关系。C++被视为“更好的C”,继承了C语言的许多语法特性,并在此基础上进行了扩展和改进。为了更好地理解这一点,我们首先来看一个有趣的例子: ...

    自己动手写操作系统(含源代码).part2

    我们有许多源代码公开的操作系统,可供随时下载和阅读,看上去好像让实现一个供自己把玩的微型操作系统变得容易很多,但事实往往不尽人意,因为这些代码动辄上万甚至几十几百万行,而且细节之间经常互相关联,要...

    自己动手写操作系统(含源代码).part1

    我们有许多源代码公开的操作系统,可供随时下载和阅读,看上去好像让实现一个供自己把玩的微型操作系统变得容易很多,但事实往往不尽人意,因为这些代码动辄上万甚至几十几百万行,而且细节之间经常互相关联,要...

Global site tag (gtag.js) - Google Analytics