第六章 复合数据类型.docx

上传人:b****5 文档编号:26420381 上传时间:2023-06-19 格式:DOCX 页数:22 大小:28.94KB
下载 相关 举报
第六章 复合数据类型.docx_第1页
第1页 / 共22页
第六章 复合数据类型.docx_第2页
第2页 / 共22页
第六章 复合数据类型.docx_第3页
第3页 / 共22页
第六章 复合数据类型.docx_第4页
第4页 / 共22页
第六章 复合数据类型.docx_第5页
第5页 / 共22页
点击查看更多>>
下载资源
资源描述

第六章 复合数据类型.docx

《第六章 复合数据类型.docx》由会员分享,可在线阅读,更多相关《第六章 复合数据类型.docx(22页珍藏版)》请在冰豆网上搜索。

第六章 复合数据类型.docx

第六章复合数据类型

第六章复合数据类型

6.1变量和赋值的进一步讨论

一个变量是由四个要素组成的:

一个名字、一个属性、一个关联和一个值。

名字指命名变量的标识符;属性指变量可以存放那种类型的值;关联指存放变量的内存位置;值指该内存位置当前时刻存放的数据。

应该认识到这里的值是可能改变的,但任何时候在盒子里总有一个值(我们将无定义的随机值也当做一个特殊的值)。

根据变量在赋值运算中的使用方式,将变量的关联部分称为左值,变量的值部分称为右值。

对于表达式而言,求值结果也存在是否可作为左值使用的问题。

一般情况下,表达式的求值结果作为右值使用,但如果一个表达式的求职结果不是void类型,并且指派了一个变量,则该表达式可作为左值。

((i<0)?

i:

j)=1.//合法的赋值运算

(i+j)=1//不合法的赋值运算

6.2指针类型

变量以两种方式被使用:

作为一个关联的名字和作为一个值的名字。

对变量的访问也有两种方式:

直接访问和间接访问。

在C++中实现对变量的间接访问的方法是:

先安排相关变量,专门用于存放变量地址。

要间接访问时,先从这些变量获得待访问的变量的地址,然后再按所获得的地址去访问要访问的变量。

指针是存放其他变量地址的变量,所以从效果上看它们指向这些数据。

指针使得数据不一定非得与某一特定变量名字相关联,指针可以指向一个没有名字的数据值。

6.2.1指针的声明

intage=30;//声明一个存放年龄的整数类型变量

让C++编译程序知道有一个新的变量,该变量的名字是标识符age,编译程序会为它分配2个字节的存储空间(假如我们使用的机器上int用两个字节表示)并将30放在这些字节中,并且编译程序知道这些字节中存放的是整数类型数值而不是浮点类型或其他类型数据。

不直接访问age的存储空间地址,而是用age这个名字访问器其存储空间。

ptr常用作pointer的缩写

指针类型是在其他数据类型后加一个类型修饰符“*”,这个类型被称为指针的基类型。

int*age_ptr;

注意“*”仅用于修饰类型,而不是变量名字的一部分。

一个指针变量占用的存储空间大小取决于机器的内存寻址方式。

指针age_ptr的类型(int*)指明age_ptr仅能指向整数类型的值,而不能指向字符类型、浮点类型或其他类型的值,即age_ptr中存放的地址所指向的存储空间中只可存放整数类型的值。

将“*”与类型名写在一起表明int*是一种复合类型,但要注意

Int*p,q;

声明的却是一个整数类型的指针变量p和一个整数类型变量q

如果把“*”和指针变量写在一起,则可以连续声明几个指针变量。

例如:

int*p,*q,*k;

注意(int*)并不能作为一个类型来使用,例如(int*)ptr;并不是一个声明,编译程序会将它理解为类型转换。

6.2.2指针的引用

“&”运算符放在操作数前面,操作数必须是一个变量名,表示取出操作数的存储空间地址;”*”运算符也放在操作数前面,操作数必须是一个指针变量,表示取出指针所指向存储空间中保持的值。

在一个指针变量前面加上“*”有两种情况:

一是声明一个指针变量,此时作为类型修饰符;二是访问指针变量所指向的变量的值,此时作为一元运算符。

空指针是值为0x00的指针变量,许多编译程序提供的函数库中定义了一个空指针名字NULL,其作用相当于0x00,赋值语句:

ptr=NULL;相当于ptr=0;

int*ptr;

声明指着ptr时没有初始化它,所以ptr中存放的值是不确定的,它随机地指向某一内存区域(这个区域的内容可能很关键)。

如果为初始化ptr就使用它:

*ptr=250;

那么存放250的两个字节将可能会写入内存中的关键区域。

C++语言在编译与运行时都不报告这种错误,这种错误在程序开发后期才能被发现,并且这种错误的出现具有随机性,因而错误的定位与修改变得十分困难。

6.2.3指针的运算

指针变量的算术运算只能做加、减运算。

必须注意指针的算术运算与指针的基类型是密切相关的。

例如指针age_ptr的当前值为350606,经过如下运算:

age_ptr=age_ptr+1;

age_ptr的当前值不是350607,而是350608。

因为指针age_ptr的基类型是int,所以指针age_ptr每次加1就指向下一个整数,所以他存放的地址值是加2而不是加1。

6.2.4按引用调用的参数传递方式

引用类型是在其他数据类型后加上一个类型修饰符“&”,该数据类型被称为引用的基类型,例如int&是基类型为int的引用类型。

注意“&”在C++语言中既可作为类型修饰符,也可作为一元运算符(取操作数的地址)或二元运算符(两个操作数进行位与运算)

引用类型的变量并不真正创建一个新的对象,而是作为另一个对象的别名。

inti=1;//真正创建了一个整数类型的对象并初始化为1

int&ir=1;//引用类型的变量必须初始化,指明ir是i的别名

引入ir作为i的别名后,对ir的运算就相当于作用在变量i上。

ir=8;//相当于将8赋值给i

cout<<&ir;//相当于输出i的地址

C++语言引入引用类型的主要作用是提供按引用调用的参数传递方式。

将函数的返回值类型定义为引用类型时,函数调用表达式可作为左值使用。

按值调用按引用调用

由于按引用调用不需要复制实际参数的一个副本,因而按引用调用的效率要高于按值调用,特别是当参数时比较大的复合数据类型时。

有时候为了效率而使用按引用调用的参数传递方式,即使并不需要修改这些实际参数的值。

为确保函数无副作用,可以使用保留字const修饰这个形式参数。

6.3数组类型

在数学上,常用一个向量表示一些相关数据组成的序列。

在程序设计中,用数组来表示,数组是数据项的有序列表,这些数据项称为数组的元素。

程序中数组有以下特点:

(1)数组中的每一个元素均属于同一类型,这种类型称为数组的基类型;

(2)每个数组中的元素个数一经确定后就保持不变,称为数组的长度;

(3)数组中的每一个元素均能直接访问,用数组下标来标识数组的元素;

(4)数组中的元素还允许是数组类型,从而产生二维数组、多维数组等结构。

6.3.1一维数组的声明

一维数组是相对多维数组而言,指数组中的元素不再是数组类型。

一维数组只需要一个参数就可以确定数组内的一个数组元素。

一维数组的声明方式为:

类型数组名[常量表达式];

常量表达式可出现常量或符号常量,但不允许有变量,因为C++语言不允许动态确定数组的长度,如:

intN;

cin>>N;

intscores[N];//出错,因为N是变量

一个数组的所有元素在存储空间中是连续存放的,两个相邻的数组元素之间没有空隙。

编译程序将根据数组的长度以及数组的基类型为数组分配相应大小的存储空间。

编译程序为数组分配的存储空间地址是不确定。

数组的大小可以用sizeof()运算符取得,如果sizeof()的操作数是一个数组变量,它将返回整个数组占用的存储空间字节数。

6.3.2一维数组元素的引用与初始化

程序中使用数组时,通常引用的是数组中的一个个元素,而不是整个数组变量,如在屏幕上输出数组scores中的内容,不能用

Cout<

而必须将数组中的元素逐个地输出到屏幕。

6.3.3数组作为函数的参数

要想将数组传递给函数,函数形式参数中的数组必须给出数组的基类型以及左右方括号“[]”,这样编译程序才能理解这个参数是一个数组类型的变量,而不是其他数据类型。

由于在数组声明时已确定了这个名字的数组长度,所以在形式参数中没有必要再次给出数组的大小。

C++语言也允许在方括号中写上数组的长度,但在方括号中写任何数字或没有数字都可以正常工作,这些数字仅起一个注释作用。

在C++语言中,编译程序对数组进行处理时,自动将数组名转化为指向这个数组首元素的指针(数组首元素的地址)。

所以,在函数调用时,只须给出数组的名字作为实际参数。

所有数组都是按引用被自动传递过去(实际上是它们起始地址的一个副本),因此如果给一个函数传递一个数组作为实际参数,并且在这个函数中改变了数组元素的值,那么,函数调用返回时这些改变仍然保持着。

