版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、计算基础计算基础C+C+语言实现语言实现在进行比较复杂的运算时,通常会借助纸张完成运算过程在进行比较复杂的运算时,通常会借助纸张完成运算过程。在利用计算机解决实际问题时,同样需要一些空间来保存待处在利用计算机解决实际问题时,同样需要一些空间来保存待处理的数据、运算的中间结果和运算的最终结果,这些空间就是计理的数据、运算的中间结果和运算的最终结果,这些空间就是计算机的内存空间。算机的内存空间。本章重点介绍计算机中数据存储的基本原理,本章重点介绍计算机中数据存储的基本原理,以及如何使用以及如何使用C+C+编写程序操作内存中的数据。通过本章的学习编写程序操作内存中的数据。通过本章的学习,一方面能够掌
2、握计算机中数据存储的基本原理;另一方面能够,一方面能够掌握计算机中数据存储的基本原理;另一方面能够使用使用C+C+提供的指针类型操作内存中的数据,解决实际问题。本提供的指针类型操作内存中的数据,解决实际问题。本章还介绍指针与函数、引用、引用与函数、指针相减运算和关系章还介绍指针与函数、引用、引用与函数、指针相减运算和关系运算等方面的内容。运算等方面的内容。2人们在进行比较复杂的运算时,通人们在进行比较复杂的运算时,通常会借助纸张完成运算过程。在利用计常会借助纸张完成运算过程。在利用计算机解决实际问题时,同样需要一些空算机解决实际问题时,同样需要一些空间来保存待处理的数据、运算的中间结间来保存待
3、处理的数据、运算的中间结果和运算的最终结果,这些空间就是计果和运算的最终结果,这些空间就是计算机的内存空间。算机的内存空间。内存内存空间中含有大量的存储单元,空间中含有大量的存储单元,每个存储单元由一个唯一的内存地址标每个存储单元由一个唯一的内存地址标识,可以存放识,可以存放1 1个字节的数据,内存地个字节的数据,内存地址的编号从址的编号从0 0开始,顺次增开始,顺次增1 1,图,图6-16-1内内存地址示例即对于容量为存地址示例即对于容量为N N的内存,其的内存,其内存地址编号为内存地址编号为0 0N-1N-1,如图,如图6-16-1所示。所示。6 6.1 .1 数据存储数据存储的基本原理的
4、基本原理3在在3232位系统中,内存地址由位系统中,内存地址由3232位二进制数组成位二进制数组成,内存地,内存地址编号从址编号从0 0开始、最大为开始、最大为2 23232-1-1,因此,因此,3232位系统理论支持的位系统理论支持的最大内存容量为最大内存容量为2 23232(=4G=4G)字节。而)字节。而在在6464位系统中,内存地位系统中,内存地址由址由6464位二进制数组成位二进制数组成,因此,因此,6464位系统理论支持的最大内位系统理论支持的最大内存容量为存容量为2 26464(=16777216T=16777216T)字节。)字节。在在运行一个程序时,系统将分配给该程序一些内存
5、空间,运行一个程序时,系统将分配给该程序一些内存空间,根据内存空间中存储的数据类型不同,可将其分为根据内存空间中存储的数据类型不同,可将其分为4 4个区域个区域。(1 1)代码代码区区: : 存放程序的代码(在运行程序时会先将程序存放程序的代码(在运行程序时会先将程序加载到内存的代码区中再执行)。加载到内存的代码区中再执行)。(2 2)全局全局数据区数据区: : 存放程序中的全局数据和静态数据(在存放程序中的全局数据和静态数据(在定义全局变量或静态变量时会在全局数据区为其分配内存空定义全局变量或静态变量时会在全局数据区为其分配内存空间来存储数据)间来存储数据)。6 6.1 .1 数据存储数据存
6、储的基本原理的基本原理4(3 3)堆堆区区: : 存放程序中的动态数据(使用动态方式分配内存放程序中的动态数据(使用动态方式分配内存时会在堆区分配内存空间来存储数据,关于动态内存分配存时会在堆区分配内存空间来存储数据,关于动态内存分配的内容请参阅的内容请参阅6.2.66.2.6节)节)。(4 4)栈栈区区: : 存放程序中的局部数据(在定义局部变量时会存放程序中的局部数据(在定义局部变量时会在栈区为其分配内存空间来存储数据)。在栈区为其分配内存空间来存储数据)。定义定义任何一个变量,系统都会为其分配一定大小的内存任何一个变量,系统都会为其分配一定大小的内存空间,访问变量实际上就是访问其所对应内
7、存空间中的数据空间,访问变量实际上就是访问其所对应内存空间中的数据。6 6.1 .1 数据存储数据存储的基本原理的基本原理5例如例如,在,在C+C+中,有如下变量中,有如下变量定义语句定义语句: 0 x61626364;: 0 x61626364;系统会系统会为为a a分配分配sizeofsizeof( (intint)=4)=4字节的内字节的内存空间,并且该片内存空间中所存空间,并且该片内存空间中所存储的数据为存储的数据为0 x616263640 x61626364,如图,如图6-26-2所示。这里数据在内存中按所示。这里数据在内存中按从高字节到低字节的顺序存储,从高字节到低字节的顺序存储,
8、在有的系统中数据在内存中是按在有的系统中数据在内存中是按从低字节到高字节的顺序存储。从低字节到高字节的顺序存储。如果要编写具有较好移植性、能如果要编写具有较好移植性、能够在多个系统下运行的程序,就够在多个系统下运行的程序,就要在编程时考虑这一不同。要在编程时考虑这一不同。6 6.1 .1 数据存储数据存储的基本原理的基本原理6提示提示: : 3232位系统中内存地址由位系统中内存地址由3232位二进制数组成。十六进制数是二位二进制数组成。十六进制数是二进制数的压缩表示形式,进制数的压缩表示形式,1 1位十六进制数相当于位十六进制数相当于4 4位二进制数,为位二进制数,为了简化地址表示,了简化地
9、址表示,3232位系统中的内存地址通常以位系统中的内存地址通常以8 8位十六进制数表位十六进制数表示,如图示,如图6-26-2所示。同理,所示。同理,6464位系统中的内存地址通常以位系统中的内存地址通常以1616位十六位十六进制数表示。进制数表示。 图图6-26-2仅为了说明数据在内存中的存储方式。实际上,在定义仅为了说明数据在内存中的存储方式。实际上,在定义一个变量时,不同环境下系统为该变量分配的内存空间可能会不一个变量时,不同环境下系统为该变量分配的内存空间可能会不同。因此,读者在自己机器上定义变量同。因此,读者在自己机器上定义变量a a并查看其所对应的内存空并查看其所对应的内存空间时一
10、般会与图间时一般会与图6-26-2所显示的内存地址不一致。所显示的内存地址不一致。在在前面的章节中,都是使用通过变量名去访问对应内存前面的章节中,都是使用通过变量名去访问对应内存中数据的方式。实际上,中数据的方式。实际上,C+C+还提供了另外一种通过指针直还提供了另外一种通过指针直接访问内存中数据的方式接访问内存中数据的方式。6 6.1 .1 数据存储数据存储的基本原理的基本原理7指针指针是用于存放内存地址的一种数据类型。指针可以是是用于存放内存地址的一种数据类型。指针可以是常量常量,例如数组名就是一个指针常量,表示该数组所占据内,例如数组名就是一个指针常量,表示该数组所占据内存空间的首地址。
11、存空间的首地址。指针也可以是变量指针也可以是变量,例如可以定义一个指,例如可以定义一个指针类型的变量保存一个内存地址。在程序设计中,可以使用针类型的变量保存一个内存地址。在程序设计中,可以使用指针常量或指针变量直接操作它们所指向的内存空间中的数指针常量或指针变量直接操作它们所指向的内存空间中的数据。下面先介绍指针变量的定义、初始化和访问方法。据。下面先介绍指针变量的定义、初始化和访问方法。u 6.2.1 6.2.1 指针指针变量的定义变量的定义指针指针是一种存储地址的数据类型,因此,也可以定义指是一种存储地址的数据类型,因此,也可以定义指针类型的变量针类型的变量指针变量。与其他类型的变量一样,
12、指针变量。与其他类型的变量一样,在使在使用指针变量之前必须先定义,其定义形式为用指针变量之前必须先定义,其定义形式为: : * * ;6.2 6.2 指针指针8其中其中, 表示指针变量所指向内存空间中数据表示指针变量所指向内存空间中数据的类型,的类型,* *表示所要定义的变量为一个指针变量,而不是普表示所要定义的变量为一个指针变量,而不是普通变量。通变量。* *作用于变量名作用于变量名,表示紧随其后的变量为一个指针,表示紧随其后的变量为一个指针变量。变量。例如例如,要同时定义两个,要同时定义两个intint型指针变量型指针变量p1p1和和p2p2,必须写成,必须写成如下形式如下形式: :int
13、int * *p1, p1, * *p2;p2; 如果如果写成写成: : intint * *p1, p2;p1, p2;则则表示定义了一个指针变量表示定义了一个指针变量p1p1和一个普通变量和一个普通变量p2p2。6.2 6.2 指针指针9指针是一种数据类型,所以指针是一种数据类型,所以也可以创建一个指针类型的也可以创建一个指针类型的数组数组。指针数组同样可以有不同的维数,这里只给出。指针数组同样可以有不同的维数,这里只给出一维指一维指针数组的定义形式针数组的定义形式: : * * ;指针指针数组中的每个元素都是指向同一数据类型的指针变数组中的每个元素都是指向同一数据类型的指针变量,量,指针
14、数组元素的访问方法与一般数组元素的访问方法完指针数组元素的访问方法与一般数组元素的访问方法完全一样全一样,例如,例如: :intint * *pArrpArr3; 3; 语句语句定义了一个包含定义了一个包含3 3个元素的一维数组,每个元素个元素的一维数组,每个元素pArrpArr00、pArrpArr11、pArrpArr22都是一个都是一个intint型指针变量。型指针变量。6.2 6.2 指针指针10u 6.2.2 6.2.2 指针指针变量的初始化变量的初始化同同普通变量一样,普通变量一样,在定义指针变量的同时可以对其进行在定义指针变量的同时可以对其进行初始化,其初始化形式为初始化,其初始
15、化形式为: : * * =;其中其中, 一般来说可以有一般来说可以有3 3种形式。种形式。 初始化为初始化为NULLNULL或或0: NULL0: NULL为系统定义的一个常量,其值为为系统定义的一个常量,其值为0 0,表示指针变量指向的是一片无效的不可访问的内存。比,表示指针变量指向的是一片无效的不可访问的内存。比如如: : intint * *p=NULL;p=NULL;6.2 6.2 指针指针11 初始化为已定义变量的地址初始化为已定义变量的地址: : 将一个已定义变量所对应将一个已定义变量所对应内存空间的首地址作为指针变量的初值,此时通过该指针变内存空间的首地址作为指针变量的初值,此时
16、通过该指针变量可以直接操作已定义变量所占据内存中的数据。比如量可以直接操作已定义变量所占据内存中的数据。比如: : intint * *p=&a;p=&a;& &a a表示获取表示获取a a所对应内存空间的首地址(即起始地址),所对应内存空间的首地址(即起始地址),其中其中& &称为取地址运算符。如果变量称为取地址运算符。如果变量a a所对应的内存空间如图所对应的内存空间如图6-26-2所示,则通过所示,则通过&a&a获取到的首地址为获取到的首地址为0 x0025f7580 x0025f758。定义指。定义指针变量针变量p p并初始化后,指针变量并初始化后,指针变量p p中存储了中存储了a a
17、所对应内存空间所对应内存空间的首地址,即的首地址,即0 x0025f7580 x0025f758,此时,也称,此时,也称“指针变量指针变量p p指向了指向了变量变量a”a”,通过指针变量,通过指针变量p p可以操作可以操作a a所对应内存空间中的数所对应内存空间中的数据据。6.2 6.2 指针指针12 初始化为某一动态分配内存空间的地址初始化为某一动态分配内存空间的地址: : 后面的章节中后面的章节中会学习到动态分配内存空间的方式,这里知道有这样一个概会学习到动态分配内存空间的方式,这里知道有这样一个概念就可以。念就可以。提示提示: : (1 1)指针指针变量的数据类型与其所指向的变量的数据类
18、型必须一致,变量的数据类型与其所指向的变量的数据类型必须一致,否则就要给出显式的强制类型转换。例如否则就要给出显式的强制类型转换。例如: : intint a; a;intint * *p1=&ap1=&a; /; /正确正确: :指针变量的数据类型与其所指向指针变量的数据类型与其所指向的的/变量变量的数据类型的数据类型一致一致char char * *p2p2=&a; /=&a; /错误错误: :指针变量的数据类型与其所指针变量的数据类型与其所指向指向/的的变量的数据类型不变量的数据类型不一致一致char char * *p3p3=(=(charchar* *)&)&a; /a; /正确正确
19、: :通过强制类型转换将通过强制类型转换将intint /型地址转换为型地址转换为charchar型地址型地址, ,但一般但一般不建议这样不建议这样使用使用6.2 6.2 指针指针13(2 2)在在一个一个3232位(或位(或6464位)系统中,内存地址以位)系统中,内存地址以3232位(或位(或6464位)位)二进制数表示,即二进制数表示,即4 4(或(或8 8)个字节。指针变量中存储的是内存地)个字节。指针变量中存储的是内存地址,因此,一个指针变量无论是什么类型,都是占用址,因此,一个指针变量无论是什么类型,都是占用4 4(或(或8 8)个)个字节的内存空间。例如,在字节的内存空间。例如,
20、在3232位系统中,前面的位系统中,前面的intint型指针变量型指针变量p1p1和和charchar型指针变量型指针变量p3p3都是占用都是占用4 4个字节的内存空间。个字节的内存空间。6.2 6.2 指针指针14u 6.2.3 6.2.3 使用使用指针访问内存中的数据指针访问内存中的数据一一个指针指向有效的内存地址后,就可以通过该指针访个指针指向有效的内存地址后,就可以通过该指针访问其所指向内存空间中的数据,访问形式为问其所指向内存空间中的数据,访问形式为: : * * 其中其中,* *被称为间接访问运算符,或取内容运算符,其与取被称为间接访问运算符,或取内容运算符,其与取地址运算符地址运
21、算符& &的功能相反,即对于任一变量的功能相反,即对于任一变量a a有有: : * *(&a)(&a)等价等价于于a a。 是指计算结果为内存地址的表达式。是指计算结果为内存地址的表达式。提示提示: : 使用取内容运算符从指针所指向的内存中取得的数据使用取内容运算符从指针所指向的内存中取得的数据一方面与内存空间中存储的数据有关,另一方面也与指针的类型一方面与内存空间中存储的数据有关,另一方面也与指针的类型有关有关。例如。例如: : 6.2 6.2 指针指针15intint a=0 x61626364; a=0 x61626364;intint * *p1p1=&a=&a; ;char char
22、 * *p2p2=(=(charchar* *)&)&a a; ;coutcoutp1,p1,p2p2endlendl; ;其中其中,变量,变量a a所对应的内存空间如图所对应的内存空间如图6-26-2所示,指针变量所示,指针变量p1p1和和p2p2中中均保存着变量均保存着变量a a的首地址的首地址0 x0025f7580 x0025f758。p1p1是是intint类型的指针,因此类型的指针,因此通过通过* *p1p1会从内存地址会从内存地址0 x0025f7580 x0025f758开始取连续开始取连续4 4个字节的数据(即个字节的数据(即一个一个intint型数据);型数据);p2p2是
23、是charchar类型的指针,因此通过类型的指针,因此通过* *p2p2会从内存会从内存地址地址0 x0025f7580 x0025f758开始取开始取1 1个字节的数据(即一个个字节的数据(即一个charchar型数据)。最型数据)。最后输出后输出* *p1p1和和* *p2p2时会分别输出时会分别输出16338379241633837924(十六进制数(十六进制数0 x616263640 x61626364所对应的十进制数)和所对应的十进制数)和d d(字符(字符dd的的ASCIIASCII码为码为0 x640 x64)。6.2 6.2 指针指针16在在程序中既可以修改指针变量所指向内存中
24、的数据,也程序中既可以修改指针变量所指向内存中的数据,也可以修改指针变量所指向的内存地址。可以修改指针变量所指向的内存地址。例如,已知例如,已知“intint a=5, b=10, a=5, b=10, * *p1=&a, p1=&a, * *p2=&b;”p2=&b;”,通过语句,通过语句* *p1=p1=* *p2;p2;可以将可以将p2p2所指向内存空间中的数据赋到所指向内存空间中的数据赋到p1p1所指向的内存空间中(即所指向的内存空间中(即将变量将变量b b的值赋给了变量的值赋给了变量a a),如图),如图6-36-3所示;通过语句所示;通过语句p1=p2;p1=p2;则可以将则可以将
25、p2p2中保存的内存地址赋给中保存的内存地址赋给p1p1(即赋值操作后(即赋值操作后p1p1与与p2p2均指向了变量均指向了变量b b所对应的内存),如图所对应的内存),如图6-46-4所示。所示。6.2 6.2 指针指针176.2 6.2 指针指针18【例例6-16-1】指针变量使用示例。指针变量使用示例。参考参考程序如下程序如下: : #include #include using using namespace namespace stdstd; ;intint mainmain()() intint a=5, b=10a=5, b=10; ;intint * *p1p1, , * *p
26、2;p2;/第第1 1次次赋值赋值p1p1=&a=&a; ;p2p2=&b=&b; ;coutcouta,ba,b,* *p1,p1,* *p2p2endlendl; ;6.2 6.2 指针指针19/第第2 2次次赋值赋值* *p1=3;p1=3;* *p2=6;p2=6;coutcouta,ba,b,* *p1,p1,* *p2p2endlendl; ;/第第3 3次次赋值赋值a=1;a=1;b=2;b=2;coutcouta,ba,b,* *p1,p1,* *p2p2endlendl; ;/第第4 4次次赋值赋值* *p1=p1=* *p2;p2;coutcouta,ba,b,* *p1,
27、p1,* *p2p2endlendl; ;6.2 6.2 指针指针20/第第5 5次次赋值赋值p1=p2;p1=p2;* *p1=8;p1=8;coutcouta,ba,b,* *p1,p1,* *p2p2endlendl; ;return return 0 0; ; 上面上面的程序中,在第的程序中,在第1 1次赋值后,指针变量次赋值后,指针变量p1p1指向变量指向变量a a所对应的内存空间,指针变量所对应的内存空间,指针变量p2p2指向变量指向变量b b所对应的内存空所对应的内存空间,如图间,如图6-56-5(a a)所示,因此输出)所示,因此输出“5,10,5,10”5,10,5,10”;
28、在第;在第2 2次次赋值后,指针变量赋值后,指针变量p1p1所指向内存空间中的数据值为所指向内存空间中的数据值为3 3,指针,指针变量变量p2p2所指向内存空间中的数据值为所指向内存空间中的数据值为6 6,如图,如图6-56-5(b b)所示,)所示,因此输出因此输出“3,6,3,6”3,6,3,6”;在第;在第3 3次赋值后,变量次赋值后,变量a a所对应所对应内存内存6.2 6.2 指针指针21空间中的数据值为空间中的数据值为1 1,变量,变量b b所对应内存空间中的数据值为所对应内存空间中的数据值为2 2,如图如图6-56-5(c c)所示,因此输出)所示,因此输出“1,2,1,2”1,
29、2,1,2”;在第;在第4 4次赋值后,次赋值后,p2p2所指向内存空间中的数据被赋到所指向内存空间中的数据被赋到p1p1所指向的内存空间中,所指向的内存空间中,如图如图6-56-5(d d)所示,因此输出)所示,因此输出“2,2,2,2”2,2,2,2”;在第;在第5 5次赋值后,次赋值后,p2p2中所保存的内存地址被赋到中所保存的内存地址被赋到p1p1中,并且中,并且p1p1所指向内存空间所指向内存空间中的数据被赋为中的数据被赋为8 8,如图,如图6-56-5(e e)所示,因此输出)所示,因此输出“2,8,8,8”2,8,8,8”。图中粗体文字表示每次赋值被修改的数据。图中粗体文字表示每
30、次赋值被修改的数据。6.2 6.2 指针指针226.2 6.2 指针指针236.2 6.2 指针指针246.2 6.2 指针指针25u 6.2.4 6.2.4 使用使用指针访问数指针访问数组中的元素组中的元素定义定义一个数组后,一个数组后,系统会为其分配内存系统会为其分配内存空间空间,例如,有如下,例如,有如下数组定义数组定义: : 则系统为则系统为一维数组一维数组a a和二维数组和二维数组b b所分配的内存空间如所分配的内存空间如图图6-66-6所示。可见,所示。可见,二二维数组中的元素在内维数组中的元素在内存中按照先行后列的存中按照先行后列的方式进行存储方式进行存储。6.2 6.2 指针指
31、针26前面前面的章节中都是使用的章节中都是使用“ ”或或“ ”的方式来访问一维数组或二维的方式来访问一维数组或二维数组中的元素。实际上,也可以使用指针来访问数组中的元数组中的元素。实际上,也可以使用指针来访问数组中的元素。例如,可以定义两个指针变量素。例如,可以定义两个指针变量p1p1和和p2p2并令它们分别指向并令它们分别指向元素元素a0a0和元素和元素b00b00的首地址,即的首地址,即: :intint * *p1, p1, * *p2;p2;p1=&a0;p1=&a0;p2p2=&=&b00;b00;根据根据6.2.36.2.3节的内容,使用节的内容,使用* *p1p1和和* *p2p
32、2可分别访问可分别访问a0a0和和b00b00。那么,应该如何访问后面的元素呢?下面介绍指。那么,应该如何访问后面的元素呢?下面介绍指针加减整数的运算,通过指针加整数的运算即可以计算出后针加减整数的运算,通过指针加整数的运算即可以计算出后面元素的首地址并通过面元素的首地址并通过“* * ”的方式访问该元素的方式访问该元素。6.2 6.2 指针指针27假设假设p p为指针,为指针,n n为正整数,则为正整数,则: : p+np+n: : 从从p p指向的地址开始的后面第指向的地址开始的后面第n n项数据的地址。项数据的地址。 p-n: p-n: 从从p p指向的地址开始的前面第指向的地址开始的前
33、面第n n项数据的地址项数据的地址。【例例6-26-2】指针加整数运算示例。指针加整数运算示例。参考参考程序如下程序如下: : #include #include using using namespace namespace stdstd; ;intint mainmain()() intint a= a=1,2,3,4, 1,2,3,4, b2=b2=5,6, 7,85,6, 7,8;intint * *p1p1=&=&a0, a0, * *p2p2=&=&b00;b00;6.2 6.2 指针指针28intint i i, j, j; ;for for ( (i i=0; =0; i i4
34、; 4; i i+)+)coutcoutaai i的首地址为的首地址为p1+ip1+i,其中存储的数据为其中存储的数据为* *( (p1+i)p1+i)endlendl; ;for for ( (i i=0; =0; i i2; 2; i i+)+)for for (j=0; j2; j(j=0; j2; j+)+)coutcoutbbi ij j的首地址的首地址为为 p2+ip2+i* *2+j2+j,其中存储的数据其中存储的数据为为 * *(p2+i(p2+i* *2+j2+j)endlendl; ;return return 0 0; ; 6.2 6.2 指针指针29上面上面的程序中,指
35、针变量的程序中,指针变量p1p1和和p2p2分别指向了元素分别指向了元素a0a0和和元素元素b00b00的首地址,的首地址,p1+ip1+i和和p2+ip2+i* *2+j2+j则分别指向了元素则分别指向了元素aai i 和元素和元素bbi ijj的首地址,如图的首地址,如图6-76-7所示所示。6.2 6.2 指针指针30因此因此,通过输出,通过输出p1+ip1+i和和p2+ip2+i* *2+j2+j,可以在屏幕上分别看,可以在屏幕上分别看到数组到数组a a和和b b中每一个元素的首地址(即中每一个元素的首地址(即& &aai i 的值和的值和& &bbi ijj的值);通过输出的值);通
36、过输出* *(p1+i)(p1+i)和和* *(p2+i(p2+i* *2+j)2+j),可以在屏幕上分,可以在屏幕上分别看到数组别看到数组a a和和b b中每一个元素的值(即中每一个元素的值(即aai i 的值和的值和bbi ijj的值)。一维数组的数组名是一个与数组同类型的指针常量,的值)。一维数组的数组名是一个与数组同类型的指针常量,即数组名即数组名a a是一个是一个intint类型的指针常量,因此,也可以用数组类型的指针常量,因此,也可以用数组名名a a代替指针变量代替指针变量p1p1改写例改写例6-26-2中的主函数中的主函数: :for (for (i i=0=0; ; i i44
37、; ; i i+)+)coutcoutaai i的首地址为的首地址为a+Ia+I,其中存储的数据为其中存储的数据为* *( (a+ia+i)endlendl; ;6.2 6.2 指针指针31上面上面程序段的运行结果与例程序段的运行结果与例6-26-2完全一样。数组名完全一样。数组名a a与指与指针变量针变量p1p1的唯一区别在于的唯一区别在于: : 指针变量指针变量p1p1中存储的内存地址可中存储的内存地址可以改变,如以改变,如p1=p1+1p1=p1+1或或p1=&p1=&aai i 等给指针变量等给指针变量p1p1的赋值运算的赋值运算都是正确的;而数组名都是正确的;而数组名a a是一个指针
38、常量,它的值就是该数是一个指针常量,它的值就是该数组的首地址组的首地址, ,不可以改变,例如不可以改变,例如a=a+1a=a+1或或a=&a=&aai i 等给指针常等给指针常量量a a的赋值运算都是错误的的赋值运算都是错误的。另外另外,在,在C+C+中,中,* *(p1+i)(p1+i)(或(或* *( (a+ia+i) ))可以写作)可以写作p1p1i i (或(或aai i ),因此,),因此,p1+ip1+i(或(或a+ia+i)也可以写作)也可以写作& &p1p1i i (或(或& &aai i )。可以将例)。可以将例6-26-2中的主函数改写为中的主函数改写为: : 6.2 6.
39、2 指针指针32for(for(i i=0=0; ; i i44; ; i i+)+)coutcoutaai i的首地址为的首地址为&p1p1i i ,其中存储的数据为其中存储的数据为p1p1i iendlendl; ;上面上面程序段的运行结果与例程序段的运行结果与例6-26-2完全一样,完全一样,& &p1p1i i 与例与例6-6-2 2中中的的p1+ip1+i等价,等价,p1p1i i 与例与例6-26-2中的中的* *(p1+i)(p1+i)等价。等价。6.2 6.2 指针指针33提示提示: : (1 1)对于对于任何一个任何一个 ,有如下两组等价关系成立,有如下两组等价关系成立: :
40、 * *(+i i) ) i i +i i &i i 例如例如,在例,在例6-26-2中,中,& &a0a0也可以写作也可以写作a+0a+0(即(即a a),&,&b00b00也也可以写作可以写作b0+b0+0 0(即(即b0b0),p1+i,p1+i也可以写作也可以写作& &p1p1i i,* *( (p1+i)p1+i)也可也可以写作以写作p1p1i i,p2+ip2+i* *2+j2+j也可以写作也可以写作& &p2p2i i* *2+j,2+j,* *( (p2+ip2+i* *2+j)2+j)也可也可以写作以写作p2p2i i* *2+j2+j。(2 2)自自增运算符增运算符+和自减
41、运算符和自减运算符-也可以用于指针运算,其使用也可以用于指针运算,其使用方法与普通变量的自增、自减运算相同。例如方法与普通变量的自增、自减运算相同。例如: : p+;/p+;/相当于相当于p=p+1p=p+1p-p-;/-;/相当于相当于p=p-1p=p-16.2 6.2 指针指针34二二维数组的数组名也是一个指针常量维数组的数组名也是一个指针常量,对于例,对于例6-26-2中的二中的二维数组维数组b b,其数组名,其数组名b b就表示二维数组的首地址。根据前面的就表示二维数组的首地址。根据前面的等价关系,等价关系,b b与与& &b0b0等价,而等价,而b0b0可以看作是由可以看作是由2 2
42、个元素组个元素组成的一维数组,即成的一维数组,即b0b0是是intint 22类型。在类型。在C+C+中,中,二维数组二维数组的首地址需要用指向行的指针变量来保存,其定义形式为的首地址需要用指向行的指针变量来保存,其定义形式为: : ( (* * );其中其中, 是指该指针变量所指向的二维数组中每行元是指该指针变量所指向的二维数组中每行元素的数量(即列数)。因此,对于例素的数量(即列数)。因此,对于例6-26-2中的二维数组中的二维数组b b,可,可以定义如下的指向行的指针变量以定义如下的指向行的指针变量: : intint ( (* *p)2;p)2;p=b;p=b;将将二维数组二维数组b
43、b的首地址赋给指向行的指针变量的首地址赋给指向行的指针变量p p后,就可后,就可以用以用p p替代替代b b访问二维数组中的元素。访问二维数组中的元素。6.2 6.2 指针指针35【例例6-36-3】指向行的指针变量示例。指向行的指针变量示例。参考参考程序如下程序如下: : #include #include using using namespace namespace stdstd; ;intint mainmain()() intint b2= b2=5,6, 7,85,6, 7,8;intint ( (* *p)2;p)2;intint i i, j, j; ;p=b;p=b;6.2
44、6.2 指针指针36for for ( (i i=0; =0; i i2; 2; i i+)+)for for (j=0; j2; j(j=0; j2; j+)+)coutcoutbbi ij j中存储的数据中存储的数据为为 ppi ijjpsps;/;/输入输入 abcabc“coutcoutpp; ;coutcoutp+2p;p;或或cincinp+2;p+2;等修改等修改p p所所指向内存空间中的数据。指向内存空间中的数据。【例例6-46-4】编写程序实现取子串的操作编写程序实现取子串的操作: : 从字符串从字符串“my my book!”book!”中自第中自第4 4个字符开始取子串,
45、共取个字符开始取子串,共取4 4个字符生成一个个字符生成一个新的字符串。新的字符串。参考程序如下参考程序如下: : #include #include using namespace using namespace stdstd; ;6.2 6.2 指针指针42intint mainmain()() char s=char s=my bookmy book!;!;char t5;char t5;intint i i, start=3, , start=3, lenlen=4=4; ;for for ( (i i=0; =0; i i lenlen; ; i i+)+)tti i=s=si+st
46、arti+start;tti i=0 0;coutcout取出的子串为取出的子串为:t tendlendl; ;return return 0 0; ; 6.2 6.2 指针指针43上面上面的程序中,通过的程序中,通过forfor循环将字符逐个从循环将字符逐个从s s中中复制到数组复制到数组t t中,最后在中,最后在t t的最后加上字符串结束符的最后加上字符串结束符00 ,如图,如图6-106-10所示所示。6.2 6.2 指针指针44如果如果要同时操作多个字符串,也可以定义一个字符型指要同时操作多个字符串,也可以定义一个字符型指针数组。针数组。【例例6-56-5】使用指针数组操作多个字符串。
47、使用指针数组操作多个字符串。参考参考程序如下程序如下: : # #include include using using namespace namespace stdstd; ;intint mainmain()() char char * *p3=p3=Beijing, Tianjin, ShanghaiBeijing, Tianjin, Shanghai;intint i i; ;for for ( (i i=0; =0; i i 3; 3; i i+)+)coutcoutppi ippi i;这样的语句是错误的。这样的语句是错误的。6.2 6.2 指针指针466.2 6.2 指针指针4
48、7u 6.2.6 6.2.6 动态动态内存分配和释放内存分配和释放在在C+C+中,除了可以通过定义变量的方式来使用内存空间中,除了可以通过定义变量的方式来使用内存空间外,还外,还可以使用可以使用newnew和和deletedelete两个关键字进行内存空间的动两个关键字进行内存空间的动态分配和释放态分配和释放。使用动态方式分配内存时会在堆区分配内存。使用动态方式分配内存时会在堆区分配内存空间来存储数据,因此动态内存分配也通常称为堆内存分配。空间来存储数据,因此动态内存分配也通常称为堆内存分配。相应地,动态内存释放也通常称为堆内存释放。相应地,动态内存释放也通常称为堆内存释放。堆堆内存分配内存分
49、配newnew的语法格式为的语法格式为: : new new ; 指定了分配的内存空间中存储的数据的类型,指定了分配的内存空间中存储的数据的类型,由于不同类型的数据需要不同尺寸的内存空间来保存,因此,由于不同类型的数据需要不同尺寸的内存空间来保存,因此, 不同,分配的内存空间大小也会不同不同,分配的内存空间大小也会不同。6.2 6.2 指针指针48堆堆内存分配成功后,会返回动态分配的内存空间的首地内存分配成功后,会返回动态分配的内存空间的首地址。址。通常将该首地址保存在一个指针变量中,以便后面可以通常将该首地址保存在一个指针变量中,以便后面可以使用该指针变量操作内存空间中的数据。使用该指针变量
50、操作内存空间中的数据。在分配内存的同时,在分配内存的同时,还可以进行内存初始化工作还可以进行内存初始化工作: : new new (););其中其中, 确定了分配的内存空间中初始存储的数据确定了分配的内存空间中初始存储的数据。例如例如: :intint * *p; p; p=new p=new intint(3(3););两两条语句执行结束后,指针变量条语句执行结束后,指针变量p p就指向了通过就指向了通过new new intint动态分配的内存空间,如图动态分配的内存空间,如图6-126-12所示。所示。6.2 6.2 指针指针496.2 6.2 指针指针50也也可以动态分配用于存储多个数
51、可以动态分配用于存储多个数据元素的内存空间,语法格式为据元素的内存空间,语法格式为: : ;其中其中, 既可以是常量也既可以是常量也可以是变量,但必须是整数,用于可以是变量,但必须是整数,用于指定元素数目。例如指定元素数目。例如: : intint * *pArraypArray; ;pArraypArray=new =new intint3;3;两两条语句执行结束后,指针变量条语句执行结束后,指针变量pArraypArray就指向了通过就指向了通过new new intint33动动态分配的内存空间,如图态分配的内存空间,如图6-136-13所示。所示。6.2 6.2 指针指针51实际上实际
52、上,可以将动态分配的内存空间看作是一个动态数可以将动态分配的内存空间看作是一个动态数组,使用指针访问堆内存的方式与使用指针访问数组的方式组,使用指针访问堆内存的方式与使用指针访问数组的方式完全相同。唯一区别在于完全相同。唯一区别在于: : 数组定义时,必须用常量表达式数组定义时,必须用常量表达式指定数组长度;而进行堆内存分配时,既可以使用常量表达指定数组长度;而进行堆内存分配时,既可以使用常量表达式,也可以用变量表达式来指定元素数目。式,也可以用变量表达式来指定元素数目。使用使用newnew分配的内存必须使用分配的内存必须使用deletedelete释放释放,否则会造成内,否则会造成内存泄露(
53、即内存空间一直处于被占用状态,导致其他程序无存泄露(即内存空间一直处于被占用状态,导致其他程序无法使用)。当系统出现大量内存泄露时,系统可用资源也会法使用)。当系统出现大量内存泄露时,系统可用资源也会相应减少,从而导致计算机处理速度变慢,当系统资源枯竭相应减少,从而导致计算机处理速度变慢,当系统资源枯竭时甚至会造成系统崩溃。时甚至会造成系统崩溃。堆内存释放堆内存释放deletedelete的语法格式为的语法格式为: : delete delete ;其中其中, 指向待释放的堆内存空间的首地址指向待释放的堆内存空间的首地址。6.2 6.2 指针指针52例如例如: :delete p;delete
54、 p;delete delete pArraypArray; ; 两两条语句可以将前面使用条语句可以将前面使用new new intint(3)(3)和和new new intint33动态动态分配的内存空间释放。分配的内存空间释放。如果如果 所指向的堆内存空间只包含一个元素,所指向的堆内存空间只包含一个元素,那么还可以那么还可以将将省掉,即省掉,即: : delete delete ;例如例如: : delete p;delete p;6.2 6.2 指针指针53上面上面的语句可以将前面使用的语句可以将前面使用new new intint(3)(3)动态分配的内存动态分配的内存空间释放。由于
55、空间释放。由于pArraypArray所指向的内存空间中包含所指向的内存空间中包含3 3个元素,个元素,因此不能使用因此不能使用delete delete pArraypArray来释放这些内存空间,而必须来释放这些内存空间,而必须使用使用delete delete pArraypArray。提示提示: : 在使用在使用newnew分配堆内存时要区分分配堆内存时要区分()()和和。()()中的中的表达式指定了内存的初值,表达式指定了内存的初值,而而中的表达式指定了元素数目。中的表达式指定了元素数目。例如例如: : p=new p=new intint(3(3););/分配了分配了1 1个个in
56、tint型元素大小的型元素大小的内存内存/空间空间, ,且其初值为且其初值为3 3pArraypArray=new =new intint3;/3;/分配了分配了3 3个个intint型元素大小的型元素大小的内存内存/空间空间6.2 6.2 指针指针54【例例6-66-6】使用堆内存分配方式实现学生成绩录入功能,要使用堆内存分配方式实现学生成绩录入功能,要求程序运行时由用户输入学生人数。求程序运行时由用户输入学生人数。参考参考程序如下程序如下: : #include #include using using namespace namespace stdstd; ;intint mainmai
57、n()() intint * *pScorepScore; ;intint n, n, i i; ;coutcoutnn; ;6.2 6.2 指针指针55pScorepScore=new =new intintn;/n;/根据学生人数动态分配根据学生人数动态分配内存内存if if ( (pScorepScore=NULL)/=NULL)/判断堆内存分配是否判断堆内存分配是否成功成功 coutcout堆内存分配失败堆内存分配失败!endlendl; ;return return 0 0; ; for for ( (i i=0; =0; i i n; n; i i+)/+)/通过通过forfor循
58、环输入学生循环输入学生成绩成绩 coutcout请输入第请输入第(i+1)(i+1)pScorepScore i i; for (for (i i=0; =0; i i n; n; i i+)/+)/通过通过forfor循环输出学生成绩循环输出学生成绩coutcout第第(i+1)(i+1)名学生的成绩为名学生的成绩为:* *( (pScore+ipScore+i)endlendl; ;6.2 6.2 指针指针56delete delete pScorepScore;/;/不再使用时将堆内存及时不再使用时将堆内存及时释放释放return return 0 0; ; 上面上面的程序中,首先,根据
59、用户输入的学生人数动态分的程序中,首先,根据用户输入的学生人数动态分配内存,并将分配到的堆内存空间首地址赋给指针变量配内存,并将分配到的堆内存空间首地址赋给指针变量pScorepScore;其次,利用;其次,利用pScorepScore对堆内存空间中的数据进行访问;对堆内存空间中的数据进行访问;最后,堆内存空间不再使用时,将其释放。根据前面的等价最后,堆内存空间不再使用时,将其释放。根据前面的等价关系,关系,pScorepScore i i 与与* *( (pScore+ipScore+i) )的作用完全相同。的作用完全相同。提示提示: : 当申请分配的内存太大、系统资源不够时,堆内当申请分配
60、的内存太大、系统资源不够时,堆内存分配会失败,此时会返回存分配会失败,此时会返回NULLNULL,表示堆内存分配失败。因,表示堆内存分配失败。因此,分配内存后,应判断返回值是否为此,分配内存后,应判断返回值是否为NULLNULL,如果是,如果是NULLNULL则则报错并退出程序。报错并退出程序。6.2 6.2 指针指针57【例例6-76-7】使用堆内存分配方式实现学生信息录入功能,要使用堆内存分配方式实现学生信息录入功能,要求程序运行时由用户输入学生人数。求程序运行时由用户输入学生人数。参考参考程序如下程序如下: : # #include include using using namespa
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 板材制造成本控制-深度研究
- 2025年广东环境保护工程职业学院高职单招高职单招英语2016-2024历年频考点试题含答案解析
- 2025年山西药科职业学院高职单招职业技能测试近5年常考版参考题库含答案解析
- 2025年山东经贸职业学院高职单招语文2018-2024历年参考题库频考点含答案解析
- 电子消费品绿色转型对品牌忠诚影响研究
- 2025年安顺职业技术学院高职单招高职单招英语2016-2024历年频考点试题含答案解析
- 四年级数学(简便运算)计算题专项练习与答案
- 2025年天津滨海职业学院高职单招语文2018-2024历年参考题库频考点含答案解析
- 2025年四平职业大学高职单招职业适应性测试近5年常考版参考题库含答案解析
- 五年级数学(小数乘法)计算题专项练习及答案汇编
- 中考模拟考试化学试卷与答案解析(共三套)
- 新人教版五年级小学数学全册奥数(含答案)
- 风电场升压站培训课件
- 收纳盒注塑模具设计(论文-任务书-开题报告-图纸)
- 博弈论全套课件
- CONSORT2010流程图(FlowDiagram)【模板】文档
- 脑电信号处理与特征提取
- 高中数学知识点全总结(电子版)
- GB/T 10322.7-2004铁矿石粒度分布的筛分测定
- 2023新译林版新教材高中英语必修一重点词组归纳总结
- 苏教版四年级数学下册第3单元第2课时“常见的数量关系”教案
评论
0/150
提交评论