《电子科技大学c第五章构造数据类型.ppt》由会员分享,可在线阅读,更多相关《电子科技大学c第五章构造数据类型.ppt(49页珍藏版)》请在三一办公上搜索。
1、第五章 构造数据类型,丘志杰电子科技大学计算机学院 软件学院,枚举类型,“枚举”是指将变量所有可能的取值一一列举出来,变量的取值只限于列举出来的常量。枚举类型的声明的一般形式如下:当没给各枚举常量指定值时,其值依次默认为0、1、2、;在定义枚举类型时,也可使用赋值号另行指定枚举常量的值。,enum 枚举类型名 枚举常量1,枚举常量2,枚举常量n;,枚举!,数组,数组是一组在内存中依次连续存放的、具有同一类型的数据变量所组成的集合体。数组元素用数组名与带方括号的数组下标一起标识。,一维数组定义与使用,一维数组定义的一般形式为:数据类型 数组名常量表达式;说明:数组元素的类型可以是void型以外的
2、任何数据类型。数组名代表数组元素在内存中的起始地址,是一个地址常量。,数组定义之后,系统会将从内存中为其分配一块连续的存储空间,从第1个数据元素开始依次存放各个数组元素。例如:int a5;,一维数组的初始化,一维数组初始化的语法形式为:数据类型 数组名 常量表达式=初值1,初值2,初值n;例如:int array3=5,6,7;int array23=1,2;,存取一维数组元素的语法形式为:数组名 下标表达式;读数组元素的地址通过数组名来读取,格式如下:数组名+整型表达式;或,使用数组要注意的地方,在使用数组时最常犯的错误是下标越界。数组名是一个地址常量,不能作为左值(赋值的目标)。因此,不
3、能将一个数组整体拷贝给另外一个数组。例如:int a5,c5,i;a=c;/错误!正确的方法是将对应的元素进行拷贝:for(i=0;i5;i+)ai=ci;,字符数组与字符串,存放字符型数据的数组称为字符数组。1.用字符进行初始化 例如:chars1=C,h,i,n,a;2.用字符串进行初始化 例如:chars2=China;,字符数组的使用,字符数组也是数组,我们同样可以通过数组名及下标引用数组中的元素。为方便对字符与字符串的处理,C+提供了许多专门处理字符与字符串的函数。参看P118表5-1。,指针,指针是C+语言最重要特性之一,也是C+的主要难点。指针提供了一种较为直观的地址操作的手段,
4、正确地使用指针,可以方便、灵活而有效地组织和表示复杂的数据。,地址与指针,地址:当定义一个变量后,内存中将会划出一块由若干个存储单元组成的区域,用于保存该变量的数据。在内存里每个存储单元都有各自的编号,称为地址。指针:在C+中,提供了指针类型,它是一种用于存放内存单元地址的变量类型,地址就存储在这种指针类型的变量中。正因为指针变量存储的是地址,用它来指明内存单元,所以形象地称这种地址变量为指针。,指针变量的定义,例如:int*ip;/定义了一个int型的指针变量ip float*fp;/定义了一个float型指针变量fp sizeof(ip)=sizeof(fp)=4;,定义指针变量的格式如下
5、:数据类型*变量名;,指针的初始化与赋值,(1)不要将一个非地址常量、变量以及无意义的实际地址赋给指针变量。如:int*p=100;/int*p=(int*)100;(对吗?)int*p=(char*)100;(2)可以使用一个已初始化的指针去给另一个指针赋值,但类型必须一致如果不一致,可进行强制类型转换。char*p=NULL;int*ip=(int*)p+100;,数据类型*指针变量名=初始地址表达式;,(3)对于基本数据类型的变量、数组元素我们可以使用取地址运算符/定义void类型的指针,指针运算,指针通常进行下列几种运算:赋值运算、取值运算、算术运算、相减运算、比较运算。(1)*和,(
6、2)指针与整数的加减运算 指针的加减运算与普通变量的加减运算不同,由于指针存储的是变量的内存地址,指针加上或减去一个整数n,表示指针从当前位置向后或向前移动n个sizeof(数据类型)长度的存储单元。因此对于不同的数据类型,n的实际大小就不同。,(3)指针自增、自减运算 指针的自增、自减运算是指针加减运算的特例。指针的自增或自减表示指针从当前位置向后或向前移动sizeof(数据类型)长度的存储单元。例如:int*p,a=5,b=6,c=7;p=/指针p后移4个字节,指向a,(4)两指针相减 当两个指针指向同一数组时,两个指针的相减才有意义。两个指针相减的结果为一整数,表示两个指针之间数组元素的
7、个数。(5)两个指针的比较运算 两个指针的比较一般用于下列两种情况:一是比较两个指针所指向的对象在内存中的位置关系;二是判断指针是否为空指针。,void类型指针,指向void类型的指针是一种不确定类型的指针,它可以指向任何类型的变量。实际使用void型指针时,只有通过强制类型转换才能使void型指针得到具体变量的值。在没有转换前void型指针不能进行指针的算术运算。例如:void*vp;/定义了一个void型指针vp inti=6,*ip;vp=,指针与字符串,字符型指针:用于存放字符型变量的地址,而字符串的本质是以0结尾的字符数组,一个字符型指针存储了字符数组的第一个元素的地址,也就存储了字
8、符串的地址,这个指针就指向了字符串。在定义一个字符数组时,可以将一个字符串常量作为初值,但将字符串常量作为初值赋给字符数组和将字符串常量作为初值赋给字符指针变量,二者的含义是不同的。例如:char str5=abcd;char*p_str=abcd;,指针与数组,1 使用指针操作符*存取数组 指针的加减运算的特点使得指针操作符特别适合处理存储在一段连续内存空间中的同类型数据。这样,使用指针操作符来对数组及其元素进行操作就非常方便。(1)一维数组的指针操作 当定义数组一维数组T aN(T为类型),下式为存取数组元素ai的等效方式:*(a+i);而a+i为ai的地址。,数组指针 数组指针是指向数组
9、的指针。例如:int(*a_p)5;等效于下列定义方式:typedef int I_A5;I_A*a_p;,数组与函数,数组名是一个地址,不能当作一个左值,但是可以作为函数的形参,接受实参传送来的地址。,当形参接受实参传送来的地址后,形参数组与实参共享内存中的一块空间。函数体通过形参对数组内容的改变会直接作用到实参上。,举例,void func(int a,int n)int i;for(i=0;in;i+)ai+=3;void main()int a=1,2,3,4,i;func(a,4);for(i=0;i4;i+)coutai:;coutendl;,请思考,func的函数原型可以为如下形
10、式吗:void func(int b,int n);void func(int a10,int n);void func(int*a,int n);,指向函数的指针,在程序运行时,数据和代码都占据一定的内存空间。每一个函数都有函数名,函数名就是该函数的代码在内存的起始地址。,函数的调用形式:函数名(参数表),其实质就是:函数代码首地址(参数表)。,函数指针就是指向某个函数的指针,是专门用于存放该函数代码首地址的指针变量。,函数指针的定义语法形式如下:,数据类型(*函数指针名)(形参表);,其中:数据类型为函数指针所指函数的返回值类型;形参表则列出了该指针所指函数的形参类型和个数。,函数指针名与
11、*外面的圆括号()是必须的,如果去掉圆括号,将被解释为函数的返回值为指针。,函数指针的定义,函数指针在使用之前也要进行赋值,使指针指向一个已经存在的函数代码的起始地址。语法形式为:函数指针名=函数名;,函数指针的初始化,例如:int add(int a,int b);/定义函数 int(*fptr)(int a,int b);/定义函数指针 fptr=add;/函数指针赋值,例如:add(1,2);(*fptr)(1,2);fptr(1,2);,函数指针的使用,调用函数指针指向的函数有如下两种格式:(*函数指针名)(实参表);函数指针名(实参表);,说明:当用指向函数的指针调用函数add()时
12、,习惯上使用(*fptr)(1,2),因为这种形式能更直观地说明是用指向函数的指针来调用函数。,二重和多重指针,如果已经定义了一个指针变量A,再定义一个指针B,用于指向A,那么称B是指向指针A的指针,这样的指针也称二重指针。,三重及以上的指针统称为多重指针。,例如:int a,*p,*pp,*ppp;p=,2023/5/27,31,动态内存分配和释放,C的做法void*malloc(size_t size);voidfree(void*pMemory);,注意:这里是以字节计算的单元数目,例如:char*p=(char*)malloc(100);strcpy(p,”Hello World!”)
13、;printf(“%sn”,p);free(p);,2023/5/27,32,C+的做法,使用new和delete,使用形式:,type*p;p=new type;delete p;,type是一个数据类型名,从堆空间中分配一块与type类型的数据一样大小的内存,用delete来释放该内存空间,2023/5/27,33,例如:动态分配和释放单个数据的存储区,#include void main()int*p;p=new int;if(p=NULL)cout“Allocation failure!n”;else*p=15;cout*p;delete p;,2023/5/27,34,用new运算符
14、初始化单个数据的存储区,语法形式为:type*p;P=new type(初始值);delete p;,初始值可以是常量、变量、以及表达式,2023/5/27,35,举例,#include void main()int*p;p=new int(100);if(p=NULL)cout“Allocation failure!n”;elsecout*p;delete p;,提问:如果p=new int(98.5),会怎么样?,2023/5/27,36,注意:用delete释放的内存空间必须是由new分配的空间,否则执行delete时将会导致严重的错误。,例如:int*p;delete p;/出错,例如
15、:int*p,value;p=delete p;/出错,2023/5/27,37,动态分配一维数组的存储空间,语法为:,type*p;p=new typenum;delete p;,num用于指定数组大小,可以是常量、变量、以及表达式,如果分配成果,new返回的指针指向数组的起始位置,2023/5/27,38,例如:#include void main()int i,*p;p=new int100;if(p=NULL)cout“Allocation failure!n”;elsefor(i=0;i 100;i+)pi=i+1;for(i=0;i 100;i+)coutpi;delete p;,
16、2023/5/27,39,引用,简单地说,引用就是给一个单元起一个别名。也就是说,引用与它所引用的变量共享存储单元。,引用主要有以下三种用法:独立引用作为函数参数作为函数返回类型,2023/5/27,40,独立引用,int i=0,k=8;int,ri是i的引用,i和ri代表同一个内存单元。,在声明独立引用时必须对它初始化,这种情况下的别名绑定是永久的。,2023/5/27,41,初始化独立引用的几种方式,“=”的右端是一个变量int a;int,“=”的右端是一个常量const float,定义常引用int x=1;const int/错误,只能使用rx,不能修改,2023/5/27,42,
17、引用作为函数参数,C+和C一样,都是采用“传值”的方式向函数传递参数,从而使实际参数和形式参数相结合的。在这种情况下,实参和形参是两个不同的单元,在结合时,实参的值将会被拷贝到形参中。,2023/5/27,43,C+函数的传值调用,void func(int num)num+;void main()int value=5;func(value);cout value;,由于“传值”方式的存在,因此试图通过改变形参来改变实参的努力是不会成功的。,/输出:5,2023/5/27,44,通过传地址来改变实参,为了解决上述问题,在C语言中,可以通过传递指针的方式来完成。我们可以通过形参指针间接地改变实
18、参。,2023/5/27,45,C语言的传指针调用,void func(int*pnum)(*pnum)+;void main()int value=5;func(,此时实参与形参的传递为:int*pnum=,/输出:6,2023/5/27,46,C+传递引用的方式,C+采用了比传递指针更好的方式:传递引用。在这种情况下,形参的名字将被看作是实参的别名,即形参就是实参本身。此时对形参的改变也就直接改变了实参。,2023/5/27,47,C+语言的引用调用,void func(int,此时实参与形参的传递为:int,/输出:6,2023/5/27,48,引用作为函数的返回,函数返回引用,实际上返回的是一个存储单元(变量),即“左值”。,如果一个函数返回引用,那么函数调用可以出现在赋值号的左边。这种情况在C语言里是见不到的。,2023/5/27,49,举例,int,/输出:50 88,值得注意的是,因为返回的引用是一个存储单元,所以函数返回后这个单元的生命期应该不会结束,否则返回值将没有意义。,