C++程序设计课件:第五章 数组与指针_第1页
C++程序设计课件:第五章 数组与指针_第2页
C++程序设计课件:第五章 数组与指针_第3页
C++程序设计课件:第五章 数组与指针_第4页
C++程序设计课件:第五章 数组与指针_第5页
已阅读5页,还剩57页未读 继续免费阅读

下载本文档

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

文档简介

1、 本章将深入学习数组包括多维数组的知识和应用,以及它们与指针的关系。 C+语言拥有在运行时获得变量地址和操纵地址的能力,这种可用来操纵地址的变量类型就是指针。指针可以用于数组,用于内存访问,还可作为函数的参数。第五章 数组与指针第五章 数组与指针5.1 数组 5.5 数组与指针 5.4 this指针 5.3 指针与地址 5.2 多维数组 5.6 字符串 5.1 数组5.1.1 数组、数组元素及其存储方式 5.1.2 数组名作为函数参数 5.1.1 数组与数组元素及其存储方式数组的引入: 数组(array)是一种顺序容器(sequence container),是由单一类型元素组成的一个有序集合

2、: int fibon10=0,1,1,2,3,5,8,13,21,34; 数组名为fibon,这是一个包含10个元素的整型一维(dimension)数组,其第一个元素为fibon0,存放0,最后一个元素为fibon9,存放34。5.1.1 数组与数组元素及其存储方式 0 1 2 3 21 34fibon0 fibon1 fibon2 fibon3 fibon8 fibon9 图5.1 数组在内存中的存储数组元素的访问方式:通过下标操作符(subscript),按元素在数组中的位置进行访问,称为索引访问(indexing)或下标访问(subscripting)。参见图5.1 。5.1.1 数组

3、与数组元素及其存储方式【例 5.1】找出整型数组各元素中的最大数和最小数。const int SIZE=15;int main() int arrSIZE, i,high,low; for (i=0;iSIZE;i+) arri=rand()%100; cout Here are the SIZE random numbers :endl; for (i=0;iSIZE;i+) coutarrit;coutendl; high=arr0;/初始化时最大和最小值均为数组首元素 low=arr0; for(i=1;ihigh) high=arri;if(arrilow) low=arri; cou

4、thighest value is highendl; coutlowest value is lowendl; return 0; 1: 数组是一种组合类型,是不能作为一个整体进行访问和处理的,只能按元素进行个别的访问和处理。 2: C+数组第一个元素的下标为0,而不是1,且下标表达方式是固定的。 3:数组元素在内存中是从低地址开始顺序排列,各元素的存储单元占用内存大小相同,各元素的存储单元之间没有空隙,可以从数组第一个元素存储单元的起始地址计算出任意一个元素存储单元的起始地址。5.1.1 数组与数组元素及其存储方式5.1.1 数组与数组元素及其存储方式结构数组定义: struct keyw

5、ord char word16; /关键字 int count; /该关键字将在源程序中出现的次数 ;初始化:结构数组初始化时可以用括号来区分每一个结构,例如:keyword keytab=auto, 0,break, 0,case, 0, ;当提供了数组中所有结构值时,不必用这种括号的形式。keyword keytab=auto, 0,break, 0,case, 0,char, 0, unsigned, 0,volatile, 0,while, 0,;5.1.1 数组与数组元素及其存储方式对象数组定义: CGoods goods3;该商品类对象数组包含3个商品对象数组元素,系统调用3次默认

6、的构造函数来建立这3个商品对象数组元素。初始化:应该完整书写各个元素的构造函数及成员数据初值:CGoods goods3=CGoods(夏利2000,30,98000.0), /调用三参数构造函数,初始化goods0CGoods(桑塔纳2000,164000.0), /调用两参数构造函数,初始化goods1CGoods() /调用默认的构造函数,初始化goods2;5.1.2 数组名作为函数参数数组作为参数:数组可以作为函数的参数。在函数调用时传递实参数组的首地址,所以在被调函数中对形参数组的处理实际就是对调用函数的实参数组的处理。 C+只传递数组首地址,而对数组边界不加检查。这带来的好处是,

7、函数对长度不等的同类数组都通用。如要指定长度可以设定另一个参数来传递数组元素的个数。求一组数的平均值const int N=10;double aver(double s ,int num) int i=0; double sum=0; for (i=0;inum;i+) sum+=si; return sum/num;void main (void) double sN=1,2,3,4,5,6,7,8,9,10; double av; av=aver(s,5); coutavendl;【例5.2】字符数组与字符数组相连接void strcat(char s,char ct) int i=0,