按值调用的参数传递方式的最大好处是函数调用没有副作用,因为被调用函数的执行结果不影响调用程序中的数据。

但数组作为函数参数时是按引用调用的,如果不想再函数体中改变数组元素的值,如何保证函数调用没有副作用呢?

可以在函数原型中数组参数前加上const修饰符,以显式指明调用该函数对数组是没有副作用的,即数组中的任何元素对不能再改函数体中改变。

6.3.4一维数据应用举例

冒泡排序法:

将相邻的两个数据做比较,把较小的数据交换到前面

6.3.5二维数组的声明

如果一个数组的基类型是一维数组,则称这种类型为二维数组。

二维数组需要两个参数方可确定数组内的一个数组元素。

声明二维数组的一般形式为:

类型数组名[常量表达式][常量表达式];

intscores[50,3];//语法错误“50,3”是逗号表达式,相当于intscores[3];

为二维数组分配存储空间可以有以行为主和以列为主两种。

以行为主(以行优先)是一行一行地存,各行按列次序连续存储,一行存完后再存下一行。

以列为主(以列优先)是一列一列地存,各列按行次序连续存储,一列存完后再存下一列。

在C++中,一律采用”以行为主”的存储形式。

6.3.6二维数组元素的引用与初始化

intmatrix[3][4]={{1,2,3,4},{1,3,5,7},{2,4,6,8}};

intmatrix[3][4]={1,2,3,4,1,3,5,7,2,4,6,8};

intmatrix[3][4]={{1,2},{2,3,5}};

与一维数组相似,在C++语言中,编译程序对二维数组进行处理时,自动将数组名转化为指向这个数组首元素的指针(数组首元素的地址)

6.3.7二维数组应用举例

符号常量的值是不可修改的,所以使用全局符号常量并无什么副作用。

一维数据作为参数时,可以不给出数组的大小;但二维数组作为形式参数则必须给出数组的大小(或只给出第二维的长度)

6.3.8指针与数组

指针类型变量可以当做数组使用,数组类型变量也可当做指针使用。

C++语言的数组名字只是一个指针而已。

虽然数组名字也是一种指针类型,但它是一种常量指针类型,其值是不可改变的。

C++语言允许以指针形式访问数组元素正是需要利用指针是变量这一特点来弥补数组名字作为常量指针的不足,以提高处理数据(特别是一组连续数据)的能力和简化对数据的操作方式。

6.3.9指针数组与数组指针

指针数组是指基类型为指针类型的一个数组,而数组指针是指基类型为数组类型的一个指针。

如果需要保留许多指针的值,可以使用指针数组。

如:

int*ptr_array[10];

