第六章指针引用和动态空间管理_第1页
第六章指针引用和动态空间管理_第2页
第六章指针引用和动态空间管理_第3页
第六章指针引用和动态空间管理_第4页
第六章指针引用和动态空间管理_第5页
已阅读5页,还剩13页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、第六章 指针、引用和动态空间管理6.1指针的概念和指针变量的定义指针是一种十分重要的构造数据类型,C+程序中常常使用指针,使用指针的好处是:更适合表达某些算法,使用指针可以写出更为紧凑和有效的程序。要学好C+必须学好指针。6.1.1指针的概念指针是一种数据类型。指针就是指针类型变量,即指针变量。指针变量常常直接简称指针。与一般变量的不同点:它存放的不是数据的值,而是另一个变量的地址。就是说指针变量:用来存放另一变量的内存地址的变量。每个变量和函数声明后,编译器就会为它们在内存中开辟一块存储区域,这块区域的地址就是变量的地址。这块区域中存放的数据值(内容)就是变量的值。对变量的访问(引用),实质

2、就是对变量存储空间的内容(数据值)进行访问。这样我可以用另一种方法来访问变量内容,即不通过变量名,而是通过变量在内存中的地址进行访问。这种访问方式就是指针访问。6.1.2 指针的定义和初始化同一般变量一样,先定义后使用。定义时要指明指针的类型,并在指针名前加修饰符*。格式:类型修饰符 *指针名 或者 类型修饰符* 指针名*只是类型修饰符、不是变量名的一部分。如语句:int * x_ptr; 或 int * x_ptr;定义了一个指向int型变量的指针(变量)x_ptr。而 char * x_ptr; 或 char * x_ptr;定义了一个指向char型变量的指针(变量)x_ptr。注意:语句

3、int* x,y; 不是定义了两个int型指针,而是定义了一个int型指针和一个int型变量。 int *x,*y;指针定义后,并不具体地指向某个变量,而只是确定了类型。可以对指针进行初始化,让它指向某个具体的变量。这通常用到运算符&。它是取地址运算符。用在操作数的前面,表示取操作数的内存地址。操作数可以:一般的变量、数组元素、结构成员等。如:float salary;float *salary_ptr=&salary;/ 将指针salary_ptr初始化为变量salary的内存地址值,也即指向了具体的salary。6.1.3 常值指针可以用const把一个指针定义为常值指针。常值有两种含义:

4、一种是指针所指向的数据为常值,这时须将const放在*号的前面。如 const char *s=“Hello!”; / char const *s=“Hello!”;/ char const *s;s=“Hello!”/ s是一个指针变量,它指向一个字符串常量。不能用该指针来改变其所指向的内容,指针s本身可以改变的。如 s=“Hi” /正确, *sY /错另一种:指针本身是常值,须将const 放在*的后面。如: char * const s=”Hello!”; / s是一个指针常量,它指向一个字符串变量。指针的内容可变,指针本身不可变。对于指针常量,必须在定义时对其初始化。与前相反。如 s=

5、“Hi”/ 错,*sY/正确也可以是上述两者的综合。两者都不能改变。6.2指针的基本操作6.2.1指针赋值:操作符指针定义时可以对它进行初始化。如:float salary;float *salary_ptr=&salary;也可以声明指针变量后赋值:如:int a=-8978;int *p; p=&a /p被赋值为变量a的地址。同类型指针可以互相赋值。如:double a;double *x=&a, *y;y=x/x, y 指向同一个变量a。int count=78, *c_ptr=&count; c_ptr=x; /错,不同类型指针特殊指针空指针。值为零的指针C+函数库中都将空指针定义为名

6、字NULL。因此将指针赋值为NULL即赋值为零。如:x=NULL;即为;x=0用修饰符void修饰的指针变量,为void 指针。任何类型的指针可赋给void指针,但反过来不行。6.2.2 取值的地址:操作符&float salary;float *salary_ptr=&salary;/ salary_ptr指向salary。6.2.3 间接访问(取内容运算符)操作符*用在指针变量的前面,表示取指针所指向的存储单元的值,也即取指针所指变量的值。如:int a=90;int a_ptr=&a;int x;x=*a_ptr; /把a_ptr所指的存储区域的内容,即变量a的值赋给x,x等于90。而*