8、j=0; while (si!=0) i+; while (ctj!=0) si+=ctj+;/while(ctj!=0) si=ctj;i+;j+; si=0;void main (void) char a40=12; char b20=abc; strcat(a,b); coutaendl;/打印字符数组a5.2 多维数组 5.2.1 多维数组 5.2.2 多维数组作为函数参数 C+中数组可以嵌套,就是多维数组。二维数组:一维数组可对应数学中的向量,而二维数组可对应矩阵,可用一个二维数组存储矩阵。5.2.1 多维数组存储与访问方式119753117131175312108642二维数组的横

9、向称为行,纵向称为列,上面这个数组为三行六列。定义二维数组的通用格式为:存储类型 类型 数组名常量行表达式 常量列表达式;行与列用常量表达式表示。5.2.1 多维数组存储与访问方式二维数组分析:上面的数组可定义为: int mat36;第一行第一列的元素为mat00,第三行第六列元素为 mat25, 下标仍是从0开始。计算机内存是一维编址的,多维数组必须要转化为一维方式存储,越右的下标变化越快,二维数组则按行排列,先排第一行,再排第二行,直到所有行排完:mat00 mat01 mat02 mat03 mat04 mat05 mat10 mat11 mat12 mat13 mat14 mat15

10、 mat20 mat21 mat22 mat23 mat24 mat25即所谓按行排列。5.2.1 多维数组存储与访问方式初始化:对于二维数组,可用嵌套一维数组初始化进行:int matrix36=1,3,5,7,9,11,2,4,6,8,10,12,3,5,7,11,13,17;也可以按数组元素存储次序列出各元素的值:int matrix36=1,3,5,7,9,11,2,4,6,8,10,12,3,5,7,11,13,17;还可以对部分元素赋初值,没有明确初值的元素清0:int matrix36=1,3,2,4,3,5,7;其结果等效于:int matrix36=1,3,0,0,0,0,2

11、,4,0,0,0,0,3,5,7,0,0,0;最后还可由初始化数据来确定数组最高维,如int matrix6=1,3,5,7,9,11,2,4,6,8,10,12,3,5,7,11,13,17;结果定义的matrix是三行六列的数组。也可以int matrix6=1,3,2,4,3,5,7;同样也是三行六列。注意这里只能最高维省略。 杨辉三角形11 11 2 11 3 3 11 4 6 4 1ai0=aii=1aij=ai-1j+ai-1j-15.2.2 多维数组作为函数参数【例5.5】矩阵转置数组作为参数传递。1 2 34 5 61 42 5 3 6bij=ajii 的取值范围?j 的取值范

12、围?5.3 指针与地址 5.3.1指针的概念 5.3.2 指针变量的赋值、初始化与简单应用引例 寻找保险箱密码 一个关于特工007寻找保险箱密码的故事关键点分析得到线索:0200单元的“紫松号”寄存箱 提示地址:1900单元找到目标:“土木”寄存箱取出内容:911寻找密码的途径分析密码911存放在某个寄存箱内,如果我们知道这个寄存箱的名字,就能够找到密码 如果不知道密码所在的寄存箱名字,知道该寄存箱的地址也照样能够取出密码 如果寄存箱的地址也不知道,但是有另外一个地方存放这个寄存箱的地址,就能顺藤摸瓜,间接找到密码密码存放示意图土木号9111900紫松号19000200名字紫松号土木号地址02

13、001900内容1900911利用指针模拟寻找保险箱密码的过程 获取密码的两种方法 int main(void)int key = 911; /* 变量key存放密码 */int *addr = NULL; /* 变量addr存放地址 */addr = &key; /* 将key的地址赋给addr */ /* 通过变量key输出密码值*/ cout“密码:“ key; /* 通过变量key的地址来输出密码值 */cout“如果我知道存放密码的地址,我也能找到密码: , *addr;return 0; 密码: 911如果我知道存放密码的地址,我也能找到密码: 911 5.3.1 指针的概念 指针

14、与间接访问: 按变量的地址直接存取变量的方法称为“直接访问”方式。存贮变量的内存空间的首地址称为该变量的地址。 如果将一个变量的地址放在另一个变量中,则存放地址的变量称为指针(Pointer)型变量。这样存取变量,也可以间接的由指针变量取得该变量的地址进行,称为“间接访问”方式。 由于指针变量中的值是另一个变量的地址,习惯上形象地称为指针变量指向该变量。指针变量中的值也简称为指针,所以指针就是地址。地址和指针指针的概念 内存单元地址 内容 变量int x = 20, y = 1, z = 155;cout x;直接访问:通过变量名访问间接访问:通过另一个变量访问把变量的地址放到另一变量中使用时

