文档介绍:第12章 C语言难点——指针初探
欢迎走进内存这片雷区,比尔盖茨曾经说过,640K内存对大多数应用来说应该足够了,看来天才也有说错话的时候,内存管理程序往往是最令程序员感到头大的地方,也是程序bug集中营, 因此,掌握内存的基本知识是十分必要的,本章要介绍内存的使用以及C语言的难点所在—指针。
计算机中的内存
熟悉计算机的读者知道,内存是平时接触较多的一个概念,问一个问题:内存是什么?从硬件形态上说,内存就是一条形物理设备,从功能上讲,内存是一个数据仓库,程序内在执行前都要被装载到内存中,才能被中央处理器执行。
举Windows系统为例,执行安装在硬盘上的某个程序,实际上是将该程序的指令和数据导入内存,供中央处理器执行的过程。
内存是由按顺序编号的一系列存储单元组成的,在内存中,每个存储单元都由唯一的地址,通过地址可以方便地在内存单元中存储信息。内存中的数据要靠供电来维持,当计算机关机或意外断电时,其中的所有数据就永久地消失了。
内存地址
可以将内存看成一个个连续小格子的集合,为了正确地访问这些小格子,必须给这些小格子编号,正如平时我们讲某栋房屋在A小区X楼Y单元Z房间一样,这个A、X、Y和Z等实际上对该房间的编号,有了这个编号,或者更通俗地说是“地址”,我们就能从一个城市的万千栋长的几乎一样的房子中找到该房间。
内存地址的引入是同样的道理,为了正确访问每个内存单元,对其进行编址,以32位计算机为例,其地址空间为32位,采用32位地址编码,诸如0X87654321的形式。
内存地址是连续的,相邻内存单元间的地址差1,可以把内存看成一个平坦连续的一维空间。
内存中保存的内容
内存中保存的是数据,这几乎是句废话,在计算机中,一切信息都是以二进制数据的形式体现的,每个内存单元的容量是1B,即8bit(8个0、1二进制位)。
中央处理器,即CPU,进行的处理离不开内存,使用过windows系统的读者都知道,双击某个可执行程序,CPU会执行它,这实际上是复杂的内存载入过程:
(1)程序要进行的操作对应的代码被装载到代码区。
(2)全局和静态数据等装载到数据区
(3)开辟堆栈,供临变量等使用
可见,内存中的数据是多种多样的,既可以是操作,也可以是数据,都被存储在一个个的内存小格子中,每个小格子存储8个二进制位。
地址就是指针
在进一步说明指针概念前,本节将使读者对指针有个感性的认识,所谓指针,指的是“储存的内容是地址的量”,两个要点:一、指针是个量,对应着一块内存区域,二,指针存储的信息是某个内存单元的地址。指针的示意如所示。
指针的定义
本节将解释一个问题:如何定义一个指针,可以说,指针是C语言中的必须内容,也是难点内容,指针是C语言管理内存的强大工具。
指针变量的声明
指针可以视为一个普通变量,通常所说的定义一个指针实际上是声明一个指针变量的过程,编译器根据指针变量声明语句,为指针变量开辟内存空间,使其有实际意义,这样,指针变量才可用。
在声明一个指针变量时,需要向编译器提供以下信息:
指针的类型,原则上指针类型应与其指向的数据类型一致,但也有例外,稍后会讲到。
指针变量名。
举例来说,下述语句用以声明一个指向int型数据的指针pInt:
int* pInt;
不难看出,要声明一个指向某种类型的指针变量,其基本形式为:
类型* 指针变量名;
要在一行语句中同时声明两个指针变量,后面的指针变量前同样要加星号,如:
int* p1=null, *p2=null;
指针变量的初始化
在声明一个指针后,编译器并不会自动完成其初始化,此时,指针的值是不确定的,也就是说,该指针指向那块内存单元是完全随机的,因此,指针变量的初始化十分重要,直接使用未加初始化的指针变量可能会给程序带来各种内存错误,因为完全不知道哪块内存会被修改掉。
如果在指针变量声明之初确实不知道该将此指针指向何处,最简单的方式是将其置“0”,C语言中提供了关键字NULL,如下:
int* pInt=NULL;
这样,指针pInt便不会在内存中乱指一气。
如果要让指针变量确切地指向某个变量,需要使用&取地址操作符。
指针变量的值
“指针变量的值”是指针本身存储的数值,这个值将被编译器当作一个地址,而不是一个一般的数值。在32位程序里,所有类型的指针的值都是一个32位整数,因为32位程序里内存地址长度都为32位。“指针所指向的内存区“就是从指针的值所代表的那个内存地址开始,长度为sizeof(指针所指向的类型)的一片内存区。
本书中,说一个指针的值是A,即是说该指针指向了以A为首地址的一片内存区域;反之,说一个指针指向了某内存区域,即是说该指针的