7、a_ptr98; /将98填入a_ptr所指的存储区域,即a的值被填为98。同理*a_ptr*a_ptr+1;/a_ptr所指的存储区域的值加1,即a的值被加了1,与a=a+1效果一样。注意:声明语句中和赋值中*的含义是不同的。声明语句中:*是指针类型修饰符,用来说明变量是指针变量;赋值语句中*是取内容运算,用来取指针变量的内容。&与*是互逆的操作,这两个操作符在一起,其作用互相抵消。如;*&r=3;与r=3;效果一样。6.2.4 判断指针是否为空指针:操作符(等于)!(不等于)(书所示了解)6.2.5 计算两地址间数据单元的个数指针存放的是内存地址,关于指针的运算就是关于地址的运算。地址是无

8、符号整数值。同类型指针相加,其结果是一个整数,表是两个地址之间可容纳的相应类型数据的个数。例子如书所示。2.6.6指针移动1.指针与整数相加或相减(移动n个单位)。指针与整数进行的加、减运算,代表着指针在内存空间上、下移动。加1表示指向当前所指单元的上一单元。减1表示指向当前所指单元的下一单元。具体的上移或下移的字节数与其类型相关。如:字长为32的计算机中,一个int型数据占4个字节,如果有int a=78;int *x=&a;/x初始化为指向变量a。在语句x=x+1(x+=1);执行后,x中存放的地址被加了4,指向变量a的下一个整数。同理,语句x=x-1(x-=1);执行后,x指向了上一个整

9、数。思考:假定一个double型数据占8个字节,x=x-3;x=x+3;又会怎么样?2. 移动一个单位在指针使用加1或减1时,也可以使用C+的增1运算符+和减1运算符。当+和与*同时作用指针时,与普通变量一样注意运算的顺序。例如:x=*p+;相当于x=*(p+) /即先将地址加1,再取地址中的数据的类型转换。又如:x=* +p;相当于x=*(+p) /含义同前而 x=+*p;相当于x=+(*p)/表示先取p所指向的单元内的数据值,再将数据值加1后赋给x。6.2.7 指针表达式的副作用(书所示)6.2.8 指针类型的强制转换任何类型的指针可以强制转换,格式:(类型修饰府*) 指针表达式如(书所示

10、):6.2.9指针操作符的综合运用(书所示)6.3 指针与数组C+中,指针与数组有着密切的关系。数组名本身就是一个指针(常量指针),对数组元素的引用即可以采用下标的形式,又可以采用指针形式;反过来,指针也可以当作数组来使用。6.3.1一维数组元素的指针访问方式如:int a10=3,56,287,78,43,65,4,37,85,1276;/ 定义并初始化了一个一维数组,它的10个元素用下标形式分别表示:a0,a1,a2-a9若使用指针形式来表示a的元素时,a可以当作一个int型的指针变量,存放着数组的首地址。则a的元素可以表示为:*(a+0)或 *a,*(a+1),*(a+2)-,*(a+9

11、)若要将a4赋值为-59,既可用语句;a4-59,*(a+4)-59;两者等效。在C+中,任何一个数组的名字都可以作为一个常量指针来使用,常量指针是指它的值不能被改变。数组名作为一个常量指针,存放的是这个数组在内存中所占区域的起始地址,也即第一个元素的地址。这样数组元素皆可以使用指针形式来表示。设数组名为a,其元素ai可以用指针形式表示为:*(a+i)。例子: includevoid main()int a5=1,2,3,4,5;couta0a1a2a3a4endl;/数组形式coutaendl;/输出数组首地址cout*a*(a+1)*(a+2)*(a+3)*(a+4)endl;/指针形式/

12、使用下标的形式或指针形式来应用数组元素,其效果是一样的。6.3.2多维数组元素的指针访问方式。二维数组用指针的形式表示的方法与一维数组类似。假设有int a34;/三行四列的数组其元素下标形式为:a00,a01,-,a22,a23。换个角度,a又可以看作一个有3个元素的一维数组,每行一个元素,每个元素又都是一个具有4个元素的一维数组。即:a0a1a2a的3个行元素可用指针表示为:*(a+0),* (a+1),*a(a+2)以第一行元素*(a+0)为例,其包含的4个元素又可以分别表示如下:*(*(a+0)+0),*(*(a+0)+1),*(*(a+0)+2),*(*(a+0)+3)/其余依次类推