15、先找到后者再从中取出前者的地址1000 20 x1002 1 y1004 155 z2000 1000 p2002地址 指针变量5.3.1 指针的概念 指针类型的区分:指针类型可以按它指向的变量的类型区分。基本类型和非基本类型都有对应的指针类型,包括类(class),甚至还有指针类型(指向指针的指针,二级指针)。 理由: 指针中只放变量首地址是不够的,还要知道占多少内存?数据又是怎样组织的?整型数占4个字节,浮点数占4个字节,字符型占1个字节,宽字符占2个字节;并且它们有各自不同的存储组织方式。5.3.1 指针的概念指针类型变量定义:存贮类型 类型 *变量名,*变量名;这里*是一个定义变量为指

16、针的说明符,而不是指针变量的一部分。 必须指出的是定义时每一个指针变量都需要一个指针变量说明符。例如:int *lp1,*lp2;如果写成int *lp1,lp2;则编译器认为lp2是整型变量,只有lp1是指向整型变量的指针型变量。5.3.2 指针变量的赋值、初始化与简单应用 指针变量的值 : 对指针决不可以任意赋一个内存地址,只能取一个已经分配了内存的变量的地址赋给指针变量。 理由:指针变量中存放的是在内存中可寻址的变量或对象的首地址,而变量或对象的内存地址是由系统来分配的。程序员不能代替系统给变量分配内存,当然也就不能给指针变量随意赋一个地址值。5.3.2 指针变量的赋值、初始化与简单应用

17、 与指针相关的运算符: “&”取地址运算符,作用于内存中一个可寻址的数据(如:变量,对象和数组元素等等),操作的结果是获得该数据的地址。“*”间接引用(dereference)运算符,作用于一个指针类型的变量,访问该指针所指向的内存数据。【例5.6】指针变量的赋值20age218age1p_age#include using namespace std; int main() int age1=18,age2=20,*p_age; p_age=&age1; /情况1 coutage1的地址是: p_ageendl;/0012FF7C coutage of wang ping is *p_age

18、endl; p_age=&age2; /情况2 cout age2的地址是: p_ageendl;/0012FF78 coutage of zhang ling is *p_age” ),再加公有成员名就可以了。【例5.7】通过结构指针来访问结构成员。*C语言的指针容易失控,在C+中增加了引用类型,它具有指针的主要功能,但限制了灵活性,使用更加安全。建议在函数参数传递中,能用“引用”时绝不用“指针”。【例5.7】 指针变量简单应用【例5.7】通过结构指针来访问结构成员。#include#includeusing namespace std;struct studentchar name20;c

19、har id10;/学号必须用字符串,当学号以0开头,整数会丢失0int age;float score;char address30;【例5.7】 指针变量简单应用int main() student st1,*prst; prst=&st1; cout请输入学生的姓名:endl; cin.getline(,20);/cin.getline可输入空格 cout请输入学号、年龄和入学成绩:st1.idst1.agest1.score; cin.get();/吸收掉换行回车符 cout请输入家庭住址:endl; cin.getline(st1.address,30); cout姓

20、名tnamen; cout学号tidn; cout年龄tagen; cout入学成绩tscoren; cout家庭住址taddressName,Name);this-Amount=Amount; this-Price=Price;5.5 数组与指针 5.5.1 数组名、指针和指针运算 5.5.2 指针作为函数参数 5.5.1 数组名、指针和指针运算数组名和指针的关系:数组名被看作该数组的第一个元素在内存中的首地址(仅在sizeof操作中例外,该操作给出数组所占内存大小)。数组名在表达式中被自动转换为一个指向数组第一个元素的指针常量。数组名中所放的地址是不可改变的,所以称指针常量(即隐含说明“元

21、素类型* const数组名”)。 数组名是指针,非常方便,但是却丢失了数组另一个要素:数组的大小,即数组元素的数量。编译器按数组定义时的大小分配内存,但运行时(run time)对数组的边界不加检测。这会带来无法预知的严重错误。数组名指向的目标是数组元素,而不是数组整体。5.5.1 数组名、指针和指针运算用指针访问数组: C+提供根据数组的存储地址访问数组元素的方法。图5.1中fibon是数组第一个元素的地址,所以*fibon是数组的第一个元素fibon0,而fibon+1是数组第二个元素的地址,*(fibon+1)是第二个元素fibon1本身。指针加1,则地址移动一个数组元素所占字节数。 数

