




已阅读5页,还剩54页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
高级语言程序设计,授课教师: 电话: 邮箱: 授课班级:电子商务2009级,第6章 指针与字符串,6.1 指针的概念 6.2 指针型变量 6.3 指针与数组 6.4 指针与函数 6.5 指针与类、对象 6.7 动态内存分配与new和delete运算符 6.8 string类,第6章 指针与字符串,C+语言拥有在运行时获得变量地址和操纵地址的能力,这种可用来操纵地址的变量类型就是指针。指针可以用于数组、内存的访问,还可作为函数的参数,6.1 指针的概念,指针是变量,是用来专门存放内存地址的变量。 为了说清楚指针变量,先讨论对变量的访问(存取)方式。 按变量的地址直接存取变量的方法称为“直接访问”方式。存贮变量的内存空间的首地址称为该变量的地址。 如果将一个变量的地址放在另一个变量中,则存放地址的变量称为指针(pointer)型变量。这样存取变量,也可以间接的由指针变量取得该变量的地址进行,称为“间接访问”方式。 由于指针变量中的值是另一个变量的地址,我们习惯上形象地称指针变量指向该变量。指针变量中的值也简称为指针,所以指针就是地址。 设a是整型变量,其值为5,其分配的内存地址为1000H(H是16进制后缀,汇编语言表示方式);又设pa是整型指针变量,其值为1000H,可以说指针pa指向变量a。,6.2 指针型变量,1. 如何定义指针 指针类型变量定义格式如下: 存贮类型 指向类型 *变量名,*变量名; 这里*是一个定义变量为指针的说明符,而不是指针变量的一部分,更不是乘号。 int a=5,*pa; /a定义为整型变量,pa定义为整型变量指针 double *p; / p定义为双精度实型变量指针 char *p3; / p3定义为字符型变量指针 int (*p4)5; p4定义为一维数组的指针,指向的数组有5个元素 int *p6; p6定义为一个整型变量指针的指针,即p6的值是一个指针型变量的地址,那个指针变量指向一个整型变量,换句话说,p6是一个二级指针变量。,2. 指针的赋值,为了给指针赋值,C+中提供了一个取变量地址运算符: /赋给p3的值为数组b的首地址,实际上p2、p3的值一样,指针变量必须先赋值再使用。对指针变量决不可任意赋一个非负整数。指针变量中存放的是在内存中可寻址的变量或对象的首地址,而变量或对象的内存地址是由系统分配的。程序员不能代替系统给变量分配内存,系统不允许给指针变量随意赋一个地址值,只能取系统分配的变量地址赋给指针变量。,2. 指针的赋值,指针赋值注意事项: 指针值是地址 指针只能指向定义时规定的类型 如有定义: int *p; double x; 则赋值语句:p= /p1的值是a的地址,p1的值又赋给p2 暂时不用的指针可赋值为0,表示空指针。这表示当前该指针并不指向该类型的任何一个变量(对象),并不是指向地址为0的内存空间。,3. 指针的运算,使用指针变量可以间接访问指针指向的单元, 如有定义:int a,*p= 其中运算符*称为间接引用(dereference)运算符,作用于一个指针类型的变量,访问该指针所指向的内存数据。实际上例中的a与*p完全是一回事。,指针的运算共有4类: 赋值运算(包括一个指针赋给另一个指针、同类型表达式的值赋给指针指向的变量) 指针加减整数(实际加减的是指向类型长度的整数倍) 同类型指针相减 同类型指针比较,【补充例1】逆序输出字符串,#include int strlen1(char); void main() char s=“abcdefg“; char *p; int n=strlen1(s); /声明调用后面定义的函数 for(p=s+n-1;p+1!=s;p-) cout*p; coutendl; int strlen1(char a) /计算给定字符串的字符个数(字符串长度) char *p=a; int i=0; while(ai+!=0)p+;/移动指针,使其指到串结束标志 return p-a; /两个地址相减,结果为串长度 ,【补充例2】指针运算例子,#include void main() int i=6,*pi1= ,与指针有关的基本运算符有以下两个。 (1)&变量名。“&”为取地址运算符,用来获取变量的首地址。 (2)*指针变量名。“*”为指向运算符,用来获取指针变量所指向变量的值。 “&“和“*”运算符都是单目运算符,其优先级高于所有双目运算符,采用从右到左的结合性。,6.3 指针与数组,6.3.1 指针与数组的关系 数组是由同一类型元素组成的一个有序集合,如: int a5=5,8,13,21,34; 该数组在系统编译时分配连续的存储空间,数组名a就是这连续空间的首地址,因此可以将数组名当作地址值(指针)看待。即 数组名是常量,是一个指针值。 如再定义:int *p; 则下述有关指针的运算是合法的: p=a;p+;-p;p+=3;p=a+2; 下述有关指针的运算是非法的: a+;-a;a+=3;a=p+2; 原因在于p是变量,a是常量!,1. 一维数组元素的指针表示 假设已有定义:int a5,*p=a; 则ai(数组中的第i+1个元素)有以下4种表示方法: ai、pi、*(a+i)、*(p+i) 前两种称为数组表示法,后两种称为指针表示法。C+中指针表示比数组表示效率高。需要提高运行效率时,仅可能使用指针表示方法。 上述表示中,数组名与指针名在使用方式上没有区别,但要注意,指针的值可以改变,数组名代表的值是不可以改变的。,6.3.2 用指针表示数组元素,【例6-3】用指针的方法编写求一个数组中所有元素之和的程序。,#include intSum(int*pPointer,intn) intnSum=0; while(n0) nSum+=*pPointer; pPointer+; n-; returnnSum; ,void main() intpnArray10=6,7,8,9,5,4,3,2,10,1; intsumArray; sumArray=Sum(pnArray,10); cout“数组各元素和:sum1=“sumArrayendl; ,2. 二维数组元素的指针表示,二维数组元素在内存中实际上是按照行优先的规定以一维(线性)的形式存储的。如:int a34; 在内存中存储顺序为:a00,a01,a02,a03, a10,a11,a12,a13, a20,a21,a22,a23等12个元素是线性排列的。 二维数组a呈现在用户面前的是3行4列的矩阵,是二维形式.因此对二维数组元素的指针表示有两种方式:一级指针表示和二级指针表示。 上述数组元素aij(i=0,1,2 j=0,1,2,3)的 一级指针表示为:*(&a00+4*i+j) 其中&a00表示首地址 二级指针表示为:*(*(a+i)+j) 其中a+i表示第i行的首地址。,a,a+1,a+2,从二维数组的角度来看,a代表整个二维数组的首地址,也就是第0行的首地址。a+1代表第1行的首地址,因此a+1的含义是a1的地址。,a0、a1、a2既然是一维数组名,而C+又规定了数组名代表 数组的首地址,因此a0代表第0行一维数组中第0列元素的地址,即&a00。a1的值是&a10。 a2的值是&a20。,第0行第1列元素地址怎么表示? 用a0+1表示,即&a01 由于ai和*(a+i)等价,因此a0+1和*(a+0)+1的值都是&a01,请记住:二维数组名(如a)是指向行的,一维数组名是指向列元素的。在行指针前面加一个*就转换为列指针,在列指针前面加一个&就成为行指针。,【补充例3】阅读程序,注意数组元素的表示方法,#include int a23=1,3,5,7,9,11; void main() couta,*a,*aendl; couta0, ,指针可以指向数组元素,也可以指向数组。 1.指向数组元素的指针 指向数组元素的指针是一级指针,如定义数组、指针: int a10,b35;int *p1,*p2,*p3; 则下述赋值是正确的: p1=是错误的,因为b是二维数组名,相当于二级指针,而p2是一级指针,因此是错误的。,6.3.3 指向数组的指针,【补充例4】阅读程序,#include int m3=12,10,8,6,4,2; void main() int *p= p为一级指针,m为二维数组,但m在内存中实际是一维存储的,可用一级指针表示,指针p初始化为指向数组的最后一个元素(m12)。 由于-的级别高于*,故*p-相当于*(p-),而不是(*p)-, *(p-)表示先取出指针p指向变量的值,再将指针的值加1。 将程序中的*p-改为(*p)-,运行程序试一试!,【例6-5】用指针的方法将二维数组的转置(行列互换)形式输出,并输出相应的指针值,进行观察、比较。 #include void main() int aMatrix34=1,2,3,4,5,6,7,8,9,10,11,12; int i,j,*p; cout“转置前的矩阵:“endl; for(i=0;i3;i+) ,p=aMatrixi; /p存放各行的起始地址 for(j=0;j4;j+) cout“*(p+j); coutendl; cout“转置后的矩阵:“endl; for(j=0;j4;j+) for(i=0;i3;i+) p=aMatrixi;/p存放各行的起始地址(注意所在的位置),cout“*(p+j); coutendl; cout“输出相应的指针值:“endl; coutaMatrix“aMatrix0“ ,2. 指向一维数组的指针,指向一维数组的指针实际上是二级指针,指向二维数组的指针实际上是三级指针等等。 一维数组指针的定义格式为: 数组元素类型名 (*数组指针名)数组元素个数 注意,定义时的()不可少,因为的级别高于*,【补充例】阅读程序。 #include int a34=1,2,3,4,5,6,7,8,9,10,11,12 void main() int (*p)4; p=a+1; coutp00,*(*(p+1)+2),*(*(p-1)+3),p-12endl; 阅读程序时,将二级指针p当作二维数组名a看待, 但要注意p的初始位置,6.3.4 指针数组,前述的数组指针是指针,他指向一个数组;而指针数组是数组,其元素是指针。一维一级指针数组定义方式为: 指针指向类型 *数组名元素个数 其中的元素个数也是数组中的指针个数 例,int *a5就定义了一个5个元素的数组,其中每个元素都是一个整型指针。 注意,int (*a)5定义的是一个指针(二级),指向一个5个整数构成的一个一维数组。,6.4 指针与函数,6.4.1 指针变量作为函数参数 指针类型也可以作为函数的参数。通过指针型参数,可以将一个变量的地址传递给函数,而通过这个地址,函数体中的语句就可以修改函数以外的变量的值。,【例6-7】通过函数调用交换两个变量的值 #include void changFunction(int*,int*); void main() int a=5,b=10; cout“函数调用前:a=“a“,b=“bendl; changFunction( ,6.4.2 指向函数的指针 1指向函数指针变量的定义与使用 在C+语言中,函数的调用实际上是通过指针来完成的。 函数的指针是一个函数在内存中的入口地址。 函数名实际上就是一个指针,它指向函数的入口。 定义一个指针变量,并赋予它函数名,这样的指针变量称为指向函数的指针变量,简称函数指针变量。我们就可以通过函数指针变量来调用它所指向的函数。,声明一个函数指针变量的形式如下: (*函数指针变量名)(参数表) 注意,定义中的两对圆括号都不要遗漏,数据类型是函数指针变量所指函数的返回值的数据类型。 例如,若定义函数 void FunctionA(int m,int n); 则对应于函数FunctionA的指针型变量可以按如下方法声明: void (*pFPointer)(int,int);,用已经定义的函数指针变量来调用函数,分两步进行: 第一步:将函数名赋给已定义的函数指针变量。采用的格式为函数指针变量名=函数名 pFpointer=FunctionA; 第二步:使用函数指针变量调用它所指的函数。采用的格式为 (*函数指针变量名)(实参表)或函数指针变量名(实参表) FunctionA(3,4) 等价于 (*pFPointer)(3,4);或pFPointer(3,4);,2函数指针变量作为函数的参数 函数指针变量的一个主要用途是在函数调用时把函数指针变量作为参数,也就是说传递的不是数值,而是函数的入口地址,目的是实现对若干个不同函数的灵活调用。具体编程时要注意的是:主调函数的实参应设置成将被调用的函数名,被调函数的相应形参应设置成接受同类型函数入口地址的函数指针变量。,【例6-9】将函数指针变量作为函数参数例题。 #include int add(int x,int y) return x+y; int sub(int x,int y) return x-y; int funct(int(*fun)(int,int),int x,int y) int result; result=(*fun)(x,y);/等价于result=fun(x,y); return result; ,void main() int a=5,b=10; cinab; couta“+”b“=“ funct(add,a,b)endl; couta“-”b“=“ funct(sub,a,b)endl; ,6.4.3指针作为函数的返回类型 函数的返回值是地址的函数称为指针函数,其定义的一般形式如下: *函数名(形参表) 函数体 int *ip; int *fFun1(intx) . return ip; ,【补充例】有若干个学生的成绩(每个学生有4门课程),要求在用户输入学生序号以后,能输出该学生的全部成绩。用指针函数来实现。 void main() float score4=60,70,80,90,56,89,67,88,34,78,90,66; float *search(float(*p0int)4,int n); float *p; int i,m; coutm; cout“Ther scores of No.“m“are: “; p=search(score,m); for(i=0;i4;i+) coutsetw(4)*(p+i); coutendl; ,float *search(float(*point)4,int n) float *pt; pt=*(point+n); return(pt); ,6.5 指针与类、对象,1. 类的指针变量 类的指针变量是一个用于保存该类对象在内存中存储空间首地址的指针型变量,同普通数据类型的指针变量有相同的性质。 声明一个类的指针变量的语法如下: *指针变量名;,2对象的指针 对象的指针指的是一个对象在内存中的首地址。取得一个对象在内存中首地址的方法同取得变量在内存中首地址的方法一样,都是通过取地址运算符“ 表示表达式&Stu1是取得对象Stu1内存中的首地址,其值的类型是CStudent*,同类指针pStu就指向对象Stu1在内存中的首地址。,已知一个对象的指针,访问该对象中成员的方法有两种: *指针变量名.成员名 或 指针变量名成员名 CStudent Stu1; Cstudent*pStu= 都是合法表达式,3this指针 this指针是每个对象中隐藏的指针。this指针是默认的。当一个对象生成后,这个对象的this指针就指向内存中保存该对象数据的存储空间的首地址。 this指针对一个对象来说是系统自动生成的,主要用于在成员函数中需要把对象本身作为参数传递给另一个函数。,【例6-11】this指针的作用例题。 #include class ThisSample int n; public: ThisSample(); ThisSample(int m) n=m; ; void addvalue(int m) ThisSample q; q.n=n+m;/此处n相当于this-n *this=q; /将临时对象q的值传回调用对象 ;,void disp() cout“n=“nendl; ; void main() ThisSample s(10); s.disp(); s.addvalue(5); /相当于函数调用:addvalue( ,6.6 指针与字符串,6.6.1 字符串指针 在C+语言中,字符串是以“0”为结束标志的字符序列,是以字符数组的形式进行存储与处理的,而数组与指针又紧密相连(数组名就保存着字符串在内存的起始地址),因此,字符串实质上与char*型指针相对应。,char*型指针变量可以在定义时进行初始化,其形式为 char*指针变量名=“字符串“; 例如: char*myString=“Thisisastring.“; char*型的指针变量(或函数参数)既可以用于接收字符串常量,也可以接收字符型数组。例如: char pString=“IloveChina!“; char*myString=“Thisisastring.“; myString=pString;,【例6-12】字符串的复制。 #include void copy_string(char*from,char*to) /复制函数 for(;*from!=0;from+,to+) *to=*from; *to=0; /赋值字符串结束标识 void main() char pSource=“I am a teacher.“; char pDestination=“you are a student.“; /pDestination字符串长度pSource字符串长度 copy_string(pSource,pDestination); coutpSourceendl; coutpDestinationendl; ,6.6.2 字符串标准库函数 实际上,C+提供了许多操作字符串数据的标准库函数,如比较字符串、搜索字符串中的字符、确定字符串长度等,我们在程序设计时可直接引用。 注意:使用字符串处理库中的函数应在程序的开头添加包含“string.h”头文件的预处理命令#include,【例6-13】例6-12字符串的复制可以直接用C+的标准库函数strcpy()来实现。 #include #include void main() char pSource=“I am a teacher.“; char pDestination=“you are a student.“; /pDestination字符串长度pSource字符串长度 strcpy(pDestination,pSource); /等价于strncpy(pDestination,pSource,19); coutpSourceendl; coutpDestinationendl; ,6.7 动态内存分配与new和delete运算符,动态内存分配是相对于静态内存分配而言的。静态内存分配是指在编译阶段就分配好存储单元空间,这些空间的大小在程序运行过程中是不可更改的,如变量、数组等;动态内存分配则是指程序员在程序语句中通过调用内存分配函数或使用内存分配运算符取得存储空间,通过动态内存分配得到的空间的大小,编译器是不知道的,完全由动态运行中的程序的当时情况决定。,6.7.1 new运算符 new运算符用于动态分配一块内存空间。new运算符的使用形式如下: 指针变量=new长度 例如: char*CBuffer=newchar256;/分配一个可以容纳256个char型数据的空间,说明: 如果分配的空间长度为1个单位,则可以省略new运算符格式中的中括号和中括号中的整数。 使用new运算符分配内存空间时,其空间长度可以是变量,也可以是数值表达式。例如: int nSize=5; int *nPInt=new intnSize+5 由new分配的内存空间是连续的,可以通过指针的变化访问所分配空间的每一个元素。如: int *nPInt=newint10; nPInt5=100; 或 *(nPInt+5)=100; 如果当前存储器无足够的内存空间可分配,则new运算符返回0(NULL)。,【例6-14】改写字符串复制函数,要求能通过源字符串的大小动态分配目的字符串的存储空间,并返回所分配空间的首地址。 #include char*toDest; char*copy_string(char*from) /复制函数 int nSize=1; while(fromnSize!=0) /求源字符串的长度并加1 /(注意nSize的初值赋1的作用) nSize+; char*to=new charnSize; /定义目的字符串并申请分配内存空间 toDest=to; /用非函数局部变量保存空间首地址 if(to!=NULL) /申请内存空间成功 for(;*from!=0;from+,to+) *to=*from; *to=0; /赋值字符串结束标识 ,return toDest; void main() char pSource=“I am a teacher.“; char*pDest; pDest=copy_string(pSource); if(pDest!=NULL) cout“源字符串:“pSourceendl; cout“目的字符串:“pDestendl; else cout“无内存空间进行复制操作!“endl; ,6.7.2 delete运算符 由new运算符分配的内存空间在使用完毕后,应该使用delete运算符释放。,delete运算符的使用有两种形式: delete指针 及 delete指针,int *pInt=new int; deletep Int; int *pManyInt=new int10; delete pManyInt; 说明: 用new运算符获得的内存空间,只许使用一次delete,不允许多次对同一块空间进行多次释放,否则将会产生严重错误。 delete只能用来释放由new运算符分配的动态内存空间,对于程序中的变量、数组的存储空间,不得使用delete运算符去释放。,6.8 string类,在处理字符串方面,C+还提供了标准的模板类string类。我们用string类将字符串定义为对象,然后利用string类提供的赋值、连接、复制、查找、交换等字符串操作功能,即可方便地实现对字符串的各种处理。与字符数组和字符指针处理字符串不同的是,string不一定要用“0”来标识字符串的结束。下标运算符“”也可以用于访问字符串中的各个字符。,由于string类的结构比较复杂,在此主要就其基本特点与用法进行介绍并举例加以说明,关于更多、更详细的内容,请读者自行参阅有关资料。 1string类对象的定义与初始化 形式1: string对象名(“字符串“) 或 string对象名=“字符串“ 形式2: string对象名(n,字符); /生成由n个字符组成的字符串,2string类对象的操作 string类对象的操作,即实现对字符串进行赋值、连接、复制、查找、交换等功能,主要通过string类对象的成员函数调用与重载运算符(、. 例如: string s1(“Hello“); int len=s1.length(); /函数length()取得s1对象的长度 couts1.data(); /支持流输出运算符,有的C+版本还支持couts1;
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 学校目标化管理制度
- 学校里学生管理制度
- 学生小菜园管理制度
- 完善危机值管理制度
- 实体化公司管理制度
- 实验室仪器管理制度
- 审计清单式管理制度
- 家具厂环境管理制度
- 库房进出入管理制度
- 征收办公章管理制度
- 2025上半年山东文旅集团有限公司直属企业招聘88人笔试参考题库附带答案详解
- 《临床精准用血培训》课件
- 《外国文学》课件-说不尽的莎士比亚教学课件:《麦克白》
- 2025中国新型储能行业发展白皮书
- 油气管道输送试题及答案
- 2025年挖掘铲运和桩工机械司机(技师)职业技能鉴定理论考试题库(含答案)
- 2024-2025学年湘少版(三起)(2024)小学英语三年级下册(全册)知识点归纳
- 《义务教育生物课程标准(2022年版)》解读
- 承包安全协议书
- 广东食品安全管理人员抽查考核题库附答案
- 2025年白芷种植市场调研报告
评论
0/150
提交评论