[]的优先级高于*,所以ptr_arrary先于[10结合,组成长度为10的数组形式,然后才决定这个数组中的每一个元素师指针类型(int*).。

如果写成int(*array_ptr)[10];

那么声明的将是一个指针类型的变量array_ptr,它指向一个长度为10的整数类型数组。

6.4字符串

字符串实际上是基类型为字符的一个特殊数组,它与普通字符数组的区别在于字符串最后有一个0值字节表示串结束。

6.4.1字符串常量与变量

字符串”A”与字符’A’的区别,编译程序为字符’A’只分配一个字节的存储空间,而为字符串”A”分配两个字节,其中一个字节存放A的ASCII编码,第二个字节存放串结束标志”\0”。

C++语言在处理字符串时,全靠这个结束标志才知道字符串的终止位置,因为括住字符串的双引号并没有存储起来,不能用它们为字符串确定边界。

字符串的长度是指字符串中所有字符的总和,包括其中的空格以及其他转义字符在内,尽管转义字符在字符串中占了几个位置,但只当做一个字符计算长度。

一个字符串常量占用的存储空间是其长度加1个字节,因为最后还要存储一个串结束标志。

字符串变量是一个基类型为字符类型的数组变量,同样遵循“先声明、后使用“的原则。

字符串定义的一般形式为:

Char数组名[元素个数];

在声明字符串常量时,可以字符串常量进行初始化,如:

charname[30]=”ZhongshanUniversity”;

这时编译程序会为字符串变量name分配30个字节的存储空间,并将”ZhongshanUniversity”中20个字符的ASCII码存储在前20个字节中,然后在第21个字节中放一个”\0”表示串结束,至于第22个至第30个字节是什么内容是不关心的。

字符串变量占用的存储空间大小与其中存放的字符串的长度之间没有相等关系,尽管name中存放的字符串长度为20,实际使用了21个字节,但它仍然占用着30个字节存储空间。

鉴于上述存储空间组织方式,在初始化字符串变量时一定要注意字符串长度不要超过其存储空间大小,如:

charname[20]=”ZhongshanUniversity”;

可能会引起严重问题,因为字符串的结束标志”\0”超出了为它分配的存储空间变价,可能破坏了其他数据。

C++语言为避免上述字符串越界错误,也帮助程序员提供了一条捷径,即不必声明字符数组的长度,由编译程序根据初始化的字符串常量的长度自动决定。

如:

charname[]=“ZhongshanUniversity”;

对于这个声明,编译程序会根据字符串常量的长度为name分配21个字节,相当于

charname[]=“ZhongshanUniversity”;

由于字符串是一个字符类型的数组,所以既可以用数组下标方式访问字符串中的各个字符,也可用指针方式访问。

逐个访问字符串中的字符时,一般使用循环语句for或while并且以判断字符是否为’\0’作为循环结束条件。

6.4.2字符串数组

constintmax_subjects=24;

char*subjects[max_subjects];

6.4.3关于字符串操作的库函数

与其他类型的数组一样,只可在声明字符串变量时用赋值运算作初始化,在其他地方不允许直接使用赋值运算,如:

charname[30];

name=“ZhongshanUniversity”;//语法错误

因为name实际上是一个常量指针,不可用赋值语句改变其值,即name不允许作为一个”左值”。

可以每次使用循环语句逐个字符赋值一个字符串,或比较两个字符串的每一个字符是否相等,但这一类常用操作已由C++系统提供,只要使用以下语句即可完成字符串的复制:

strcpy(name,”ZhongshanUniversity”);

这些常用函数组织成标准库的形式供程序员重用,该标准库的名字为string。

#include

(1)unsignedintstrlen(constchar*str);

返回字符串str中字符个数,包括其中的空格与转义字符,但不包括结束标记’\0’

(2)char*strcpy(char*str1,constchar*str2);

将str2指向的字符串复制到str1指向的位置并返回str1。

注意为str1分配的存储空间必须能放下str2指向的字符串。

以下是初学者常犯的错误:

char*str;

strcpy(str,”Becareful”);//可能引起严重的问题

因为str所指向的存储空间地址是不确定的,我们还没有让这个指针指向一块已分配到的存储空间。

char*str;

str=“Becareful.”;

因为字符串常量已经分配了存储空间,赋值后指针str指向这一空间。

charstr[20];

strcpy(str,”Becareful”);

因为str已经静态地分配了20个字节的空间,所以可以将字符串常量复制到这一存储空间。

注意为str静态或动态申请的存储空间大小不可小于12个字节,否则会出现越界写入错误。

(3)char*strcat(char*str1,constchar*str2);

将字符串str2连接到字符串str1后,形成一个新字符串,原先str1的结束标记’\0’被取消。

函数返回值为str1。

注意为字符串常量str1分配的存储空间一定要足够大,能够容纳两个字符串连接后的新字符串。

(4)intstrcmp(constchar*str1,constchar*str2);

比较两个字符串str1和str2的内容是否相同(按字典排序方法)。

如果str1小于str2则返回负数,str1等于str2则返回零,str1大于str2则返回整数。

(5)char*strchr(constchar*str,intch);

寻找字符串str中第一出现字符ch的位置。

如果找到ch,则返回指向该位置的指针,否则返回空指针。

(6)char*strstr(constchar*str1,constchar*str2);

寻找字符串str2在字符串str1中第一次出现的位置,不包括str2的结束标记’\0’。

如果找到str2,则返回指向该位置的指针;否则返回空指针。

6.4.4字符串与指针数组应用的例子(主函数带参数)

程序员写出源程序之后,要利用编译程序吧源程序转换为机器语言程序,再利用连接程序把编译所得的机器语言程序组织处理成为可装入内存并执行的可执行机器语言程序(或称可执行文件),最后才能执行这个程序。

得到了可执行目标程序之后,在操作系统环境下,直接输入可执行文件名便可以执行这个程序,不必每次都从源程序编译、连接后才去执行。

主函数带参数

stdlib.h

(1)把指针s所指向的数字字符串转换为整数(int):

intatoi(constchar*s);

(2)把指针s所指向的数字字符串转换为实数(double):

Doubleatof(constchar*s);

(3)把指针s所指向的数字字符串转换为长整数(long):

longatoll(constchar*s);

主函数带参数主要有以下两种方式:

intmain(intargc,char*argv[]);

intmain(intargc,char*argv[],char*env[]);

其中argc是一个整数,表示传给主函数的命令行参数个数,其实际值是实际参数个数加1(把命令本身也当做一个参数);

argv是一个指针数组,argv[0]指向命令(包括路径);argv[1]指向执行程序名后的第一个参数,argv[2]为执行程序名后的第二个参数,……,依此类推。

env也是一个指针函数,env[]的每一个元素将指示相关的环境值(作为一般用户实际没有必要去详细了解它)。

6.5指向对象的指针

对象一经声明就为对象的成员分配踩踩空间,并调用其构造函数进行初始化,对象生存期结束时自动调用其析构函数,并释放对象占用的存储空间。

一种较好的解决途径是先声明这些对象,但并不立即分配存储空间和调用构造函数,在需要这些对象时才这样做,使用完这些对象后立即调用其西沟函数并释放其占用的存储空间,而不是留待对象生存期接受才有C++系统自动回收存储空间。

这一途径是使用C++语言指向对象的指针。

由于使用对象指针比直接使用对象更加灵活、方便,所以应尽量使用对象指针代替对象。

特别是作为函数参数或返回值时,使用对象指针比使用对像本身具有更清晰的语义。

6.5.1对象指针

如果声明的一个指针的基类型是一个类类型,那么这个指针称为对象指针,它指向一个对象。

如:

CIRCULAR_NUMBERS*angle_ptr;

注意这时C++仅仅为这个指针分配了存放指针值的存储空间,并没有分配存放一个属于CIRCULAR_NUMBERS类型的对象空间。

用运算符“->”访问这个对象的公有数据成员或成员函数。

如:

angle_ptr->increment();

相当于:

angle.increment();

在C++语言一个类的成员函数体中,都隐含提供了一个对象指针,这个对象指针用保留字this命名,它指向该成员函数正在操作的对象。

保留字this不常用,只是在需要返回当前对象或指向当前对象的指针时才用到this.

6.5.2对象的动态创建与撤销

C++语言使用new和delete运算符完成对象的动态创建与撤销。

运算符new的一般形式为:

指针=new类型名(初始化表);

其中,初始化表及其括号是可选内容,类型既可以是基本数据类型,也可以是类类型。

如果是类类型,则初始化表相当于将实际参数传递给该类的构造函数。

例如:

int*int_ptr;

int_ptr=newint;

又如:

char*string;

string=newchar[40];char*string=newchar[40]l

注意这里使用方括号与静态声明一个数组时使用方括号的区别:

声明数组时方括号内只允许出现常量表达式,而new则允许在表达式在使用变量。

分配了存储空间后才能使用strcpy()函数,如:

strcpy(string,”ZhongshanUniversity”);

以上动态分配的string与以下静态分配的string2:

charstring2[40];

均占用40个字节的存储空间,都可以使用strcpy函数从另一个字符串复制过来。

但string是一个指针变量,而string2是一个常量指针,它不能指向其他的字符串,例如:

string=string2;

是合法的,而

string2=string;//错误

则是不合法的。

对于类类型也可以用new分配存储空间,如:

CIRCULAR_NUMBERS*angle_ptr;

angle_ptr=newCIRCULAR_NUMBERS(0,359,250);

在类型名字后用圆括号括住构造函数的实际参数,在new操作是angle_ptr所指向对象的构造函数才被调用,并且完成存储空间的分配。

如果我们设计的类没有构造函数,那么new后只需要接着类的名字,圆括号与初始化表均不出现。

由new分配存储空间并不保证每一次都成功。

如果new分配存储空间失败,则返回给指针的值是一个空指针’\0’,即一些标准库中定义的名字NULL。

如果这时不考虑new操作是否成功,继续使用这个指针是很危险的。

由经验的程序员在每次new操作后,都会判断内存分配是否成功,然后再决定下一步的操作,其模式如下:

CIRCULAR_NUMBERS*angle_ptr;

angle_ptr=newCIRCULAR_NUMBERS(0,359,250);

if(angle_ptr==NULL)//内存分配失败后的处理if(ngle_ptr)

{

….

}else{//内存分配成功后的处理

../

}

如果不再需要所分配的存储空间,可以使用delete运算符释放它们。

如:

deleteint_ptr;

deletestring;

第一条语句释放了指针int_ptr占用的存储空间,*int_ptr变得没有意义的了。

第二条语句释放了string所指向的40个字节,string将不再存放字符串内容。

注意用delete释放空间后,指针的值仍是原来指向的地址,而不是空值NULL。

不能通

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 考试认证 > IT认证

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1