22、组实际访问方式: C+语言的下标运算符 是以指针作为操作数的,fiboni被编译系统解释为*(fibon+i),即表示为fibon所指(固定不可变)元素向后第i个元素。无论以下标方式或指针方式存取数组元素时,系统都是转换为指针方法实现。5.5.1 数组名、指针和指针运算指针的算术运算和关系运算:1. 指针变量与整型量的加减表示移动指针,以指向当前目标前面或后面的若干个位置的目标。指针与整型量i的加减等于指针值(地址)与i*sizeof(目标类型)积的加减,得出新的地址。*运算结果并不表明那儿有一个指针所规定的数据类型的变量,这称作不对数组边界做检查。所以指针必须小心使用。2. 只有当两个同类型

23、的指针变量指向同一个数组时才可以进行减法运算,结果表示由第一个指针所指元素到第二个指针所指元素之间的元素数量。这里数量算头不算尾。*两个指针相加是毫无意义的。建立两个指针间的指针,不能写p=(p1+p2)/2,必须写p=p1+(p2-p1)/2。 5.5.1 数组名、指针和指针运算3当且仅当两个同类型指针变量指向同一数组中的元素时,可以用关系运算符,=,!=等进行比较,比较规则是指向后面元素的指针大,指向同一元素的相等。指针同样可以进行”+”,”-“运算,运算结果也是指向后一个或前一个数组元素。*但是有”+”和”-”的表达式往往容易出错,必须小心使用,如:y=*pfib+;由于后”+”的优先级

24、高于”*”,所以该表达式等效于y=*(pfib+),又因是后”+”,所以y中取值为*pfib,而pfib增1后指向下一个元素。这条语句在C+中是常用的。千万不可误解为将pfib所指目标增1。【例5.8】指针与数组相关的运算,演示怎样访问数祖【例5.8】访问数组的方法#include Using namespace std;void main() int i,fibon10=0,1,1,2,3,5,8,13,21,34,*pfib1,*pfib2; pfib1=pfib2=fibon; /也可以用pfib1=pfib2=&fibon0 cout使用数组显示斐波那契数列endl; for(i=0;

25、i10;i+) coutfibonitpfib1iendl; cout使用指针显示斐波那契数列endl; for(i=0;i10;i+) cout*(fibon+i)t*pfib2+endl; /注意:fibon+是错误的,而pfib2+是正确的 cout显示指针相减,应为数组长度:; coutpfib2-pfib1endl; /pfib2已指向数组末尾 return 0;5.5.2 指针作为函数参数 引用调用与指针传值调用:C+中函数的参数的基本使用方法是传值。为了弥补单纯传值的不足,以引用作为函数的参数,从逻辑上讲引用是别名,在函数中对参数的操作,就是对实参的操作,而在物理上是传实参的地址

26、。将指针用作函数的参数时,传的仍然是值,指针的值,这个值就是指针所指向的变量或对象的内存首地址,在物理上传的是指针的值,在逻辑上讲是把另一个变量的地址传过去了,可以看作传地址。 建议在函数参数传递中,能用“引用”时绝不用“指针”。 【例5.9】用指针代替引用实现两数据的交换【例5.9】用指针代替引用实现两数据的交换【例5.9】用指针代替引用实现两数据的交换#include using namespace std;void swap(double *d1,double *d2)double temp;temp=*d1;*d1=*d2;*d2=temp;int main(void)double x

27、,y;cout”请输入x和y的值”xy;swap(&x,& y);cout”x=”xt”y=”yendl;return 0;用引用实现两数据的交换用引用实现两数据的交换#include using namespace std;void swap(double &d1,double &d2)double temp;temp=d1;d1=d2;d2=temp;int main(void)double x,y;cout”请输入x和y的值”xy;swap(x, y);cout”x=”xt”y=”yendl;return 0;5.5.2 指针作为函数参数指针作为返回值:函数的返回值也可以是指针。如希望返

28、回多个值,可以用引用参数或指针参数来等效实现,如果我们希望返回一个数组,并且这个数组生命期不在该函数中消亡,我们可以返回一个指向该数组的指针。 指针变量可以代替数组作为函数的参数,而且更常见。在下一节C风格字符串的库函数中,总是用指向字符的指针取代字符数组作为形式参数。但是实参必须是字符数组名(字符串)或已指向字符串的指针。5.6 字符串 5.6.2 标准的C+string类 5.6.1 C字符串(自学) 【例5.10】 字符串处理本例显示算法的演变,可见指针应用之妙。void scopy1(char s , char ct ) int i = 0; while ( cti != 0) si

