版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、指针和数组通过空间的标识符来处理该空间数据的方式称为直接引用。处理简单的数据时,直接引用的形式简单、容易实现,但用来处理大量数据却不简单。例如,存储1万个整数需要1万个名称,传递1万个数据需要1万次赋值,这都是既繁琐又低效的操作。而且1万个整数一般还会是一个序列,数据之间具有逻辑上的前后顺序,那么按逻辑上的顺序去处理这些数据就需要先按逻辑的顺序存储这些数据。既要表示数据,又要表示数据之间的关系,这是直接引用方式难以实现的。为了解决这个问题,我们参考机器语言中的要素地址。机器指令由操作码和操作数组成,操作数一般是数据的地址。在机器语言程序中,地址是处理和数据之间的媒介。在机器语言程序设计中,一个
2、重要的步骤是为数组安排空间,以确定它们的地址。空间相邻,地址就容易计算。按照这种逻辑可以得出一个很自然的设计方案:一组类型相同、逻辑上具有前后关系的数据存储在一组前后相邻的空间,这样可以通过一个数据的地址简单地计算出其余数据空间的地址,然后通过空间地址(而不是名称)去处理数据,我们称这种访问方式为间接引用。要实现这种设计,就需要把这组相邻的数据空间作为一个整体以及相应的地址都引入C语言类型。1指针常量1.1指针的类型变量的名称经过编译之后就在系统内部“消失”了,留下了地址和类型,地址是该变量空间的起始地址,类型是该变量的类型(见图1中的表)。类型将指示编译器怎样操作特定地址上的内存区域:该区域
3、包含多少连续的字节,数据存储的格式,以及可以实施哪些基本操作,我们把这个类型称为地址的基类型。通过地址来操作数据空间的方式称为间接引用。以表1为例,地址0x12ff78的基类型为整型,通过该地址去间接引用时,系统将连续4个字节0x12ff780x12ff7b当作整型变量空间。地址0x12ff70的基类型是双浮点型,编译器将0x12ff700x12ff77的8个字节视为双浮点型空间。同样的地址,由于地址的基类型不同,编译器对该地址上的空间的解释也不同,或者说编译器将其看作不同类型的数据空间。例如,上面的地址0x12ff78,如果地址的基类型是单浮点型,那么间接引用的结果是,0x12ff780x1
4、2ff7b为单浮点型空间。为了实现我们的设计,需要首先把地址这个硬件操作机制中的数据引入C语言。而在C语言中,数据要有类型。类型是数据的“身份”,决定着数据存储空间的大小、存储格式和对数据可以实施的基本操作。从存储空间的大小和存储格式来说,地址相当于无符号整型数,即按无符号整型格式存储,而且在32位操作系统中需要占用4个字节。但是地址的操作与无符号整型数的不同,它与间接引用的数据有关,因此,为把地址这个数据引入C,需要为它定义新类型。新类型应该具有什么样的标识符?这就要分析地址的特点。地址关联着两个存储空间,以图1的地址0x12ff7c为例:一个是地址本身作为常量存储的空间;另一个是通过该地址
5、间接引用的数据空间,即我们形象地用箭头指向的整型变量n的空间。根据这个处理特点,把地址本身的类型称为指针类型或指针型,指针指向的数据的类型称为指针的数据类型或指针型的基类型或指针的基类型。因此,指针是一个复合类型。1变量与地址当我们说一个指针是某种类型或某种类型的指针,指的是该指针的基类型,或该指针指向的数据的类型。例如一个指针是整型的,或一个整型指针,是指该指针的基类型是整型的,或指针指向的数据是整型的。指针是一个复合类型,因此它的标识符也是复合的,由表示指针类型的符号*和表示指针基类型的符号联合组成。例如,整型指针用int*表示,双浮点型指针用double*表示。*代表指针类型,int或d
6、ouble表示指针的基类型。例如图1的地址0x12ff78,地址的基类型为整型,被引入C语言之后,用字面值常量来表示便是(int*)0x12ff78,我们称之为指针型字面值常量或指针字面值常量。1.2指针的基本操作现在我们需要把地址的间接引用操作引入C语言作为指针型的基本操作:在指针前加间接引用运算符,也称解引用运算符*,所得表达式作为该指针指向的空间的标识符,这种由指针运算构成的数据空间表达式称为间接引用表达式或解引用表达式。图1的表代表了下面的等价式:x=*(double*)0x12ff70m=*(int*)0x12ff78n=*(int*)0x12ff7c我们可以做个实验来证实这个等价式
7、。首先通过输出语句确定变量的地址:printf("%x,%x,%xn",&n,&m,&x);输出变量n、m和x的地址假设输出结果是12ff7c,12ff78,12ff70(如果不是,那么以输出的结果为准)。然后通过指针常量间接修改变量n、m和x的值:*(int*)0x12ff7c=5;/相当于n=5;相当于 m=n;*(int*)0x12ff78=*(int*)0x12ff7c;/*(double*)0x12ff70=3.1415;/相当于x=3.1415;printf("n=%d,m=%d,x=%fn",n,m,x);输出变量n
8、、m和x的值,检验结果在我们的设计方案中,由一个数据空间地址计算出其余的数据空间地址是主要的操作,现在我们将它设计为指针类型的基本操作:指针加减一个整数。假设一组双浮点型数5.5、6.6、7.7、8.8、9.9,它们的存储空间按地址从小到大依次相邻,地址依次为0x120000、0x120008、0x120010、0x120018、0x120020,用指针字面值常量来表示便是(int*)0x120000、(int*)0x120008、(int*)0x120010、(int*)0x120018、(int*)0x120020。如果用指针加减一个整数的基本运算来表示,那么指向5.5的存储空间的指针(i
9、nt*)0x120000加1应该是指向6.6的存储空间的指针(int*)0x120008,加2应该是指向7.7的存储空间的指针(int*)0x120010,依次类推(见图2)。反过来,指向9.9的存储空间的指针(int*)0x120020减1应该是指向8.8的存储空间的指针(int*)0x120018,减2应该是指向7.7的存储空间的指针(int*)0x120010,依次类推。概括地说,一个指针加上(或减去)一个整数所得到的指针,其地址会增加(或减少)指针基类型大小(字节数)的该整数倍,即指针的算术运算单位是该指针基类型的大小,或者说是指针指向的数据类型的大小。图2指针算术运算对指针做加减整数
10、的运算是没有限制的,但是对指针间接引用的空间是有限制的,它必须是系统分配的、可以由指针间接引用的空间,否则就可能破坏系统空间的数据。这个限制使我们不能随便使用一个指针字面值常量进行间接引用运算。例如下面的语句:*(int*)0x12ff7c=6;只有在0x12ff7c确是一个已经定义的整型数据空间地址的时候才是合理的。取址运算&实质上是指针的基本操作。例如,有下面的等价式:x=*(double*)0x12ff70对上面的等价式左右实施取址运算&,有等价式:&x=&*(double*)0x12ff70=(double*)0x12ff70对上面的等价式左右实施间接引
11、用运算*,有等价式:*&x=*(double*)0x12ff70=x上面的等式说明取址运算&和间接引用运算*互为逆运算。指针的值是无符号整型数,可以实施逻辑运算和关系运算。综上所述,间接引用*、取址&、加减一个整数、两个指针相减、关系运算和逻辑运算是指针的基本操作。两个指针能够相加或相乘吗?不行,因为它无意义。一种类型应该包含哪些基本操作,这取决于我们设计这种数据类型的目的或用途。2数组类型我们的设计是,一组类型相同、逻辑上有前后关系的数据,存储在物理上前后相邻的变量空间,使得通过一个数据空间的地址可以计算出其余的数据空间地址,然后通过空间地址(而不是空间名称)去间接访
12、问数据(空间)。前面介绍过把地址作为指针引入C语言,现在我们把物理上前后相邻的一组变量作为一个整体引入C语言。我们把这个整体称为数组类型变量,简称数组,把每一个作为成员的变量称为数组元素,数组元素空间按地址从小到大依次相邻。数组元素的个数称为数组长度或容量。根据我们的设计,对数组元素的引用是间接的,这需要知道指向第一个数组元素的指针。而编译器对空间的分配是随条件变化的,指向第一个数组元素的指针不能是字面值常量,只能是符号指针常量,即用符号表示的指针常量,这个符号由数组名兼任,称为(一维)数组指针,数组元素类型就是数组指针的基类型。数组名既是数组变量的标识符,又是指向第一个数组元素的指针常量,具
13、体代表什么要根据上下文来确定。定义一个数组需要指出数组名、数组长度和数组元素类型(数组指针基类型)数组的定义格式为:类型标识符数组名整型常量表达式;其中类型标识符表示数组元素类型,整型常量表达式表示数组长度即容量。数组类型没有独立的标识符,因为数组实际上是一个复合类型,数组的存储格式、存储空间大小和基本操作由其数组元素类型和数组长度决定,所以数组类型由数组元素类型和数组长度联合表示。当我们说某种类型的数组或数组是某种类型时,是指该数组的数组元素是某种类型的。例如,定义一个长度为5、数组名是d、数组元素类型为双浮点型的数组,即长度为5、数组名是d的双浮点型数组:doubled5;/长度为5,数组
14、名是d的双浮点型数组数组名d既表示数组(变量),又表示指向第一个数组元素的指针常量,具体表示什么呢?若实施sizeof运算,则d代表数组,结果是:sizeof(d)=5*sizeof(double)=5*8=40/5个数组元素空间大小之和还可以由表达式sizeof(d)/sizeof(do-uble)计算出整型数组d的容量即长度。若实施算术运算和间接引用运算,则d代表数组指针。根据指针的性质,d,d+1,d+2,d+3,d+4依次是指向第1至第5个数组元素的指针,实施间接引用运算之后,*d,*(d+1),*(d+2),*(d+3),*(d+4)依次是第1至第5个数组元素的间接引用表达式。不过,
15、一般采用符合数学习惯的下标表达式或索引表达式:d0,d1,d2,d3,d4,其中“”是下标运算符或索引运算符,其中的整数称为数组元素下标或索引。数组元素的间接运算表达式和下标表达式是一回事(见图3)。3数组的综合特征长度为n的数组,下标为0n-1,超过下标范围的索引访问是非法的,不管编译器对超越下标范围的访问如何处理,我们都要自觉地遵守这个实际上属于我们自己的设计。例如,对上面定义的数组d,下标表达式d5和d-2是非法的。这不是一种规定,而是数组和数组指针作为一个整体的表现:数组元素没有名称,它要由数组指针间接引用,它的索引访问或下标访问的实质就是数组指针的间接引用运算(例如d2=*(d+2)
16、,这是数组对数组指针的依赖;而数组指针是其间接引用范围由数组范围决定的指针。一个变量可以看作是长度为1的数组。例如:intn=5;&n等价于长度为1的整型数组指针,因此(&n)0与n等价:(&n)0=*(&n)=*&n=n数组是一个复合类型(见图3),包含数组类型、数组指针类型和数组元素类型。数组的类型由数组元素的类型和数组长度复合表示,例如长度为5的双浮点型数组的类型是double5。数组指针的基类型是数组元素类型,数组指针的间接引用运算只有在该数组范围内实施才有意义,这是指针对数组的依赖,而数组的元素没有名称,对数组元素的引用依赖指针,这是数组对指针
17、的依赖。数组指针和数组共用一个名称隐含了这种整体关系。d作为数组指针和&d的值相同,但它们不是同一类型的指针,d等价于&d0,其基类型等价于数组元素d0的类型double,所以数组指针d的类型double*,算术运算单位是8,而&d的基类型是数组d的类型doulbe5,所以&d的类型是doulbe(*)5,运算单位是40。3指针变量数组元素没有名称,只能依赖数组指针的间接引用。数组指针是打开数组元素空间的“钥匙”。如果把数组指针传给同类型的指针变量,那么该指针变量就可以和数组指针“共享”一个数组空间,我们称此为地址传递。一个指针,不论什么类型,在32位机上都只占
18、4个字节,所以复制数组指针比复制数组中的数据更有效率。指针变量的定义格式为:类型标识符*变量名;以图4为例,把数组指针a赋给指针变量p,就有了等价式:pi=ai但是,指针变量p与数组指针a不等价,因为前者是指针变量,后者是指针常量。指针变量p与数组a也不等价,下面的等式可以说明:sizeof(p)=4/指针变量空间大小sizeof(a)=20/数组空间大小而且指针&p与&a值不同,基类型也不同,&p是p空间地址,是指向指针空间p的指针,类型是int*,而&a是数组空间地址,是指向数组空间的指针,类型是int(*)5。因为数组名称既表示数组指针又表示数组,所以要从
19、数组名称中取出数组指针赋给指针变量,就需要隐式类型转换,通常称之为decay。图4指针变量如果传递数组指针的目的是传递数组的值,那么应该把数组指针传递给同类型指针变量。例如,整型数组指针应该传给整型指针变量,双浮点型数组指针应该传给双浮点型指针变量。下面我们以反例来说明这样做的意义。inta5=10,15,20,25,30;/整型数组double*pd;/双浮点型指针变量pd=(double*)a;/整型数组指针经强制转换之后赋给双浮点型指针变量在32位机上,双浮点型指针pd的算术运算单位是8个字节,而整型指针常量a的运算单位是4个字节,因此,pd+i的值和a+i的值不等,从而pdi和ai也不
20、等。又例:inta5=10,15,20,25,30;/整型数组float*pf;/单浮点型指针变量pf=(float*)a;/整型数组指针经强制转换后赋给单浮点型指针变量在32位机上,单浮点型指针pf的算术运算单位是4个字节,整型指针常量a的运算单位也是4个字节,因此,pf+i的值和a+i的值相等,但是编译器对它们所指向的数据类型解释不同:pfi是单浮点型,ai是整型。具体地说,a0以普通整型格式存储着10,而pf0按单浮点型格式“解读”时,其中存储的不是10;而且对a0可以实施求余运算,对pf0不能实施该运算。如果传递数组指针的目的是“让出”数据处理之后而“空闲下来”的数组空间,那么可以把该
21、数组指针传递给不同类型的指针变量,但是需要强制类型转换。以图5为例,把长度为2的双符点型数组指针d传递给整型指针变量pi,通过pi可以访问长度为4的整型数组空间(按类型大小计算,长度为2的双浮点型数组空间可以用做长度为4的整型数组空间)。双浮点型数组指针d和整型指针变量pi都指向同一个空间,我们用哪一种类型的指针去间接引用,这个空间就是哪一种类型的数组空间,而且空间中的数据是最后存储的数据。例如,在语句int*pi=(int*)d执行之后,pi0=17执行之前,虽然指针d和pi都指向一个空间,但是d0和d1中的双浮点型数2.125和3.625还存在,执行了语句pi0=17和pi1=29以后,d
22、0中的双浮点型数2.125已经不存在,改为两个整型数17和29,但是d1的值3.625还存在。5由不同类型数据共享的数组空间一个变量可以看作是一个长度为1的数组,因此指向变量的指针可以看作是指向长度为1的数组的指针(见图6)。pn0=*pn=(&n)0=n图6指向变量的指针一个序列存储在一维数组中,其元素在逻辑上的前后位置由数组元素的下标来表示。可是如何存储一个矩阵呢?矩阵的元素在逻辑上有两个位置,行的前后位置和列的前后位置。为此需要引入二维数组。二维数组是数组元素为一维数组(称行一维数组)的一维数组。因为一维数组的元素类型是相同的,所以一个二维数组的行一维数组的类型相同,长度相同,元
23、素的类型也相同。行一维数组的个数称为二维数组的行数,行一维数组的长度称为二维数组的列数。行一维数组也称为二维数组行元素,行一维数组元素也称二维数组元素。二维数组定义格式为:类型标识符数组名行数列数;例如,定义一个4行3列的二维整型数组:inta43;二维数组作为特殊的一维数组,数组长度为4,其数组元素为:a0,a1,a2,a3它们分别是长度为3的行一维整型数组,类型都是int3。行一维数组的元素的类型是整型,而且依次为:a00a01a02/行一维数组a0的数组元素a10a11a12/行一维数组a1的数组元素a20a21a22/行一维数组a2的数组元素a30a31a32/行一维数组a3的数组元素
24、与一维数组类似,作为特殊的一维数组,数组名a既表示数组(用斜体a表示以示区别),又表示数组指针。当a表示数组时,它的类型是由元素类型即行一维数组类型int3和数组长度即行数也即行一维数组个数4联合构成,48int43。而且sizeof(a)=Esizeof(ai)=4*12=当a表述数组指针时,有等式:a=&a0a0作为行一维数组表达式,既表示行一维数组类型(用斜体a0表示以示区别),又表示行一维数组指针。在上面等式的取址运算&a0中,a0表示行一维数组,因此指针a的基类型是行一维数组类型int3,算术运算单位是12,即一个行一维数组大小,有等式a+i=&ai(i=03
25、)因此被称为二维数组指针,类型用int(*)3表示。二维数组a的其他综合特性见表1和图7图7二维整型数组a43(阴影部分表示指针常量)一个长度为n的一维数组可以看作是1行n列二维数组。例如:doubled5=1,2,3,4,5;&d相当于1行5列二维双浮点型数组指针(见图8)。反之,一个m行n列二维数组可以看作长度为m*n的一维数组。图8长度为5的一维数组d可以看作1行5列二维数组5 二维指针变量与二维数组指针常量对应的是二维指针变量,定义格式为:类型指示符(*指针变量名)列数;举例说明:int(*p)3;/二维指针变量pinta43=1,2,3,4,5,6,7,8,9,10,11,1
26、2;/ 二维整型数组p=a;/二维数组指针传递这时的二维指针变量p等价于二维数组指针a:p+i=a+i(i=0,1,2,3)pi=ai(i=0,1,2,3)pij=aij(i=0,1,2,3,j=0,1,2)但是不等价于二维数组a:下面的等式可以说明:sizeof(p)=4/p表示指针变量sizeof(a)=48/a表示二维数组图9二维指针变量和二维数组6 二维数组和(一维)指针一个m行n列二维数组,可以看作是长度为m*n的一维数组。例如:inta43=1,2,3,4,5,6,7,8,9,10,11,12;a0是指向行一维数组元素a00的指针常量,它等价于长度为12的一维整型数组指针,该一维数
27、组的12个元素依次为:a00a01a02a03a04a05a06a07a08a09a010a011二维数组指针a的行下标(假设用i表示)增加1,地址值增加12,一维数组指针a0的下标增加1,地址值4,于是有等式:a0i*3+j=aij于是,可以把二维数组的行一维数组的地址传给(一维)指针变量:int*p=a0; /int *p=*a;或 int *p=&a00;11 字符指针数组和字符指针的指针于是有等式(见图10):pi*3+j=a0i*3+j=aij图10二维数组和(一维)指针变量7 指针数组和指针的指针所谓一维指针数组,就是数组元素为(一维)指针变量的一维数组。例如:char*a5;a是长度为5的字符型指针数组,数组元素a0、a1、a2、a3、a4都是字符型指针变量,它们各自可以指向一维字符数组,特别是字符串:a0="File"a1="Edit"a2="Compile"a3="Run"a4="Tools"指针数组可以初始化:char*a5="File","Ed
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026年湖北交通职业技术学院单招综合素质考试备考题库含详细答案解析
- 2026广东嘉城建设集团有限公司选聘职业经理人1人参考考试题库及答案解析
- 2026年黑龙江旅游职业技术学院高职单招职业适应性测试备考题库及答案详细解析
- 2026年湖南工艺美术职业学院单招职业技能考试备考题库含详细答案解析
- 2026年包头轻工职业技术学院单招职业技能考试备考试题含详细答案解析
- 2026年平顶山工业职业技术学院高职单招职业适应性测试备考试题及答案详细解析
- 2026年漳州理工职业学院单招综合素质笔试备考题库含详细答案解析
- 2026年齐齐哈尔理工职业学院单招职业技能考试参考题库含详细答案解析
- 2026年漳州科技学院单招综合素质考试备考试题含详细答案解析
- 2026年包头轻工职业技术学院单招综合素质笔试备考题库含详细答案解析
- 江苏省连云港市2024-2025学年第一学期期末调研考试高二历史试题
- 生成式人工智能与初中历史校本教研模式的融合与创新教学研究课题报告
- 2025年湖北烟草专卖局笔试试题及答案
- 2026年开工第一课复工复产安全专题培训
- 中西医结合治疗肿瘤的进展
- 特殊人群(老人、儿童)安全护理要点
- 《煤矿安全规程(2025)》防治水部分解读课件
- 2025至2030中国新癸酸缩水甘油酯行业项目调研及市场前景预测评估报告
- 2025年保安员职业技能考试笔试试题(100题)含答案
- 尾矿库闭库综合治理工程项目可行性研究报告
- 员工自互检培训
评论
0/150
提交评论