13、。由此可知二维数组a的任一个元素aij的指针形式:*(*(a+i)+j)也可以只将行、列下标中的一个元素用指针形式表示,另一个用下标形式表示。二维数组a的任一个元素aij也可以用如下形式表示:*(ai+j) 或 (*(a+i)j此外,由于无论一维还是多维数组,在内存中都以一维的形式存放的,可以按存放的顺序来使用指针。例如:上述数组,其任一个元素aij也可以用:*(a+i*4+j)表示。/乘以4因为第二维的大小为4。例子(书所示):6.3.3关于“指向数组的指针”数组名可以作为常量指针使用。常量指针的值是不能改变的,以任何形式对它进行赋值或修改都是不允许的。例如:float total4=3.5

14、6,-45.52,90,127.39;float x,y;x=*total;total=total+1/非法;y=*total;上面,将数组名total的值加1,这是不合法的。这时可以用一个变量指针来代替常量指针,让它指向该数组,而它的值可以被修改。Float * p=total;/将p初始化为指向数组totalx=* p;p=p+1;/合法y=*pp是一个变量指针,完全可以对它进行加1操作。其中,让p指向total也可以用:float *p=&total0;/将p初始化为total0的地址,也即数组的首地址。指向数组的指针可以被修改,而数组名是常量指针,其值不能被修改,只能固定的指向某一数组

15、。指针的形式来引用数组,指针也可以直接当成数组来用。例子:当成数组来用的指针includevoid main() int x3=4,5,6;int *p=x;/让指针p直线数组xcoutx0x1x2;coutp0p1p2endl;/先将指针p初始化为指向数组x,将p作为数组来使用,它的3个元素p0,p1,p2实际上就是*p,*(p+1),*(p+2),即指针*(p+i)可以使用下标形式pi。输出为例子指向数组的指针的另一个例子include void main()char str1=“Whats that?”;char str2=“Its a book。”;char *ptr;coutstr1

16、endl;coutstr2endl;ptr=strl; /让ptr指向str1coutptrendl;ptr=str2; /让ptr指向str2coutptrendl;/程序中ptr是指向字符串的指针,存放的是字符串的首地址,而不是字符串本身,str1 、str2也是字符串的指针,但它们是常量指针。输出: Whats that? Whats that?Its a book。 Its a book”。6.3.4 字符指针与字符串数组名就是指针,任何指向字符型数组第1个元素的指针都可以代表存储字于该处的字符串。(书所示)。6.3.5 指针数组与命令行参数数组是一批同类型变量的有序集合,同类型变量可

17、以包括指针。当一个数组的元素都是某种相同类型的指针,那么这个数组就是常量指针。定义格式:double *cost/声明了一个含有10个元素的一维数组cost, cost的每一个元素(cost0,-cost9)都是一个double 指针,可以指向任意一个double型数据。指针数组使用会带来很大的好处。如:字符串数组的处理。/用二维字符数组存放某班50个学生姓名。事先要确定姓名的最大长度,姓名长度达不到最大长度,造成存储空间的浪费。就可以指针数组来解决char *name50=“Wangqingping”,“Wangqiang”,“Liuli”-;可见,使用指针数组来存放多个字符串,可以不用考虑

18、字符串的长度,它按实际长度来存储,非常方便,实用。例子(书)6.3.6数组参数实际上是指针对数组参数的说明,形式上是在说明数组,实际上在说明指针。是在说明指向数组的指针。(书所示)6.4指针与函数6.4.1指针参数函数传址调用的参数可以是指针类型、数组名、或引用等地址类型的变量。C+对实参变量存储地址间接操纵参数的值,若在函数代码执行过程中参数的值进行了修改,这种变化在调用结束将保存在实参变量中。例子:includevoid exch(int *x,int *y)int z;z=*x;*x=*y;*y=z;void main( )int a=3, b=5;exch(&a,&b);cout“a”

19、a“,b=”bendl;程序输出:a=5,b=3。变量a,b的值已经交换。在本例中对指针类型的形参,调用exch(&a,&b)分别将变量a,b的存储地址传给指针变量x,y。注意实参和形参的内存地址一致。指针作为函数的参数时,实参传递地址给形参,实参和形参访问共同的地址单元。利用指针可以实现调用函数与被调用函数双向传递信息。指针变量作为函数参数时应注意:*变量的指针、数组的指针、函数指针、链表指针等都可以作函数的实参和形参。*当函数形参是指针时,实参可以是指针、数组名、变量的地址,不能是数组元素和常量、变量、表达式。*当函数实参是指针,其形参可以是指针,也可以是数组。6.4.2指针函数:返回指针

20、的函数函数可以返回指针值,这样的函数称为指针函数。定义的格式:类型修饰符 *函数名(形参表)函数体例子(书所示)注意:指针函数所返回的指针不能指向函数返回后即不存在的对象,如函数中的自动变量、形参变量等。6.4.3函数指针:指向函数的指针指针变量除了用来存放变量、数组或结构等数据来型的内存地址外,还可用来以存放函数在内存中的入口地址。函数指针的格式:函数类型 (*指针变量名)(形参表)语句:double (*ptr)(double double);定义了一个指向具有两个double 型形参,返回值类型为double型的函数指针变量ptr,以后可以用它调用任何具有两个double形参的doubl

21、e型函数。例子:用函数指针调用函数# include double max(double x,double y)double z; if(xy) z=x;else z=y;return z;void main()double a,b,c;cinabc;c=max(a,b);/通过函数名调用函数cout“a=”a“,b=”b“,max=”cendl;double (*ptr)(double x,double y);/声明函数指针ptr=&max;c=(*ptr)(a,b)/通过函数指针调用函数cout“a=”a“,b=”b“,max=”cendl;ptr=max;/与ptr=&max;等价cou

22、t“a=”a“,b=”b“,max=” (*ptr)(a,b)endl;/一次用函数名调用,2两次用函数指针调用,结果相同。为函数指针变量赋值时,ptr=&max与ptr=max两种形式等价,都是将函数入口地址传给函数指针。因此不涉及实参或形参,不能写成ptr=max(a,b)。6.4.4 作为参数传递的函数把函数指针作为参数传送给另一个函数是定义函数指针变量的主要用途之一。函数指针作为参数就是通知一个函数在适当的时候通过函数指针去回调另一个函数以完成具体任务。例子(书所示)6.5引用6.5.1引用变量和引用参数1.引用类型引用是通过变量存储地址访问变量的一种语法机制。C+通过取地址运算符“&

23、”,引入了一种新的数据类型“引用类型”。定义格式:类型& 变量,或类型 &变量。格式中的“变量”是引用类型的变量,简称一个引用,格式中“类型”称为引用的基类型。如:int & 是对int类型的引用类型, float &是对float类型的应用类型。引用定义格式与指针格式十分相似。本质上,指针是地址变量,而引用一旦定义后,其地址是固定的,变化的只是该地址中的内容。2.独立引用是对变量的引用。在定义引用变量之前必须先定义被引用的变量。int k; int& k_adr=k;(或int &k_adr=k;)/定义了一个int型变量k和它的引用k_adr,相当与为k取了一个别名。对k和k_adr的操作

24、对变量的影响是完全相同的。指向变量的指针也可以看作变量的别名。指针变量的值可以改变,而引用只能与一个变量关联。例子:对变量引用的操作#include void main() int k=32; int& k_adr=k;cout“k=”k“ k_adr=”k_adrendl;k+;cout“k=”k“ k_adr=”k_adrendl;k_adr-5;cout“k=”k“ k_adr=”k_adrendl;int i=100;k_adr+i;cout“k=”k“ k_adr=”k_adrendl;k=32 k=32k=33 k=33k=-5 k=-5k=95 k=953.参数引用引用通常用来作为函数的参数以实现传址调用例子:例子:includevoid exch(int &x,int &y)int z; z=x;x=y;y=z;void main( )int a=3, b

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论