29、= cti; i +; si = 0; 由于数组与指针的等价性,同样可以用指针进行:void scopy2(char *s, char *ct) while(*ct != 0) *s = *ct; s = s + 1; ct = ct + 1; *s = 0;【例5.10】字符串处理可直接用运算符 + 表示增量,循环条件测试也可以简化:void scopy3(char *s, char *ct) while(*ct) *s+ = *ct+; *s = 0;本例还可以进一步简化为在条件测试的同时进行字符复制:void scopy3(char *s, char *ct) while( *s+ =

30、*ct+);C+/C 标准库提供了字符串复制函数 : char *strcpy(char *s,const char *ct)。返回值是指向复制后字符串中首字符的指针。 5.6.2 标准的C+string类建议使用C+的string类,它重载了运算符,连接、索引和复制等操作不必使用函数,使运算更加方便,而且不易出错。string类包含在名字空间std中的头文件。#includeusing namespace std;5.6.2 标准的C+string类string类的使用方法:(1) string类有三个构造函数:string str; /调用默认的构造函数,建立空串string str(OK

31、); /调用采用C字符串初始化的构造函数string str(str1); /调用复制构造函数,str是str1的副本(2) string类字符元素的访问比C字符串有所增强:stri /返回str中索引i处字符的引用,不查是否出界str.at(i) /返回str中索引i处字符的引用,查是否出界5.6.2 标准的C+string类(3) string类重载了一些运算符,特别注意当目标串较小,无法容纳新的字符串,系统会自动分配更多的空间给目标串,不必顾虑出界:str1=str2; /str1成为str2的副本str1+=str2; /str2的字符数据连接到str1的尾部str1+str2; /返

32、回一个字符串,它将str2连接到str1的尾部str1=str2; str1!=str2; /比较串是否相等,返回布尔值str1str2; str1=str2; /基于字典序的比较,返回布尔值5.6.2 标准的C+string类(4) string类的输入输出。输出与C风格字符串同样方便,使用插入运算符,代码读取的是以空白字符结束的字符串,输入完整的字符串可用非成员函数getline,注意格式:getline(cin,str); /串以n结束getline(cin,str,ch); /串以ch结束5.6.2 标准的C+string类(5) string类有一些常用的成员函数可进行字符串处理:s

33、tr.substr(pos,length1); /返回对象的一个子串,从pos位置起,长length1个字符str.empty(); /查是否空串str.insert(pos,str2); /将str2插入str的pos位置处str.erase(pos,length1); /在str位置pos处起,删除长度为length1的字串str.find(str1); /返回str1首次在str中出现时的索引str.find(str1,pos); /返回从pos处起str1首次在str中出现时的索引str.length(str); /返回串长度5.6.2 标准的C+string类(6) C字符串到str

34、ing类对象是由构造函数隐式自动进行,而string类对象到C字符串的转换必须执行显示的类型转换,应调用成员函数str.c_str(); /将string类转换为C风格字符串,返回char*在教材第4章习题4.9将人民币类转换为浮点数,那是由转换函数显式完成的,反之由浮点数转换为人民币类由对应的构造函数隐式自动完成。这是一个规则。(7) string类重载了插入和提取运算符,当先输入数值,后输入串,不必先吸收回车,不会产生C风格字符串那样的空串问题(参见例9.3)。5.6.2 标准的C+string类【例5.12】判断字符串是否为回文。回文是指顺读和反读都一样的串,这里不分大小写,并滤去所有非

35、字母字符,如:Madam,Im Adam.Golf,No Sir,prefer prison flog!都是回文。string类的优点: string类有自己的构造函数和析构函数,如果它作为类或结构的成员,要记住它是成员对象,当整个类对象建立和撤销时,会自动调用作为成员对象的string字符串的构造和析构函数。 【例5.12】判断字符串是否为回文 bool is_pal(const string& s) /判断是否回文string punct(,;:.? ); /包括空格符string str(make_lower(s); /大写改小写str=remove_punct(str,punct); /滤去所有非字母字符 return str=reverse(str);string make_lower(const string& s) /所有大写改为小写string temp(s);int i,s_length=s.length();for(i=0;is_length;i+) tempi=tolower(si);/tolower()是cc

温馨提示

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

评论

0/150

提交评论