《C程序设计谭浩强完整版》由会员分享,可在线阅读,更多相关《C程序设计谭浩强完整版(930页珍藏版)》请在金锄头文库上搜索。
1、C+程序设计程序设计谭浩强编著谭浩强编著清华大学出版社清华大学出版社课件制作:南京理工大学课件制作:南京理工大学陈清华陈清华朱红朱红1第一章第一章C+概述概述C+语言发展历史语言发展历史自从自从1946年第一台电子数字计算机年第一台电子数字计算机ENIAC问世以来,随着计算机应用领域的不断扩大,问世以来,随着计算机应用领域的不断扩大,促进了计算机技术的高速发展,尤其是近年促进了计算机技术的高速发展,尤其是近年来计算机的硬件和软件都是日新月异。作为来计算机的硬件和软件都是日新月异。作为应用计算机的一种工具应用计算机的一种工具程序设计语言,得程序设计语言,得到不断的充实和完善。每年都有新的程序设到
2、不断的充实和完善。每年都有新的程序设计语言问世,老的程序设计语言不断地更新计语言问世,老的程序设计语言不断地更新换代。换代。220世世纪纪60年年代代,MartinRichards为为计计算算机机软软件件人人员员在在开开发发系系统统软软件件时时,作作为为记记述述语语言言使使用用而而开开发发了了BCPL语语言言(BasicCombinedProgrammingLanguage)。1970年年,KenThompson在在继继承承BCPL语语言言的的许许多多优优点点的的基基础础上上发发明明了了实实用用的的B语语言言。到到了了1972年年,贝贝尔尔实实验验室室的的DennisRitchie和和Bria
3、nkernighan在在B语语言言的的基基础础上上,作作了了进进一一步步的的充充实实和和完完善善,设设计计出出了了C语语言言。当当时时,设设计计C语语言言是是为为了了编编写写UNIX操操作作系系统统的的。以以后后,C语语言言经经过过多多次次改改进进,并并开开始始流流行行。C+是是在在C语语言言的的基基础础上上发发展展和和完完善善的的,而而C是是吸收了其它语言的优点逐步成为实用性很强的语言吸收了其它语言的优点逐步成为实用性很强的语言。3C语言的主要特点是:语言的主要特点是:1、C语语言言是是一一种种结结构构化化的的程程序序设设计计语语言言,语语言言本本身身简简洁洁、使使用用灵灵活活方方便便。既既
4、适适用用于于设设计计和和编编写写大大的的系系统统程程序序,又又适适用用于于编编写写小小的的控控制制程程序序,也也适适用科学计算。用科学计算。2、它它既既有有高高级级语语言言的的特特点点,又又具具有有汇汇编编语语言言的的特特点点。运运算算符符丰丰富富,除除了了提提供供对对数数据据的的算算术术逻逻辑辑运运算算外外,还还提提供供了了二二进进制制的的位位运运算算。并并且且也也提提供供了了灵灵活活的的数数据据结结构构。用用C语语言言编编写写的的程程序序表表述述灵灵活活方方便便,功功能能强强大大。用用C语语言言开开发发的的程程序序,其其结结构构性性好好,目目标程序质量高,程序执行效率高。标程序质量高,程序
5、执行效率高。43、程程序序的的可可移移植植性性好好。用用C语语言言在在某某一一种种型型号号的的计计算算机机上上开开发发的的程程序序,基基本本上上可可以以不不作作修修改改,而而直直接接移植到其它型号和不同档次的计算机上运行。移植到其它型号和不同档次的计算机上运行。4、程程序序的的语语法法结结构构不不够够严严密密,程程序序设设计计的的自自由由度度大大。这这对对于于比比较较精精通通C语语言言的的程程序序设设计计者者来来说说,可可以以设设计计出出高高质质量量的的非非常常通通用用的的程程序序。但但对对于于初初学学者者来来说说,要要能能比比较较熟熟练练运运用用C语语言言来来编编写写程程序序,并并不不是是一
6、一件件容容易易的的事事情情。与与其其它它高高级级语语言言相相比比而而言言,调调试试程程序序比比较较困困难难。往往往往是是编编好好程程序序输输入入计计算算机机后后,编编译译时时容容易易通通过过,而而在在执执行行时时还还会会出出错错。但但只只要要对对C语语言言的的语语法法规规则则真真正正领领会会,编编写写程程序序及及调调试试程程序序还是比较容易掌握的。还是比较容易掌握的。5随随着着C语语言言应应用用的的推推广广,C语语言言存存在在的的一一些些缺缺陷陷或或不不足足也也开开始始流流露露出出来来,并并受受到到大大家家的的关关注注。如如:C语语言言对对数数据据类类型型检检查查的的机机制制比比较较弱弱;缺缺
7、少少支支持持代代码码重重用用的的结结构构;随随着着软软件件工工程程规规模模的的扩扩大大,难难以以适适应应开开发发特大型的程度等等。特大型的程度等等。6为为了了克克服服C语语言言本本身身存存在在的的缺缺点点,并并保保持持C语语言言简简洁洁、高高效效,与与汇汇编编语语言言接接近近的的特特点点,1980年年,贝贝尔尔实实验验室室的的BjarneStroustrup博博士士及及其其同同事事对对C语语言言进进行行了了改改进进和和扩扩充充,并并把把Simula67中中类类的的概概念念引引入入到到C中中。并并在在1983年年由由RickMaseitti提提议议正正式式命命名名为为C+(CPlusPlus)。
8、后后来来,又又把把运运算算符符的的重重载载、引引用用、虚虚函函数数等等功功能能加加入入到到C+中中,使使C+的的功能日趋完善。功能日趋完善。当当前前用用得得较较为为广广泛泛的的C+有有:VC+(VisualCPlus Plus)、 BC+(Borland C Plus Plus)、AT&TC+等。等。7简单的简单的C+程序介绍程序介绍高级语言编译过程高级语言编译过程源程序源程序(文本文件)(文本文件)*.CPP目标文件目标文件(二进制文件)(二进制文件)*.OBJ可执行文件可执行文件(二进制文件)(二进制文件)*.EXE库文件库文件(各种函数)(各种函数)在在VitualC+系统中,可直接从源
9、程序编译连接至可执行系统中,可直接从源程序编译连接至可执行程序,但依然要生成程序,但依然要生成*.OBJ及及*.EXE这两个文件。这两个文件。F7编译编译连接连接compilelink8一个简单的一个简单的C+程序程序#includevoidmain(void)cout“Iamastudent.n”;/输出字符串输出字符串主函数主函数函数体函数体开始开始函数体函数体结束结束输出流,在屏幕上打输出流,在屏幕上打印引号内的字符串印引号内的字符串分号,一条完整分号,一条完整语句的结束符语句的结束符本程序编译执行后,在本程序编译执行后,在DOS屏幕上打印出屏幕上打印出Iamastudent.包含文件包
10、含文件注释或说明注释或说明9编译过程:编译过程:1)启动)启动VisualC+,选择选择“文件文件”菜单中的菜单中的“新建新建”命令,选择命令,选择“文件文件”标签中的标签中的“C+SourceFile”选项。选项。2)选择源程序存放的目录和输入源程序名,单击)选择源程序存放的目录和输入源程序名,单击“确定确定”。3)在在编辑器中编写源程序。编辑器中编写源程序。4)单击)单击F7或或“编译编译”中的中的“重建全部重建全部”编译源程编译源程序,若编译通过,单击序,若编译通过,单击“执行执行”,在,在DOS屏上看屏上看结果结果,任按一键返回编辑器。任按一键返回编辑器。10启动启动VC+编译系统编译
11、系统11VC+编译编译系统界面系统界面单击单击“File”菜菜单中单中“New”命命令令12选择选择“Files”选项选项卡卡选择选择C+源源文件命令文件命令输入文件名输入文件名输入文件输入文件存放位置存放位置单击选择单击选择驱动器驱动器选择驱动选择驱动器或目录器或目录13C+源文件源文件编辑界面编辑界面输入输入C+源代码源代码14可以将此源可以将此源代码另起文代码另起文件名存盘件名存盘15选择编译命令,将源文选择编译命令,将源文件件.cpp生成生成.obj文件文件16如果编译出错,会出现提示信息,如果编译出错,会出现提示信息,指出错误的位置及种类指出错误的位置及种类错误所在行错误所在行错误的
12、原因错误的原因17双击错误双击错误所在行所在行光标移到该行光标移到该行18生成可执生成可执行文件行文件通过后单通过后单击该命令击该命令运行程序运行程序19运行结果显示运行结果显示在在DOS屏上屏上注意:不可以在软盘上注意:不可以在软盘上运行程序!应该把保存运行程序!应该把保存在软盘中的源文件拷贝在软盘中的源文件拷贝到硬盘的目录中再运行到硬盘的目录中再运行!20源程序所在目录源程序所在目录未编译前,只未编译前,只有一个源程序有一个源程序21编译运行后,出编译运行后,出现众多附加文件现众多附加文件同时,产生一个同时,产生一个子目录子目录Debug22Debug目录中,有目录中,有obj和和EXE文
13、件文件23#includevoidmain(void)couti;/从键盘上输入变量从键盘上输入变量i的值的值cout“i的的值值为为:”in;/输输出出变变量量i的的值值另一个例子另一个例子24第二章第二章 数据类型、运算符与表达式数据类型、运算符与表达式252000H2001H2002H2003H2004H33+5=?5运算器运算器(2000H)+(2002H)用一个字节表示整数,范围为用一个字节表示整数,范围为-128127;用两个字节表;用两个字节表示整数,范围为示整数,范围为-3276832767。一般用四个字节表示整。一般用四个字节表示整数。数。(举例举例)内存内存CPU内存内存d
14、ata外存外存Program8硬盘硬盘软盘软盘261514 13 12 11 109876543210有符号数有符号数无符号数无符号数0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 132767327670 1 1 1 1 1 1 1 1 1 1 1 1 1 1 032766327660 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1110 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0001 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1-1(补码补码)655351 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0-2655341 0
15、 0 0 0 0 0 0 0 0 0 0 0 0 0 1-32767327691 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-327683276827常量与变量常量与变量常量:在程序运行过程中,其值一直保持不变的量常量:在程序运行过程中,其值一直保持不变的量为常量。为常量。常量也区分不同的类型:常量也区分不同的类型:30,40为整型,为整型,30.0,40.0为实型,为实型,编辑器只是根据其表面形式来判断其编辑器只是根据其表面形式来判断其类型。类型。变量:在程序运行过程中,其值可以改变的量为变量:在程序运行过程中,其值可以改变的量为变量。变量。变量在程序的执行中能够赋值,发生变
16、化变量在程序的执行中能够赋值,发生变化。变量。变量有一个名字,有一个名字,并在使用之前要说明其类型并在使用之前要说明其类型,一经,一经说明,说明,就在内存中占据与其类型相应的存储单元。就在内存中占据与其类型相应的存储单元。28#include#definePRICE30/常量,在程序中保持不变常量,在程序中保持不变voidmain(void)intnum,total;/定义变量定义变量,在内存中开辟区间在内存中开辟区间num=10;/变量赋值变量赋值,10为常量为常量total=num*PRICE;cout“total=“total;/输出结果输出结果其中:其中:num=10total=num
17、*PRICE是赋值号,不同于数学意义上的等号。是赋值号,不同于数学意义上的等号。numtotal10300PRICE3029C+中有多种数据类型,均有常量与变量之分,各中有多种数据类型,均有常量与变量之分,各占不同的内存空间,正确定义与使用数据是编写程占不同的内存空间,正确定义与使用数据是编写程序的基本前提。序的基本前提。30变量名的命名方法:变量名的命名方法:变量名、数组名、函数名变量名、数组名、函数名称为称为标识符标识符。标识符只能由标识符只能由字母、数字、下划线字母、数字、下划线这三种字符组成,且第这三种字符组成,且第一个字符必须为字母或下划线,长度不大于一个字符必须为字母或下划线,长度
18、不大于247个字符,个字符,大小写不通用大小写不通用。(关键字不能作为标识符)。(关键字不能作为标识符)。关键字即是关键字即是VC+的语法要求中使用的字的语法要求中使用的字。如如intifwhile等。等。正确的标识符:正确的标识符:INT,sum,de12,SUM等。等。变量必须使变量必须使用前定义,以分配空间。用前定义,以分配空间。举例说明举例说明31abcEnglish 2xy x-y if Else b(3) def Chine_bbb3yAbsFloatfloat一般变量都是用匈牙利命名法命名的。一般变量都是用匈牙利命名法命名的。intnCount;charchChoice;32整型
19、数据整型数据整型常量:整型常量:常量是根据其表面形式来判定,整型量即是没有小数点的常量是根据其表面形式来判定,整型量即是没有小数点的整数,范围:整数,范围:-231(231-1),有三种形式,有三种形式:1)十进制(默认方式)十进制(默认方式)431345876542)八进制)八进制以以0开头开头043,056,0113)十六进制)十六进制以以0x开头开头0x120xa30x340xdf(举例说明)(举例说明)33#includevoidmain(void)intint10,int8,int16;/定义定义3个整型变量个整型变量int10=10;/默认为十进制默认为十进制int8=010;/八
20、进制八进制int16=0x10;/十六进制十六进制coutint10=int10endl;coutint8=int8endl;coutint16=int16endl;输出输出int10=10int8=8int16=1634整型变量:整型变量:分为有符号型与无符号型。分为有符号型与无符号型。有符号型:有符号型:short在内存中占两个字节,范围为在内存中占两个字节,范围为-215(215-1)int在内存中占四个字节,范围为在内存中占四个字节,范围为-231(231-1)long在内存中占四个字节,范围为在内存中占四个字节,范围为-2-31231-1无符号型:无符号型:最高位不表示符号位最高位不
21、表示符号位unsignedshort在内存中占两个字节,范围为在内存中占两个字节,范围为0216-1unsignedint在内存中占四个字节,范围为在内存中占四个字节,范围为0232-1unsignedlong在内存中占四个字节,范围为在内存中占四个字节,范围为0232-1351)整型常量整型常量亦有长短之分,常量中无亦有长短之分,常量中无unsigned型,但一型,但一个非负的整型常量可以赋给个非负的整型常量可以赋给unsigned型的变量。型的变量。2)若一个常量定义为长整型数,则在其后加)若一个常量定义为长整型数,则在其后加l或或L进行区进行区分。分。如:如:32l32L564L等,内存
22、为其分配四个字节存储。等,内存为其分配四个字节存储。一个数在内存中为一个数在内存中为1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1当这个数为有符号数时,是当这个数为有符号数时,是-1;为无符号数时,是;为无符号数时,是232-1内存中的数是以内存中的数是以补码补码的形式存放的。(举例说明)的形式存放的。(举例说明)1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 136#includevoidmain()unsignedshorta;shortintb=-1;a=b;couta=aendl;结果:结果:65535不同类型的整型数据间不同类型的整型数据间的赋值归根到底就
23、是一的赋值归根到底就是一条:条:按存储单元中的存按存储单元中的存储形式直接传送。储形式直接传送。a1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1b1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1unsignedshorta;37实型数据实型数据实型数又称浮点数,有两种表示方式:实型数又称浮点数,有两种表示方式:1)十进制形式:)十进制形式:23.024.53.567892)指数形式:指数形式:23E1145e-1356789e1e前有数字,后前有数字,后面必须是整数。面必须是整数。实型变量分单精度实型变量分单精度float和双精度和双精度double两种形式:两种
24、形式:float:占四个字节,提供占四个字节,提供78位有效数字。位有效数字。double:占八个字节,提供占八个字节,提供1516位有效数字。位有效数字。举例说明举例说明38#includevoidmain(void)floata,b;doublec,d;a=0.01;b=3.45678e-2;c=3.45678e-2;d=9.7654e-5;couta=atb=bendl;coutc=ctd=dendl;a=0.01b=0.0345678c=0.0345678d=9.7654e-005Pressanykeytocontinue39如果为实数,则用浮点数的形式在内存存储,表示如下:如果为实数
25、,则用浮点数的形式在内存存储,表示如下:JtJSfS阶符阶符阶码阶码数符数符尾数尾数实数是既有整数又有小数的数。实数是既有整数又有小数的数。实数可以表示成:实数可以表示成:N=SRJS称为尾数,尾数决定有效数字,即数字的精度。称为尾数,尾数决定有效数字,即数字的精度。J表示指数(阶码)。表示指数(阶码)。R是基数,可取是基数,可取2,4,8,16等,对具体机器而言,基数等,对具体机器而言,基数取好后,就不能再变了。取好后,就不能再变了。数有正有负数有正有负,所以设置数符所以设置数符;阶码亦有正负阶码亦有正负,所以设置阶所以设置阶符符40一般用一般用4个字节表示一个浮点数,也有用个字节表示一个浮
26、点数,也有用8个字个字节表示的。节表示的。字长一定,尾数越多,精度越高;阶码越多,字长一定,尾数越多,精度越高;阶码越多,范围越大。范围越大。当计算机中出现小于机器所能表示的最小数当计算机中出现小于机器所能表示的最小数时,机器只能当零来处理时,机器只能当零来处理,当出现超过机器所能当出现超过机器所能表示的最大数时,出现溢出现象表示的最大数时,出现溢出现象,一旦出现溢出,一旦出现溢出,就会停止运算。就会停止运算。定点数,浮点数均会出现溢出现定点数,浮点数均会出现溢出现象。象。41字符型数据(字符型数据(char)字符型数据实际上是作为字符型数据实际上是作为整型数据整型数据在内存中存储的。在内存中
27、存储的。计算机是以字符编码的形式处理字符的,因此,我们在计算机内部计算机是以字符编码的形式处理字符的,因此,我们在计算机内部是以是以ASCII码码的形式表示所有字符的。所以的形式表示所有字符的。所以7位二进制数即可表示出位二进制数即可表示出一个字符,一个字符,我们用一个字节的容量(我们用一个字节的容量(8位)存储一个字符。位)存储一个字符。例如:字符例如:字符A的的ASCII码为码为0x41或或65,在内存中表示为:,在内存中表示为:01000001在程序中表示为:在程序中表示为:chargrade;/定义一个字符型的变量空间定义一个字符型的变量空间(1个字节个字节)grade=A;/必须用必
28、须用表示,否则易与标识符混同表示,否则易与标识符混同内括起来的字符表示该字符的内括起来的字符表示该字符的ASCII码。码。42进一步,由于在内存中的形式与整型数据相同,所以,进一步,由于在内存中的形式与整型数据相同,所以,可以直接用可以直接用其整型值给变量赋值。其整型值给变量赋值。chargrade;grade=65;以下的赋值形式均是等同的。以下的赋值形式均是等同的。grade=A;grade=65;grade=0x41;grade=0101;#includevoidmain(void)chara,b;a=A;/输入输入ASCII码码b=65;/输入十进制数输入十进制数couta=aendl
29、;coutb=bendl;输出:输出:a=Ab=A即在内存中的表示均是相同的即在内存中的表示均是相同的0100000143非打印字符非打印字符有些有些ASCII的字符代表某些操作,不能打印出来,的字符代表某些操作,不能打印出来,如回车、退格等,可用两种方式表示这些字符。如回车、退格等,可用两种方式表示这些字符。1)用)用ASCII码的形式码的形式charre=13;2)用转义字符)用转义字符charre=n;(p15)44转义字符转义字符含含义义ASCII代码代码a响铃响铃7换行,将当前位置移到下一行开头换行,将当前位置移到下一行开头10水平制表(跳到下一个水平制表(跳到下一个tab位置)位置
30、)9退格,将当前位置移到前一列退格,将当前位置移到前一列8回车,将当前位置移到本行开头回车,将当前位置移到本行开头13换页,将当前位置移到下页开头换页,将当前位置移到下页开头12v竖向跳格竖向跳格8反斜杠字符反斜杠字符“”92单引号(撇号)字符单引号(撇号)字符39双引号字符双引号字符340空字符空字符0ddd1到到3位位8进制数所代表的字符进制数所代表的字符xhh1到到2位位16进制数所代表的字符进制数所代表的字符45转义字符虽然包含转义字符虽然包含2个或多个字符,但它只代个或多个字符,但它只代表一个字符。表一个字符。编译系统在见到字符编译系统在见到字符“”时,时,会接着找它后面的字符,把它
31、处理成一个字会接着找它后面的字符,把它处理成一个字符,在内存中只占一个字节。符,在内存中只占一个字节。46典型转义字符典型转义字符:n换行换行b退格退格t下一下一个输出区个输出区若输出中包含这些特定格式,则再加一个若输出中包含这些特定格式,则再加一个输出输出c:tctc表示为表示为coutc:tctc;可以用转义字符表示任一一个可以用转义字符表示任一一个ASCII字符字符ddd(八进制)八进制)xhh(十六进制)(十六进制)101x41x6114147#includevoidmain(void)charc1,c2,c3,c4;charn1,n2;c1=a;/字符常量字符常量c2=97;/十进制
32、十进制c3=x61;/转义字符转义字符c4=0141;/八进制八进制coutc1=c1tc2=c2endl;coutc3=c3tc4=c4endl;n1=n;/转义字符:回车转义字符:回车n2=t;/转义字符:下一个输出区转义字符:下一个输出区(Tab)cout使用转义字符使用转义字符n;coutc1=c1n2c2=c2n1;coutc3=c3n2c4=c4n1;输出:输出:c1=ac2=ac3=ac4=a使用转义字符使用转义字符c1=ac2=ac3=ac4=a48字符串常量:字符串常量:用用表示,表示,在内存中顺序存放,以在内存中顺序存放,以0结束。结束。如:如:CHINA0x430x480
33、x490x550x410a在内存中占一个字节在内存中占一个字节a占两个字节占两个字节aa0实际上实际上内存是对应字符的内存是对应字符的ASCII码形式码形式010000110100100001001001010101010100000100000000CHINA001100001011000010000000049标识符常量标识符常量在在C+中中有有二二种种方方法法定定义义标标识识符符常常量量,一一种种是是使使用用编编译译预预处理指令;另一种是使用处理指令;另一种是使用C+的常量说明符的常量说明符const。例如:例如:#definePRICE30/在程序中凡是出现在程序中凡是出现PRICE均
34、用均用30替代替代#definePI3.1415926#defineS“China”constfloatpi=3.1415926;/将将变量变量pi定义为定义为常量常量(举例说明)(举例说明)50#include#definePI3.14156#defineSChinavoidmain(void)constfloatpi=3.14156;/变量作为常量使用变量作为常量使用coutPI=PIendl;cout10*PI=10*PIendl;coutSendl;/PI=PI+3;/pi=pi+4;coutPI=PIendl;coutpi=piendl;输出:输出:PI=3.1415610*PI=3
35、1.4156ChinaPI=3.14156pi=3.1415651下下列列常常量量的的表表示示在在C+C+中中是是否否合合法法?若若不不合合法法,指指出出原原因因;若合法,则指出常量的数据类型。若合法,则指出常量的数据类型。3276735u1.25e3.43L0.0086e-3287 “ComputerSystem”“a” a9645-0+0.5-.56752变量变量1)在在程程序序的的执执行行过过程程中中,其其值值可可以以改改变变的的量量称为变量。称为变量。2)变量名必须用标识符来标识。变量名必须用标识符来标识。3)变变量量根根据据其其取取值值的的不不同同值值域域,分分为为不不同同类类型型的
36、的变变量量:整整型型变变量量、实实型型变变量量、字字符符型型变变量、构造型变量、指针型变量等等。量、构造型变量、指针型变量等等。534)对对于于任任一一变变量量,编编译译程程序序要要为为其其分分配配若若干干个个字字节节(连连续续的的)的的内内存存单单元元,以以便便保保存存变变量的取值量的取值。5)当当要要改改变变一一个个变变量量的的值值时时,就就是是把把变变量量的的新新的的取取值值存存放放到到为为该该变变量量所所分分配配的的内内存存单单元元中中;用用到到一一个个变变量量的的值值时时,就就是是从从该该内内存存单单元中取出数据。元中取出数据。6)不不管管什什么么类类型型的的变变量量,通通常常均均是
37、是变变量量的的说说明在前,使用变量在后。明在前,使用变量在后。54inti,j,k;/定义了三个整型变量定义了三个整型变量i,j,kfloatx,y,z;/定义了三个实型变量定义了三个实型变量x,y,zcharc1,c2;/说明了二个字符型变量说明了二个字符型变量c1,c2doubledv1;/说明了一个双精度型变量说明了一个双精度型变量dv1k四个字节的四个字节的连续空间连续空间j四个字节的四个字节的连续空间连续空间i四个字节的四个字节的连续空间连续空间z四个字节的四个字节的连续空间连续空间y四个字节的四个字节的连续空间连续空间x四个字节的四个字节的连续空间连续空间dv1八个字节的八个字节的
38、连续空间连续空间c21个字节的个字节的空间空间c11个字节的个字节的空间空间开辟空间后开辟空间后,空空间中为随机值间中为随机值55变量赋初值变量赋初值在定义变量的在定义变量的同时同时给变量赋值,即在内存中开辟出一个空给变量赋值,即在内存中开辟出一个空间后马上给此空间赋值。间后马上给此空间赋值。但这个空间的值并不是固定不变的,但这个空间的值并不是固定不变的,在程序的运行中一样在程序的运行中一样可以改变。可以改变。chara=x64,b=d;inta1=6,a2=98;a=A;b=n;a1=011;a2=121;inta=4;/定义语句,在开辟空间后马上为空间赋定义语句,在开辟空间后马上为空间赋值
39、值a=6;/重新为该空间赋值重新为该空间赋值a4 656算术运算符和算术表达式算术运算符和算术表达式一、算术运算符和算术表达式一、算术运算符和算术表达式+*%用算术运算符连接起来的式子是算术表达式用算术运算符连接起来的式子是算术表达式两个整数相除结果为整数两个整数相除结果为整数1/2=05/2=2整数才可求余,余数的符号与左边数的符号相同。整数才可求余,余数的符号与左边数的符号相同。3%2=1-3%2=-13%-2=1-3%-2=-18%4=0二、优先级与结合性二、优先级与结合性()()*/%+57三、强制转换类型三、强制转换类型(类型名)(表达式)(类型名)(表达式)(double)a(in
40、t)(x+y)(int)6.2%4=2在强制类型运算后原变量不变,但得到一个所需类在强制类型运算后原变量不变,但得到一个所需类型的中间变量。型的中间变量。如:如:intx;floaty=5.8;x=(int)y;x=5y=5.8y的值没有改的值没有改变,仍是单精变,仍是单精度浮点型度浮点型58四、自增、自减运算符四、自增、自减运算符(难点)难点)+i6i37inti,j;i=3;j=+i;i=4j=4+在前在前,先运算先运算,后赋后赋值值inti,j;i=3;j=i+;i=4j=3+在后在后,先赋值先赋值,后运后运算算j44i3j34i=6;i+;i=i+1i=7+i;i=i+1i=7i=6;
41、i;i=i1i=5i;i=i1i=5i6 7591)自增、自减运算符只能用于变量,不可用于常量和表自增、自减运算符只能用于变量,不可用于常量和表达式达式因为表达式在内存内没有具体空间,常量所占的空间不能因为表达式在内存内没有具体空间,常量所占的空间不能重新赋值重新赋值3+(x+y)+(i)+若若i=3,j=2(i+)+j等于等于5i=4,j=22)结合方式自右至左,优先级最高,向右取最大)结合方式自右至左,优先级最高,向右取最大i+(i+)i+j(i+)+j60赋值运算符和赋值表达式赋值运算符和赋值表达式bmw=2002=左边左边必须是变量名。必须是变量名。若若“=”两边变量类型不同,在赋值时
42、要进两边变量类型不同,在赋值时要进行行类型转换类型转换。转换原则:根据左边变量的类型转换。转换原则:根据左边变量的类型转换。61少字节少字节多字节多字节1)若多字节变量为)若多字节变量为unsigned,则转换后多余字节补则转换后多余字节补零。零。0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 11 1 1 1 1 1 1 1unsignedshortinta=-1;unsignedlongb;b=a;a ab b621 1 1 1 1 1 1 1 1 1 1 1 1 1 1 11 1 1 1 1 1 1 1有符号型,符号扩展有符号型,符号扩展shortinta=-1;longb;
43、b=a;2)若多字节变量为有符号型,则转换后扩展少字)若多字节变量为有符号型,则转换后扩展少字节的最高位。节的最高位。转换后,数据的符号不变。转换后,数据的符号不变。a ab b63多字节多字节少字节少字节低位照搬低位照搬1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1inta=-1;shortintb;b=a;b=-1inta=65535;shortintb;b=a;b=-1b ba a1 1 1 1 1 1 1 164赋值表达式赋值表达式a=b=5;b=5a=5=的结合性为的结合性为自右至左自右至左复合的赋值运算符复合的赋值运算符a+=3a=a+3x*=y+3x=x*(y+3
44、)x/=x-4x=x/(x-4)x+=yx=x+yi+=j-i=i+(j-)65a=12;a+=a-=a*a;12aa=a-(a*a)=12-(12*12)=-132a=a+(-132)=-132-132=-264-132-26466关系运算符和关系表达式关系运算符和关系表达式关系运算符(比较运算)关系运算符(比较运算)=!=1.=与与=2.a=5;赋值运算赋值运算a=5;判断是否相等判断是否相等2.=的优先级大于的优先级大于=!=3.算术运算符的优先级大于关系运算符的优先级算术运算符的优先级大于关系运算符的优先级67关系表达式:用关系运算符将表达式连接起来称为关系表达式:用关系运算符将表达式
45、连接起来称为关系表达式。其值非真即假。在关系表达式。其值非真即假。在C+语言中,用非语言中,用非0代表真,用代表真,用0表示假。表示假。关系表达式的结果只有两个,关系表达式的结果只有两个,真为真为1,假为,假为0。a=2b=3c=4a2ab+ca=2a=aaab=a=2aAb=a+1c-a=a00100110168逻辑运算符逻辑运算符1.运算符运算符与与&或或|非非!AB结果结果000010100111有有0出出0,全,全1出出1A,B同时成立同时成立&AB结果结果000011101111有有1出出1,全,全0出出0A或或B有一个成立有一个成立|A结果结果0 110有有0出出1,有有1出出0!
46、69江苏籍的男生江苏籍的男生江苏籍的学生和所有男生江苏籍的学生和所有男生非江苏籍的学生非江苏籍的学生江苏籍江苏籍&男生男生例如:两个条件:例如:两个条件:江苏籍江苏籍男生男生江苏籍江苏籍|男生男生!江苏籍!江苏籍注意:注意:1.优先级:优先级:!&|!算术算术关系关系逻辑逻辑赋值赋值逗号逗号703.不可写为不可写为1x10应为:应为:1x&x3&2|8=1)&(c=5)10073sizeof()()运算符运算符sizeof()运运算算符符是是一一个个单单目目运运算算符符,用用于于计计算算某某一一个个操作数类型的字节数操作数类型的字节数。其格式为:。其格式为:sizeof()sizeof(int
47、)/其值为其值为4sizeof(float)/其值为其值为4sizeof(double)/其值为其值为8sizeof(char)/其值为其值为174逗号运算符和逗号表达式逗号运算符和逗号表达式表达式表达式1,表达式,表达式2,表达式,表达式3,表达式,表达式n顺序求解,结果为最后一个表达式的值,并且优先顺序求解,结果为最后一个表达式的值,并且优先级最低。级最低。a=(3+4,5*6,2+1);a=3a=3*3,a+6,a+7;16(a=3*5,a*4),a+520a=9a=1575下列语句中表达式中下列语句中表达式中i,j的值各为多少的值各为多少1、inti=0,j=0;2、inti=0,j=
48、1;i=3,(j+)+i;i+=j*=3;3、inti=1,j=0;4、inti=1,j=1;j=i=(i=3)*2);i+=j+=2;i=3,j=1i=3,j=3i=6,j=6i=4,j=376各类数值型数据间的混合运算各类数值型数据间的混合运算整型、实型、字符型数据间可以混合运算。整型、实型、字符型数据间可以混合运算。floatdoublelongunsignedintchar10+a+1.5-87.65*b在进行运算时,在进行运算时,不同类型的数据要先转换成同一类不同类型的数据要先转换成同一类型的数据再进行运算。型的数据再进行运算。转换规则如下:转换规则如下:77第三章第三章 简单的输入
49、输出简单的输入输出78输入语句:输入语句:cin程序在执行期间,程序在执行期间,接收外部信息的操作称为接收外部信息的操作称为程序的输入程序的输入;而把;而把程序向外部发送信息的操程序向外部发送信息的操作称为程序的输出作称为程序的输出。在。在C+中没有专门的输中没有专门的输入输出语句,所有输入输出是通过入输出语句,所有输入输出是通过输入输出输入输出流流来实现的。来实现的。79要要使使用用C+提提供供的的输输入入输输出出时时,必必须须在在程程序序的开头增加一行:的开头增加一行:#include 即即包包含含输输入入输输出出流流的的头头文文件件“iostream.h”。有有关关包包含含文文件件的的作
50、作用用,在在编编译译预预处处理理部部分分(第五章)作详细介绍。(第五章)作详细介绍。80 输入十进制整数和实数cin.(举例说明)(举例说明)inta,b;cinab;/程序运行至此停下,等待从键盘输入变量值程序运行至此停下,等待从键盘输入变量值键盘输入:键盘输入:35或:或:35均可。均可。输入语句自动过滤空白字符。输入语句自动过滤空白字符。a3键盘键盘b5键盘键盘81浮点型数据同整型数据一样。浮点型数据同整型数据一样。floatc,d;cincd;charch1,ch2;cinch1ch2;若输入:若输入:ab则则ch1为为a, ch2为为b。若输入:若输入:ab则则ch1为为a, ch2
51、为为b。字符型变量过滤空白字符。字符型变量过滤空白字符。cin格式过滤空白字符格式过滤空白字符82floata;inti1,i2;charch1,ch2;cini1ai2ch1ch2;输入:输入:345.6781abi2:1在缺省的情况下,在缺省的情况下,cin自动跳过输入的空格自动跳过输入的空格,换言,换言之,之,cin不能将输入的空格赋给字符型变量,同样不能将输入的空格赋给字符型变量,同样地,回车键也是作为输入字符之间的分隔符,地,回车键也是作为输入字符之间的分隔符,也不也不能将输入的回车键字符赋给字符型变量能将输入的回车键字符赋给字符型变量。a:5.578i1:34ch1:ach2:b8
52、3若若要要把把从从键键盘盘上上输输入入的的每每一一个个字字符符,包包括括空空格格和和回回车车键键都都作作为为一一个个输输入入字字符符赋赋给给字字符符型型变变量量时时,必必须须使用函数使用函数cin.get()。其格式为:。其格式为:cin.get();cin.get()从从输输入入行行中中取取出出一一个个字字符符,并并将将它它赋赋给给字字符符型型变变量量。这这个个语语句句一一次次只只能能从从输输入入行行中中提提取取一一个个字符。字符。charc1;cin.get(c1);84charch1,ch2,ch3;cin.get(ch1);cin.get(ch2);cin.get(ch3);输入:输入
53、:AB则:则:ch1:A并且在输入缓冲区中保留回车键。并且在输入缓冲区中保留回车键。ch2:空格空格ch3:B空格的空格的ASCII码为码为3200100000ch2ch285输入十六进制或八进制数据输入十六进制或八进制数据在缺省的情况下,系统约定输入的整型数是十进在缺省的情况下,系统约定输入的整型数是十进制数据。当要求按八进制或十六进制输入数据时,制数据。当要求按八进制或十六进制输入数据时,在在cin中必须指明相应的数据类型:中必须指明相应的数据类型:hex为十六进为十六进制;制;oct为八进制;为八进制;dec为十进制为十进制。86inti,j,k,l;cinhexi;/指明输入为十六进制
54、数指明输入为十六进制数cinoctj;/指明输入为八进制数指明输入为八进制数cink;/输入仍为八进制数输入仍为八进制数cindecl;/指明输入为十进制数指明输入为十进制数当执行到语句当执行到语句cin时,若输入的数据为:时,若输入的数据为:11111212结果:结果:i:17j:9k:10l:1287使用非十进制数输入时,要注意以下几点:使用非十进制数输入时,要注意以下几点:1、八八进进制制或或十十六六进进制制数数的的输输入入,只只能能适适用用于于整整型型变量变量,不适用于字符型变量,实型变量。,不适用于字符型变量,实型变量。2、当当在在cin中中指指明明使使用用的的数数制制输输入入后后,
55、则则所所指指明明的的数数制制一一直直有有效效,直直到到在在接接着着的的cin中中指指明明输输入入时时所所使使用用的的另另一一数数制制为为止止。如如上上例例中中,输输入入k的的值值时时,仍为八进制。仍为八进制。883、输输入入数数据据的的格格式式、个个数数和和类类型型必必须须与与cin中中所所列列举举的的变变量量类类型型一一一一对对应应。一一旦旦输输入入出出错错,不不仅仅使使当当前前的的输输入入数数据据不不正正确确,而而且且使使得得后后面面的的提提取取数数据据也也不正确。不正确。cina,b;cinab;cinab;inta,b;cinab;89输出数据输出数据cout与输入与输入cin对应的输
56、出是对应的输出是cout输出流。输出流。当当要要输输出出一一个个表表达达式式的的值值时时,可可使使用用cout来来实实现现,其一般格式为:其一般格式为:cout.;其中运算符其中运算符“”称为插入运算符,它将紧跟其后称为插入运算符,它将紧跟其后的表达式的值,输出到显示器的表达式的值,输出到显示器当前光标当前光标的位置。的位置。90inta=6;floatf1=12.4;chars1=“abcd”;coutatf1ts1endl;t为转义字符为转义字符Tabendl为回车或为回车或n显示器显示器显示器显示器显示器显示器a6f112.4s10dcba612.4abcd91cout将将双引号中的字符
57、串常量双引号中的字符串常量按其原样输出按其原样输出charch1=a,ch2=b;cout“c1=“ch1t“c2=“ch2endl;c1=ac2=binti1=4,i2=5;floata=3.5;cout“a*i1=“a*i1endl“a*i2=“a*i2endl;a*i1=14a*i2=17.592指定输出项占用的宽度:指定输出项占用的宽度:在在输输出出的的数数据据项项之之间间进进行行隔隔开开的的另另一一种种办办法法是是指指定定输输出出项项的宽度的宽度。如上面的两个输出语句可改写为:。如上面的两个输出语句可改写为:coutsetw(6)isetw(10)jendl;_4_12coutset
58、w(5)msetw(10)j*kendl;_7_24其中其中setw(6)指明其后的指明其后的输出项占用的字符宽度为输出项占用的字符宽度为6,即括,即括号中的值指出紧跟其后的输出项占用的字符位置个数,号中的值指出紧跟其后的输出项占用的字符位置个数,并向右对齐并向右对齐。setw是是“setwidth”的缩写。的缩写。93使用使用setw()应注意以下三点:应注意以下三点:1、在在程程序序的的开开始始位位置置必必须须包包含含头头文文件件iomanip.h,即即在在程程序的开头增加:序的开头增加:#include2、括括号号中中必必须须给给出出一一个个表表达达式式(值值为为正正整整数数),它它指指
59、明明紧跟其后输出项的宽度。紧跟其后输出项的宽度。3、该设置仅对其后的一个输出项有效该设置仅对其后的一个输出项有效。一旦按指定的宽。一旦按指定的宽度输出其后的输出项后,又回到原来的缺省输出方式。度输出其后的输出项后,又回到原来的缺省输出方式。94输出八、十六进制数和科学表示法的实数输出八、十六进制数和科学表示法的实数对对于于整整型型数数据据可可指指定定以以十十六六进进制制或或八八进进制制输输出出,而而对对于于实实型型数数据据可可指指定定以以科科学学表表示示法法形形式式输输出出。例例如如,设设有有如如下一个程序:下一个程序:#includevoidmain(void)floatx=3.14,y=1
60、00;cout.setf(ios:scientific,ios:floatfield);/表明浮点数用科学表示法输出表明浮点数用科学表示法输出coutxt;coutyy?真真假假z=xz=y983、循环、循环A当当P为真为真当型当型i+i=10i+PAYN100if语句语句判断选择判断选择语句,有三种形式:语句,有三种形式:1)if(表达式)(表达式)语句语句语句语句条件条件真真假假语句语句2语句语句1条件条件真真假假2)if(表达式)(表达式)语句语句1else语句语句2if(ab)coutb)couta;elsecoutb)a=1;b=0;elsea=0;b=1;a=0b=1a=1b=0a
61、b真真假假104if(ij)i+;if(ij);i+;i+ij真真假假if总是与它上面最近的总是与它上面最近的else配对,如要改变,用复合语配对,如要改变,用复合语句句。注意书写格式注意书写格式,相互配对的语句要对齐。,相互配对的语句要对齐。ij真真假假i+105例:输入两个实数,按代数值由小到大次序输出这两个数。例:输入两个实数,按代数值由小到大次序输出这两个数。voidmain(void)floata,b,t;/定义变量定义变量coutab;/给变量赋值给变量赋值a:7,b:3if(ab)t=a;a=b;b=t;/交换数据,用中间变量交换数据,用中间变量coutatbendl;/输出变量
62、输出变量bat73773输出结果:输出结果:37106嵌套的条件语句(举例说明)嵌套的条件语句(举例说明)x=100;a=10;b=20;ok1=5;ok2=0;if(ab?a:b;/求求a,b中的大者中的大者当当a=2b=1ab为真,表达式的值等于为真,表达式的值等于a,max值为值为2当当a=1b=2ab为假,表达式的值等于为假,表达式的值等于b,max值为值为2注意:注意:1.条件运算符的优先级比赋值运算符高条件运算符的优先级比赋值运算符高2.x=(x=3)?x+2:x-33.2.结合方向自左至右结合方向自左至右ab?a:cd?c:d4.3.三个表达式的类型可不同三个表达式的类型可不同z
63、=ab?A:a+bx=5108x=9,y=6,z=5;x=(x+y)%z=x%z+y%z)?1:0;coutx=xendl;x=1;y=2;z=3;x+=y+=z;couty?x+:y+)endl;y=y+z=5x=x+5=69x=0109voidmain(void)intx=1,y=2,z=3;x+=y+=z;coutxy?y:xendl;coutxy?x+:y+endl;coutx“,”yendl;couty?x+:y+endl;couty“,”zendl;x=3;y=z=4;cout=y&y=x)?1:0endl;cout=y&y=xendl;xyz输出输出653653666356636
64、,667996797,934434403441110执行以下程序段后,变量执行以下程序段后,变量a,b,c的值分别是:的值分别是:intx=10,y=9;inta,b,c;a=(-x=y+)?-x:+y;b=x+;c=y;x=8y=10a=8b=8x=9c=10111voidmain(void)inta=5,b=1,c=0;if(a=b+c)cout“*n”;elsecout“$n”;*112switch语句语句多分支选择语句。多分支选择语句。if语句只有两个分支,而实际问题中常常语句只有两个分支,而实际问题中常常需要用到多分支的选择。如,成绩分为需要用到多分支的选择。如,成绩分为A(1008
65、5)、B(8470)、C(6960)、D(60以下以下)等。等。A10085YBY8470CY6960DYnopassNNNN显示出错显示出错113cin.get(grade);if(grade=A)cout“10085n”;elseif(grade=B)cout“8470n”;elseif(grade=C)cout“6960n”;elseif(grade=D)cout“nopassn”;elsecout“errorn”;114switch(表达式)表达式)case常量表达式常量表达式1:语句:语句1case常量表达式常量表达式2:语句:语句2case常量表达式常量表达式n:语句:语句ndef
66、ault:语句:语句n+1switch(grade)caseA:cout“10085n”;caseB:cout“8470n”;caseC:cout“6960n”;caseD:cout“nopassn”;default:cout“errorn”;如果如果grade为为A,则结则结果为果为1008584706960nopasserror115其流程为:先计算表达式的值,然后顺序地其流程为:先计算表达式的值,然后顺序地与与case子句中所列出的各个常量进行比较,若子句中所列出的各个常量进行比较,若表达式的值与常量中的值相等,就开始进入表达式的值与常量中的值相等,就开始进入相应的相应的case语句执行
67、程序,语句执行程序,遇到遇到case和和default也不再进行判断,直至也不再进行判断,直至switch语句结束。语句结束。如果如果要使其在执行完相应的语句后中止执行下一要使其在执行完相应的语句后中止执行下一语句,可以在语句后加语句,可以在语句后加break。116switch(grade)caseA:cout“10085n”;break;caseB:cout“8470n”;break;caseC:cout“6960n”;break;caseD:cout“nopassn”;break;default:cout“errorn”;117注意:注意:1、switch与与if不同,它仅能判断一种逻辑
68、关系,即不同,它仅能判断一种逻辑关系,即表达式是否表达式是否等于等于指定的常量,而指定的常量,而if可以计算并判断可以计算并判断各种表达式。各种表达式。2、case子句后必须为常量,常常是整型和字符型。子句后必须为常量,常常是整型和字符型。3、default可以省略,这时,不满足条件什么也不可以省略,这时,不满足条件什么也不执行。执行。1184、case和和default只起标号的作用,只起标号的作用,顺序可以颠倒顺序可以颠倒,颠倒时注意后面的颠倒时注意后面的break语句。语句。5、多个、多个case语句可以共用一组程序。语句可以共用一组程序。caseA:caseB:caseC:cout“p
69、ass!n”;119voidmain(void)inti=10;switch(i)case9:i+;case10:i+;case11:i+;default:i+;cout“i=”iendl;i=11i=12i=13i=13120intx=1,y=0,a=0,b=0;switch(x)case1:switch(y)case0:a+;break;case1:b+;break;case2:a+;b+;break;case3:a+;b+;cout“a=“at“b=”bendl;a=1a=2b=1a=2b=1121有有3 3个整数个整数a,b,ca,b,c,由键盘输入,输出其中最大的数。,由键盘输入,输
70、出其中最大的数。122while语句语句while(表达式)表达式)语句组语句组1语句组语句组2表达式表达式语句组语句组1真真语句组语句组2假假a=3;while(a100)a=a+5;cout“a=“a;当循环语句超过一条时,要当循环语句超过一条时,要用用将语句组组合在一起。将语句组组合在一起。123求求1+2+3+100voidmain(void)inti=1,sum=0;/定义变量,初始化定义变量,初始化while(i=100)/构造循环构造循环sum=sum+i;/循环体,多次执行循环体,多次执行i=i+1;cout“sum=”sumendl;/输出结果输出结果循环条件循环条件初值初值
71、循环次数循环次数1234.99100101sumi0112真真33真真64真真105真真真真100真真101真真5050假假sum50500sum1i1233641005050101循环结束循环结束!实际上是将实际上是将i不停地累加到一起不停地累加到一起124注意:注意:1、循环体如果为一个以上的语句,用、循环体如果为一个以上的语句,用括起。括起。2、循环体内或表达式中必须有使循环结束的条件,、循环体内或表达式中必须有使循环结束的条件,即一定有一个循环变量。即一定有一个循环变量。3、while表达式可以成为语句,要特别小心。表达式可以成为语句,要特别小心。125k=2;while(k!=0)c
72、outk,k-;coutendl;k循环条件循环条件输出输出输出:输出:212真真21真真10假假回车回车126voidmain(void)intnum=0;while(num=2)num+;coutnumendl;num循环条件循环条件输出输出1230真真11真真22真真33假假无无127voidmain(void)inty=10;while(y-);cout“y=”yendl;y条件条件输出输出输出:输出:y=-1输出是什么?输出是什么?循环几次?循环几次?10真真无无9真真无无.真真无无1真真无无0假假1循环:循环:10次次128k=10;while(k=0)k=k-1;coutk;k1
73、0表达式表达式0输出:输出:0129x=10;while(x!=0)x-;x=10;while(x)x-;x=10;while(x-);x=10;while(-x);以下语句,循环退出时以下语句,循环退出时x为多少?为多少?x=0x=0x=-1x=0130#includevoidmain()charch;while(cin.get(ch)&ch!=n)switch(ch-2)case0:case1:cout(char)(ch+4);case2:cout(char)(ch+4);break;case3:cout(char)(ch+3);default:cout(char)(ch+2);break
74、;coutendl;从键盘输入从键盘输入2473,则程序,则程序的输出结果是:的输出结果是:输出:输出:668977131直到直到P为真为真A直到型直到型dowhile语句语句表达式表达式语句组语句组1真真语句组语句组2假假do语句组语句组1while(表达式)(表达式);语句组语句组2132求求1+2+3+100voidmain(void)inti=1,sum=0;/定义变量,初始化定义变量,初始化do/构造循环构造循环sum=sum+i;/循环体,多次执行循环体,多次执行i=i+1;while(i=100);cout“sum=”sum0)&(y5);cout“y=“y“,”“x=”xend
75、l;y0x0条件条件输出:输出:y=1,x=010假假若为若为while循环,则循环,则一次也不执行循环一次也不执行循环体,输出为:体,输出为:y=0,x=0135s=7;dos-=2;while(s=0);cout“s=”sendl;第一次第一次s75表达式表达式N输出:输出:s=5136for语句语句for(表达式(表达式1;表达式;表达式2;表达式表达式3)语句组语句组1(循环体循环体)语句组语句组2N表达式表达式2语句组语句组1Y语句组语句组2表达式表达式1表达式表达式3for(循环变量赋初值循环变量赋初值;循环结束条件;循环结束条件;循环变量增值循环变量增值)137求求1+2+3+1
76、00voidmain(void)inti,sum;for(i=1,sum=0;i=100;i+)sum=sum+i;cout“sum=”sumendl;voidmain(void)inti,sum;i=1;sum=0;while(i=100)sum=sum+i;i=i+1;cout“sum=”sumendl;138注意:注意:1、当型循环,条件测试是在循环开始时进行,有可能一次、当型循环,条件测试是在循环开始时进行,有可能一次也进入不了循环体。也进入不了循环体。2、for语句中的三个表达式可以部分省略或全部省略,语句中的三个表达式可以部分省略或全部省略,但但;不能省略,不能省略,若省略表达式若
77、省略表达式2,则表示循环条件,则表示循环条件为真为真。3、for语句中三个表达式可以是任何有效的语句中三个表达式可以是任何有效的C语言表达式。语言表达式。139voidmain(void)chari,j;for(i=a,j=z;ij;i+,j-)coutij;coutendl;次数次数ijij输出输出输出:输出:azbycx.lomnaz真真azby真真bycx真真cx真真.真真.mnmn.nm假假CR140以下循环结果如何?以下循环结果如何?for(i=0,k=-1;k=1;i+,k+)cout“*n”;以下循环最多执行以下循环最多执行_次,最少执行次,最少执行_次次for(i=0,x=0;
78、ix;101141循环的嵌套循环的嵌套一个循环体内又包含另一个完整的循环体,称为循一个循环体内又包含另一个完整的循环体,称为循环的嵌套。环的嵌套。注意:注意:1、循环体内有多个语句要用括起来。、循环体内有多个语句要用括起来。2、书写格式要清晰。、书写格式要清晰。for(;).for(;).142voidmain(void)inti,j,k=0,m=0;for(i=0;i2;i+)for(j=0;j3;j+)k+;k-=j;m=i+j;cout“k=“k“,m=“mendl;ii2jjn)1、m被被n除得到余数除得到余数r(0rn)r=m%nm=6n=4r=m%n=6%4=2while(r=m%
79、n)m=n;n=r;最小公倍数为两数之积除以最大公约数。最小公倍数为两数之积除以最大公约数。4*6/2=122、若、若r=0,则算法结束,则算法结束,n为最大公约数,否则做为最大公约数,否则做33、mn,nr,回到回到1m=4n=2r=m%n=4%2=0所以,公约数所以,公约数=2146最大公约数:能同时被最大公约数:能同时被m和和n整除的最大数。整除的最大数。r=mn?n:mfor(i=1;ir;i+)if(m%i=0&n%i=0)a=i;couta;147将将12345的每位分别打印出来。的每位分别打印出来。1234510512345/10123412341041234/101231231
80、03123/10121210212/1011%1011/100while(n)coutn%10=1e-5)S=S+term;term=(-1)*term*x*x/(2*n)*(2*n-1);n+;term=(-1)*term*t;前一项前一项当前项当前项旧的旧的新的新的后一项后一项(-1)前一项前一项t设通项为设通项为term,则可以写出迭代公式,则可以写出迭代公式t=x*x/(2*n)*(2*n-1)150t=x*x/(2*n)*(2*n-1)第第n项项/第第n-1项:项:第一项:第一项:term=1;第一次循环:第一次循环:S=S+term;term=(-1)*term*t;第二次循环:第
81、二次循环:S=S+term;term=(-1)*term*t;这时这时左边的左边的term代表第二项,而代表第二项,而右边的右边的term为第一项。为第一项。这时这时左边的左边的term代表第三项,而代表第三项,而右边的右边的term为第二项。为第二项。term=(-1)*term*t;前一项前一项当前项当前项同样是同样是term,在循环中不断用旧的数值去推导赋值出新的,在循环中不断用旧的数值去推导赋值出新的数值。数值。151S=0;term=1;n=1;/一定要赋初值一定要赋初值while(fabs(term)=1e-5)S=S+term;term=(-1)*term*x*x/(2*n)*(
82、2*n-1);n+;旧的旧的新的新的152break语句和语句和continue语句语句break在在switch语句中,可以语句中,可以使流程跳过判断体使流程跳过判断体,执执行下面的程序行下面的程序。在循环体中,也可以从循环体内跳在循环体中,也可以从循环体内跳出循环体,提前结束循环出循环体,提前结束循环。for(;)cinx;if(x=123)break;当输入当输入123时,结束循环。时,结束循环。break只能退出一层循环或只能退出一层循环或switch语句。语句。153a=10;y=0;doa+=2;y+=a;cout“a=“a“,y=“y50)break;while(a=14);第一
83、次:第一次:a=12y=12输出:输出:a=12,y=12第二次:第二次:a=16y=28输出:输出:a=16,y=28第三次:第三次:a=16y=44输出:输出:a=16,y=44第四次:第四次:a=16y=60输出:输出:a=16,y=60154continue:其作用为:其作用为结束本次循环结束本次循环,即跳过循环体中下面,即跳过循环体中下面尚未执行的语句,尚未执行的语句,接着进行下一次是否执行循环的判定接着进行下一次是否执行循环的判定。voidmain(void)inti;for(i=1;i=5;i+)if(i%2)cout“*”;elsecontinue;cout“#”;cout“$
84、n”;ii=5i%2输出输出输出:输出:*#*#*#$1真真1*#2真真0无无3真真1*#4真真0无无5真真1*#6假假$155voidmain(void)inti,j,x=0;for(i=0;i2;i+)x+;for(j=0;j=3;j+)if(j%2)continue;x+;x+;cout“x=“xendl;jj%2xi=0i2第一次第一次jj%2xi=1i2第二次第二次i=2i2结束结束输出:输出:x=80假假21真真22假假33真真3440假假61真真62假假73真真748156voidmain(void)intk=0;charc=A;doswitch(c+)caseA:k+;brea
85、k;caseB:k-;caseC:k+=2;break;caseD:k=k%2;continue;caseE:k=k*10;break;default:k=k/3;k+;while(cG);cout“k=”kendl;c+ck输出:输出:k=4A真真B2B真真C4C真真D7D真真E1E真真F11F假假G4157总结:总结:在循环体中,在循环体中,break从循环体内跳出循环体,提前从循环体内跳出循环体,提前结束循环结束循环。for(.;.;.).break;.158continue:其作用为:其作用为结束本次循环结束本次循环,即跳过循环体,即跳过循环体中下面尚未执行的语句,中下面尚未执行的语句
86、,接着进行下一次是否执行接着进行下一次是否执行循环的判定循环的判定。for(.;.;.).continue;.while(.).continue;.159求素数:只可以被求素数:只可以被1与自身整除的数。与自身整除的数。判断一个数判断一个数t是否为素数,用是否为素数,用2到到t-1循环除。循环除。for(i=2;it;i+)if(t%i=0)break;if(i=t)cout“是素数。是素数。n”;elsecout=t/2)160求范围内的素数求范围内的素数(50100):for(t=50,k=0;t=100;t+)for(i=2;it;i+)if(t%i=0)break;if(i=t)cou
87、tt“;k+;if(k%5=0)coutendl;判断判断t是否是否为素数为素数保证每行输出保证每行输出5个数据个数据161鸡兔共有鸡兔共有30只,脚共有只,脚共有90只,问鸡兔各有多少?只,问鸡兔各有多少?voidmain(void)inti;/i代表鸡,则兔为代表鸡,则兔为30-i只只for(i=0;i=15;i+)if(2*i+4*(30-i)=90)cout“鸡鸡”iendl;cout“兔兔”30-iendl;162一百万富翁一百万富翁遇到一陌生人,陌生人找他谈一个换钱遇到一陌生人,陌生人找他谈一个换钱的计划,该计划如下:我每天给你十万元,而你第的计划,该计划如下:我每天给你十万元,而
88、你第一天只需给我一分钱,第二天我仍给你十万元,你一天只需给我一分钱,第二天我仍给你十万元,你给我两分钱,第三天我仍给你十万元,你给我四分给我两分钱,第三天我仍给你十万元,你给我四分钱,钱,.,你每天给我的钱是前一天的两倍,直到,你每天给我的钱是前一天的两倍,直到满一个月(满一个月(30天),百万富翁很高兴,欣然接受了天),百万富翁很高兴,欣然接受了这个契约。请编写程序计算陌生人给百万富翁多少这个契约。请编写程序计算陌生人给百万富翁多少钱,百万富翁给陌生人多少钱?钱,百万富翁给陌生人多少钱?163利用循环语句编程,打印下列图形:利用循环语句编程,打印下列图形:*找规律:找规律:上面四行上面四行行
89、号行号空格空格星号星号131222313404for(i=0;i0;j-)cout;for(k=1;k=i+1;k+)cout*;coutendlendl;行号:行号:i空格:空格:4-i星号:星号:i164voidmain(void)inti,j,k;for(i=0;i0;j-)cout;for(k=1;k=i+1;k+)cout*;coutendlendl;for(i=0;i0;j-)cout*;coutendlendl;165打印图形:打印图形:*行号行号空格空格星号星号031123215307行号:行号:i空格:空格:3-i星号:星号:2*i+1如果打印如果打印n行行行号:行号:0n-
90、1空格:空格:0n-1-i166计算:计算:222222.2222222?累加和累加和s0设通项为设通项为tt的初值为的初值为222=2*10+2;222=22*10+2;2222=222*10+2;t=t*10+2;所以,通项的循环表示为:所以,通项的循环表示为:前一项前一项当前项当前项循环体为:循环体为:s=s+tt=t*10+2;167voidmain(void)intt,s;s=0;t=2;for(inti=0;i7;i+)s=s+t;t=t*10+2;coutsendl;168满足以下条件三位数满足以下条件三位数n,它除以,它除以11所得到的商等于所得到的商等于n的各位数字的平方和,
91、且其中至少有两位数字相的各位数字的平方和,且其中至少有两位数字相同。同。131131/11=1112+32+12=11分析:分析:数字应该从数字应该从100循环到循环到999将每位数字剥出,判断其是否满足条件将每位数字剥出,判断其是否满足条件169满足以下条件三位数满足以下条件三位数n,它除以,它除以11所得到的商等于所得到的商等于n的各位数字的平方和,且其中至少有两位数字相的各位数字的平方和,且其中至少有两位数字相同。同。131131/11=1112+32+12=11分析:分析:用用a,b,c分别代表三位数,分别代表三位数,a,b,c分别从分别从0循环到循环到9,组,组成所有可能的三位数,然
92、后找出满足条件的数来。成所有可能的三位数,然后找出满足条件的数来。170求求n=1000时时的近似值的近似值分析:分析:通项:通项:s=st迭代算法:迭代算法:上次迭代上次迭代的结果的结果本次计算本次计算的结果的结果迭代结束条件:迭代结束条件:迭代迭代1000次次注意注意s与与t的初始值的初始值n从从1开始迭代开始迭代s=1171下面程序的功能是用公式求下面程序的功能是用公式求的近似值,直到最后一项的值的近似值,直到最后一项的值小于小于10-6为止。请填空。为止。请填空。voidmain(void)inti=1;_pi=0;while(i*i=10e+6)pi=_;i+;pi=sqrt(6.0
93、*pi);cout“pi=”piendl;doublepi+1.0/(i*i)172有有1020个西瓜,第一天卖一半多两个,以后每天卖剩下的个西瓜,第一天卖一半多两个,以后每天卖剩下的一半多两个,问几天以后能卖完?请填空。一半多两个,问几天以后能卖完?请填空。#include”stdio.h”voidmain(void)intday,x1,x2;day=0;x1=1020;while(_)x2=_;x1=x2;day+;cout“day=”dayendl;x1x1/2-2173第五章 函数与编译预处理174概述概述函数是程序代码的一个自包含单元,用于完函数是程序代码的一个自包含单元,用于完成某
94、一特定的任务。成某一特定的任务。C+是由函数构成的,是由函数构成的,函数是函数是C+的基本模块的基本模块。有的函数完成某一操作;有的函数计算出一有的函数完成某一操作;有的函数计算出一个值。通常,一个函数即能完成某一特定操个值。通常,一个函数即能完成某一特定操作,又能计算数值。作,又能计算数值。175为什么要使用函数?为什么要使用函数?1、避免重复的编程。、避免重复的编程。2、使程序更加模块化,便于阅读、修改。、使程序更加模块化,便于阅读、修改。参数(多个)参数(多个)函数值函数值(唯一)唯一)函数体函数体所编写的函数应尽量少与主调函数发生所编写的函数应尽量少与主调函数发生联系,这样便于移植。联
95、系,这样便于移植。176说明:说明:1、一个源程序文件由一个或多个函数组成,编译程序以文、一个源程序文件由一个或多个函数组成,编译程序以文件而不是以函数为单位进行编译的。件而不是以函数为单位进行编译的。2、一个程序可以由多个源文件组成,可以分别编译,统一、一个程序可以由多个源文件组成,可以分别编译,统一执行。执行。3、一个程序必须有且只有一个、一个程序必须有且只有一个main()函数,函数,C+从从main()函数开始执行。函数开始执行。4、C+语言中,语言中,所有函数都是平行独立的,无主次、相互所有函数都是平行独立的,无主次、相互包含之分包含之分。函数可以嵌套调用,不可嵌套定义函数可以嵌套调
96、用,不可嵌套定义。5、从使用角度来说,分标准函数和用户自定义函数;从形、从使用角度来说,分标准函数和用户自定义函数;从形式来说,分无参函数和有参函数。式来说,分无参函数和有参函数。177库函数是库函数是C+编译系统已预定义的函数编译系统已预定义的函数,用户根据,用户根据需要可以直接使用这类函数。库函数也称为标准函需要可以直接使用这类函数。库函数也称为标准函数。数。为了方便用户进行程序设计,为了方便用户进行程序设计,C+把一些常用数学把一些常用数学计算函数(如计算函数(如sqrt()、exp()等)、字符串处理函数、等)、字符串处理函数、标准输入输出函数等,都作为库函数提供给用户,标准输入输出函
97、数等,都作为库函数提供给用户,用户可以直接使用系统提供的库函数。用户可以直接使用系统提供的库函数。库函数有很多个,当用户使用任一库函数时,在程库函数有很多个,当用户使用任一库函数时,在程序中必须包含相应的头文件。序中必须包含相应的头文件。如如#include等。等。178用户在设计程序时,可以将完成某一相对独立功能用户在设计程序时,可以将完成某一相对独立功能的程序定义为一个函数。用户在程序中,根据应用的程序定义为一个函数。用户在程序中,根据应用的需要,由的需要,由用户自己定义函数用户自己定义函数,这类函数称为用户,这类函数称为用户自定义的函数。自定义的函数。根据定义函数或调用时是否要给出参数,
98、又可将函根据定义函数或调用时是否要给出参数,又可将函数分为:无参函数和有参函数。数分为:无参函数和有参函数。179函数定义的一般形式函数定义的一般形式一、无参函数一、无参函数主调函数并不将数据传给被调函数。主调函数并不将数据传给被调函数。类型说明类型说明函数名(函数名(void)函数体函数体无参函数主要用于完成某一操作。无参函数主要用于完成某一操作。不传递参数不传递参数参数(多个)参数(多个)函数值函数值(唯一)唯一)函数体函数体180voidmain(void)printstar();print_message();printstar();voidprintstar(void)cout“*n
99、”;voidprint_message(void)couty)?x:y;returnz;voidmain(void)inta,b,c;cinab;c=max(a,b);cout“Themaxis”cy)?x:y;returnz;voidmain(void)inta,b,c;cinab;c=max(a,b);cout“Themaxis”cy)?x:y;returnz;voidmain(void)inta,b,c;cinab;c=max(a+b,a*b);cout“Themaxis”cendl;先计算,后先计算,后赋值赋值若若a为为3,b为为5,则实参,则实参为为8,15,分别送给形参,分别送给形
100、参x,y。187说明:说明:1、在未出现函数调用时,形参并不占内存的存储单元,、在未出现函数调用时,形参并不占内存的存储单元,只只有在函数开始调用时,形参才被分配内存单元有在函数开始调用时,形参才被分配内存单元。调用结束。调用结束后,形参所占用的内存单元被释放。后,形参所占用的内存单元被释放。2、实参对形参变量的传递是、实参对形参变量的传递是“值传递值传递”,即单向传递。,即单向传递。在在内存中实参、形参分占不同的单元内存中实参、形参分占不同的单元。3、形参只作用于被调函数,可以在别的函数中使用相同的、形参只作用于被调函数,可以在别的函数中使用相同的变量名。变量名。5a8b实参实参xy形参形参
101、58188voidfun(inta,intb)a=a*10;b=b+a;coutatbendl;voidmain(void)inta=2,b=3;fun(a,b);coutatbendl;ab23ab232023202323189voidfun(intx,inty)x=x*10;y=y+x;coutxtyendl;voidmain(void)inta=2,b=3;fun(a+b,a*b);coutatby)returnx;elsereturny;若函数体内没有若函数体内没有return语语句,就一直执行到函数体句,就一直执行到函数体的末尾,然后返回到主调的末尾,然后返回到主调函数的调用处。函数
102、的调用处。先计算,后返回先计算,后返回可以有多个可以有多个return语句语句193不带返回值的函数可说明为不带返回值的函数可说明为void型。型。函数的类型与函数参数的类型没有关系。函数的类型与函数参数的类型没有关系。doubleblink(inta,intb)如果函数的类型和如果函数的类型和return表达式中的类型不一致,表达式中的类型不一致,则以函数的类型为准。则以函数的类型为准。函数的类型决定返回值的函数的类型决定返回值的类型。类型。对数值型数据,可以自动进行类型转换。对数值型数据,可以自动进行类型转换。既然函数有返回值,这个值当然应属于某一个确定既然函数有返回值,这个值当然应属于某
103、一个确定的类型,应当在定义函数时指定函数值的类型。的类型,应当在定义函数时指定函数值的类型。intmax(floata,floatb)/函数值为整型函数值为整型函数返回值的类型,也是函数的类型函数返回值的类型,也是函数的类型194参数(多个)参数(多个)函数值函数值(唯一)唯一)函数体函数体intmax(inta,intb)intz;z=xy?x:y;returnz;如果有函数返回如果有函数返回值值,返回值就是函返回值就是函数值数值,必须惟一。必须惟一。如果有函数返回如果有函数返回值值,函数的类型就函数的类型就是返回值的类型是返回值的类型函数体的类型、形式参数的类型必须函数体的类型、形式参数的
104、类型必须在函数的定义中体现出来。在函数的定义中体现出来。195函数的调用函数的调用函数调用的一般形式函数调用的一般形式函数名(实参列表);函数名(实参列表);形参与实参类型相同,一一对应。形参与实参类型相同,一一对应。i=2;f(i,+i);函数调用的方式函数调用的方式作为语句作为语句printstar();作为表达式作为表达式c=max(a,b);作为另一个函数的参数作为另一个函数的参数coutmax(a,b);实际调用:实际调用:f(3,3);1961)被调用的函数必须是已存在的函数被调用的函数必须是已存在的函数2)如果使用库函数,必须用如果使用库函数,必须用#include在一个函数中调
105、用另一函数(即被调用函数)需要在一个函数中调用另一函数(即被调用函数)需要具备哪些条件呢?具备哪些条件呢?3)函数调用遵循函数调用遵循先定义、后调用先定义、后调用的原则,即的原则,即被调被调函数应出现在主调函数之前函数应出现在主调函数之前。197floatmax(floatx,floaty)floatz;z=(xy)?x:y;returnz;voidmain(void)floata,b,c;cinab;c=max(a+b,a*b);cout“Themaxis”cy)?x:y;returnz;voidmain(void)floata,b,c;floatmax(float,float);cinab
106、;c=max(a,b);cout“Themaxis”cendl;函数原型说明函数原型说明函数定义函数定义定义是一个完整的函数单位,定义是一个完整的函数单位,而原型说明仅仅是说明函数的而原型说明仅仅是说明函数的返回值及形参的类型返回值及形参的类型。200voidmain(void)inti=2,x=5,j=7;voidfun(int,int);fun(j,6);coutitjtxendl;voidfun(inti,intj)intx=7;coutitjtxendl;2i5x7j676jxi7输出:输出:767275201voidmain(void)intx=2,y=3,z=0;voidadd(i
107、nt,int,int);cout“(1)x=“x“y=“y“z=“zendl;add(x,y,z);cout(“(3)x=“x“y=“y“z=“zendl;voidadd(intx,inty,intz)z=x+y;x=x*x;y=y*y;cout(“(2)x=“x“y=“y“z=“zx;y=f1(x);cout“x=“x“,y=“y0.00001);returns;voidmain(void)floatx;cinx;cout“s=“fun(x)endl;206计算计算100200之间的素数,用函数之间的素数,用函数prime()判断一个数是判断一个数是否是素数,若是该函数返回否是素数,若是该函
108、数返回1,否则返回,否则返回0。voidmain(void)for(inti=100;i=200;i+)if(prime(i)=1)coutit;intprime(intx)for(inti=2;ixy;coutgys(x,y)endl;intgys(inta,intb)intr;if(axyz;coutgys(x,y,z)endl;intgys(inta,intb,intc)intr;if(ac?r:c;for(inti=r-1;i=1;i-)if(a%i=0&b%i=0&c%i=0)break;returni;209写一个函数验证哥德巴赫猜想;一个不小于写一个函数验证哥德巴赫猜想;一个不小
109、于6 6的偶的偶数可以表示为两个素数之和,如数可以表示为两个素数之和,如6=3+3, 8=3+5, 6=3+3, 8=3+5, 10=3+710=3+7。在主函数中输入一个不小于。在主函数中输入一个不小于6 6的偶数的偶数n n,函数中输出以下形式的结果,函数中输出以下形式的结果34=3+31210函数的嵌套调用函数的嵌套调用C语言中,语言中,所有函数都是平行独立的,无主次、相所有函数都是平行独立的,无主次、相互包含之分互包含之分。函数可以嵌套调用,不可嵌套定义。函数可以嵌套调用,不可嵌套定义。intmax(inta,intb)intc;intmin(inta,intb)return(ab?a
110、:b);intmax(inta,intb)intc;c=min(a,b);return(ab?a:b);intmin(inta,intb)return(ab?a:b);嵌套定义嵌套定义嵌套调用嵌套调用平行定义平行定义211调用调用b函数函数a函数函数b函数函数main函数函数调用调用a函数函数结束结束(2)(3)(4)(5)(6)(7)(8)(9)在在main函数中调用函数中调用a函数,在函数,在a函数中又调用函数中又调用b函数。函数。212intpower(intm,intn)/mninti,product=m;for(i=1;in;i+)product=product*m;returnpr
111、oduct;intsum_of_power(intk,intn)/nk的累加和的累加和inti,sum=0;for(i=1;ikm;coutf(k,m)=sum_of_power(k,m)1intage(intn)intc;c=age(n-1)+2;returnc;voidmain(void)intage(int);coutage(5)endl;intage(intn)intc;if(n=1)c=10;elsec=age(n-1)+2;returnc;必须有递归结束条件必须有递归结束条件215intage(intn)intc;if(n=1)c=10;elsec=age(n-1)+2;retur
112、nc;voidmain(void)intage(int);coutage(5)1floatfac(intn)floaty;if(n=0)|(n=1)y=1;elsey=n*fac(n-1);returny;voidmain(void)floaty;intn;coutn;coutn“!=”fac(n)endl;fac(5)n=5y=5*fac(4)fac(4)n=4y=4*fac(3)fac(3)n=3y=3*fac(2)fac(2)n=2y=2*fac(1)fac(1)n=1y=1returnyreturnyy=2returnyy=6returnyy=24returnyy=120217ints
113、ub(int);voidmain(void)inti=5;coutsub(i)i;f(i);voidf(intn)if(n=0)return;elsecoutn%10;f(n/10);coutn%10;return;f(1234)coutn%10f(n/10)f(123)coutn%10f(n/10)f(12)coutn%10f(n/10)f(1)coutn%10f(n/10)f(0)n=0returncoutn%10returncoutn%10returncoutn%10returncoutn%10return4321123443211234输入:输入:1234219voidrecur(ch
114、arc)coutc;if(c5)recur(c+1);cout=10)f(n/10);coutnendl;voidmain(void)f(12345);112123123412345221作用域和存储类作用域和存储类作用域是指程序中所说明的标识符在哪一个区间内作用域是指程序中所说明的标识符在哪一个区间内有效,即在哪一个区间内可以使用或引用该标识符有效,即在哪一个区间内可以使用或引用该标识符。在在C+中,作用域共分为五类:中,作用域共分为五类:块作用域、文件作块作用域、文件作用域、函数原型作用域、函数作用域和类的作用域。用域、函数原型作用域、函数作用域和类的作用域。222块作用域块作用域我们把用
115、花括号括起来的一部分程序称为一个块。我们把用花括号括起来的一部分程序称为一个块。在块内说明的标识符,只能在该块内引用,即其在块内说明的标识符,只能在该块内引用,即其作用域在该块内,开始于标识符的说明处,结束作用域在该块内,开始于标识符的说明处,结束于块的结尾处。于块的结尾处。在一个函数内部定义的变量或在一个块中定义的变在一个函数内部定义的变量或在一个块中定义的变量称为局部变量。量称为局部变量。223在函数内或复合语句内部定义的变量,其作用域是在函数内或复合语句内部定义的变量,其作用域是从定义的位置起到函数体或复合语句的结束从定义的位置起到函数体或复合语句的结束。形参形参也是局部变量。也是局部变
116、量。floatf1(inta)intb,c;.floatf2(intx,inty)inti,j;.voidmain(void)intm,n;.x,y,i,j有效有效a,b,c有效有效m,n有效有效224主函数主函数main中定义的变量,也只在主函数中有效,中定义的变量,也只在主函数中有效,同样属于局部变量同样属于局部变量。不同的函数可以使用相同名字的局部变量,它们在不同的函数可以使用相同名字的局部变量,它们在内存中分属不同的存储区间,互不干扰。内存中分属不同的存储区间,互不干扰。voidmain(void)intx=10;intx=20;coutxendl;coutxendl;2010x10x
117、20定义变量既是在定义变量既是在内存中开辟区间内存中开辟区间225注意:注意:具具有有块块作作用用域域的的标标识识符符在在其其作作用用域域内内,将将屏屏蔽其作用块包含本块的同名标识符,即蔽其作用块包含本块的同名标识符,即变量名相同,局部更优先。变量名相同,局部更优先。226voidmain(void)inta=2,b=3,c=5;coutatbtcendl;inta,b=2;a=b+c;coutatbtcendl;c=a-b;coutatbtcendl;a2b3c5235725ab27-123-1227voidmain(void)inta=1,b=2,c=3;+a;c+=+b;intb=4,c
118、;c=b*3;a+=c;cout“first:”atbtcendl;a+=c;cout“second:”atbtcendl;cout“third:”atbtcendl;a=2b=3,c=6b=4c=12a=14a=14,b=4,c=12a=26a=26,b=4,c=12a=26,b=3,c=6228文件作用域文件作用域在函数外定义的变量称为全局变量。在函数外定义的变量称为全局变量。全局变量的作用域称为文件作用域,即在整个文件全局变量的作用域称为文件作用域,即在整个文件中都是可以访问的。中都是可以访问的。其缺省的作用范围是其缺省的作用范围是:从定义全局变量的位置开始从定义全局变量的位置开始到该源
119、程序文件结束到该源程序文件结束。当在块作用域内的变量与全局变量同名时,当在块作用域内的变量与全局变量同名时,局部变局部变量优先。量优先。229p,q有效有效intp=1,q=5;floatf1(inta)intb,c;.charc1,c2;main()intm,n;.a,b,c有效有效m,n有效有效c1,c2有效有效全局变量全局变量局部变量局部变量全局变量全局变量增加了函数间数据联系的渠道增加了函数间数据联系的渠道,在函数调,在函数调用时可以得到多于一个的返回值。用时可以得到多于一个的返回值。2304intmin;intmax(intx,inty)intz;min=(xy)?x:y;retur
120、nz;voidmain(void)inta,b,c;cinab;c=max(a,b);cout“Themaxis”cendl;cout“Theminis”minb?a:b;returnc;voidmain(void)inta=8;coutmax(a,b)endl;3a5ba88a5bmax(8,5)输出:输出:8232intx;voidcude(void)x=x*x*x;voidmain(void)x=5;cude();coutxendl;输出:输出:125输出:输出:5intx=5;x为为0233在块作用域内可通过作用域运算符在块作用域内可通过作用域运算符“:”来引用来引用与局部与局部变量同
121、名变量同名的全局变量。的全局变量。#includeinti=100;voidmain(void)inti,j=50;i=18;/访问访问局部变量局部变量i:i=:i+4;/访问全部变量访问全部变量ij=:i+i;/访问全部变量访问全部变量i和局部变量和局部变量jcout”:i=”:in;cout”i=”in;cout”j=”jn;:i=104i=18j=108234函数原型作用域函数原型作用域在函数原型的参数表中说明的标识符所具有的作用在函数原型的参数表中说明的标识符所具有的作用域称为函数原型作用域,域称为函数原型作用域,它从其说明处开始,到函它从其说明处开始,到函数原型说明的结束处结束数原型
122、说明的结束处结束。floattt(intx,floaty);/函数函数tt的原型说明的原型说明由于所说明的标识符与该函数的定义及调用无关,由于所说明的标识符与该函数的定义及调用无关,所以,所以,可以在函数原型说明中只作参数的类型说可以在函数原型说明中只作参数的类型说明,而省略参量名明,而省略参量名。floattt(int,float);235inti=0;intworkover(inti)i=(i%i)*(i*i)/(2*i)+4);cout“i=“iendl;returni;intrest(inti)i=i2?5:0;returni;voidmain(void)inti=5;rest(i/2
123、);cout“i=“iendl;rest(i=i/2);cout“i=“iendl;i=rest(i/2);cout“i=“iendl;workover(i)cout“i=“iendl;i=5i=2i=5i=0i=5236存储类存储类外存外存内存内存程序程序程程序序区区静态存储区静态存储区动态存储区动态存储区存放程存放程序代码序代码存放变量存放变量需要区分变量的存储类型需要区分变量的存储类型237作用域作用域全局变量全局变量局部变量局部变量生存期生存期动态存储变量动态存储变量静态存储变量静态存储变量静态存储:在文件运行期间有固定的存储空间,直到文件静态存储:在文件运行期间有固定的存储空间,直到
124、文件运行结束。运行结束。动态存储:在程序运行期间根据需要分配存储空间,动态存储:在程序运行期间根据需要分配存储空间,函数函数结束后立即释放空间结束后立即释放空间。若一个函数在程序中被调用两次,。若一个函数在程序中被调用两次,则每次分配的单元有可能不同。则每次分配的单元有可能不同。程序区程序区静态存储区静态存储区动态存储区动态存储区全局变量全局变量静态局部变量静态局部变量动态局部变量动态局部变量238局部变量局部变量的分类的分类动态变量(动态变量(auto):默认,存储在动态区):默认,存储在动态区寄存器变量(寄存器变量(register):):在在cpu内部存储内部存储静态局部变量(静态局部变
125、量(static):存储在静态区):存储在静态区动态局部变量未被赋值时,动态局部变量未被赋值时,其值为随机值其值为随机值。其作用域的函。其作用域的函数或复合语句结束时,数或复合语句结束时,空间被程序收回空间被程序收回。程程序序执执行行到到静静态态局局部部变变量量时时,为为其其在在静静态态区区开开辟辟存存储储空空间间,该空间一直被保留,该空间一直被保留,直到程序运行结束。直到程序运行结束。由于存储在静态区,静态局部变量或全局变量未赋初值时,由于存储在静态区,静态局部变量或全局变量未赋初值时,系统自动使之为系统自动使之为0。239intfun(inta)intc;staticintb=3;c=a+
126、b+;returnc;voidmain(void)intx=2,y;y=fun(x);coutyendl;y=fun(x+3);coutyendl;x2ya2b3c5455a5只赋一次初值只赋一次初值c9599输出:输出:变量变量b是静态局部变量,在内存是静态局部变量,在内存一旦开辟空间,就不会释放,空一旦开辟空间,就不会释放,空间值一直保留间值一直保留240intf(inta)intb=0;staticintc=3;b=b+1;c=c+1;returna+b+c;voidmain(void)inta=2,i;for(i=0;i3;i+)coutf(a)endl;i=0a=2b=0,b=1c=
127、3,c=4输出:输出:7i=1a=2b=0,b=1c=4,c=5输出:输出:8i=2a=2b=0,b=1c=5,c=6输出:输出:9789只赋一次只赋一次初值初值241intfunc(inta,intb)staticintm=0,i=2;i+=m+1;m=i+a+b;returnm;voidmain(void)intk=4,m=1,p;p=func(k,m);coutpendl;p=func(k,m);coutpendl;func(4,1)a=4,b=1m=0,i=2i=3m=3+4+1=8func(4,1)a=4,b=1m=8,i=3i=3+8+1=12m=12+4+1=17输出:输出:8,
128、17242intq(intx)inty=1;staticintz=1;z+=z+y+;returnx+z;voidmain(void)coutq(1)t;coutq(2)t;coutq(3)am;c=a*b;couta“*”b“=“cendl;d=power(m);couta“*”m“=“dendl;文件文件file2.c中的内容为:中的内容为:externinta;intpower(intn)inti,y=1;for(i=1;iy)?x:y;returnz;voidmain(void)inta,b,c;cinab;c=max(a+b,a*b);cout“Themaxis”cendl;249使
129、用内联函数时应注意以下几点:使用内联函数时应注意以下几点:1、C+中中,除除在在函函数数体体内内含含有有循循环环,switch分分支支和和复复杂杂嵌嵌套的套的if语句外,所有的函数均可定义为内联函数。语句外,所有的函数均可定义为内联函数。2、内内联联函函数数也也要要定定义义在在前前,调调用用在在后后。形形参参与与实实参参之之间间的关系与一般的函数相同。的关系与一般的函数相同。3、对对于于用用户户指指定定的的内内联联函函数数,编编译译器器是是否否作作为为内内联联函函数数来来处处理理由由编编译译器器自自行行决决定定。说说明明内内联联函函数数时时,只只是是请请求求编编译译器器当当出出现现这这种种函函
130、数数调调用用时时,作作为为内内联联函函数数的的扩扩展展来来实实现现,而不是命令编译器要这样去做。而不是命令编译器要这样去做。4、正正如如前前面面所所述述,内内联联函函数数的的实实质质是是采采用用空空间间换换取取时时间间,即即可可加加速速程程序序的的执执行行,当当出出现现多多次次调调用用同同一一内内联联函函数数时时,程程序序本本身身占占用用的的空空间间将将有有所所增增加加。如如上上例例中中,内内联联函函数数仅仅调用一次时,并不增加程序占用的存储间。调用一次时,并不增加程序占用的存储间。250具有缺省参数值和参数个数可变的函数具有缺省参数值和参数个数可变的函数在在C+中定义函数时,允许给参数指定一
131、个缺中定义函数时,允许给参数指定一个缺省的值。省的值。在调用函数时,若明确给出了这种实在调用函数时,若明确给出了这种实参的值,则使用相应实参的值;若没有给出相参的值,则使用相应实参的值;若没有给出相应的实参,则使用缺省的值。(举例说明)应的实参,则使用缺省的值。(举例说明)251intfac(intn=2)intt=1;for(inti=1;i=n;i+)t=t*i;returnt;voidmain(void)coutfac(6)endl;输出:输出:720fac()输出:输出:2252intarea(intlong=4,intwidth=2)returnlong*width;voidmain
132、(void)inta=8,b=6;coutarea(a,b)endl;coutarea(a)endl;coutarea()endl;48168253使用具有缺省参数的函数时,应注意以下几点:使用具有缺省参数的函数时,应注意以下几点:1.不可以靠左边缺省不可以靠左边缺省2.函数原型说明时可以不加变量名函数原型说明时可以不加变量名floatv(float,float=10,float=20);intarea(intlong,intwidth=2)intarea(intlong=4,intwidth)3.只只能能在在前前面面定定义义一一次次缺缺省省值值,即即原原型型说说明明时时定定义义了缺省值,后面
133、函数的定义不可有缺省值。了缺省值,后面函数的定义不可有缺省值。错误!错误!254参数个数可变的函数到目前为止,在定义函数时,都明确规定了函数的参数个数及类型。在调用函数时,实参的个数必须与形参相同。在调用具有缺省参数值的函数时,本质上,实参的个数与形参的个数仍是相同的,由于参数具有缺省值,因此,在调用时可省略。在某些应用中,在定义在某些应用中,在定义函数时,并不能确定函数的参数个数,参数的个数在调时才能确定函数时,并不能确定函数的参数个数,参数的个数在调时才能确定。在C+中允许定义参数个数可变的函数。255首先,必须包含头文件“stdarg.h”,因为要用到里面的三个库函数va_start()
134、、va_arg()和va_end()。其次,要说明一个va_list类型的变量。va_list与int,float类同,它是C+系统预定义的一个数据类型(非float),只有通过这种类型的变量才能从实际参数表中取出可变有参数。如:va_listap;ab.ap(va_list)变量(可变参数)va_start(ap,b):初始化va_arg(ap,int):依次取参数va_end(ap):正确结束256va_start():有两个参数,va_start(ap,b);b即为可变参数前的最后一个确定的参数。va_arg():有两个参数,va_arg(ap,int)int即为可变参数的数据类型名。i
135、nttemp;temp=va_arg(ap,int);va_end():完成收尾工作。va_end(ap);在调用参数个数可变的函数时,必定有一个参数指明可变参数的个数或总的实参个数。如第一个参数值为总的实际参数的个数。257使用参数数目可变的函数时要注意以下几点:1、在定义函数时,固定参数部分必须放在参数表的前面,可变参数在后面,并用省略号“.”表示可变参数。在函数调用时,可以没有可变的参数。2、必须使用函数va_start()来初始化可变参数,为取第一个可变的参数作好准备工作;使用函数va_arg()依次取各个可变的参数值;最后用函数va_end()做好结束工作,以便能正确地返回。3、在调
136、用参数个数可变的函数时,必定有一个参数指明可变参数的个数或总的实参个数。258函数的重载函数的重载所谓函数的重载是指完成不同功能的函数可以具所谓函数的重载是指完成不同功能的函数可以具有有相同的函数名相同的函数名。C+的编译器是根据的编译器是根据函数的实参函数的实参来确定应该调用来确定应该调用哪一个函数的。哪一个函数的。intfun(inta,intb)returna+b;intfun(inta)returna*a;voidmain(void)coutfun(3,5)endl;coutfun(5)endl;8252591、定定义义的的重重载载函函数数必必须须具具有有不不同同的的参参数数个个数数,
137、或或不不同同的的参参数数类类型型。只只有有这这样样编编译译系系统统才才有有可可能能根据不同的参数去调用不同的重载函数。根据不同的参数去调用不同的重载函数。2、仅返回值不同时,不能定义为重载函数。、仅返回值不同时,不能定义为重载函数。即仅函数的类型不同,不能定义为重载函数即仅函数的类型不同,不能定义为重载函数intfun(inta,intb)returna+b;floatfun(inta,intb)return(float)a*a;voidmain(void)coutfun(3,5)endl;coutfun(3,5)x;coutsin(x)endl;coutsin(x,x)endl;coutsi
138、n(x,10)endl;sin(x,x)sin(x,10)不同的参不同的参数类型数类型261intadd(inta,intb,intc)returna+b+c;intadd(inta,intb)returna+b;voidmain(void)cout3+5=add(3,5)endl;cout3+5+8=add(3,5,8)endl;不同的参不同的参数个数数个数262高级语言编译过程高级语言编译过程源程序源程序(文本文件)(文本文件)*.CPP目标文件目标文件(二进制文件二进制文件)*.OBJ可执行文件可执行文件(二进制文件)(二进制文件)*.EXE库文件库文件(各种函数)(各种函数)编译编译连
139、接连接编译预处理编译预处理C语言提供的编译预处理的功能有以下三种:语言提供的编译预处理的功能有以下三种:宏定义宏定义文件包含文件包含条件编译条件编译编译预处理编译预处理263宏定义宏定义不带参数的宏定义不带参数的宏定义用一个指定的标识符(即名字)来代表一个字符串,用一个指定的标识符(即名字)来代表一个字符串,以后凡在程序中碰到这个标识符的地方都用以后凡在程序中碰到这个标识符的地方都用字符串字符串来代替来代替。这个标识符称为这个标识符称为宏名宏名,编译前编译前的替代过程称为的替代过程称为“宏展开宏展开”。#define标识符标识符字符串字符串264#definePRICE30voidmain(v
140、oid)intnum,total;/*定义变量定义变量*/num=10;/*变量赋值变量赋值*/total=num*PRICE;couttotal=“totalendl;编译前用编译前用30替代替代编译程序将宏定义的内容认为是编译程序将宏定义的内容认为是字符串字符串,没有任何,没有任何实际的物理意义。实际的物理意义。2651、宏展开只是一个简单的、宏展开只是一个简单的“物理物理”替换,不做替换,不做语语法检查法检查,不是一个语句,不是一个语句,其后不加分号其后不加分号“;”注意:注意:2、#define命令出现在函数的外面,其有效范围为命令出现在函数的外面,其有效范围为定义处至本源文件结束。可
141、以用定义处至本源文件结束。可以用#undef命令终止宏命令终止宏定义的作用域。定义的作用域。#defineG9.8voidmain(void).#undefGintmax(inta,intb).2663、对程序中用双引号括起来的字符串内容,即使、对程序中用双引号括起来的字符串内容,即使与宏名相同,也不进行置换。与宏名相同,也不进行置换。4、在进行宏定义中,可以用已定义的宏名,进行、在进行宏定义中,可以用已定义的宏名,进行层层置换。层层置换。267#defineR3.0#definePI3.1415926#defineL2*PI*R#defineSPI*R*Rvoidmain(void)cout
142、“L=“L“S=”Sxy;area=S(x,y);/*area=x*y;*/形式参数形式参数实际参数实际参数宏定义宏定义宏调用宏调用定义的宏定义的宏实参代入后还原实参代入后还原269按按#define命令行中指定的字符串从左至右进行置命令行中指定的字符串从左至右进行置换宏名,字符串中的换宏名,字符串中的形参以相应的实参代替形参以相应的实参代替,字符,字符串中的非形参字符保持不变。串中的非形参字符保持不变。#defineS(a,b)a*barea=S(3,2)3*2机械机械地将实参代入地将实参代入宏定义的形参形式宏定义的形参形式S(a,b)等同于等同于a*bS(3,2)等同于等同于3*2270#
143、definePI3.1415926#defineS(r)PI*r*rvoidmain(void)floata,area,b;a=3.6;b=4.0;area=S(a);cout“r=“a“narea=”areaendl;S(r)PI*r*rS(a)PI*a*aPI*a*a编译前机械替换,编译前机械替换,实参形参一一对应实参形参一一对应271#definePI3.1415926#defineS(r)PI*r*rvoidmain(void)floata,area,b;a=1;b=2;area=S(a+b);cout“r=“a“narea=”areaendl;S(r)PI*r*rS(a+b)PI*a
144、+b*a+b编译前机械替换,编译前机械替换,实参形参一一对应实参形参一一对应宏展开时实参不运宏展开时实参不运算,不作语法检查算,不作语法检查#defineS(r)PI*(r)*(r)S(a+b)PI*(a+b)*(a+b)错误错误272定义宏时在宏名与带参数的括弧间不能有空格。定义宏时在宏名与带参数的括弧间不能有空格。#defineS_(r)P*r*r带参数的宏与函数调用的区别带参数的宏与函数调用的区别相同:有实参、形参,代入调用。相同:有实参、形参,代入调用。不同之处:不同之处:1、函数调用先求表达式的值,然后代入形参函数调用先求表达式的值,然后代入形参,而宏只是,而宏只是机机械替换械替换。
145、2、函数调用时形参、实参进行类型定义函数调用时形参、实参进行类型定义,而宏不需要,只,而宏不需要,只是作为是作为字符串替代字符串替代。3、函数调用是在运行程序时进行的,其目标代码短,但程函数调用是在运行程序时进行的,其目标代码短,但程序执行时间长序执行时间长。而宏调用是在编译之前完成的,运行时已。而宏调用是在编译之前完成的,运行时已将代码替换进程序中,目标代码长,执行时间稍快。将代码替换进程序中,目标代码长,执行时间稍快。一般用宏表示实时的、短小的表达式。一般用宏表示实时的、短小的表达式。273#defineA3#defineB(a)(A+1)*a)执行执行x=3*(A+B(7);后,后,x的
146、值为的值为:93#defineneg(x)(-x)+1)intneg(intx)returnx+1;voidmain(void)inty;y=neg(1);cout“y=“yendl;y=0编译前机械替换,编译前机械替换,实参形参一一对应实参形参一一对应(-1)+1)274文件包含文件包含一个源文件可以将另外一个源文件的全部内容包含进来,一个源文件可以将另外一个源文件的全部内容包含进来,即将另外的文件包含到本文件之中。即将另外的文件包含到本文件之中。#include“文件名文件名”file1.cppBA#include“file2.cpp”ABfile1.cppfile2.cpp275注意:注
147、意:1、文件名是、文件名是C的源文件名,是文本文件,后缀名可的源文件名,是文本文件,后缀名可以任选。以任选。*.cpp*.h2、一个、一个#include语句只能指定一个被包含文件。语句只能指定一个被包含文件。3、文件名用双引号或尖括号括起来。、文件名用双引号或尖括号括起来。4、包含后所有源文件编译为一个可执行文件。包含后所有源文件编译为一个可执行文件。276条件编译条件编译C语言允许有选择地对程序的某一部分进行编译。语言允许有选择地对程序的某一部分进行编译。也就是对一部分源程序指定编译条件。也就是对一部分源程序指定编译条件。源程序源程序可以将部分源程序可以将部分源程序不不转换为机器码转换为机
148、器码277条件编译有以下几种形式:条件编译有以下几种形式:1、#ifdef标识符标识符程序段程序段1#else程序段程序段2#endif当标识符已被定义过(用当标识符已被定义过(用#define定义定义),则对程序段,则对程序段1进行编译,进行编译,否则编译程序段否则编译程序段2.#defineDEBUG.#ifdefDEBUGcoutxtyendl;#endif标识符标识符2782、#ifndef标识符标识符程序段程序段1#else程序段程序段2#endif与形式与形式1相反,当标识符没有被相反,当标识符没有被定义过(用定义过(用#define定义定义),则,则对程序段对程序段1进行编译,否
149、则编译进行编译,否则编译程序段程序段2。#defineDEBUG.#ifndefDEBUGcoutxtyendl;#endif调试完后加调试完后加#defineDEBUG,则不输出,则不输出调试信息。调试信息。2793、#if表达式表达式程序段程序段1#else程序段程序段2#endif当表达式为真当表达式为真(非零非零),编译程序段编译程序段1,表达式,表达式为零,编译程序段为零,编译程序段2。#defineDEBUG1.#ifDEBUGcoutxtyendl;#endif调试完后改为调试完后改为#defineDEBUG0,则不输出调试信息。,则不输出调试信息。采用条件编译后,可以使机器代码
150、程序缩短。采用条件编译后,可以使机器代码程序缩短。280以下程序的运行结果是:以下程序的运行结果是:#defineDEBUGvoidmain(void)inta=14,b=15,c;c=a/b;#ifdefDEBUGcout“a=“octa“b=“bendl;#endifcout“c=“deccx1;/从键盘输入从键盘输入x0dox0=x1;x1=x0-(x0*x0-a)/(2*x0);/while(fabs(x1-x0)=1e-6);cout”x=”x1endl;旧值算本次循环的新值旧值算本次循环的新值上一循环的新值成为本次循环的旧值上一循环的新值成为本次循环的旧值2862、弦截法、弦截法f
151、(x)xyx1、在、在x轴上取两点轴上取两点x1和和x2,要确保要确保x1与与x2之间有且只有方程唯一的解之间有且只有方程唯一的解。x1x2f(x1)f(x2)2、x1与与x2分别与分别与f(x)相交于相交于y1=f(x1)、y2=f(x2)。3、做直线通过、做直线通过y1、y2与与x轴交于轴交于x0点。点。x0x2x04、若、若|f(x0)|满足给定的精度,则满足给定的精度,则x0即是方程的解,否则,若即是方程的解,否则,若f(x0)*f(x1)0,则则方程的解应在方程的解应在x2与与x0之间,令之间,令x1=x0,继续,继续做做2,直至满足精度为止。直至满足精度为止。287用两分法求方程的
152、根。用两分法求方程的根。x3-5x2+16x-80=0#includefloatf(floatx)returnx*x*x-5*x*x+16*x-80;floatxpoint(floatx1,floatx2)floatx0;x0=(x1*f(x2)-x2*f(x1)/(f(x2)-f(x1);returnx0;voidmain(void)floatx1,x2,x0,f0,f1,f2;docoutx1x2;f1=f(x1);f2=f(x2);while(f1*f20);dox0=xpoint(x1,x2);f0=f(x0);if(f0*f1)0)x1=x0;f1=f0;elsex2=x0;f2=f
153、0;while(fabs(f0)=0.0001);cout”x=”x0endl;输入输入x,输出,输出f(x)输入输入x1,x2,输出,输出x0判断输入是否合法判断输入是否合法2883、两分法、两分法f(x)xyx1、在、在x轴上取两点轴上取两点x1和和x2,要确保要确保x1与与x2之间有且只有方程之间有且只有方程唯一的解唯一的解。x1x22、求出、求出x1,x2的中点的中点x0。x0x2x03、若、若|f(x0)|满足给定的精度,则满足给定的精度,则x0即是方程的解,否则,即是方程的解,否则,若若f(x0)*f(x1)0,则则方程的解应在方程的解应在x2与与x0之间,令之间,令x1=x0,继
154、续做,继续做2,直至满足精度为止。直至满足精度为止。x0=(x1+x2)/2289用两分法求方程的根。用两分法求方程的根。x3-5x2+16x-80=0#includefloatf(floatx)returnx*x*x-5*x*x+16*x-80;voidmain(void)floatx1,x2,x0,f0,f1,f2;docoutx1x2;f1=f(x1);f2=f(x2);while(f1*f20);dox0=(x1+x2)/2;f0=f(x0);if(f0*f1)0)x1=x0;f1=f0;elsex2=x0;f2=f0;while(fabs(f0)=0.0001);cout”x=”x0
155、endl;输入输入x,输出,输出f(x)判断输入是否合法判断输入是否合法x0=(x1+x2)/2求求x1与与x2的中点的中点290intq(intx)inty=1;staticintz=1;z+=z+y+;returnx+z;voidmain(void)coutq(1)t;coutq(2)t;coutq(3)eps;n+)s+=t;t=n*t/(2*n+1);return_;main()doublex;coutx;cout“=“=10)f(n/10);coutnendl;voidmain(void)f(12345);112123123412345293voidmain(void)chars;c
156、in.get(s);while(s!=n)switch(s-2)case0:case1:couts+4;case2:couts+4;break;case3:couts+3;default:couts+2;break;cin.get(s);coutendl;输入:输入:2347545455555657294第六章第六章数组数组295一维数组的定义和引用一维数组的定义和引用数组是同一类型的一组值(数组是同一类型的一组值(10个个char或或15个个int),在内存中顺序存放在内存中顺序存放。整个数组共用一个名字,而其中的每一项又称整个数组共用一个名字,而其中的每一项又称为一个元素。为一个元素。一、
157、定义方式:一、定义方式:类型说明符类型说明符数组名数组名常量表达式常量表达式;inta4;/表明表明a数组由数组由4个个int型元素组成型元素组成定义类型定义类型数组名称数组名称元素个数元素个数296inta4;/表明表明a数组由数组由4个个int型元素组成型元素组成其元素分别为:其元素分别为:a0,a1,a2,a3其序号从其序号从0开始开始。若存放首地址为。若存放首地址为2000H,则在,则在内存中为:内存中为:a3a2a1a02010H200CH2008H2004H2000HC+不允许对数组的大小作动态的定义,不允许对数组的大小作动态的定义,即即数组的数组的大小不能是变量大小不能是变量,必
158、须是常量,必须是常量。必须是常数必须是常数297如果要根据不同的数值改变数组的大小,可如果要根据不同的数值改变数组的大小,可用常量表达式。如:用常量表达式。如:#defineSIZE50voidmain(void)intartSIZE;.298二、一维数组元素的引用二、一维数组元素的引用数组必须先定义,具体引用时(赋值、运算、输出)其元数组必须先定义,具体引用时(赋值、运算、输出)其元素素等同于变量等同于变量。voidmain(void)inti,a10;for(i=0;i=0;i-)coutait;cout=3)2113853211.f7f6f5f5f4f3f2f1f0fi=fi-1+fi-
159、2voidmain(void)inti;intf20=1,1;for(i=2;i20;i+)fi=fi-1+fi-2;for(i=0;i20;i+)if(i%5=0)cout“n”;coutfit;302下面程序的运行结果是:下面程序的运行结果是:voidmain(void)inta6,i;for(i=1;i3)%5;coutait;iai3440-4随机随机a5a4a3a2a1a0输出:输出:-404431-420344453303排序算法排序算法用起泡法对用起泡法对6个数排序(由小到大)个数排序(由小到大)将相邻的两个数两两比较,将小的调到前头。将相邻的两个数两两比较,将小的调到前头。98
160、5420895420859420854920854290854209第一趟第一趟循环循环5次次584209548209542809第二趟第二趟循环循环4次次854209543089543089453089435089430589第三趟第三趟循环循环3次次304430589340589304589304589第四趟第四趟循环循环2次次034589第五趟第五趟循环循环1次次总结:总结:n次数次数趟数趟数j(1n-1)54321n-j12345共有共有6个数个数for(j=1;j=n-1;j+)for(i=1;iai+1)t=ai;ai=ai+1;ai+1=t;305一般,元素的序号从一般,元素的序
161、号从0开始,因此,程序可以变动如下:开始,因此,程序可以变动如下:for(j=0;jn-1;j+)for(i=0;iai+1)t=ai;ai=ai+1;ai+1=t;306二维数组的定义和引用二维数组的定义和引用一、定义方式:一、定义方式:类型说明符类型说明符数组名数组名常量表达式常量表达式常量表达式常量表达式;inta34;其元素分别为:其元素分别为:a00,a01,a02,a03,a10,a11,a12,a13,a20,a21,a22,a23表明表明a数组由数组由34个个int型元素组成型元素组成定义类型定义类型数组名数组名行数行数列数列数307其行列的序号均其行列的序号均从从0开始开始。
162、若存放首地址为。若存放首地址为2000H,则在内存中为:则在内存中为:a00a01a02a03a10a11 a12a13a20a21a22a232000H2008H2010H 2014H201cH 2020H2028H 202cH即在内存中,多维数组依然是即在内存中,多维数组依然是直线顺序直线顺序排列的,排列的,第第一个元素位于最低地址处。一个元素位于最低地址处。其元素分别为:其元素分别为:a00,a01,a02,a03,a10,a11,a12,a13,a20,a21,a22,a23308二、二维数组的引用二、二维数组的引用与一维数组一样,二维数与一维数组一样,二维数组必须先定义,其维数必组必
163、须先定义,其维数必须是常量。具体引用时须是常量。具体引用时(赋值、运算、输出)其(赋值、运算、输出)其元素等同于变量。元素等同于变量。voidmain(void)inta23,i,j;cout“Input2*3numbersn”;for(i=0;i2;i+)/*输入输入*/for(j=0;jaij;for(i=0;i2;i+)/*输出输出*/for(j=0;j3;j+)coutaijt;cout“n”;输入:输入:123456输出:输出:_1_2_3_4_5_6定义定义赋值赋值输出输出309三、二维数组的初始化三、二维数组的初始化在定义数组的同时给数组元素赋值。即在编译阶段在定义数组的同时给数
164、组元素赋值。即在编译阶段给数组所在的内存赋值。给数组所在的内存赋值。1、分行赋值、分行赋值inta34=1,2,3,4,5,6,7,8,9,10,11,12;2、顺序赋值、顺序赋值inta34=1,2,3,4,5,6,7,8,9,10,11,12;/依次赋值依次赋值3103、部分赋值、部分赋值inta34=1,5,9;/*a00=1,a10=5,a20=9其余元素为其余元素为0*/inta34=0,1,5;/*a00=0,a01=1,a10=5*/1000500090000100500000003114、分行或全部赋值时,分行或全部赋值时,可以省略第一维,第二维可以省略第一维,第二维不可省。不
165、可省。inta4=1,2,5,6,7,8,9,10,11,12;5、不能给数组整体赋值,只能一个一个地赋值。、不能给数组整体赋值,只能一个一个地赋值。6、用、用static定义的数组不赋初值,系统均默认其为定义的数组不赋初值,系统均默认其为0。staticinta23;inta23=1,2,3,.,12;312voidmain(void)inta33,i,j;for(i=0;i3;i+)for(j=0;j3;j+)if(i=2)aij=ai-1ai-1j+1;elseaij=j;coutaijt;cout“n”;i=0a00=0a01=1a02=2i=1a10=0a11=1a12=2a20=a
166、1a10+1=a10+1=1i=2a21=a1a11+1=a11+1=2a22=a1a12+1=a12+1=3输出:输出:_0_1_2_0_1_2_1_2_3313有一个有一个3434的矩阵,要求编程序求出其中值最大的的矩阵,要求编程序求出其中值最大的那个元素的值,以及其所在的行号和列号。那个元素的值,以及其所在的行号和列号。先考虑解此问题的思路。从若干个数中求最大者的先考虑解此问题的思路。从若干个数中求最大者的方法很多,我们现在采用方法很多,我们现在采用“打擂台打擂台”算法。如果有算法。如果有若干人比武,先有一人站在台上,再上去一人与其若干人比武,先有一人站在台上,再上去一人与其交手,败者下
167、台,胜者留台上。第三个人再上台与交手,败者下台,胜者留台上。第三个人再上台与在台上者比,同样是败者下台,胜者留台上。如此在台上者比,同样是败者下台,胜者留台上。如此比下去直到所有人都上台比过为止。最后留在台上比下去直到所有人都上台比过为止。最后留在台上的就是胜者。的就是胜者。314程序模拟这个方法,开始时把程序模拟这个方法,开始时把a00a00的的值赋给变量值赋给变量maxmax,maxmax就是开始时的擂主,就是开始时的擂主,然后让下一个元素与它比较,将二者中然后让下一个元素与它比较,将二者中值大者保存在值大者保存在maxmax中,然后再让下一个元中,然后再让下一个元素与新的素与新的maxm
168、ax比,直到最后一个元素比完比,直到最后一个元素比完为止。为止。maxmax最后的值就是数组所有元素中最后的值就是数组所有元素中的最大值。的最大值。315max=a00;/使使max开始时取开始时取a00的值的值for(i=0;i=2;i+)/从第从第0行到第行到第2行行for(j=0;jmax)/如果某元素大于如果某元素大于maxmax=aij;/max将取该元素的值将取该元素的值row=i;/记下该元素的行号记下该元素的行号icolum=j;/记下该元素的列号记下该元素的列号jcoutrowtcolumtmaxendl;316将数组行列式互换。将数组行列式互换。12345657891472
169、58369for(i=0;i3;i+)for(j=0;j3;j+)t=aij;aij=aji;aji=t;for(i=0;i3;i+)for(j=0;ji;j+)t=aij;aij=aji;aji=t;317打印杨辉三角形打印杨辉三角形11121 2131 33141 4641515101051aij=ai-1j-1+ai-1j318voidmain(void)staticintn2,i,j,k;for(i=0;i2;i+)nj+=ni+i+1;coutnktnk+endl;21319以下程序用于从键盘上输入若干个学生的成绩,统计出平以下程序用于从键盘上输入若干个学生的成绩,统计出平均成绩,并
170、输出低于平均成绩的学生成绩。均成绩,并输出低于平均成绩的学生成绩。输入负数结束输入负数结束voidmain()floatx100,sum=0,ave,a;intn=0,i;couta;ave=sum/n;cout“ave=“aveendl;for(i=0;_;i+)if(_)cout“x“i“”xiaa=0sum+=an+inxix;i=0;while(x)ai=x%8;x=x/8;i+;n=i;for(i=n-1;i=0;i-)coutai;coutx;2536913 25 34 56 7836913 34 56 78x25y25343432336913 34 56 78x25y253434
171、36913 25 56 78x3434y345656324voidmain(void)inta6=1,4,7,10,12;intx;for(inti=0;i5;i+)coutait;coutendl;coutx;for(i=0;ix)break;for(intj=i;j=5;j+)inty=aj;aj=x;x=y;for(i=0;i6;i+)coutait;coutx;25369 132534 56 78326voidmain(void)inta6=1,4,7,10,12;intb6;intx;for(inti=0;i5;i+)coutait;coutendl;coutx;for(i=0;i5
172、;i+)if(aix)bi=ai;elsebreak;bi=x;for(intj=i;j5;j+)bj+1=aj;for(i=0;i6;i+)coutbit;coutx;2578563425for(i=n-1;i=0;i-)从后向前循环从后向前循环328voidmain(void)inta6=2,5,8,10,12;intx;for(inti=0;i5;i+)coutait;coutendl;coutx;for(i=4;i0;i-)if(aix)ai+1=ai;elsebreak;ai+1=x;for(i=0;i6;i+)coutait;coutendl;关键!从后面开始循环关键!从后面开始循
173、环从前向后移数从前向后移数不大于退出循环不大于退出循环赋值赋值329用筛选取法求出用筛选取法求出2200之间的所有素数。之间的所有素数。筛法:首先将筛法:首先将1n个数为数组置初值。个数为数组置初值。2的倍数不的倍数不是素数,置是素数,置0;3的倍数不是素数,置的倍数不是素数,置0;5的倍数不的倍数不是素数,置是素数,置0;.,依次类推,最后将数组中不,依次类推,最后将数组中不是是0的元素输出。的元素输出。23456789 10 11 12 13 14 15 16 17 18 19 20230507090 11 0 13 0 15 0 17 0 19 0230507000 11 0 13 00
174、0 17 0 19 0330数组作为函数参数数组作为函数参数一、数组元素作函数参数一、数组元素作函数参数数组元素作函数实参,用法与一般变量作实参相同,数组元素作函数实参,用法与一般变量作实参相同,是是“值传递值传递”。331有两个数据系列分别为:有两个数据系列分别为:inta8=26,1007,956,705,574,371,416,517;intb8=994,631,772,201,262,763,1000,781;求第三个数据系列求第三个数据系列c,要求,要求c中的数据是中的数据是ab中对应中对应数的最大公约数。数的最大公约数。inta8=26,1007,956,705,574,371,4
175、16,517;intb8=994,631,772,201,262,763,1000,781;c8=2,1,4,3,2,7,8,11332intgys(intm,intn)intr;if(mn)r=m;m=n;n=r;while(r=m%n)m=n;n=r;returnn;voidmain(void)inta8=26,1007,956,705,574,371,416,517;intb8=994,631,772,201,262,763,1000,781;intc8;for(inti=0;i8;i+)ci=gys(ai,bi); /对应元素的公约数对应元素的公约数for(i=0;i8;i+)cout
176、cit;coutendl;求求m,n的最大公约数的最大公约数,作为函数值返回作为函数值返回循环求对应数组元素循环求对应数组元素的最大公约数的最大公约数333二、用数组名作函数参数二、用数组名作函数参数用数组名作函数参数,用数组名作函数参数,实参与形参都应用数组名实参与形参都应用数组名。这时,这时,函数传递的是数组在内存中的地址函数传递的是数组在内存中的地址。在在C+中,数组名被认为是中,数组名被认为是数组在内存中存放的数组在内存中存放的首地址首地址。实参中的数组地址传到形参中,实参形参实参中的数组地址传到形参中,实参形参共用同共用同一段内存一段内存。334voidfun(inta2)for(i
177、nti=0;i2;i+)ai=ai*ai;voidmain(void)intb2=2,4;coutb0tb1endl;fun(b);coutb0tb1endl;24b2000H2004Hb就是就是2000Haa同样为数组首地址,也是同样为数组首地址,也是2000H2000H数组数组b和数组和数组a占据同一段内存占据同一段内存416输出:输出:24416335voidsort(intx,intn)intt,i,j;for(i=0;in-1;i+)for(j=0;jxj+1)t=xj;xj=xj+1;xj+1=t;voidmain(void)inta5=20,4,16,8,10;sort(a,5)
178、;for(inti=0;i5;i+)coutait;20416810ax16108420336有一个一维数组,内放有一个一维数组,内放10个学生成绩,求平均成绩个学生成绩,求平均成绩。voidmain(void)staticfloatscore10=100,90,.;floataver;aver=average(score);cout“aver=“avern;floataverage(floatarray)inti;floataver,sum=array0;for(i=1;i10;i+)sum=sum+arrayi;aver=sum/10;returnaver;数组名作数组名作函数实参函数实参
179、数组名作数组名作函数形参函数形参337注意:注意:1、用数组名作函数参数,应在主调函数和被调函、用数组名作函数参数,应在主调函数和被调函数中分别定义数组,且类型一致。数中分别定义数组,且类型一致。2、需指定实参数组大小,、需指定实参数组大小,形参数组的大小可不指形参数组的大小可不指定定。数组名作实参实际上是传递数组的首地址数组名作实参实际上是传递数组的首地址。3383、C+语言规定,语言规定,数组名代表数组在内存中存储数组名代表数组在内存中存储的首地址的首地址,这样,数组名作函数实参,实际上传,这样,数组名作函数实参,实际上传递的是数组在内存中的首地址。递的是数组在内存中的首地址。实参和形参共
180、占实参和形参共占一段内存单元一段内存单元,形参数组中的值发生变化,也相形参数组中的值发生变化,也相当于实参数组中的值发生变化当于实参数组中的值发生变化。score8score6score4score2score0array8array6array4array2array0scorearray339程序中的函数程序中的函数p()用于计算:用于计算:主函数利用函数完成计算主函数利用函数完成计算intp(inta,intx,intb,inty,intn)inti,s;for(_;in;i+)s+=_;returns;intd=2,3,5,4,9,10,8;intv=7,6,3,2,5,1,8,9,3
181、,4;intw=1,2,3,4,5,6,7,8,9,10;voidmain(void)cout“ns1=“_;cout“ns2=“_;a*xi+b*yii=0,s=0p(1,d,2,v,8)p(3,v,4,w,10)340inta10,i;voidsub1(void)for(i=0;i10;i+)ai=i+i;voidsub2(void)inta10,max,i;max=5;for(i=0;imax;i+)ai=i;voidsub3(inta)inti;for(i=0;i10;i+)coutait;coutendl;voidmain(void)sub1();sub3(a);sub2();sub
182、3(a);输出:输出:024681012141618024681012141618341编写程序,在被调函数中删去一维数组中所有编写程序,在被调函数中删去一维数组中所有相同的数,使之只剩一个,数组中的数已按由相同的数,使之只剩一个,数组中的数已按由小到大的顺序排列,被调函数返回删除后数组小到大的顺序排列,被调函数返回删除后数组中数据的个数。中数据的个数。例如:例如:原数组:原数组:2223445666677899101010删除后:删除后:2345678910342用多维数组名作函数参数用多维数组名作函数参数同样,实参向形参传递的是数组的首地址。同样,实参向形参传递的是数组的首地址。如果实参、
183、形参是二维数组,如果实参、形参是二维数组,则形参可以省略第一维则形参可以省略第一维,不,不可省略第二维,且可省略第二维,且第二维必须与实参中的维数相等第二维必须与实参中的维数相等。intarray10intscore510intarray310intscore510intarray8intscore510错误错误343有一个有一个34的矩阵,求其中的最大元素的矩阵,求其中的最大元素。intmax_value(intarray4)inti,j,k,max;max=array00;for(i=0;i3;i+)for(j=0;jmax)max=arrayij;return(max);voidmain
184、(void)staticinta34=1,3,5,7,2,4,6,8,15,17,34,12;cout“maxis”max_value(a)t;实参实参形参形参函数值函数值数组数组a与数组与数组array共用一段内存共用一段内存344字符数组字符数组用来存放字符数据的数组是字符数组,用来存放字符数据的数组是字符数组,字符数组中字符数组中的一个元素存放一个字符的一个元素存放一个字符。一、字符数组的定义一、字符数组的定义char数组名数组名常量表达式常量表达式;charc4;/*每个元素占一个字节每个元素占一个字节*/c0=I;c1=m;c2=_;类型类型数组名数组名数组大小数组大小345二、字符
185、数组的初始化二、字符数组的初始化与数值数组的初始化相同,取其相应字符的与数值数组的初始化相同,取其相应字符的ASCII值。值。charc10=I,a,m,a,b,o,y;随机随机yobamaIcc0c9346如果字符个数大于数组长度,做错误处理;如果数值个数如果字符个数大于数组长度,做错误处理;如果数值个数小于数组长度,后面的字节全部为小于数组长度,后面的字节全部为0。如果省略数组长度,则字符数即为数组长度。如果省略数组长度,则字符数即为数组长度。staticcharc=I,a,m,a,g,i,r,l;同理,也可定义和初始化一个二维或多维的字符数组。分同理,也可定义和初始化一个二维或多维的字符
186、数组。分层或省略最后一维。层或省略最后一维。charst1=65,66,68;ABD347三、字符数组的引用三、字符数组的引用voidmain(void)charc10=I,a,m,a,b,o,y;inti;for(i=0;i10;i+)coutci;cout“n”;定义定义输出输出348四、字符串和字符串结束标志四、字符串和字符串结束标志C+语言将字符串作为字符数组来处理。语言将字符串作为字符数组来处理。字符串常量:字符串常量:“CHINA”,在机内被处理成一个无在机内被处理成一个无名的字符型一维数组名的字符型一维数组。CHINA 0C+语言中约定用语言中约定用0作为字符串的结束标志,作为字
187、符串的结束标志,它占内存空间,但不计入串长度。它占内存空间,但不计入串长度。有了结束标志有了结束标志0后,程序往往后,程序往往依据它判断字符串是否结依据它判断字符串是否结束束,而不是根据定义时设定的长度,而不是根据定义时设定的长度。349字符串与字符数组的区别:字符串与字符数组的区别:chara=C,H,I,N,A;charc=“CHINA”;随机随机随机随机ANIHC长度占长度占5个个字节字节随机随机0ANIHC长度占长度占6个字节个字节字符数组字符数组字符串字符串350可以用字符串的形式为字符数组赋初值可以用字符串的形式为字符数组赋初值charc=“Iamaboy”;/*长度长度11字节,
188、以字节,以0结结尾尾*/chara=I,a,m,a,b,o,y;/*长度长度10字节字节*/如果数组定义的长度大于字符串的长度,后面均为如果数组定义的长度大于字符串的长度,后面均为0。charc10=“CHINA”;00000ANIHCc0的的ASCII为为0,而而(空格空格)的的ASCII为为32。351charw=T,u,r,b,o,0;Turbo 0charw=“Turbo0”;Turbo 0charw=“Turbo0”;Turbo 0charw=Turbo0;非法非法352chara25=“abcd”,“ABCD”;abcd0ABCD0在在语句中语句中字符数组不能用赋值语句字符数组不能
189、用赋值语句整体赋值整体赋值。charstr12;str=“TheString”;str为字符数组在内存中存储的地址,一经定义,便成为常为字符数组在内存中存储的地址,一经定义,便成为常量,不可再赋值。量,不可再赋值。charstr12=“TheString”;非法,在语句中赋值非法,在语句中赋值定义数组,开辟空定义数组,开辟空间时赋初值间时赋初值353字符数组的输入输出字符数组的输入输出逐逐个个字字符符的的输输入入输输出出。这这种种输输入入输输出出的的方方法法,通通常常是是使使用循环语句来实现的。如:用循环语句来实现的。如:charstr10;cout“输入十个字符:输入十个字符:”;for(i
190、nti=0;istri;/A.A行将输入的十个字符依次送给数组行将输入的十个字符依次送给数组str中的各个元素。中的各个元素。定义定义赋值赋值354把把字字符符数数组组作作为为字字符符串串输输入入输输出出。对对于于一一维维字字符符数数组组的的输输入入,在在cincin中中仅仅给给出出数数组组名名;输输出出时时,在在coutcout中也只给出中也只给出数组名数组名。voidmain(void)chars150,s260;couts1;cins2;cout“ns1=“s1;cout“ns2=“s2“n”;输入:输入:abcdstringcin只能输入一个单只能输入一个单词,不能输入一行词,不能输入
191、一行单词。单词。数组名数组名数组名数组名输出到输出到0为为止止355当要把当要把输入的一行输入的一行作为一个字符串送到字符数组中作为一个字符串送到字符数组中时,则要使用函数时,则要使用函数cin.getline()。这个函数的第一。这个函数的第一个参数为字符数组名,第二个参数为允许输入的最个参数为字符数组名,第二个参数为允许输入的最大字符个数。大字符个数。cin.getline(数组名数组名,数组空间数数组空间数);chars180;.cin.getline(s1,80);首先开辟空间首先开辟空间参数是数组名参数是数组名356voidmain(void)chars381;cout”输入一行字符
192、串输入一行字符串:”;cin.getline(s3,80);/Acout”s3=”s3=a&si=A&si=Z)&word=0)word=1;num+;elseif(si=|si=t)word=0;i+;coutnum=numendl;表明前一字符非字母表明前一字符非字母改变状态,防止继续对改变状态,防止继续对下一字母计数下一字母计数改变状态,碰到下一改变状态,碰到下一个字母时开始计数个字母时开始计数360六、字符串处理函数六、字符串处理函数C中没有对字符串变量进行赋值、合并、比较中没有对字符串变量进行赋值、合并、比较的运算符,但提供了许多的运算符,但提供了许多字符串处理函数字符串处理函数,用
193、户可,用户可以调用以调用#include“string.h”所有字符串处理函数的实参都是所有字符串处理函数的实参都是字符数组名字符数组名3611、合并两个字符串的函数、合并两个字符串的函数strcat(str1,str2)staticcharstr120=“Iama”;staticcharstr2=“boy”;strcat(str1,str2);Iama00b o y 0Iamaboy 0将第二个字符串将第二个字符串str2接到第一个字符串接到第一个字符串str1后。后。注意:第一个字符串要有足够的空间。注意:第一个字符串要有足够的空间。空间足够大空间足够大3622、复制两个字符串的函数、复制
194、两个字符串的函数strcpy(str1,str2)staticcharstr120=“Iama”;staticcharstr2=“boy”;strcpy(str1,str2);00amaIstr10yobstr200a0yobstr1strcpy(str1,“CHINA”);0ANIHCstr1strcpy(“CHINA”,str1);str1=str2; str1=“CHINA”;字符串正确赋值字符串正确赋值均为非法均为非法3633、比较两个字符串的函数、比较两个字符串的函数strcmp(str1,str2)此函数用来比较此函数用来比较str1和和str2中字符串的内容。函数对字符串中字符串
195、的内容。函数对字符串中的中的ASCII字符字符逐个两两比较逐个两两比较,直到遇到不同字符或,直到遇到不同字符或0为止。函数值由两个对应字符相减而得。为止。函数值由两个对应字符相减而得。该函数具有返回值,返回值是两字符串对应的该函数具有返回值,返回值是两字符串对应的第一个第一个不同不同的的ASCII码的差值。码的差值。若两个字符串完全相同,函数值为若两个字符串完全相同,函数值为0。if(strcmp(str1,str2)=0).用来判断两字符用来判断两字符串是否相等串是否相等364staticcharstr120=“CHINA”;staticcharstr2=“CHINB”;coutstrcmp
196、(str1,str2)endl;输出:输出:-1staticcharstr120=“CHINA”;staticcharstr2=“AHINB”;coutstrcmp(str1,str2)endl;输出:输出:2if(str1=str2)cout“yesn”;if(strcmp(str1,str2)=0)cout“yesn”;非法非法正确正确3654、求字符串长度的函数、求字符串长度的函数strlen(str1)长度不包括长度不包括0。函数参数为数组名,返回值为数组首字母到函数参数为数组名,返回值为数组首字母到0的长度。的长度。并非数组在内存中空间的大小。并非数组在内存中空间的大小。chars8
197、0;strcpy(s,“abcd”);coutstrlen(s)endl;输出:输出:400a0yobstr1输出:输出:3coutstrlen(str1)endl;coutsiziof(s)endl;输出:输出:80366charstr120=“CHINA”;coutstrlen(str1)endl;输出:输出:5charsp=“x69082”;coutstrlen(sp)endl;输出:输出:6charsp=“tv0willn”;coutstrlen(sp)endl;输出:输出:3charstr120=“abook”;coutstrlen(str1)endl;输出:输出:13675、str
198、lwr(str1)将将str1中的大写字母转换成小写字母。中的大写字母转换成小写字母。6、strupr(str1)将将str1中的小写字母转换成大写字母。中的小写字母转换成大写字母。3687、函数、函数strncmp(字符串字符串1,字符串字符串2,maxlen)函数原型为函数原型为:intstrncmp(charstr1,charstr2,intm)第三个参数为正整数,它限定了至多比较的字符个数第三个参数为正整数,它限定了至多比较的字符个数若字符串若字符串1或字符串或字符串2的长度小于的长度小于maxlen的值时,函数的的值时,函数的功能与功能与strcmp()相同。相同。当二个字符串的长度
199、均大于当二个字符串的长度均大于maxlen的值时,的值时,maxlen为至为至多要比较的字符个数。多要比较的字符个数。coutstrncmp(“China”,“Chifjsl;kf”,3)n;输出:输出:0369第三个参数为正整数,它限定了至多拷贝的字符个数第三个参数为正整数,它限定了至多拷贝的字符个数若若字符串字符串2的长度小于的长度小于maxlen的值时,函数的功能与的值时,函数的功能与strcpy()相同。相同。当字符串当字符串2的长度大于的长度大于maxlen的值时,的值时,maxlen为至多要拷为至多要拷贝的字符个数。贝的字符个数。8、函数、函数strncpy(字符数组名字符数组名1
200、,字符串字符串2,maxlen)函数原型为函数原型为:voidstrncmp(charstr1,charstr2,intm)370chars90,s190;strncpy(s,abcdssfsdfk,3);/Astrncpy(s1,abcdef,90);/Bcoutsendl;couts1endl;输出:输出:abc输出:输出:abcdef注注意意,二二字字符符串串之之间间不不能能直直接接进进行行比比较较,赋赋值值等等操操作作,这些操作必须通过字符串函数来实现。这些操作必须通过字符串函数来实现。空间足够大空间足够大371输入三个字符串按大小输出。输入三个字符串按大小输出。输入输入n个字符串按大
201、小输出。个字符串按大小输出。372voidchanged(charstr1,charstr2)charstr380;strcpy(str3,str1);strcpy(str1,str2);strcpy(str2,str3);voidmain(void)chars180,s280,s380;cout0)changed(s1,s2);if(strcmp(s1,s3)0)changed(s1,s3);if(strcmp(s2,s3)0)changed(s2,s3);coutsorted:endlendl;couts1endls2endls3endl;373voidchanged(charstr1,c
202、harstr2)charstr380;strcpy(str3,str1);strcpy(str1,str2);strcpy(str2,str3);voidmain(void)charss1080;inti,j;coutInput10strings:n;for(i=0;i10;i+)cin.getline(ssi,80);for(i=0;i9;i+)for(j=0;j0)changed(ssj,ssj+1);coutsorted:endlendl;for(i=0;i10;i+)coutssiendl;374用用选择法对选择法对6个数排序(由小到大)个数排序(由小到大)设定一个变量,放入数组中的最
203、小数的设定一个变量,放入数组中的最小数的序号序号,然后将其与,然后将其与最上面的数比较交换。最上面的数比较交换。024589a6a5a4a3a2a12、amin与与a2比较比较1min1、min=13、min=22min4、amin与与a3比较比较024589a6a5a4a3a2a1即即9与与8比较比较假定元素假定元素序号序号为为1的数是最的数是最小的数小的数这时,最小数这时,最小数的序号变为的序号变为2即即8与与5比较比较375024589a6a5a4a3a2a1amin与与a4比较比较3minmin=3min=44minamin与与a5比较比较024589a6a5a4a3a2a102458
204、9a6a5a4a3a2a1amin与与a6比较比较5minmin=5min=66minamin与与a1交换交换924580a6a5a4a3a2a1第一趟,循环第一趟,循环5次次这时,最小数这时,最小数的序号变为的序号变为3即即5与与4比较比较这时,最小数这时,最小数的序号变为的序号变为4即即4与与2比较比较这时,最小数这时,最小数的序号变为的序号变为5第一趟比较完毕,第一趟比较完毕,最小数是最小数是a6,最小,最小数的序号为数的序号为6376924580a6a5a4a3a2a1amin与与a3比较比较2minmin=2min=33minamin与与a4比较比较924580a6a5a4a3a2a
205、1924580a6a5a4a3a2a1amin与与a5比较比较4minmin=4min=55minamin与与a6比较比较924580a6a5a4a3a2a1从第二个数开始从第二个数开始比较,假定最小比较,假定最小数的序号为数的序号为2377984520a6a5a4a3a2a1amin与与a2交换交换5minmin=5第二趟,循环第二趟,循环4次次第二趟比较完毕,第二趟比较完毕,最小数是最小数是a5,最小,最小数的序号为数的序号为5378984520a6a5a4a3a2a1amin与与a4比较比较3minmin=3min=44minamin与与a5比较比较984520a6a5a4a3a2a19
206、84520a6a5a4a3a2a1amin与与a6比较比较4minmin=4min=44minamin与与a3交换交换985420a6a5a4a3a2a1第三趟,循环第三趟,循环3次次379985420a6a5a4a3a2a1amin与与a5比较比较4minmin=4min=44minamin与与a6比较比较985420a6a5a4a3a2a1985420a6a5a4a3a2a1amin与与a4交换交换4minmin=4第四趟,循环第四趟,循环2次次380985420a6a5a4a3a2a1amin与与a6比较比较5minmin=5min=55minamin与与a5交换交换985420a6a5
207、a4a3a2a1第五趟,循环第五趟,循环1次次总结:总结:n次数次数趟数趟数i(1n-1)54321n-i12345共有共有6个数个数for(i=1;i=n-1;i+)min=i;for(j=i;jaj)min=j;t=amin;amin=ai;ai=t;381一般,元素的序号从一般,元素的序号从0开始,因此,程序可以变动如下:开始,因此,程序可以变动如下:for(i=0;in-1;i+)min=i;for(j=i;jaj)min=j;t=amin;amin=ai;ai=t;小循环,找最小循环,找最小数的序号,小数的序号,从从i找起找起大循环,找到大循环,找到后与后与i交换交换每一次循环前设每
208、一次循环前设置最小数的序号置最小数的序号382调试程序的方法:调试程序的方法:1)单步调试:以行为单位,每运行一步,程序就会中断,)单步调试:以行为单位,每运行一步,程序就会中断,可以实时查询目前各变量的状态及程序的走向。可以实时查询目前各变量的状态及程序的走向。可以选择可以选择是否进入子函数是否进入子函数。2)运行到光标处运行到光标处,可以直接使程序运行到,可以直接使程序运行到光标处光标处再进行再进行单步调试,这种方法可以不必运行正确的循环而直接到有单步调试,这种方法可以不必运行正确的循环而直接到有疑问的地方。疑问的地方。383在在a数组中查找与数组中查找与x值相同的元素所在的位置,数据从值
209、相同的元素所在的位置,数据从a1元素开始存放,请填空:元素开始存放,请填空:#defineMAX10voidmain(void)intaMAX+1,x,i;for(i=1;i_;coutx;a0=x;i=MAX;while(x!=_)_;if(_)coutx“thepos:”iendl;elsecout“Notfound”endl;aiaii-i!=0384voidmain(void)charstr=“SSSWILTECH1111W1WALLMP1”;charc;intk;for(k=2;(c=strk)!=0;k+)switch(c)caseA:couta;continue;case1:br
210、eak;case1:while(c=str+k)!=1&c!=0);case9:cout#;caseE:caseL:continue;default:coutc;continue;cout*;coutendl;S W I T C H * # W a M P *385以下程序分别在以下程序分别在a数组和数组和b数组中放入数组中放入an+1和和bn+1个由小到大的有个由小到大的有序数,程序把两个数组中的数按由小到大的顺序归并到序数,程序把两个数组中的数按由小到大的顺序归并到c数组中,数组中,请填空:请填空:voidmain(void)inta10=1,2,5,8,9,10,an=5;intb10=
211、1,3,4,8,12,18,bn=5;inti,j,k,c20,max=9999;aan+1=ban+1=max;i=j=k=0;while(ai!=max|bj!=max)if(aibj)ck=_;k+;_elseck=_;k+;_;for(i=0;ik;i+)coutci;coutstudent1;student1;cincinstudent1.num; student1.num=100;student1.num; student1.num=100;可以将一个结构体变量可以将一个结构体变量整体整体赋给另外一个相同类型的结构赋给另外一个相同类型的结构体变量。体变量。 student2=stu
212、dent1;student2=student1;2 2、嵌套的结构体变量必须逐层引用。、嵌套的结构体变量必须逐层引用。student1.student1.birthday.birthday.dayday=25;=25;3 3、结构体变量中的成员可以同一般变量一样进行运算。、结构体变量中的成员可以同一般变量一样进行运算。student1.birthday.day+; student1.birthday.day+; student1.score+=60;student1.score+=60;错误错误必须用成员名引用必须用成员名引用397对局部变量类型的结构体变量初始化对局部变量类型的结构体变量初始
213、化voidmain(void)structstudentlongintnum;charname20;charsex;charaddr30;student1=901031,“LiLin”,M,“123BeijingRoad”;coutstudent1.nameendl;输出:输出:LiLin对变量初始化,一一赋值对变量初始化,一一赋值398关于结构类型变量的使用,说明以下几点关于结构类型变量的使用,说明以下几点: :1 1、同类型的结构体变量之间可以直接赋值。这种、同类型的结构体变量之间可以直接赋值。这种赋值等同于各个成员的依次赋值。赋值等同于各个成员的依次赋值。 2 2、结结构构体体变变量量不
214、不能能直直接接进进行行输输入入输输出出,它它的的每每一一个个成成员员能能否否直直接接进进行行输输入入输输出出,取取决决于于其其成成员员的的类类型型,若若是是基基本本类类型型或或是是字字符符数数组组,则则可可以以直直接接输输入入输出。输出。3 3、结结构构体体变变量量可可以以作作为为函函数数的的参参数数,函函数数也也可可以以返返回回结结构构体体的的值值。当当函函数数的的形形参参与与实实参参为为结结构构体体类类型型的的变变量量时时,这这种种结结合合方方式式属属于于值值调调用用方方式式,即即属属于值传递。(举例说明)于值传递。(举例说明)399结构体数组结构体数组结构体数组中的结构体数组中的每个元素
215、都是一个结构体类型的变每个元素都是一个结构体类型的变量量,其中包括该类型的各个成员。数组各元素在内,其中包括该类型的各个成员。数组各元素在内存中连续存放。存中连续存放。400一、结构体数组的定义一、结构体数组的定义structstudentintnum;charname20;charsex;intage;floatscore;charaddr30;structstudentstu30;structstudentintnum;charname20;charsex;intage;floatscore;charaddr30;stu30;直接定义直接定义401二、结构体数组的初始化二、结构体数组的初始
216、化structstudentintnum;charname20;charsex;stu3=1011,LiLin,M,1012,WangLan,F,1013,LiuFang,F;402structstudentintnum;charname20;charsex;stu=1011,LiLin,M,1012,WangLan,F,1013,LiuFang,F;403以下程序的结果是:以下程序的结果是:voidmain(void)structdateintyear,month,day;today;coutsizeof(structdate)endl;12404根据下面的定义,能打印出字母根据下面的定义,
217、能打印出字母M的语句是:的语句是:structpersoncharname9;intage;structpersonclass10=“Jone”,17,“Paul”,19,“Mary”,18,“Adam”,16;A)coutclass3.nameendl;B)coutclass3.name1endl;C)coutclass2.name1endl;D)coutclass2.name0endl;输出:输出:Adam输出:输出:d输出:输出:a输出:输出:M405结构体类型的静态成员当当把把结结构构体体类类型型中中的的某某一一个个成成员员的的存存储储类类型型定定义义为为静静态态时时,表表示示在在这这
218、种种结结构构类类型型的的所所有有变变量量中中,编编译译程程序序为为这这个个成成员员只只分分配配一一个个存存储储空空间间,即即这这种种结结构构体体类类型型的的所所有有变变量量共共同同使使用用这这个个成成员员的的存存储空间储空间。 :;其中类型要与在结构体中定义该成员的类型一致,结构体类型名其中类型要与在结构体中定义该成员的类型一致,结构体类型名指明静态成员属于哪一个结构体指明静态成员属于哪一个结构体。structsstaticintid;inteng;ints:id=50;这时,未定义结构体变量,这时,未定义结构体变量,但已将静态成员的空间安但已将静态成员的空间安排好排好。数据类型结构体类型若有
219、定义:ss1,s2;则变量s1,s2的id成员占用同一存储空间(静态区)。406在结构体中说明的静态成员属于引用性说明,必须在文件作用域中的某一个地方对静态的成员进行定义性说明,且仅能说明一次。ints:id;说明id的初值为0(静态变量的缺省初值均为静态变量的缺省初值均为0)407共用体共用体C+语言中,允许语言中,允许不同的数据类型使用不同的数据类型使用同一存储区域同一存储区域,即,即同一存储区域由不同类型的变量共同表示。这种数据类型同一存储区域由不同类型的变量共同表示。这种数据类型就是共用体。就是共用体。union共用体名共用体名成员表列;成员表列;变量表列;变量表列;uniondata
220、inti;charch;floatf;a,b,c;uniondataa,b,c;这几个成员在共用体变量中存放在同一地址,相互覆盖,这几个成员在共用体变量中存放在同一地址,相互覆盖,其长度为最长的成员的长度其长度为最长的成员的长度。408共用体变量的引用共用体变量的引用不能整体引用共用体变量,只能引用变量中不能整体引用共用体变量,只能引用变量中的成员。的成员。a.i表示为整型表示为整型a.ch表示为字符型表示为字符型a.f表示为符点型表示为符点型409共用体变量的特点共用体变量的特点1、共用体的空间在某一时刻只有一个成员在起作、共用体的空间在某一时刻只有一个成员在起作用。用。2、共用体变量中的成
221、员是最后一次放入的成员。、共用体变量中的成员是最后一次放入的成员。3、共用体变量不能在定义时赋初值。、共用体变量不能在定义时赋初值。4、共用体变量不能作为函数的参数或函数值,但、共用体变量不能作为函数的参数或函数值,但可使用指向共用体的指针变量。可使用指向共用体的指针变量。5、共用体可以作为结构的成员,结构体也可以作、共用体可以作为结构的成员,结构体也可以作为共用体的成员。为共用体的成员。410unionuninti;doubley;structstchara10;unionunb;coutsizeof(structst)endl;18411unionunshortinta;charc2;w;
222、w.c0=A;w.c1=a;coutoctw.aendl;低字节低地址低字节低地址高字节高地址高字节高地址aAw.c1w.c02000H2001H输出:输出:0605010 1 1 0 0 0 0 1 0 1 0 0 0 0 0 1a65?56?652000H2001H412voidmain(void)unionEXAMPLEstructintx,inty;in;inta,b;e;e.a=1;e.b=2;e.in.x=e.a*e.a;e.in.y=e.b+e.b;coute.in.xte.in.ysun)6、枚举值可以进行加减一个整数、枚举值可以进行加减一个整数n的运算,得到其前后第的运算,得
223、到其前后第n个元素的值。个元素的值。workday=sun;workday=(week)(workday+2);workday=tue7、枚举值可以按整型输出其序号值。、枚举值可以按整型输出其序号值。workday=tue;coutworkday;2417voidmain(void)enumteamqiaut,cubs=4,pick,dodger=qiaut-2;coutqiauttcubst;coutpicktdodgeri;实际上放到定义实际上放到定义i单元单元的的地址中地址中。2、间接访问、间接访问将变量的地址存放在另一个单元将变量的地址存放在另一个单元p中中,通过,通过p取出变量的地取
224、出变量的地址,再针对变量操作。址,再针对变量操作。一个变量的地址称为该变量的指针。一个变量的地址称为该变量的指针。如果在程序中定义了一个变量或数组,那么,这个变量或如果在程序中定义了一个变量或数组,那么,这个变量或数组的地址(指针)也就确定为一个数组的地址(指针)也就确定为一个常量常量。ii2000H2000H3000Hp421变量的变量的指针指针和指向变量的和指向变量的指针变量指针变量变量的指针就是变量的指针就是变量的地址变量的地址,当变量定义后,其指针(地当变量定义后,其指针(地址)是一常量。址)是一常量。可以可以定义一个变量定义一个变量专门用来专门用来存放存放另一变量的另一变量的地址地址
225、,这种,这种变量我们称之为变量我们称之为指针变量指针变量。在编译时同样分配一定字节的。在编译时同样分配一定字节的存储单元,未赋初值时,该存储单元内的值是存储单元,未赋初值时,该存储单元内的值是随机随机的。的。指针变量定义的一般形式为:指针变量定义的一般形式为:类型标识符类型标识符*变量名变量名int*i_point;i2000Hinti;&i:2000H指针类型指针类型变量名变量名422指针指针变量变量同样也可以赋值:同样也可以赋值:inti,*i_point;i_point=&i;也可以在定义也可以在定义指针变量指针变量时赋初值:时赋初值:inti;int*i_point=&i;*在在定义语
226、句定义语句中只表示变量的类型是指针,没有任何计算中只表示变量的类型是指针,没有任何计算意义。意义。*在语句中表示在语句中表示“指向指向”。&表示表示“地址地址”。一个指针变量只能指向同一类型的变量一个指针变量只能指向同一类型的变量。即整型指针变量。即整型指针变量只能放整型数据的地址,而不能放其它类型数据的地址。只能放整型数据的地址,而不能放其它类型数据的地址。3000Hi_point2000Hi2000H4232000H2000H3000Hi_pointinti;int*i_point=&i;*i_point=3;表示表示指向指向表示表示类型类型i3424指针变量的引用指针变量的引用指针变量只
227、能指针变量只能存放地址存放地址,不要将非地址数据赋给指针变量。,不要将非地址数据赋给指针变量。int*p,i;p=100;p=&i;voidmain(void)inta=10,b=100;int*p1,*p2;p1=&a;p2=&b;coutatbendl;cout*p1t*p2endl;10010bap1p2&b&a非法非法指针变量赋值指针变量赋值指针变量引用指针变量引用1010010100表示表示指向指向425voidmain(void)inta,b;int*p1,*p2;p1=&a;p2=&b;*p1=10;*p2=100;coutatbendl;cout*p1t*p2endl;bap1
228、p2&b&a10010通过指针对通过指针对变量赋值变量赋值指针变量赋值指针变量赋值指针变量引用指针变量引用426voidmain(void)inta,b;int*p1,*p2;*p1=10;*p2=100;coutatbendl;cout*p1t*p2ab;p1=&a;p2=&b;if(ab)p=p1;p1=p2;p2=p;coutatbendl;cout*p1t*p2ab;point1=&a;point2=&b;if(ab)swap(point1,point2);cout“a=“a“,b=”bendl;cout*point1“,”*point2ab;point1=&a;point2=&b;i
229、f(ab)swap(a,b);cout“a=“a“,b=”bn;cout*point1t*point2;swap(intx,inty)intt;t=x;x=y;y=t;x10y100t10a10point1&ab100point2&b10010x=100y=10输出:输出:a=10,b=10010,100值传递值传递435用指针变量作函数参数,在被调函数的执行用指针变量作函数参数,在被调函数的执行过程中,过程中,应使指针变量所指向的参数值发生应使指针变量所指向的参数值发生变化,变化,这样,函数在调用结束后,其变化值这样,函数在调用结束后,其变化值才能保留回主调函数。才能保留回主调函数。用指针变
230、量作函数参数,可以得到多个变化用指针变量作函数参数,可以得到多个变化了的值。了的值。函数调用函数调用不能改变实参指针变量的值,但不能改变实参指针变量的值,但可可以改变实参指针变量所指向变量的值以改变实参指针变量所指向变量的值。436voidgrt(int*x,int*y,int*z)cout+*x,+*y,*(z+)endl;inta=10,b=40,c=20;voidmain(void)prt(&a,&b,&c);prt(&a,&b,&c);x&aa10+*x:*(z+):11,41,2012,42,20*x=*x+1*z;z=z+1437voidmain(void)inta=0,i,*p,
231、sum;for(i=0;i*p;sum=s(p);cout“sum=”sumendl;输入:输入:135sum=11sum=13sum=15p&aa1p&asum10sumints(int*p)intsum=10;sum=sum+*p;returnsum;1111438sub(int*s)staticintt=0;t=*s+t;returnt;voidmain(void)inti,k;for(i=0;i4;i+)k=sub(&i);cout“sum=“kt;cout“n”;i=0 t=*s+t=0 k=0sum=0i=1 t=*s+t=1 k=1sum=1i=2 t=*s+t=3 k=3sum
232、=3i=3 t=*s+t=6 k=6sum=6sum=0sum=1sum=3sum=6439int*p;voidmain(void)inta=1,b=2,c=3;p=&b;pp(a+c,&b);cout“(1)”ab*pendl;pp(inta,int*b)intc=4;*p=*b+c;a=*p-c;cout“(2)”a*b*pendl;*p=*b+4=2+4=6a=6-c=2(2)266(1)166b2p&bb&ba4440举例:最大最小值、方程根举例:最大最小值、方程根441数组的数组的指针指针和指向数组的和指向数组的指针变量指针变量数组与变量一样,在内存中占据单元,有地数组与变量一样,在
233、内存中占据单元,有地址,一样可以用指针来表示。址,一样可以用指针来表示。C+规定:规定:数组数组名就是数组的起始地址名就是数组的起始地址;又规定:;又规定:数组的指数组的指针就是数组的起始地址针就是数组的起始地址。数组元素的指针就。数组元素的指针就是数组元素的地址。是数组元素的地址。442一、指向数组元素的指针变量的定义与赋值一、指向数组元素的指针变量的定义与赋值inta10,*p;p=&a0;p=a;p是变量,是变量,a为常量。为常量。2024H2020H201CH2018H2014H2010H200CH2008H2004H2000Ha9a8a7a6a5a4a3a2a1a0ap&a0若数组元
234、素为若数组元素为int型,则指向其的指针变型,则指向其的指针变量也应定义为量也应定义为int型。型。inta10;int*p=a;int*p=&a0;数组第一个元素的地址数组第一个元素的地址直接用数组名赋值直接用数组名赋值这两种情况均为赋初值这两种情况均为赋初值443二、通过指针引用数组元素二、通过指针引用数组元素inta10;int*p=a;2024H2020H201CH2018H2014H2010H200CH2008H2004H2000Ha9a8a7a6a5a4a3a2a1a0ap&a0*p=1;a0=1;1C+C+规定,规定,p+1p+1指向数组的指向数组的下一下一个元素个元素,而不是下
235、一个字节。而不是下一个字节。*(p+1)=2;a1=2;2*+p=2;p=p+1;*p=2;p=2004H为指针变量赋初值为指针变量赋初值通过指针变量为通过指针变量为数组元素赋值数组元素赋值指针变量也重新赋值指针变量也重新赋值444*(a+1)=2;*(a+1)与与a1等同。等同。*+a=2;a为常量,不可赋值。为常量,不可赋值。p+i或或a+i均表示均表示ai的地址的地址&ai2024H2020H201CH2018H2014H2010H200CH2008H2004H2000Ha9a8a7a6a5a4a3a2a1a0ap&a012*(p+1)=2;a1=2;*+p=2;错误错误*(a+i)ai
236、*(p+i)pip=p+1;*p=2;p=2004H445用用指向数组的指针变量指向数组的指针变量输出数组的全部元素输出数组的全部元素voidmain(void)inta10,i;int*p;for(i=0;iai;for(p=a;pa+10;p+)cout*pt;voidmain(void)inta10,i;int*p=a;for(i=0;iai;for(i=0;i10;i+)cout*p+t;输入数组元素输入数组元素指针变量赋初值指针变量赋初值指向下一元素指向下一元素输出指针指向的数据输出指针指向的数据*p,p=p+1输出数据后指针加输出数据后指针加1446voidmain(void)in
237、tx=1,2,3;ints,i,*p;s=1;p=x;for(i=0;i3;i+)s*=*(p+i);coutsendl;6321xpi=0s=s*(*(p+0) =s*1=1i=1s=s*(*(p+1) =s*2=2i=2s=s*(*(p+2) =s*3=6p+1p+2447staticinta=1,3,5,7,11,13;main()int*p;p=a+3;cout*pt(*p+)endl;cout*(p-2)t*(a+4)endl;11751113571113a0a1a2a3a4a5p&a3448三、数组名作函数参数三、数组名作函数参数数组名可以作函数的实参和形参,传递的是数组名可以作函
238、数的实参和形参,传递的是数组的数组的地址地址。这样,。这样,实参、形参共同指向同一段内存单元实参、形参共同指向同一段内存单元,内存单元中的数据发生变化,这种变化会反应到主内存单元中的数据发生变化,这种变化会反应到主调函数内。调函数内。在函数调用时,在函数调用时,形参数组并没有另外开辟新的存储形参数组并没有另外开辟新的存储单元单元,而是以实参数组的首地址作为形参数组的首,而是以实参数组的首地址作为形参数组的首地址。地址。这样形参数组的元素值发生了变化也就使实这样形参数组的元素值发生了变化也就使实参数组的元素值发生了变化参数组的元素值发生了变化。449voidmain(void)intarray1
239、0;.f(array,10);.f(intarr,intn).实参数组实参数组形参数组形参数组,必须进行类型说明必须进行类型说明用数组名作形参,因为接收的是地址,用数组名作形参,因为接收的是地址,所以可以不指定具体的元素个数。所以可以不指定具体的元素个数。1、形参实参都用数组名、形参实参都用数组名4502028H2024H2020H201CH2014H2010H200CH2008H2004H2000Harray9array8array7array6array5array4array3array2array1array0array,arrarr0指向同一指向同一存储区间存储区间4512、实参用数
240、组名,形参用指针变量、实参用数组名,形参用指针变量voidmain(void)inta10;.f(a,10);.f(int*x,intn).实参数组实参数组形参指针形参指针4523、形参实参都用指针变量、形参实参都用指针变量voidmain(void)inta10,*p;p=a;.f(p,10);.f(int*x,intn).实参指针实参指针形参指针形参指针实参指针变量调用前必须赋值实参指针变量调用前必须赋值4534、实参为指针变量,形参为数组名、实参为指针变量,形参为数组名voidmain(void)inta10,*p;p=a;.f(p,10);.f(intx,intn).实参指针实参指针形
241、参数组形参数组454将数组中的将数组中的n个数按相反顺序存放。个数按相反顺序存放。voidinv(intx,intn)intt,i,j,m=(n-1)/2;for(i=0;i=m;i+)j=n-1-i;t=xi;xi=xj;xj=t;voidmain(void)inti,a10=3,7,9,11,0,6,7,5,4,2;inv(a,10);for(i=0;i10;i+)coutait;245760119x9x8x7x6x5x4x3x2x1x0a9a8a7a6a5a4a3a2a1a0x,a37x与与a数组指向同数组指向同一段内存一段内存455voidinv(int*x,intn)int*p,t,
242、*i,*j,m=(n-1)/2;i=x;j=x+n-1;p=x+m;for(;i=p;i+,j-)t=*i;*i=*j;*j=t;voidmain(void)inti,a10=3,7,9,11,0,6,7,5,4,2;inv(a,10);for(i=0;i10;i+)coutait;用指针变量来用指针变量来接受地址接受地址245760119x9x8x7x6x5x4x3x2x1x0a9a8a7a6a5a4a3a2a1a0x,a37ijp456输入输入1010个整数,将其中最小的数与第一个数个整数,将其中最小的数与第一个数对换,把最大的数与最后一个数对换。写对换,把最大的数与最后一个数对换。写3
243、3个个函数:函数:输入输入1010个数;个数;进行处理;进行处理;输出输出1010个数。个数。457编写函数编写函数intfun(intx,int*pp),其功能是,求出其功能是,求出能整除能整除x且不是偶数的各整数,并按照从小到大的且不是偶数的各整数,并按照从小到大的顺序放在顺序放在pp指向的内存中,函数返回值为这些整指向的内存中,函数返回值为这些整数的个数。数的个数。若若x的值为的值为30,数组中的数为数组中的数为1,3,5,15,函数返回,函数返回4。458intfun(intx,int*pp)intk=0;for(inti=1;ix;n=fun(x,a);for(inti=0;in;i
244、+)coutait;cout=a&*pchar=z)*pchar=*pchar-32;pchar+;if(*pchar=0)break;pchar+;voidmain(void)charstr100;cin.getline(str,100);change(str);coutstrendl;461数组名作函数参数数组名作函数参数数组名可以作函数的实参和形参,传递的是数组名可以作函数的实参和形参,传递的是数组的数组的地址地址。这样,。这样,实参、形参共同指向同一段内存单元实参、形参共同指向同一段内存单元,内存单元中的数据发生变化,这种变化会反应到主内存单元中的数据发生变化,这种变化会反应到主调函数
245、内。调函数内。在函数调用时,在函数调用时,形参数组并没有另外开辟新的存储形参数组并没有另外开辟新的存储单元单元,而是以实参数组的首地址作为形参数组的首,而是以实参数组的首地址作为形参数组的首地址。地址。这样形参数组的元素值发生了变化也就使实这样形参数组的元素值发生了变化也就使实参数组的元素值发生了变化参数组的元素值发生了变化。462既然数组做形参没有开辟新的内存单元,接受的只既然数组做形参没有开辟新的内存单元,接受的只是实参数组的首地址,那么,这个首地址也可以在是实参数组的首地址,那么,这个首地址也可以在被调函数中用一个被调函数中用一个指针变量指针变量来接受,通过在被调函来接受,通过在被调函数
246、中对这个数中对这个指针变量的指针变量的指向指向进行操作而使实参数组进行操作而使实参数组发生变化。发生变化。ap实参实参,在主调函在主调函数开辟的空间数开辟的空间形参形参,用指针变用指针变量来接受地址量来接受地址实际上在被调函数中只开辟了实际上在被调函数中只开辟了p的空间,里面放的是的空间,里面放的是a的值。的值。463四、指向多维数组的指针和指针变量四、指向多维数组的指针和指针变量用指针变量也可以指向多维数组,表示的同样是多维数组用指针变量也可以指向多维数组,表示的同样是多维数组的首地址。的首地址。inta34;/首地址为首地址为2000Ha23a22a21a20a13a12a11a10a03
247、a02a01a00200CH2008H2004H2000Haa2a1a02000H2010H2020H可以将可以将a数组看作一个一维数组,这个一维数组的数组看作一个一维数组,这个一维数组的每个元素每个元素又是一个具有又是一个具有4个个int型数据的一维数组型数据的一维数组,这样,这样,我们就可我们就可以利用一维数组的概念来以利用一维数组的概念来标记标记一些写法。一些写法。a00a01a02a03a10a11 a12a13a20a21a22a232000H2008H2010H 2014H201cH 2020H2028H 202cH464a0=*(a+0)a+0为为a0的地址的地址&a0,其值为,
248、其值为2000H。a1=*(a+1)a+1为为a1的地址的地址&a1,其值为,其值为2010H。a2=*(a+2)a+2为为a2的地址的地址&a2,其值为,其值为2020H。a23a22a21a20a13a12a11a10a03a02a01a00200CH2008H2004H2000Haa2a1a02000H2010H2020Ha0为一维数组名为一维数组名,其数组有四个,其数组有四个int型的元素:型的元素:a00,a01,a02,a03同样,同样,a0代表一维数组的首地址,所以,代表一维数组的首地址,所以,a0为为&a00。465a23a22a21a20a13a12a11a10a03a02a
249、01a00200CH2008H2004H2000H2020H2010H2000Haa2a1a0a0代表一维数组的首地址代表一维数组的首地址,也就是也就是一维数组名一维数组名,a0为为&a00。a0为为&a00a00=*(a0+0)b0=*(b+0)a0+1为为&a01a01=*(a0+1)b1=*(b+1)a0+2为为&a02a02=*(a0+2)b2=*(b+2)a0+3为为&a03a03=*(a0+3)b3=*(b+3)a1+2为为&a12a12=*(a1+2)行行列列把把a0看成看成一维数组一维数组baij=*(ai+j)466a为二维数组名为二维数组名,a+1为为a1的的地址地址,也就
250、是数组第,也就是数组第一行的地址,所以一行的地址,所以a为为行指针行指针。a1为一维数组名为一维数组名,a1+1为为a11的的地址地址,也就是,也就是数组第一行第一列的地址,所以数组第一行第一列的地址,所以a1为为列指针列指针。a23a22a21a20a13a12a11a10a03a02a01a00200CH2008H2004H2000H2020H2010H2000Haa2a1a0a1+2为为&a12a12=*(a1+2)行行列列aij=*(ai+j)467可以看到:可以看到:a,a+0,*(a+0),a0,&a00表示的都表示的都是是2000H,即二维数组的首地址。,即二维数组的首地址。实际
251、上,实际上,a0,a1,a2并不是并不是实际的元素实际的元素,它们在,它们在内存内存并不占具体的存储单元并不占具体的存储单元,只是为了我们表示方,只是为了我们表示方便起见而设计出的一种表示方式。便起见而设计出的一种表示方式。a为行指针,加为行指针,加1移动一行。移动一行。*a或或a0为列指针,加为列指针,加1移动一列。移动一列。a23a22a21a20a13a12a11a10a03a02a01a00200CH2008H2004H2000H2020H2010H2000Haa2a1a0468a1=*(a+1)*(a+1)+2=&a12*(*(a+1)+2)=a12*(a+1)=*(a1)=*(*(
252、a+1)+0)=a10(*(a+1)1=*(*(a+1)+1)=a11*(a+1)1=*(a+1)1)=*(*(a+1)+1)=*(a+2)=a20注意二维数组的各种表示法,注意二维数组的各种表示法,a为常量。为常量。a23a22a21a20a13a12a11a10a03a02a01a00200CH2008H2004H2000H2020H2010H2000Haa2a1a0469inta34=1,3,5,7,9,11,13,15,17,19,21,23;设数组的首地址为设数组的首地址为1900H,则:,则:a为为_*a为为_a+2为为_*a+2为为_*(a+1)+2为为_*a为为_*(*a+9)
253、为为_(a+1)1为为_1908H1900H1920H1900H1918H1191920Ha23a22a21a20a13a12a11a10a03a02a01a00190CH1908H1904H1900H1920H1910H1900Haa2a1a0470voidmain(void)staticinta34=1,3,5,7,9,11,13,15,17,19,21,23;int*p;for(p=a0;pa0+12;p+)if(p-a0)%4=0)coutendl;cout*pt;a00a01a02a03a10a11a12a13a20a21a22a23pp+1a0+113579111315171921
254、23for(p=a;pa+12;p+)a0是列指针是列指针类型不匹配!类型不匹配!a+1471a00a01a02a03a10a11a12a13a20a21a22a23pinta34,*p;如何用如何用p表示二维数组中的任一元素?表示二维数组中的任一元素?p=a0*p*(a0+0)a00p+1*(a0+1)a01p+2*(a0+2)a02p+3*(a0+3)a03p+4*(a0+4)a10*(p+4*1+0)p+5*(a0+5)a11*(p+4*1+1)aij*(p+4*i+j)*(p+m*i+j)m为第二维的维数。是个常数为第二维的维数。是个常数p+2p+4472fun(int*q1,int*
255、q2,int*q3)*q3=*q2+*q1;voidmain(void)inti,j,a33=1,1,*p1,*p2,*p3;p1=a0,p2=a0+1,p3=a0+2;for(i=2;i9;i+)fun(p1+,p2+,p3+);for(i=0;i3;i+)for(j=0;j3;j+)coutaijt;coutendl;程序输出的第一行为程序输出的第一行为_第二行为第二行为_第三行为第三行为_11p1p2p3i=2*q3=2i=3*q3=3i=4*q3=5235112473指向由指向由m个整数组成的个整数组成的一维数组一维数组的指针变量的指针变量int(*p)m;int(*p)4,a4;ap
256、p+1指针加指针加16个字节个字节。a+1指针加指针加4个字节个字节。a+1p+1指向下一行指向下一行474int(*p)4,a34;a23a22a21a20a13a12a11a10a03a02a01a00200CH2008H2004H2000Hpp+1p+2p为行指针为行指针,可以直接将二维数组名,可以直接将二维数组名a赋给赋给p。这样,。这样,a与与p等同等同。a23*(*(a+2)+3)p23*(*(p+2)+3)apa两种表示两种表示完全等价完全等价a为常量为常量p为变量为变量475若有以下的定义和语句,则下面各个符号的若有以下的定义和语句,则下面各个符号的正确含义是:正确含义是:in
257、ta34,(*p)4;p=a;1.p+12.*(p+2)3.*(p+1)+24.*(*p+2)a23a22a21a20a13a12a11a10a03a02a01a00200CH2008H2004H2000Hpp+1p+2aa数组第一行元素的首地址数组第一行元素的首地址为行指针为行指针a数组第二行元素的首地址数组第二行元素的首地址为列指针为列指针&a20&a12为列指针为列指针数据元素数据元素*(*(p+0)+2)=a02476若若有有以以下下的的定定义义和和语语句句,则则对对a数数组组元元素素的的非非法引用是:法引用是:inta23,(*pt)3;pt=a;1)pt002)*(pt+1)22)
258、3)*(pt1+2)3)*(a0+2)*(pt+1)2 右右结结合合性性*(pt+1)2)*(*(pt+1+2)*(*(pt+3)=pt30477多维数组的指针作函数参数多维数组的指针作函数参数主要注意的是函数的主要注意的是函数的实参实参究竟是行指针还是究竟是行指针还是列指针,从而决定函数列指针,从而决定函数形参形参的类型。的类型。要求要求实实参、形参一一对应,类型一致参、形参一一对应,类型一致。(举例)。(举例)478求二维数组求二维数组a34的平均值。的平均值。voidmain(void)floatscore34=65,67,70,60,80,87,90,81,90,99,100,98;f
259、loatsum=0;for(inti=0;i3;i+)for(intj=0;j4;j+)sum=sum+scoreij;cout“aver=“sum/12endl;479voidmain(void)floatscore34=65,67,70,60,80,87,90,81,90,99,100,98;floataver;aver=fun1(score,3);aver=fun2(*score,12);p1618.15480字符串的字符串的指针指针和指向字符串的和指向字符串的指针变量指针变量字符串的表示形式字符串的表示形式1、用字符数组实现、用字符数组实现voidmain(void)charstrin
260、g=“IloveChina”;coutstring;Il o v eC h i n a 0stringstring为数组名,代表数组的首地址,是常量。为数组名,代表数组的首地址,是常量。数组首地址数组首地址481charstring20;string=“IloveChina”;strcpy(string,“IloveChina”);cin.getline(string);/从键盘输入从键盘输入0anihCevolIstring错误!常量不错误!常量不能赋值能赋值正确赋值形式正确赋值形式4822、用字符、用字符指针指针表示字符串表示字符串voidmain(void)char*string=“Il
261、oveChina”;coutstring;Il o v eC h i n a 0string字符串常量字符串常量指针变量指针变量将内存中字符串常量的首地址赋给一个指针变量将内存中字符串常量的首地址赋给一个指针变量483voidmain(void)char*string;string=“IloveChina”;*string=“IloveChina”;char*string;cin.getline(string);指针变量赋值,合法指针变量赋值,合法具体字符具体字符指针未赋值就作指向运算指针未赋值就作指向运算484将字符串将字符串a复制到字符串复制到字符串b。voidmain(void)char
262、a=“Iamaboy”,b20;inti;for(i=0;*(a+i)!=0;i+)*(b+i)=*(a+i);*(b+i)=0;coutaendl;coutbendl;Ia mab oy 0abi=0 *(b+i)=*(a+i)bi=aiIi=1i=2ay 0必须以必须以0结束结束485voidmain(void)chara=“Iamaboy”,b20;char*p1,*p2;inti;p1=a;p2=b;for(;*p1!=0;p1+,p2+)*p2=*p1;*p2=0;coutaendl;coutbendl;Ia mab o y 0abp1ap2b*p2=*p1Ia+1p1b+1p2p1
263、p20必须以必须以0结束结束y486voidmain(void)chara=“Iamaboy”,b20;char*p1,*p2;inti;p1=a;p2=b;for(;*p1!=0;p1+,p2+)*p2=*p1;*p2=0;coutaendl;coutbendl;for(;*p1!=0;)*p2+=*p1+;*p2=0;while(*p2+=*p1+);for(;*p2+=*p1+;);for(;(*p2+=*p1+)!=0;);487以下程序判断输入的字符串是否以下程序判断输入的字符串是否“回文回文”,若是回文,输出,若是回文,输出YES。voidmain(void)chars81,cr,
264、*pi,*pj;inti,j,n;cin.getline(s);n=strlen(s);pi=_;pj=_;/pi指向串开始,指向串开始,pj指向最后指向最后while(*pi=)_;while(*pj=)_;while(_)&(*pi=*pj)pi+;_;if(pipj)cout“NO”endl;elsecout“YESn”;ss+n-1pi+pj-pj-pipj488字符串字符串指针指针作函数参数作函数参数将一个字符串从一个函数传递到另一个函数,将一个字符串从一个函数传递到另一个函数,可以用地址传递的办法。即用可以用地址传递的办法。即用字符数组名作字符数组名作参数或用指向字符串的指针变量作
265、参数参数或用指向字符串的指针变量作参数。在。在被调函数中可以改变原字符串的内容。被调函数中可以改变原字符串的内容。489将字符串将字符串a复制到字符串复制到字符串b。voidmain(void)chara=“Iamateacher”;charb=“Youareastudent”;copy_string(a,b);coutaendl;coutbendl;copy_string(charfrom,charto)inti;for(i=0;fromi!=0;i+)toi=fromi;toi=0;abfromtofrom与与a一个地址,一个地址,to与与b一个地址一个地址490将字符串将字符串a复制到字
266、符串复制到字符串b。voidmain(void)chara=“Iamateacher”;charb=“Youareastudent”;copy_string(a,b);coutaendl;coutbendl;copy_string(char*from,char*to)for(;*from!=0;)*to+=*from+;*to=0;for(;*from+=*to+;);也可以用字符指针来接受数组名也可以用字符指针来接受数组名abfromto491字符指针变量与字符数组字符指针变量与字符数组字符字符数组数组和字符和字符指针变量指针变量都可以实现字符串的存储都可以实现字符串的存储和运算,区别在于:
267、和运算,区别在于:字符数组名是常量字符数组名是常量,定义时必须指明占用的空间大,定义时必须指明占用的空间大小。小。字符指针变量是变量字符指针变量是变量,里面存储的是字符型地址,里面存储的是字符型地址,可以整体赋值,可以整体赋值,但字符串必须以但字符串必须以0结尾结尾。492voidmain(void)charstr80=“hcance”;fun(str);coutstr0)swap(s1,s2);if(strcmp(s2,s3)0)swap(s2,s3);if(strcmp(s1,s2)0)swap(s1,s2);couts1endls2endls3m;fun(str1,str2,m);cou
268、tstr2endl;495voidfun(char*p1,char*p2,intm)intn=strlen(p1);if(nm)cout“Notransn”;*p2=0;return;for(inti=m,p1=p1+m-1;iy?x:y;这时,指针变量这时,指针变量p中放的是中放的是max函数在内存中的入口地址。函数在内存中的入口地址。函数类型函数类型(*指针变量名指针变量名)(参数类型参数类型);int(*p)(int,int);专门存放函数地址的专门存放函数地址的指针变量指针变量称为称为指向函数的指针指向函数的指针变量变量。p空间的内容只能空间的内容只能放函数的地址放函数的地址且该函数的
269、返回值为整型数且该函数的返回值为整型数同时该函数具有两个整型形参同时该函数具有两个整型形参498函数名函数名max代表函数在内存中的入口地址,代表函数在内存中的入口地址,是一个是一个常量常量,不可被赋值。,不可被赋值。而指向函数的指针变量而指向函数的指针变量p可以先后指向不同的可以先后指向不同的同种同种类型类型的函数。但不可作加减运算。的函数。但不可作加减运算。p=max;p=min;int(*p)(int,int);定义定义赋值赋值499如何用指向函数的指针变量调用函数?如何用指向函数的指针变量调用函数?intmax(intx,inty)returnxy?x:y;voidmain(void)
270、inta,b,c;cinab;c=max(a,b);coutcy?x:y;voidmain(void)inta,b,c,max(int,int);int(*p)(int,int);p=max;cinab;c=p(a,b);coutcendl;给指针变给指针变量赋值量赋值通过指针通过指针变量调用变量调用一般的调一般的调用方法用方法定义指向函数定义指向函数的指针变量的指针变量实际上就是用实际上就是用p替换函数名替换函数名c=(*p)(a,b)500用二分法求方程的解。用二分法求方程的解。f1(x)=x2-3指向函数的指针变量作指向函数的指针变量作函数参数函数参数(实现通用函数)(实现通用函数)50
271、1二分法求解方程二分法求解方程f(x)xyx01、在、在x轴上取两点轴上取两点x1和和x2,要确保要确保x1与与x2之间有且只有方程之间有且只有方程唯一的解唯一的解。x1x2x02、做、做x0=(x1+x2)/2。3、若、若|f(x0)|满足给定的精度,则满足给定的精度,则x0即是方程的解,否则,即是方程的解,否则,若若f(x0)*f(x1)0,则,则方程的解应在方程的解应在x2与与x0之间,令之间,令x1=x0,继续做继续做2,直至满足精度为止。直至满足精度为止。x2x0x2=x0x0=(x1+x2)/2502用二分法求方程的解。用二分法求方程的解。f1(x)=x2-3voidmain(vo
272、id)floatx1,x2,x0;docoutx1x2;while(f1(x1)*f1(x2)0);floatf1(floatx)returnx*x-3;dox0=(x1+x2)/2;if(f1(x1)*f1(x0)=1e-6);coutx0endl;判断判断x1与与x2之间之间是否有方程根是否有方程根输入初值输入初值求中值求中值循环迭代循环迭代循环结束条件循环结束条件已知已知x求求f1(x)503当求解方程当求解方程f2(x)=3x2-5x-3时,同样时,同样main()floatx1,x2,x0;docoutx1x2;while(f2(x1)*f2(x2)0);floatf2(floatx
273、)return3*x*x-5*x-3;dox0=(x1+x2)/2;if(f2(x1)*f2(x0)=1e-6);coutx0endl;可以看到,虽然算法相同,仅是可以看到,虽然算法相同,仅是方程方程不同,两个程序不能不同,两个程序不能通用。通用。可以用指向函数的指针变量,设计相同算法的可以用指向函数的指针变量,设计相同算法的通用函数通用函数。504floatdevide(float(*fun)(float)floatx1,x2,x0;docoutx1x2;while(fun(x1)*fun(x2)0);dox0=(x1+x2)/2;if(fun(x1)*fun(x0)=1e-6);retur
274、nx0;floatf1(floatx)returnx*x-3;floatf2(floatx)return3*x*x-5*x-3;main()floaty1,y2;y1=devide(f1);y2=devide(f2);couty1ty2;调用函数调用函数,实参为函实参为函数名数名f1形参用指向函数形参用指向函数的指针变量的指针变量fun接接受函数名受函数名用用fun调用函调用函数,实际调用数,实际调用的是实参函数的是实参函数505实参:实际的函数名(函数地址)实参:实际的函数名(函数地址)形参:指向函数的指针变量形参:指向函数的指针变量与实参函数的类型完全一致(返回值、参数)与实参函数的类型完
275、全一致(返回值、参数)通用函数:所有的内部函数调用都用通用函数:所有的内部函数调用都用函数指针调用函数指针调用506梯形法求定积分的公式梯形法求定积分的公式abf(a)f(b)分成分成n份,每份长度份,每份长度h=(b-a)/n积分结果为曲线与积分结果为曲线与x轴之间轴之间部分的面积,也即为每份部分的面积,也即为每份面积之和。面积之和。S=(上底下底)上底下底)*高高/2=(f(a+i*h)+f(a+(i+1)*h)*h/2其中其中i=0(n-1)a+n*h=b任意一份:高:任意一份:高:h上底:上底:f(a+i*h)a+i*h下底:下底:f(a+(i+1)*h)507S=(f(a)+f(b)
276、/2+f(a+i*h)*h(i=1(n-1)将上式展开,除将上式展开,除f(a),f(b)外,每一底边都参与运算两次,所以有:外,每一底边都参与运算两次,所以有:y=(f(a)+f(b)/2;h=(b-a)/n;for(i=1;in;i+)y=y+f(a+i*h);y=y*h;可利用这一公式,计算所有函可利用这一公式,计算所有函数的定积分,也即做成通用公数的定积分,也即做成通用公式,具体的函数由式,具体的函数由指向函数的指向函数的指针变量来代替,指针变量来代替,在主调函数在主调函数中为这个指针变量赋值。中为这个指针变量赋值。S=(上底下底)上底下底)*高高/2=(f(a+i*h)+f(a+(i
277、+1)*h)*h/2其中其中i=0(n-1)a+n*h=b初值初值计算累加和计算累加和508floatjifen(float(*pf)(float),floata,floatb)y=(pf(a)+pf(b)/2;h=(b-a)/2;for(i=1;in;i+)y=y+pf(a+i*h);y=y*h;returny;y2=jifen(f2,2.0,5.0);voidmain(void)floaty;y=jifen(f1,1.0,3.0);coutyab;p=max(&a,&b);cout*p*y)pt=x;elsept=y;returnpt;返回类型是指针返回类型是指针用指针类用指针类型接收型接
278、收ab随机随机p&ax24&bypt&b&b输出:输出:4该指针所指向的空间是在主调该指针所指向的空间是在主调函数中开辟的。函数中开辟的。511char*strc(char*str1,char*str2)char*p;for(p=str1;*p!=0;p+);do*p+=*str2+;while(*str2!=0);*p=0;return(str1);voidmain(void)chars180=“computer”,s2=“language”,*pt;pt=strc(s1,s2);coutptendl;computerlanguagep指向指向str1的最后的最后str2向向p赋值赋值最后最
279、后0结结束束512co m puter 0s1str1pco m puter 0s2str2pstr2co m puter 0p513已知函数已知函数int*f(int*),有以下说明语句:,有以下说明语句:int*p,*s,a;函数正确的调用形式是:函数正确的调用形式是:A)a=*f(s)B)*p=f(s)C)s=f(*p)D)p=f(&a)514指针指针数组数组和和指向指针的指针指向指针的指针指针数组的概念指针数组的概念一个数组,其元素均为一个数组,其元素均为指针类型指针类型的数据,称为指针的数据,称为指针数组。也就是说,数组。也就是说,指针数组中的每一个元素都是指指针数组中的每一个元素都
280、是指针变量,可以放地址针变量,可以放地址。类型标识类型标识*数组名数组名数组长度说明数组长度说明int*p4;int(*p)4;pp3p2p1p0地址地址地址地址地址地址地址地址p为数组名,内有四个元为数组名,内有四个元素,每个元素可以放一素,每个元素可以放一个个int型数据的地址型数据的地址p为指向有四个为指向有四个int型元素的一维数组的行指针型元素的一维数组的行指针515voidmain(void)floata=100,200,300,400,500;float*p=&a0,&a1,&a2,&a3,&a4;inti;for(i=0;i5;i+)cout*pit;coutendl;pp4p
281、3p2p1p0&a4&a3&a2&a1&a0a4a3a2a1a0a500400300200100p数组元素数组元素内放地址内放地址*pi=*(*(p+i)p+0p+1p+2p+3p+4516voidmain(void)inta12=1,2,3,.11,12;int*p4,i;for(i=0;i4;i+)pi=&ai*3;coutp32endl;p32=*(*(p+3)+2)=*(p3+2)12123456789101112app0p1p2p3&a0&a3&a6&a9p+0p+1p+2p+3*(p+3)p3+1p3+2517常用字符指针数组,数组中的元素指向字符串首地址,这常用字符指针数组,数组
282、中的元素指向字符串首地址,这样比字符数组节省空间。样比字符数组节省空间。char*str=“China”,“Japan”,“America”;3090H3000H2000Hstrstr2str1str0“America”“Japan”“China”str14*(*(str+1)+4)*str2*(*(str+2)+0)*str*(*(str+0)+0)nAC518将若干字符串按字母顺序(由小到大)输出。将若干字符串按字母顺序(由小到大)输出。voidmain(void)voidsort();voidprint();char*alpha=“Followme”,“Basic”,“GreatWall
283、”,“FORTRAN”,“Computerdesign”;intn=5;sort(alpha,n);print(alpha,n);519voidsort(char*alpha,intn)char*temp;inti,j,k;for(i=0;in-1;i+)k=i;for(j=i+1;j0)k=j;if(k!=i)temp=alphai;alphai=alphak;alphak=temp;voidprint(char*alpha,intn)inti;for(i=0;in;i+)coutalphaiendl;alpha0alpha1alpha2alpha3alpha4“Followme”“Basi
284、c”“GreatWall”“FORTRAN”“Computerdesign”交换地址交换地址选择法排序选择法排序520指向指向指针指针的指针变量的指针变量inti,*p;p=&i;i2000H2000Hp3000H3000Hprt5000H同样,同样,p p也有地址,可以再引用一个指针变量指向也有地址,可以再引用一个指针变量指向它。它。prt=&p;p=&iinti,*p,*prt;称称prtprt为为指向指针指向指针的指针变量。其的指针变量。其基类型基类型是指向整是指向整型数据的型数据的指针变量指针变量,而非整型数据。,而非整型数据。521prt=p;p=&i;prt=&p;prt=&i;*
285、p=i;*prt=i;非法非法,基类基类型不符型不符i2000H2000Hp3000H3000Hprt5000H522voidmain(void)a5=1,3,5,7,9;int*num5=&a0,&a1,&a2,&a3,&a4;int*p,i;p=num;for(i=0;i5;i+)cout*pt;p+;97531a&a4&a3&a2&a1&a0numnumpp=p+1;指向指向num数组下一个元素数组下一个元素13579p=&num0523voidmain(void)char*alpha=“Followme”,“Basic”,“GreatWall”,“FORTRAN”,“Computerd
286、esign”;char*p;inti;for(i=0;i5;i+)p=alpha+i;cout*pendl;alpha4alpha3alpha2alpha1alpha0ComputerdesignFORTRANGreatWallBasicFollowmealphaalpha+1i=0p=alphai=1p=alpha+1524voidmain(void)char*n4=“China”,“Japan”,“England”,“Germany”;char*p;inti;p=n;for(i=0;i4;i+,p+)cout(char)(*(*p+2)+1)endl;n“China”“Japan” “En
287、gland”“Germany”p*(*p+2)+1=*(p0+2)+1=p02+1输出:输出:jqhs525以下程序的输出结果是:以下程序的输出结果是:char*alpha6=“ABCD”,”EFGH”,”IJKL”,”MNOP”,”QRST”,”UVWX”;char*p;main()inti;p=alpha;for(i=0;i4;i+)cout*(pi);coutendl;*(pi)=*(*(p+i)=*(*(p+i)+0)输出:输出:AEIMalpha5alpha4alpha3alpha2alpha1alpha0alphapABCDEFGHIJKLMNOPQRSTUVWX526以下程序的输
288、出结果是:以下程序的输出结果是:char*alpha6=“ABCD”,”EFGH”,”IJKL”,”MNOP”,”QRST”,”UVWX”;char*p;main()inti;p=alpha;for(i=0;i4;i+)cout(*p)i;coutendl;输出:输出:ABCDalpha5alpha4alpha3alpha2alpha1alpha0alphapABCDEFGHIJKLMNOPQRSTUVWX(*p)i=*(p+0)i=p0i527若有以下定义,则下列哪种表示与之等价。若有以下定义,则下列哪种表示与之等价。chars35=“aaaa”,”bbbb”,”cccc”;A)char*s
289、1=“aaaa”,”bbbb”,”cccc”;B)char*s23=“aaaa”,”bbbb”,”cccc”;C)chars33=“aaaa”,”bbbb”,”cccc”;D)chars44=“aaaa”,”bbbb”,”cccc”;528以下程序调用函数以下程序调用函数swap_p将指针将指针s和和t所指单元所指单元(a和和b)中的内容交换,中的内容交换,请填空。请填空。voidswap_p(_ss,_tt)intterm;term=_;*ss=_;*tt=term;main()inta=10,b=20,*s,*t;s=&a;t=&b;swap_p(&s,&t);printf(“%d%d”,
290、a,b);int*int*ss*tt10a&as20b&bt&sss&tttterm529假设有说明:假设有说明:char*argv=“hello”,“nanjing”,“jiangsu”;char*pargv=argv;以下语句的输出结果如何?以下语句的输出结果如何?cout*(pargv+1)endl;cout(char)(*pargv+1)endl;cout*(*pargv+1)endl;cout*(*(pargv+2)+4)endl;argv“hello” “nanjing”“jiangsu”pargvnanjingieg530voidmain()char*s=“1995”,”1996
291、”,”1997”,”1998”;char*sp=s+3,s+2,s+1,s;charss5;ss0=*sp0;ss1=*(*sp1+1);ss2=*(*sp2+2);ss3=*sp33+6;ss4=0;coutssendl;s0s1s2s31995199619971998ss+3s+2s+1sspss19970531总结:总结:通过行指针引用二维数组元素通过行指针引用二维数组元素inta34,*p3,(*pp)4,*prt;for(i=0;i3;i+)pi=ai;pp=a;prt=p;8a2a1a0pp+2pp+1pp8p2p1p0apprtprt+1prt+2a23*(*(pp+2)+3)a
292、23*(*(p+2)+3)a23*(*(a+2)+3)a23*(*(prt+2)+3)a23pp23p23prt23532inta34,*p3,(*pp)4,*prt;for(i=0;i3;i+)pi=ai;pp=a;prt=p;8p2p1p0apprtprt+1prt+2a:二维数组名,:二维数组名,常量常量p:指针数组名,:指针数组名,常量常量pp:指向具有四个元素的一维数组的指针:指向具有四个元素的一维数组的指针变量变量prt:指向指针的:指向指针的指针变量指针变量533指针数组作指针数组作main()函数的形参函数的形参程序是由程序是由main()函数处向下执行的。函数处向下执行的。m
293、ain函数也可以带参函数也可以带参数。数。其它函数由其它函数由main函数调用的,即在程序中调用的,函数调用的,即在程序中调用的,但但main函数却是由函数却是由DOS系统调用的系统调用的,所以所以main函数实参的值是在函数实参的值是在DOS命令行中给出的命令行中给出的,是随着文件的运行命令一起给出的。,是随着文件的运行命令一起给出的。可执行文件名可执行文件名实参实参1实参实参2.实参实参nS9_16CHINAJAPANAMERICAN可执行文件可执行文件S9_16.EXE三个形参三个形参534main函数形参的形式:函数形参的形式:main(intargc,char*argv)main(i
294、ntargc,char*argv)argc为命令行中参数的个数(包括文件名);为命令行中参数的个数(包括文件名);argv为指向命令行中参数(字符串)的指针数组。为指向命令行中参数(字符串)的指针数组。S9_16CHINAJAPANAMERICAN文件名文件名实参实参1实参实参2实参实参3argc=4argv3argv2argv1argv0“AMERICAN”“JAPAN”“CHINA”“S9_16.EXE”argvargv535main(intargc,char*argv)while(argc1)cout*argvendl;+argv;-argc;argc=4argv3argv2argv1a
295、rgv0“AMERICAN”“JAPAN”“CHINA”“S9_16.EXE”argvS9_16.EXECHINAJAPANargvS9_16CHINAJAPANAMERICAN文件名文件名实参实参1实参实参2实参实参3536B9_1BeijingChinamain(intargc,char*argv)while(argc-1)cout*(+argv)p1p2p1538在内存动态分配存储空间在内存动态分配存储空间在定义变量或数组的同时即在定义变量或数组的同时即在内存为其开辟了指定在内存为其开辟了指定的固定空间的固定空间。intn,a10;charstr100;在程序内我们有时需要根据实际需要开
296、辟空间在程序内我们有时需要根据实际需要开辟空间,如,如输入学生成绩,但每个班的学生人数不同,一般将输入学生成绩,但每个班的学生人数不同,一般将人数定得很大,这样占用内存。人数定得很大,这样占用内存。一经定义,即为固定地址的一经定义,即为固定地址的空间,在内存不能被别的变空间,在内存不能被别的变量所占用。量所占用。539#defineN100.floatscoreN5;cinn;for(inti=0;in;i+)for(j=0;jscoreij;.无论班级中有多少个学无论班级中有多少个学生,程序均在内存中开生,程序均在内存中开辟辟10051005个实型数空间个实型数空间存放学生成绩,造成内存放学
297、生成绩,造成内存空间的浪费。存空间的浪费。540如何根据需要在程序的运行过程中如何根据需要在程序的运行过程中动态分配动态分配存储内存空间存储内存空间?intn;cinn;floatscoren5;错误!错误!数组的维数数组的维数必须是常量必须是常量利用利用new运算符可以在程序中动态开辟内存空间。运算符可以在程序中动态开辟内存空间。new数据类型数据类型单位数单位数;newint4;在内存中开辟了在内存中开辟了4个个int型的数据空间,即型的数据空间,即16个字节个字节541new new 相当于一个函数,在内存开辟完空间后,返相当于一个函数,在内存开辟完空间后,返回这个空间的首地址,这时,回
298、这个空间的首地址,这时,这个地址必须用一这个地址必须用一个指针保存下来个指针保存下来,才不会丢失。,才不会丢失。int*p;pp=newint;new开辟的空间开辟的空间*p=6;6可以用可以用*p对这个空间进行运算。对这个空间进行运算。newint;在内存中开辟出四在内存中开辟出四个字节的空间个字节的空间542intn,*p;cinn;p=newintn;p指向新开辟空间的首地址。指向新开辟空间的首地址。p同样,利用同样,利用new运算符也可以开辟连续的多个空间运算符也可以开辟连续的多个空间(数组数组)。for(inti=0;ipi;可以用可以用pi的形式来引用新开辟的内存单元。的形式来引用
299、新开辟的内存单元。543注意:用注意:用newnew开辟的内存单元没有名字,指向其开辟的内存单元没有名字,指向其首地址的首地址的指针指针是引用其的唯一途径,若指针变量重新赋值,则用是引用其的唯一途径,若指针变量重新赋值,则用newnew开辟的内存单元就在内存中开辟的内存单元就在内存中“丢失丢失”了,别的程序也了,别的程序也不能占用这段单元,直到重新开机为止。不能占用这段单元,直到重新开机为止。int*p,a4;p=newint4;p=a;anew开辟的单元开辟的单元p该段内存由于失去了该段内存由于失去了“名名字字”,再也无法引用,再也无法引用544用用 new new 运算符分配的空间,运算符
300、分配的空间,不能在分配空间时不能在分配空间时进行初始化进行初始化。 deletedelete运运算算符符用用来来将将动动态态分分配配到到的的内内存存空空间间归归还还给给系统,使用格式为:系统,使用格式为: delete pdelete p;同样,用同样,用newnew开辟的内存单元如果程序不开辟的内存单元如果程序不“主动主动”收回,那么这段空间就一直存在,直到重新开机收回,那么这段空间就一直存在,直到重新开机为止。为止。545delete也可以收回用也可以收回用new开辟的连续的空间。开辟的连续的空间。int*point;cinn;point=newintn;.deletepoint;int*
301、point;point=newint;.deletepoint;注意:在此期间,注意:在此期间,point指针不能重指针不能重新赋值,新赋值,只有用只有用new开辟的空间才开辟的空间才能用能用delete收回收回。当内存中没有足够的空间给予当内存中没有足够的空间给予分配时,分配时,new运算符返回空指运算符返回空指针针NULL(0)。)。546以下程序求两个数的大者,请填空。以下程序求两个数的大者,请填空。voidmain(void)int*p1,*p2;p1=_;p2=_;cin_;if(*p2*p1)*p1=*p2;deletep2;cout“max=”_*p2547main()int*s
302、1,*s2;sub1(&s1,&s2);sub2(&s1,&s2);cout*s1t*s2endl;sub3(s1,s2);sub4(s1,s2);cout*s1t*s2endl;sub1(int*p1,int*p2)*p1=newint;*p2=newint;sub2(int*p1,int*p2)*p1=10;*p2=20;*p1=*p2;sub3(int*p1,int*p2)p1=newint;p2=newint;sub4(int*p1,int*p2)*p1=1;*p2=2;*p2=*p1;s1&s1p1&s1*s1202011548引用引用对变量起另外一个名字对变量起另外一个名字 ( (
303、外号外号) ),这个名字称为该,这个名字称为该变量的引用。变量的引用。&=;其中其中原变量名原变量名必须是一个已定义过的变量必须是一个已定义过的变量。如:。如:intmax;int&refmax=max;refmax并没有并没有重新在内存中开辟单元,只是重新在内存中开辟单元,只是引用引用max的单元。的单元。max与与refmax在内存中占用同一地址在内存中占用同一地址,即同一地址两个名字即同一地址两个名字。549maxrefmax510intmax;int&refmax=max;max=5;20refmax=10;refmax=max+refmax;max与与refmax同一地址同一地址55
304、0对引用类型的变量,说明以下几点:对引用类型的变量,说明以下几点:1、引用在定义的时候要初始化。、引用在定义的时候要初始化。2、对引用的操作就是对被引用的变量的操作。、对引用的操作就是对被引用的变量的操作。int&refmax;int&refmax=max;错误,没有具体的引用对象错误,没有具体的引用对象max是已定义过的变量是已定义过的变量3、引用类型变量的初始化值不能是一个常数。引用类型变量的初始化值不能是一个常数。如:如:int&ref1=5;/是错误的。是错误的。int&ref=i;5514、引用同变量一样有地址,可以对其地址进行、引用同变量一样有地址,可以对其地址进行操作,即将其地址
305、赋给一指针。操作,即将其地址赋给一指针。inta,*p;int&m=a;apm10p=&m;*p=10;&m&是变量的引用是变量的引用&是变量的地址是变量的地址5525、可以用动态分配的内存空间来初始化一个引用变量。、可以用动态分配的内存空间来初始化一个引用变量。float&reff=*newfloat;/用用new开辟一个空间,取一个别名开辟一个空间,取一个别名reffreff=200;/给空间赋值给空间赋值coutreff;/输出输出200delete&reff; /收回这个空间收回这个空间这个空间只有别名,但程序可以引用到。这个空间只有别名,但程序可以引用到。float*p,a;p=ne
306、wfloat;floata=*newfloat;错误!错误!553指针与引用的区别:指针与引用的区别:1、指针是通过地址、指针是通过地址间接间接访问某个变量,而引用是访问某个变量,而引用是通过别名通过别名直接直接访问某个变量。访问某个变量。2、引用必须初始化,而、引用必须初始化,而一旦被初始化后不得再作一旦被初始化后不得再作为其它变量的别名为其它变量的别名。554当当&a&a的前面有的前面有类型符类型符时时(如(如int &aint &a),它必然是),它必然是对引用的声明对引用的声明;如果前面;如果前面无类型符(如无类型符(如cout&acout&a), ,则是取变量的地址。则是取变量的地址
307、。555以下的声明是非法的以下的声明是非法的1、企图建立数组的引用、企图建立数组的引用int&a9;2、企图建立指向引用的指针、企图建立指向引用的指针int&*p;3、企图建立引用的引用、企图建立引用的引用int&px;intm=10;int&y=10;int&z;float&t=&m;int&x=m;556voidmain(void)constint&r=8;/说明说明r为常量,不可赋值为常量,不可赋值coutr=rendl;/r+=15;/r为常量,不可作赋值运算为常量,不可作赋值运算coutr=rendl;对常量(用对常量(用const声明)的引用声明)的引用557引用与函数引用与函数引
308、用的用途主要是用来作引用的用途主要是用来作函数的参数函数的参数或或函数的返回值。函数的返回值。引用作函数的形参,实际上是在被调函数中对引用作函数的形参,实际上是在被调函数中对实参变量实参变量进行操作。进行操作。voidchange(int&x,int&y)/x,y是实参是实参a,b的别名的别名intt;t=x;x=y;y=z;voidmain(void)inta=3,b=5;change(a,b);/实参为变量实参为变量coutatbendl;a3b5xyt353输出:输出:53558引用作为形参,实参是引用作为形参,实参是变量而不是地址变量而不是地址,这与指针变量作,这与指针变量作形参不一样
309、。形参不一样。voidchange(int&x,int&y)intt;t=x;x=y;y=z;voidmain(void)inta=3,b=5;change(a,b);/实参为实参为变量变量coutatbendl;voidchange(int*x,int*y)intt;t=*x;*x=*y;*y=z;voidmain(void)inta=3,b=5;change(&a,&b);/实参为实参为地址地址coutatbendl;形参为整型引用形参为整型引用形参为指针变量形参为指针变量a3b5xyt&a&b353559voiddd(int&x,int&y,intz)x=x+z;y=y-x;z=10;c
310、out“(2)”xtytzendl;voidmain(void)inta=3,b=4,c=5;for(inti=0;i2;i+)dd(a,b,c);cout“(1)”atbtcendl;(2)8-410(2)13-1710(1)13-175x=8y=-4z=10x=13y=-17z=10560voidf1(int*px) *px+=10;voidf2(int&xx)xx+=10;voidmain(void)intx=0;coutx=xendl;f1(&x);coutx=xendl;f2(x);coutx=xendl;x=0x=10x=20561函数的返回值为引用类型函数的返回值为引用类型可以把
311、函数定义为引用类型,这时函数的返回值即可以把函数定义为引用类型,这时函数的返回值即为某一变量的引用(别名),为某一变量的引用(别名),因此,它相当于返回因此,它相当于返回了一个变量,所以可对其返回值进行赋值操作。这了一个变量,所以可对其返回值进行赋值操作。这一点类同于函数的返回值为指针类型一点类同于函数的返回值为指针类型。562先调用,再赋值先调用,再赋值inta=4;int&f(intx)a=a+x;returna;voidmain(void)intt=5;coutf(t)endl;f(t)=20;coutf(t)endl;t=f(t);coutf(t)endl;函数返回函数返回a的引的引用
312、,即用,即a的别名的别名输出输出9(a=9)输出输出25(a=25)a=20t=30输出输出60(a=60)先调用,再赋值先调用,再赋值563一个函数返回引用类型,一个函数返回引用类型,必须返回某个类型的变量必须返回某个类型的变量。语句:语句:getdata()=8;就相当于就相当于int&temp=8;temp=8;注意:由于函数调用返回的引用类型是在函数运行注意:由于函数调用返回的引用类型是在函数运行结束后产生的,所以结束后产生的,所以函数不能返回自动变量和形参函数不能返回自动变量和形参。返回的变量的引用,返回的变量的引用,这个变量必须是全局变量或静这个变量必须是全局变量或静态局部变量,即
313、存储在静态区中的变量态局部变量,即存储在静态区中的变量。564我们都知道,函数作为一种程序实体,它有我们都知道,函数作为一种程序实体,它有名字、类型、地址和存储空间,一般说来名字、类型、地址和存储空间,一般说来函函数不能作为左值数不能作为左值(即函数不能放在赋值号左(即函数不能放在赋值号左边)。但如果将函数定义为返回引用类型,边)。但如果将函数定义为返回引用类型,因为返回的是一个变量的别名,就可以将函因为返回的是一个变量的别名,就可以将函数放在左边,即给这个变量赋值。数放在左边,即给这个变量赋值。565int&f(int&x)staticintt=2;t=x+;returnt;voidmain
314、(void)inta=3;coutf(a)endl;f(a)=20;a=a+5;coutf(a)endl;a=f(a);coutf(a)endl;输出输出3a=4t=3t=20a=5a=10输出输出10a=11a=11输出输出11a=12566const类型变量类型变量当用const限制说明标识符时,表示所说明的数据类型为常量类型。可分为const型常量和const型指针。可用const限制定义标识符量,如:constintMaxLine=1000;constfloatPi=3.1415926用const定义的标识符常量时,一定要对其初始化。在说明时进行初始化是对这种常量置值的唯一方法,不能用
315、赋值运算符对这种常量进行赋值。如:MaxLine=35;567const型指针1)禁写指针声明语句格式为:数据类型*const指针变量名如:intr=6;int*constpr=&r;则指针pr被禁写,即pr将始终指向一个地址,成为一个指针常量。它将不能再作为左值而放在赋值号的左边。(举例说明)虽然指针被禁写,但其间接引用并没有被禁写。即可以通过pr对r赋值。*pr=8;同样,禁写指针一定要在定义的时候赋初值。568voidmain(void)inta,b;int*constpa=&a;/一定要赋初值,pa是常量,不能在程序中/被改变*pa=10;/可以间接引用pa=&b;/非法,pa为常量a
316、b&apa105692)禁写间接引用声明语句格式如下:const数据类型*指针变量名;所声明的指针指向一禁写的实体,即间接引用不能被改写。如:constint*p;所以程序中不能出现诸如*p=的语句,但指针p并未被禁写,因而可对指针p进行改写。570voidmain(void)inta=3,b=5;constint*pa=&b;/可以不赋初值pa=&a;/指针变量可以重新赋值cout*paendl;/输出3*pa=10;/非法,指针指向的内容不能赋值a=100;/变量可以重新赋值cout*panum=10;/为新开辟的结构体空间中的为新开辟的结构体空间中的num成员赋值成员赋值p-score=
317、90;nextscorenump1090用指针引用结用指针引用结构体内的成员构体内的成员(*p).num5751、首先定义两个结构体类型的指针、首先定义两个结构体类型的指针STU*p1,*p2;2、用、用new在内存中开辟一个结构体变量的空间,将地址赋给在内存中开辟一个结构体变量的空间,将地址赋给p1。p1=newstudent;/*STUstructstudent*/3、将数据赋给刚开辟的变量空间。、将数据赋给刚开辟的变量空间。cinp1-nump1-score;4、若输入的数据有效,将首地址作为链表头,、若输入的数据有效,将首地址作为链表头,head=p1;令令p2=p1,p1继续用继续用
318、new开辟新的开辟新的内存空间。内存空间。5、将下一个数据赋给新开辟的变量空间。、将下一个数据赋给新开辟的变量空间。p1=newstudent;/*STUstructstudent*/cinp1-nump1-score;6、若输入的数据有效,将、若输入的数据有效,将p2与与p1连接起来连接起来,p2-next=p1再令再令p2=p1,p1继续用继续用new开辟开辟新的内存空间。做新的内存空间。做5。若输入的数据无效,。若输入的数据无效,p2就是链表的尾,则就是链表的尾,则p2-next=NULL。headp2A2000Hp13000HBp13000Hp22090HCp12090Hp26000H
319、Dp10ABC576headp2A2000Hp13000HBp13000Hp22090HCp12090Hp26000HDp10ABC577STU*p1,*p2,*head;head=NULL;p1=p2=newstudent;cinp1-nump1-score;if(p1-num!=0)head=p1;p1=newstudent;cinp1-nump1-score;if(p1-num!=0)p2-next=p1;p2=p1;p1=newstudent;cinp1-nump1-score;if(p1-num!=0)p2-next=p1;p2=p1;p1=newstudent;cinp1-nump
320、1-score;if(p1-num=0)p2-next=NULL;return(head);第一结点第一结点第二结点第二结点第三结点第三结点最后结点最后结点返回链表头返回链表头578STU*creat()STU*head,*p1,*p2;n=0;head=NULL;p1=p2=newstudent;cinp1-nump1-score;while(p1-num!=0)n=n+1;if(n=1)head=p1;elsep2-next=p1;p2=p1;p1=newstudent;cinp1-nump1-score;p2-next=NULL;return(head);n为全局变量,表示结点数为全局变
321、量,表示结点数开辟新结点开辟新结点向新结点输入数据向新结点输入数据不满足输入条件,结束不满足输入条件,结束5792、输出链表、输出链表voidprint(STU*head)STU*p;p=head;while(p!=NULL)coutnumtscorenext;A3000H2000H3000HB3050H3050HC6000H6000HD2090H2090HB0head输出数据输出数据p指向下一结点指向下一结点5803、删除链表、删除链表A3000H2000H3000HB6000H6000HD2090H2090HB0head1、首先定义两个结构体类型的指针、首先定义两个结构体类型的指针STU*
322、p1,*p2;2、将链表的表头赋给、将链表的表头赋给p1,p1=head;3、判断、判断p1所指向的结点是否是要删除的结点所指向的结点是否是要删除的结点p1-numa1。4、若、若p1-num!=a1,p2=p1;p1指向下一个结点指向下一个结点p1=p1-next,继续判断继续判断下一个结点是否是要删除的结点。继续做下一个结点是否是要删除的结点。继续做3。5、若、若p1-num=a1,则则p1当前指向的结点就是要删除的结点,将当前指向的结点就是要删除的结点,将p2的指针成员指向的指针成员指向p1所指的下一个结点。所指的下一个结点。p2-next=p1-next;这样就删除了一个结点。这样就删
323、除了一个结点。p2p1p1p1p22090H581特殊情况:特殊情况:1 1、若链表为空链表,返回空指针。、若链表为空链表,返回空指针。2 2、删除的结点为头结点时,、删除的结点为头结点时,headhead指向下一个结点指向下一个结点3 3、链表内没有要删除的结点,返回提示信息。、链表内没有要删除的结点,返回提示信息。582structstudent*del(structstudent*head,intnum)structstudent*p1,*p2;if(head=NULL)coutnum&p1-next!=NULL)p2=p1;p1=p1-next;if(num=p1-num)if(num
324、=head-num)head=p1-next;elsep2-next=p1-next;n=n-1;elsecoutnum与与p0-num,若若p1-numnum,p2=p1;p1=p1-next;继续比较。继续比较。3、若、若p1-num=p0-num,p0应插在应插在p1与与p2之间,则之间,则p2-next=p0;p0-next=p1;p2p1p17000H6000Hp2584特殊情况:特殊情况:1、若链表为空链表,将插入结点作为唯一的结点,、若链表为空链表,将插入结点作为唯一的结点,head=p0;返回。返回。2、若插入结点中的数据最小,则插入的结点作为、若插入结点中的数据最小,则插入的
325、结点作为头结点。头结点。3、插入到链尾,插入结点为最后一个结点。、插入到链尾,插入结点为最后一个结点。p2-next=p0;p0-next=NULL;p0-next=head;head=p0;585STU*insert(STU*head,STU*stud)STU*p0,*p1,*p2;p1=head;p0=stud;if(head=NULL)head=p0;p0-next=NULL;elsewhile(p0-nump1-num)&(p1-next!=NULL)p2=p1;p1=p1-next;if(p0-numnum)if(head=p1)head=p0;elsep2-next=p0;p0-n
326、ext=p1;elsep1-next=p0;p0-next=NULL;n=n+1;return(head);链表为空链表为空未找到结点,循环未找到结点,循环找到结点找到结点插入在第一个结点前插入在第一个结点前插入在最插入在最后一个后后一个后586voidmain(void)STU*head,stu;intdel_num;head=creat();print(head);coutdel_num;head=del(head,del_num);print(head);coutstu.numstu.score;head=insert(head,&stu);print(head);建立链表建立链表打印链
327、表打印链表删除结点删除结点插入结点插入结点coutstu.numstu.score;head=insert(head,&stu);print(head);变量,固定空间变量,固定空间58733000H2000H3000H76000H6000H122090H2090H280head107000Hstu70006000H588voidmain(void)STU*head,*stu;intnum;.coutstu-numstu-score;while(stu-num!=0)head=insert(head,stu);print(head);coutstu-numstu-score;如果要插入结点,动
328、态开辟新结点如果要插入结点,动态开辟新结点指针,可以赋值指针,可以赋值重新开辟空间重新开辟空间589用用typedef定义类型定义类型typedef定义新的类型来代替已有的类型。定义新的类型来代替已有的类型。typedef已定义的类型已定义的类型新的类型新的类型typedeffloatREALREALx,y;1、typedef可以定义类型,但不能定义变量。可以定义类型,但不能定义变量。2、tyoedef只能对已经存在的类型名重新定义一个类型名,只能对已经存在的类型名重新定义一个类型名,而不能创建一个新的类型名。而不能创建一个新的类型名。typedefstructstudentinti;int*
329、p;REC;RECx,y,*pt;structstudentx,y,*pt;floatx,y;590typedefchar*CHARP;CHARPp1,p2;char*p1,*p2;typedefcharSTRING81;STRINGs1,s2,s3;chars181,s281,s381;1、先按定义变量的方法写出定义体、先按定义变量的方法写出定义体chars81;2、把变量名换成新类型名、把变量名换成新类型名charSTRING81;3、在前面加、在前面加typedeftypedefcharSTRING81;4、再用新类型名定义变量、再用新类型名定义变量STRINGs;#defineREAL
330、float编译前简单替换编译前简单替换typedef:编译时处理,定义一个类型替代原有的类型。编译时处理,定义一个类型替代原有的类型。591第九章第九章类和对象类和对象面向对象的程序设计面向对象的程序设计592按钮对象:按钮对象:按钮的内容、大小,按钮的字体、图案等等按钮的内容、大小,按钮的字体、图案等等针对按钮的各种操作,创建、单击、双击、拖动等针对按钮的各种操作,创建、单击、双击、拖动等班级对象:班级对象:班级的静态特征,所属的系和专业、班级的人数,班级的静态特征,所属的系和专业、班级的人数,所在的教室等。这种静态特征称为属性;所在的教室等。这种静态特征称为属性;班级的动态特征,如学习、开
331、会、体育比赛等,班级的动态特征,如学习、开会、体育比赛等,这种动态特征称为行为。这种动态特征称为行为。593任何一个对象都应当具有这两个要素,一是属性任何一个对象都应当具有这两个要素,一是属性(attribute);二是行为;二是行为(behavior),即能根据外,即能根据外界给的信息进行相应的操作。界给的信息进行相应的操作。对象是由一组属性和对象是由一组属性和一组行为构成的。一组行为构成的。面向对象的程序设计采用了以上人们所熟悉的这种面向对象的程序设计采用了以上人们所熟悉的这种思路。使用面向对象的程序设计方法设计一个复杂思路。使用面向对象的程序设计方法设计一个复杂的软件系统时,的软件系统时
332、,首要的问题是确定该系统是由哪些首要的问题是确定该系统是由哪些对象组成的,并且设计这些对象。在对象组成的,并且设计这些对象。在C+中,中,每个每个对象都是由数据和函数对象都是由数据和函数(即操作代码即操作代码)这两部分组成这两部分组成的。的。594我们可以对一个对象进行封装处理,把它的我们可以对一个对象进行封装处理,把它的一部分属性和功能对外界屏蔽,也就是说从一部分属性和功能对外界屏蔽,也就是说从外界是看不到的、甚至是不可知的。外界是看不到的、甚至是不可知的。使用对象的人完全可以不必知道对象内部的使用对象的人完全可以不必知道对象内部的具体细节,只需了解其外部功能即可自如地具体细节,只需了解其外
333、部功能即可自如地操作对象。操作对象。把对象的内部实现和外部行为分隔开来。把对象的内部实现和外部行为分隔开来。595传统的面向过程程序设计是围绕功能进行的,用一传统的面向过程程序设计是围绕功能进行的,用一个函数实现一个功能。个函数实现一个功能。所有的数据都是公用的所有的数据都是公用的,一,一个函数可以使用任何一组数据,而一组数据又能被个函数可以使用任何一组数据,而一组数据又能被多个函数所使用。程序设计者必须考虑每一个细节,多个函数所使用。程序设计者必须考虑每一个细节,什么时候对什么数据进行操作什么时候对什么数据进行操作。面向对象程序设计采取的是另外一种思路。它面对面向对象程序设计采取的是另外一种
334、思路。它面对的是一个个对象。实际上,每一组数据都是有特定的是一个个对象。实际上,每一组数据都是有特定的用途的,是某种操作的对象。也就是说,的用途的,是某种操作的对象。也就是说,一组操一组操作调用一组数据作调用一组数据。596程序设计者的任务包括两个方面:一是程序设计者的任务包括两个方面:一是设计所需的各种类和对象,即决定把哪些数设计所需的各种类和对象,即决定把哪些数据和操作封装在一起;二是考虑怎样向有关据和操作封装在一起;二是考虑怎样向有关对象发送消息,以完成所需的任务。对象发送消息,以完成所需的任务。各个对各个对象的操作完成了,整体任务也就完成了。象的操作完成了,整体任务也就完成了。因此人们
335、设想把相关的数据和操作放在因此人们设想把相关的数据和操作放在一起,形成一个整体,与外界相对分隔一起,形成一个整体,与外界相对分隔。这。这就是面向对象的程序设计中的对象。就是面向对象的程序设计中的对象。597程序程序= =算法数据结构算法数据结构在面向过程的结构化程序设计中,人们常使在面向过程的结构化程序设计中,人们常使用这样的公式来表述程序用这样的公式来表述程序598对象对象 = = 算法算法 数据结构数据结构程序程序=(=(对象对象+ +对象对象+ +对象对象+)+ +)+ 消息消息 消息的作用就是对对象的控制。消息的作用就是对对象的控制。程序设计的关键是设计好每一个对象以及确程序设计的关键
336、是设计好每一个对象以及确定向这些对象发出的命令,使各对象完成相定向这些对象发出的命令,使各对象完成相应的操作。应的操作。面向对象的程序组成:面向对象的程序组成:599每一个实体都是对象。有一些对象是具有相每一个实体都是对象。有一些对象是具有相同的结构和特性的。同的结构和特性的。每个对象都属于一个特定的类型。每个对象都属于一个特定的类型。在在C+C+中对象的类型称为类中对象的类型称为类(class)(class)。类代表类代表了某一批对象的共性和特征。了某一批对象的共性和特征。类是对象的抽类是对象的抽象,而对象是类的具体实例象,而对象是类的具体实例(instance)(instance)。600
337、类是一种复杂的数据类是一种复杂的数据类型类型,它是将,它是将不同类型不同类型的数据的数据和和与这些数据相关的运算与这些数据相关的运算封装在一起封装在一起的的集合体。集合体。类的定义类的定义类将一些数据及与数据相关的类将一些数据及与数据相关的函数函数封装在一封装在一起,使类中的数据得到很好的起,使类中的数据得到很好的“保护保护”。在。在大型程序中不会被随意修改。大型程序中不会被随意修改。601类的定义格式:类的定义格式:class类名类名private:成员数据成员数据;成员函数;成员函数;public:成员数据成员数据;成员函数;成员函数;protected:成员数据成员数据;成员函数;成员函
338、数;;关键字关键字类名类名私有私有公有公有保护保护classStudentprivate:charName20;floatMath;floatChiese;public:floataverage;voidSetName(char*name);voidSetMath(floatmath);voidSetChinese(floatch);floatGetAverage(void);分号不能少分号不能少602用关键字用关键字priviate限定的成员称为限定的成员称为私有成员私有成员,对私有成员对私有成员限定在该类的内部使用限定在该类的内部使用,即,即只只允许该类中的成员函数使用私有的成员数允许该类
339、中的成员函数使用私有的成员数据据,对于私有的成员函数,只能被,对于私有的成员函数,只能被该类内该类内的成员函数调用的成员函数调用;类就相当于私有成员的;类就相当于私有成员的作用域。作用域。603用关键字用关键字public限定的成员称为限定的成员称为公有成员公有成员,公有成员的数据或函数不受类的限制,公有成员的数据或函数不受类的限制,可以可以在类内或类外自由使用在类内或类外自由使用;对类而言是透明的。;对类而言是透明的。604而用关键字而用关键字protected所限定的成员称为所限定的成员称为保护保护成员成员,只允许在类内及该类的派生类中使用,只允许在类内及该类的派生类中使用保护的数据或函数
340、。即保护成员的作用域是保护的数据或函数。即保护成员的作用域是该类及该类的派生类该类及该类的派生类。605私有成员私有成员 公有成员公有成员 保护成员保护成员类内函数类内函数 可以调用可以调用 可以调用可以调用 可以调用可以调用类外函数类外函数 不可调用不可调用 可以调用可以调用 不可调用不可调用私有函数私有函数 公有函数公有函数 保护函数保护函数类内函数类内函数 可以调用可以调用 可以调用可以调用 可以调用可以调用类外函数类外函数 不可调用不可调用 可以调用可以调用 不可调用不可调用606每一个限制词每一个限制词(private等等)在类体中可使用多在类体中可使用多次。一旦使用了限制词,该限制
341、词一直有效,次。一旦使用了限制词,该限制词一直有效,直到下一个限制词开始为止。直到下一个限制词开始为止。如果未加说明,类中成员默认的访问权限是如果未加说明,类中成员默认的访问权限是private,即私有的。,即私有的。607classStudentcharName20;floatMath;floatChiese;public:floataverage;voidSetName(char*name);voidSetMath(floatmath);voidSetChinese(floatch);floatGetAverage(void);均为私有权限均为私有权限均为公有权限均为公有权限608clas
342、sAfloatx,y;public:voidSetxy(floata,floatb)x=a;y=b;voidPrint(void)coutxtyendl;xySetxy()Print()A私有数据私有数据公有函数公有函数在在类外不能直接使用类外不能直接使用x或或y,必须通过,必须通过Setxy()给给x或或y赋值,通过赋值,通过Print()输出输出x或或y。609成员函数与成员数据的定义不分先后,可以先说明成员函数与成员数据的定义不分先后,可以先说明函数原型函数原型,再在类体外定义函数体。,再在类体外定义函数体。classAfloatx,y;public:voidSetxy(floata,f
343、loatb)x=a;y=b;voidPrint(void)coutxtyendl;在类体内定在类体内定义成员函数义成员函数610classAfloatx,y;public:voidSetxy(floata,floatb);voidPrint(void);;voidA:Setxy(floata,floatb)x=a;y=b;voidA:Print(void)coutxtyendl;在类体内说明在类体内说明成员函数原型成员函数原型在类体外定在类体外定义成员函数义成员函数611:()./函数体函数体在类体外定义成员函数的格式:在类体外定义成员函数的格式:voidA:Setxy(floata,floa
344、tb)x=a;y=b;函数类型函数类型类名类名函数名函数名形参列表形参列表函数体函数体612在定义一个类时,要注意如下几点:在定义一个类时,要注意如下几点:1、类类具具有有封封装装性性,并并且且类类只只是是定定义义了了一一种种结结构构(样样板板),所所以以类类中中的的任任何何成成员员数数据据均均不不能能使使用用关关键键字字extern,auto或或register限定其存储类型限定其存储类型。2、在在定定义义类类时时,只只是是定定义义了了一一种种导导出出的的数数据据类类型型,并并不不为为类类分分配配存存储储空空间间,所所以以,在在定定义义类类中中的的数数据据成成员员时时,不能对其初始化不能对其
345、初始化。如:。如:classTestintx=5,y=6;/是不允许的是不允许的externfloatx; /是不允许的是不允许的613在在C+语言中,语言中,结构体类型结构体类型只是类的一个特只是类的一个特例。结构体类型与类的唯一的区别在于:例。结构体类型与类的唯一的区别在于:在在类中,其成员的缺省的存取权限是私有的;类中,其成员的缺省的存取权限是私有的;而在结构体类型中,其成员的缺省的存取权而在结构体类型中,其成员的缺省的存取权限是公有的。限是公有的。614内联成员函数内联成员函数当当我我们们定定义义一一个个类类时时,可可以以在在类类中中直直接接定定义义函函数数体体。这这时时成成员员函函数
346、在编译时是作为数在编译时是作为内联函数内联函数来实现的。来实现的。同时,我们也可以在类体外定义类的内联成员函数,在类体内说明同时,我们也可以在类体外定义类的内联成员函数,在类体内说明函数,函数,在类体外定义时,在成员函数的定义前面加上关键字在类体外定义时,在成员函数的定义前面加上关键字inline。classAfloatx,y;public:voidSetxy(floata,floatb);voidPrint(void);;inlinevoidA:Setxy(floata,floatb)x=a;y=b;inlinevoidA:Print(void)coutxtyendl;说明该成员函数为内联说
347、明该成员函数为内联615对象对象只有在定义了属于类的变量后,系统才会为只有在定义了属于类的变量后,系统才会为类的变类的变量量分配空间。分配空间。在定义类时,只是定义了一种在定义类时,只是定义了一种数据类型数据类型,即即说明程说明程序中可能会出现该类型的数据,序中可能会出现该类型的数据,并不为类分配存储并不为类分配存储空间。空间。类的变量我们称之为类的变量我们称之为对象对象。对象是类的实例对象是类的实例,定义对象之前,一定要先说明该,定义对象之前,一定要先说明该对象的类。对象的类。616不同对象占据内存中的不同区域,它们所保存的数不同对象占据内存中的不同区域,它们所保存的数据各不相同,但据各不相
348、同,但对成员数据进行操作的成员函数的对成员数据进行操作的成员函数的程序代码均是一样的程序代码均是一样的。存储类型存储类型类名类名对象对象1,对象,对象2,.;Studentst1,st2;对象的定义格式:对象的定义格式:类名类名对象名对象名在建立对象时,只为对象分配用于保存数据成员的内存空在建立对象时,只为对象分配用于保存数据成员的内存空间,间,而成员函数的代码为该类的每一个对象所共享而成员函数的代码为该类的每一个对象所共享。617对象的定义方法同结构体定义变量的方法一样,也对象的定义方法同结构体定义变量的方法一样,也分三种,分三种,当类中有数据成员的访问权限为私有时,当类中有数据成员的访问权
349、限为私有时,不允许对对象进行初始化不允许对对象进行初始化。classAfloatx,y;public:voidSetxy(floata,floatb)x=a;y=b;voidPrint(void)coutxtyendl;a1,a2;voidmain(void)Aa3,a4;定义全局对象定义全局对象定义局部对象定义局部对象618对象的使用对象的使用一个对象的成员就是该对象的类所定义的成员,有一个对象的成员就是该对象的类所定义的成员,有成员数据和成员函数成员数据和成员函数,引用时同结构体变量类似,引用时同结构体变量类似,用用“.”运算符。运算符。619classAfloatx,y;public:f
350、loatm,n;voidSetxy(floata,floatb)x=a;y=b;voidPrint(void)coutxtyendl;voidmain(void)Aa1,a2;/定义对象定义对象a1.m=10;a1.n=20;/为公有成员数据赋值为公有成员数据赋值a1.Setxy(2.0,5.0);/为私有成员数据赋值为私有成员数据赋值a1.Print();Print()Setxy()a1nmyxPrint()Setxy()a2nmyx10202.05.0输出:输出:2 5620用成员选择运算符用成员选择运算符“.”只能访问对象的只能访问对象的公有公有成员成员,而不能访问对象的私有成员或保护成
351、,而不能访问对象的私有成员或保护成员。员。若要访问对象的私有的数据成员,只能若要访问对象的私有的数据成员,只能通过对象的公有成员函数来获取通过对象的公有成员函数来获取。621classAfloatx,y;public:floatm,n;voidSetxy(floata,floatb)x=a;y=b;voidPrint(void)coutxtyendl;voidmain(void)Aa1,a2;a1.m=10;a1.n=20; /为公有成员数据赋值为公有成员数据赋值a1.x=2;a1.y=5;a1.Setxy(2.0,5.0);a1.Print();必须通过类内公有函必须通过类内公有函数访问私有
352、数据成员数访问私有数据成员非法,私有成员非法,私有成员不能在类外访问不能在类外访问622同类型的对象之间可以整体赋值,这种赋值与对象的成员的访问同类型的对象之间可以整体赋值,这种赋值与对象的成员的访问权限无关。权限无关。classAfloatx,y;public:floatm,n;voidSetxy(floata,floatb)x=a;y=b;voidPrint(void)coutxtyendl;voidmain(void)Aa1,a2;a1.m=10;a1.n=20;/为公有成员数据赋值为公有成员数据赋值a1.Setxy(2.0,5.0);a2=a1;a1.Print();a2.Print(
353、);同类型的对象之同类型的对象之间可以整体赋值间可以整体赋值相当于成员数相当于成员数据间相互赋值据间相互赋值623对象可以作函数的入口参数(实参、形参),也可对象可以作函数的入口参数(实参、形参),也可以作函数的出口参数。这与一般变量作为函数的参以作函数的出口参数。这与一般变量作为函数的参数是完全相同的。数是完全相同的。可以定义类类型的指针,类类型的引用,对象数可以定义类类型的指针,类类型的引用,对象数组,指向类类型的指针数组和指向一维或多维数组,指向类类型的指针数组和指向一维或多维数组的指针变量组的指针变量一个类的对象,可作为另一个类的成员一个类的对象,可作为另一个类的成员624类体的区域称
354、为类体的区域称为类作用域类作用域。类的成员函数与。类的成员函数与成员数据,其作用域都是属于类的作用域,成员数据,其作用域都是属于类的作用域,仅在该类的范围内有效,仅在该类的范围内有效,故不能在主函数中故不能在主函数中直接通过函数名和成员名来调用函数直接通过函数名和成员名来调用函数。类作用域、类类型的作用域和对象的作用域类作用域、类类型的作用域和对象的作用域625classAfloatx,y;public:floatm,n;voidSetxy(floata,floatb)x=a;y=b;voidPrint(void)coutxtyendl;voidmain(void)Aa1,a2;a1.m=20
355、;a1.n=10;a1.Setxy(2.0,5.0);a1.Print();voidmain(void)Aa1,a2;m=20;n=10;Setxy(2.0,5.0);Print();用对象名调用用对象名调用不能直接调用不能直接调用626类类型的作用域:类类型的作用域:在函数定义之外定义的类,在函数定义之外定义的类,其类名的作用域为其类名的作用域为文件作用域文件作用域;而在函数体;而在函数体内定义的类,其类名的作用域为内定义的类,其类名的作用域为块作用域块作用域。对象的作用域对象的作用域与前面介绍的变量作用域完全与前面介绍的变量作用域完全相同相同,全局对象、局部对象、局部静态对象全局对象、局部
356、对象、局部静态对象等。等。627classAfloatx,y;public:floatm,n;voidSetxy(floata,floatb)x=a;y=b;voidPrint(void)coutxtyendl;a3,a4;voidmain(void)Aa1,a2;classBinti,j;public:voidSetij(intm,intn)i=m;j=n;Bb1,b2;a1.Setxy(2.0,5.0);b1.Setij(1,2);类类A:文件作用域,在:文件作用域,在整个文件中有效整个文件中有效类类B:块作用域,:块作用域,在函数内有效。在函数内有效。全局对象全局对象局部对象局部对象62
357、8类的嵌套在定义一个类时在定义一个类时,在其类体中又包含了一个在其类体中又包含了一个类的完整定义,称为类的嵌套类的完整定义,称为类的嵌套。类是允许嵌套定义的类是允许嵌套定义的。629classAclassBinti,j;public:voidSetij(intm,intn)i=m;j=n;floatx,y;public:Bb1,b2;voidSetxy(floata,floatb)x=a;y=b;voidPrint(void)coutxtyendl;类类B包含在类包含在类A中,中,为嵌套定义为嵌套定义嵌套类的对象嵌套类的对象在类在类A的定义中,并不为的定义中,并不为b1,b2分分配空间,配空间
358、,只有在定义类只有在定义类A的对象的对象时,才为嵌套类的对象分配空间时,才为嵌套类的对象分配空间。嵌套类的作用域在类嵌套类的作用域在类A的定义结的定义结束时结束束时结束。630类的对象如何引用私有数据成员类的对象如何引用私有数据成员1、通过公有函数为私有成员赋值、通过公有函数为私有成员赋值classTestintx,y;public:voidSetxy(inta,intb)x=a;y=b;voidPrintxy(void)coutx=xty=yendl;voidmain(void)Testp1,p2;p1.Setxy(3,5);p1.Printxy();调用公有函数为调用公有函数为私有对象赋值
359、私有对象赋值6312、利用指针访问私有数据成员利用指针访问私有数据成员classTestintx,y;public:voidSetxy(inta,intb)x=a;y=b;voidGetxy(int*px,int*py)*px=x;*py=y;/提取提取x,y值值voidPrintxy(void)coutx=xty=yendl;voidmain(void)Testp1,p2;p1.Setxy(3,5);inta,b;p1.Getxy(&a,&b);/将将a=x,b=ycoutatbendl;Setxy()Getxy()Printxy()xy35ba&apx&bpy35输出:输出:3 56323
360、、利用函数访问私有数据成员、利用函数访问私有数据成员classTestintx,y;public:voidSetxy(inta,intb)x=a;y=b;intGetx(void)returnx;/返回返回x值值intGety(void)returny;/返回返回y值值voidPrintxy(void)coutx=xty=yendl;voidmain(void)Testp1,p2;p1.Setxy(3,5);inta,b;a=p1.Getx();b=p1.Gety();/将将a=x,b=ycoutatbendl;函数值就是私有函数值就是私有成员变量的值成员变量的值6334、利用引用访问私有数据
361、成员、利用引用访问私有数据成员classTestintx,y;public:voidSetxy(inta,intb)x=a;y=b;voidGetxy(int&px,int&py)px=x; py=y; /提取提取x,y值值voidPrintxy(void)coutx=xty=yendl;voidmain(void)Testp1,p2;p1.Setxy(3,5);inta,b;p1.Getxy(a,b);/将将a=x,b=ycoutatbendl;Setxy()Getxy()Printxy()xy35bapxpy35输出:输出:3 5634类引用举例(三角形类:三角形的三边及与三边相关的运算)
362、类引用举例(三角形类:三角形的三边及与三边相关的运算)classTriangleprivate:floata,b,c;/三边为私有成员数据三边为私有成员数据public:voidSetabc(floatx,floaty,floatz);/置三边的值置三边的值voidGetabc(float&x,float&y,float&z);/取三边的值取三边的值floatPerimeter(void);/计算三角形的周长计算三角形的周长floatArea(void);/计算三角形的面积计算三角形的面积voidPrint(void);/打印相关信息打印相关信息;635voidTriangle:Setabc(
363、floatx,floaty,floatz)a=x;b=y;c=z;/置三边的值置三边的值voidTriangle:Getabc(float&x,float&y,float&z)/取三边的值取三边的值x=a; y=b;z=c;floatTriangle:Perimeter(void)return(a+b+c)/2;/计算三角形的周长计算三角形的周长floatTriangle:Area(void)/计算三角形的面积计算三角形的面积floatarea,p;p=Perimeter();area=sqrt(p-a)*(p-b)*(p-c)*p);returnarea;voidTriangle:Print
364、(void)/打印相关信息打印相关信息coutPeri=Perimeter()tArea=Area()endl;636voidmain(void)TriangleTri1;/定义三角形类的一个实例(对象)定义三角形类的一个实例(对象)Tri1.Setabc(4,5,6);/为三边置初值为三边置初值floatx,y,z;Tri1.Getabc(x,y,z);/将三边的值为将三边的值为x,y,z赋值赋值coutxtytzendl;cout“s=”Tri1.Perimeter()endl;/求三角形的周长求三角形的周长cout“Area=”Tri1.Area()endl;/求三角形的面积求三角形的面
365、积coutTri1:endl;Tri1.Print();/打印有关信息打印有关信息637类引用举例(学生类:学生的姓名成绩及相关的运算)类引用举例(学生类:学生的姓名成绩及相关的运算)classStucharName20;/学生姓名学生姓名floatChinese;/语文成绩语文成绩floatMath;/数学成绩数学成绩public:floatAverage(void); /计算平均成绩计算平均成绩floatSum(void);/计算总分计算总分voidShow(void);/打印信息打印信息voidSetStudent(char*,float,float);/为对象置姓名、成绩为对象置姓名、
366、成绩voidSetName(char*);/为对象置姓名为对象置姓名char*GetName(void);/取得学生姓名取得学生姓名;638floatStu:Average(void)return(Chinese+Math)/2;/平均成绩floatStu:Sum(void)returnChinese+Math;/总分voidStu:Show(void) /打印信息coutName:NameendlScore:ChinesetMathtaverage:Average()tSum:Sum()endl;voidStu:SetStudent(char*name,floatchinese,floatm
367、ath)strcpy(Name,name);/置姓名Chinese=chinese;/置语文成绩Math=math;/置数学成绩char*Stu:GetName(void) returnName;/返回姓名639voidmain(void)Stup1,p2;p1.SetStudent(“Liqing”,98,96);/对象置初值对象置初值p2.SetStudent(WangGang,90,88);/对象置初值对象置初值p1.Show();/打印信息打印信息p2.Show();/打印信息打印信息p1.SetName(“Zhaojian”);/重新置重新置p1对象的名字对象的名字p1.Show()
368、;cout“p1.Name:”p1.GetName()endl;/打印对象的名打印对象的名字字cout“p1.average:”p1.Average()endl;/打印对象的打印对象的成绩成绩640成员函数的重载成员函数的重载类中的成员函数与前面介绍的普通函数一样,类中的成员函数与前面介绍的普通函数一样,成员函数可以成员函数可以带有缺省的参数带有缺省的参数,也可以,也可以重载重载成员函数成员函数。重载时,函数的形参必须在重载时,函数的形参必须在类型类型或或数目数目上不上不同。同。641classTestintx,y;intm,n;public:voidSetxy(inta,intb)x=a;y
369、=b;voidSetxy(inta,intb,intc,intd)x=a;y=b;m=c;n=d;voidPrintxy(intx)cout“m=mt“n=nendl;voidPrintxy(void)coutx=xty=yendl;voidmain(void)Testp1,p2;p1.Setxy(3,5);p2.Setxy(10,20,30,40);/参数不同参数不同p1.Printxy();p2.Printxy();p2.Printxy(2);/参数、类型不同参数、类型不同输出:输出:x=3y=5x=10y=20m=30n=40642classStucharName20;floatChin
370、ese;floatMath;floatEnglish;floatPhysical;public:floatAverage(void);/语文、数学平均成绩floatAverage(intn);/四门课的平均成绩floatSum(void);/语文、数学总分floatSum(intn);/四门课总分voidShow(void);voidSetStudent(char*,float,float);/置姓名、语文、数学初值voidSetStudent(char*,float,float,float,float);/置姓名、成绩voidSetName(char*);char*GetName(void)
371、;643可以有缺省参数的成员函数,若形参不完全可以有缺省参数的成员函数,若形参不完全缺省,则必须从形参的缺省,则必须从形参的右边右边开始缺省。开始缺省。644缺省参数的成员函数缺省参数的成员函数classAfloatx,y;public:floatSum(void)returnx+y;voidSet(floata,floatb=10.0)x=a;y=b;voidPrint(void)coutx=xty=yendl;voidmain(void)Aa1,a2;a1.Set(2.0,4.0);couta1:;a1.Print();couta1.sum=a1.Sum()endl;a2.Set(20.0
372、);couta2:;a2.Print();couta2.sum=a2.Sum()endl;不缺省参数,不缺省参数,a1.x=2,a1.y=4缺省参数,缺省参数,a2.x=20,a2.y=10645定义类的指针及如何用指针来引用对象定义类的指针及如何用指针来引用对象classAfloatx,y;public:floatSum(void)returnx+y;voidSet(floata,floatb)x=a;y=b;voidPrint(void)coutx=xty=ySet(2.0,3.0);/通过指针引用对象的成员函数通过指针引用对象的成员函数p-Print();coutSum()endl;a2
373、.Set(10.0,20.0);a2.Print();Setxy()Getxy()Printxy()xy2.03.0pa1646定义类的数组及数组中元素的引用定义类的数组及数组中元素的引用voidmain(void)Stustu3;/定义类的数组定义类的数组Stu*pstu;/定义类的指针定义类的指针pstu=stu;/为指针赋值为指针赋值inti;stu0.SetStudent(“A”,90,90);/通过数组元素的引用通过数组元素的引用赋值赋值stu1.SetStudent(B,80,80);stu2.SetStudent(C,70,70);for(i=0;iShow();/指针变量指向数
374、组元素指针变量指向数组元素pstu+;/指针变量加一,指向下一元素指针变量加一,指向下一元素stupstupstu647返回引用类型的成员函数返回引用类型的成员函数(可以返回私有数据成员的引用可以返回私有数据成员的引用)classAfloatx,y;public:float&Getx(void)returnx; /返回返回x的引用的引用voidSet(floata,floatb)x=a;y=b;voidPrint(void)coutxtyendl;voidmain(void)Aa1,a2;a1.Set(3,5);couta1:; a1.Print();a1.Getx()=30;/将将a1对象中
375、的对象中的x成员赋值成员赋值coutnMax)/空间不够,动态开辟存储空间空间不够,动态开辟存储空间int*list;list=newintnMax+1;/开辟一较大的空间开辟一较大的空间for(inti=0;ix=a;this-y=b;系统自动将对象的指系统自动将对象的指针带到成员函数中针带到成员函数中653当对一个对象调用成员函数时,当对一个对象调用成员函数时,编译程序先编译程序先将对象的地址赋给将对象的地址赋给this指针,然后调用成员函指针,然后调用成员函数,数,每次成员函数存取数据成员时,也隐含每次成员函数存取数据成员时,也隐含使用使用this指针。指针。this指针具有如下形式的缺
376、省说明:指针具有如下形式的缺省说明:Stu*constthis;类名类名即即this指针里的地址是一个常量指针里的地址是一个常量654classSpublic:char*strp;intlength;voidIni(char*s);voidPrint(void);voidCopy(S&s);voidmain(void)Ss1,s2;s1.Ini(“China”);s2.Ini(“”);s1.Print();s2.Copy(s1);s2.Print();s1.Copy(s1);voidS:Ini(char*s)length=strlen(s);strp=newcharlength+1;strcp
377、y(strp,s);voidS:Print(void)coutstrpendl;voidS:Copy(S&s)if(strp)deletestrp;length=s.length;strp=newcharlength+1;strcpy(strp,s.strp);655voidS:Ini(char*s)length=strlen(s);strp=newcharlength+1;strcpy(strp,s);voidS:Copy(S&s)if(strp)deletestrp;length=s.length;strp=newcharlength+1;strcpy(strp,s.strp);*strp
378、lengthIni()Print()Copy()S字符串首址字符串首址字符串长度字符串长度s1.Ini(“China”);求长度求长度对象动态对象动态开辟空间开辟空间空间赋值空间赋值length=5strpC hina 0s2.Copy(s1);0strpC hina 0656voidS:Copy(S&s)if(strp)deletestrp;length=s.length;strp=newcharlength+1;strcpy(strp,s.strp);s1.Copy(s1);strpC hina 0length=5随机随机随机随机随机随机随机随机随机随机随机随机失去了原来的内容,失去了原来
379、的内容,不能正确复制不能正确复制657voidS:Copy(S&s)if(&s=this)cout“不能复制本身不能复制本身n”;elseif(strp)deletestrp;length=s.length;strp=newcharlength+1;strcpy(strp,s.strp);判断是否是自身复制判断是否是自身复制this为正在调用该函为正在调用该函数的数的对象对象的地址的地址s2.Copy(s1);s1.Copy(s1);if(s=*this)658第十章第十章构造函数和析构函数构造函数和析构函数659构造函数和析构函数是在类体中说明的两种构造函数和析构函数是在类体中说明的两种特殊
380、的成员函数特殊的成员函数。构造函数是在创建对象时,使用给定的值来构造函数是在创建对象时,使用给定的值来将对象初始化。将对象初始化。析构函数的功能正好相反,是在系统释放对析构函数的功能正好相反,是在系统释放对象前,对对象做一些善后工作象前,对对象做一些善后工作。660构构造造函函数数是是类类的的成成员员函函数数,系系统统约约定定构构造造函函数数名名必必须须与与类类名名相相同同。构构造造函函数数提提供供了了初初始始化对象的一种简单的方法化对象的一种简单的方法。构造函数构造函数可以带参数、可以重载可以带参数、可以重载,同时没有,同时没有返回值。返回值。661classAfloatx,y;public
381、:A(floata,floatb)x=a;y=b;/构造函数,初始化对象构造函数,初始化对象floatSum(void)returnx+y;voidSet(floata,floatb)x=a;y=b;Print(void)coutx=xty=yendl;voidmain(void)Aa1(2.0,3.0);/定义时调用构造函数初始化定义时调用构造函数初始化Aa2(1.0,2.0);a2.Set(10.0,20.0);/利用成员函数重新为对象赋值利用成员函数重新为对象赋值a1.Print();a2.Print();662对构造函数,说明以下几点:对构造函数,说明以下几点:1.构构造造函函数数的的
382、函函数数名名必必须须与与类类名名相相同同。构构造造函函数数的的主主要要作作用用是是完完成成初初始始化化对对象象的的数数据据成成员以及其它的初始化工作员以及其它的初始化工作。2.在在定定义义构构造造函函数数时时,不不能能指指定定函函数数返返回回值值的类型,也不能指定为的类型,也不能指定为void类型类型。3.一一个个类类可可以以定定义义若若干干个个构构造造函函数数。当当定定义义多个构造函数时,多个构造函数时,必须满足函数重载的原则。必须满足函数重载的原则。6634.构造函数可以指定参数的缺省值。构造函数可以指定参数的缺省值。5.若若定定义义的的类类要要说说明明该该类类的的对对象象时时,构构造造函
383、函数数必必须须是是公公有有的的成成员员函函数数。如如果果定定义义的的类类仅仅用用于于派派生生其其它它类类时时,则则可可将将构构造造函函数数定定义义为为保护的成员函数保护的成员函数。由由于于构构造造函函数数属属于于类类的的成成员员函函数数,它它对对私私有有数数据据成成员员、保保护护的的数数据据成成员员和和公公有有的的数数据据成成员员均能进行初始化均能进行初始化。664classAfloatx,y;public:A(floata,floatb=10)x=a;y=b;A()x=0;y=0;voidPrint(void)coutxtyendl;voidmain(void)Aa1,a2(20.0),a3
384、(3.0,7.0);a1.Print();a2.Print();a3.Print();00201037带缺省参数的构造函数带缺省参数的构造函数不带参数的构造函数不带参数的构造函数每一个对象必每一个对象必须要有相应的须要有相应的构造函数构造函数665每一个对象必须要有相应的构造函数每一个对象必须要有相应的构造函数若没有显式定义构造函数,若没有显式定义构造函数,系统默认缺省的构造函数。系统默认缺省的构造函数。classAfloatx,y;public:A()voidPrint(void)coutxtyendl;隐含的缺省的构造函数隐含的缺省的构造函数Aa1,a2;只允许这样定义对象只允许这样定义对
385、象对象开辟了空间,但没有初始化对象开辟了空间,但没有初始化666对局部对象,静态对象,全局对象的初始化对局部对象,静态对象,全局对象的初始化对于局部对象对于局部对象,每次定义对象时,都要调用每次定义对象时,都要调用构造函数。构造函数。对于静态对象对于静态对象,是在首次定义对象时,调用是在首次定义对象时,调用构造函数的,且由于对象一直存在,构造函数的,且由于对象一直存在,只调用只调用一次构造函数一次构造函数。对于全局对象,是对于全局对象,是在在main函数执行之前调用函数执行之前调用构造函数的构造函数的。667classAintx,y;public:A(inta)x=a;cout“1n”;A(i
386、nta,intb)x=a,y=b;cout“2n”;Aa1(3);voidf(void)Ab(2,3);voidmain(void)Aa2(4,5);f();f();1222668classAfloatx,y;public:A(floata,floatb)x=a;y=b;cout初始化自动局部对象初始化自动局部对象n;A() x=0;y=0;cout初始化静态局部对象初始化静态局部对象n;A(floata) x=a;y=0;cout初始化全局对象初始化全局对象n;voidPrint(void)coutxtyendl;Aa0(100.0);/定义全局对象定义全局对象voidf(void)cout
387、进入进入f()函数函数n;Aa2(1,2);staticAa3;/初始化局部静态对象初始化局部静态对象voidmain(void)cout进入进入main函数函数n;Aa1(3.0,7.0);/定义局部自动对象定义局部自动对象f();f();初始化全局对象初始化全局对象进入进入main函数函数初始化自动局部对象初始化自动局部对象进入进入f()函数函数初始化局部静态变量初始化局部静态变量进入进入f()函数函数初始化自动局部对象初始化自动局部对象初始化自动局部对象初始化自动局部对象669缺省的构造函数缺省的构造函数在在定定义义类类时时,若若没没有有定定义义类类的的构构造造函函数数,则则编编译器译器
388、自动自动产生一个缺省的构造函数,其格式为:产生一个缺省的构造函数,其格式为:className:className()缺缺省省的的构构造造函函数数并并不不对对所所产产生生对对象象的的数数据据成成员员赋初值赋初值;即;即新产生对象的数据成员的值是不确定的。新产生对象的数据成员的值是不确定的。670classAfloatx,y;public:A()/缺省的构造函数,编译器自动产生缺省的构造函数,编译器自动产生,可以不写可以不写floatSum(void)returnx+y;voidSet(floata,floatb)x=a;y=b;voidPrint(void)coutx=xty=yendl;vo
389、idmain(void)Aa1,a2;/产生对象时,自动调用缺省的构造函数,不赋值产生对象时,自动调用缺省的构造函数,不赋值a1.Set(2.0,4.0);couta1:;a1.Print();couta1.sum=a1.Sum()endl;a2.Print();/打印随机值打印随机值671关于缺省的构造函数,说明以下几点:关于缺省的构造函数,说明以下几点:1、在在定定义义类类时时,只只要要显显式式定定义义了了一一个个类类的的构构造函数,则编译器就不产生缺省的构造函数造函数,则编译器就不产生缺省的构造函数2、所有的对象在定义时,必须调用构造函数所有的对象在定义时,必须调用构造函数不存在没有构造
390、函数的对象!不存在没有构造函数的对象!672classAfloatx,y;public:A(floata,floatb)x=a; y=b; voidPrint(void)coutxtyendl; ;voidmain(void)Aa1;Aa2(3.0,30.0);显式定义了构造函数,不显式定义了构造函数,不产生缺省的构造函数产生缺省的构造函数error,定义时,没有定义时,没有构造函数可供调用构造函数可供调用6733、在在类类中中,若若定定义义了了没没有有参参数数的的构构造造函函数数,或或各各参参数数均均有有缺缺省省值值的的构构造造函函数数也也称称为为缺缺省省的的构构造造函数,函数,缺省的构造函
391、数只能有一个。缺省的构造函数只能有一个。4、产产生生对对象象时时,系系统统必必定定要要调调用用构构造造函函数数。所所以以任一对象的构造函数必须唯一任一对象的构造函数必须唯一。674classAfloatx,y;public:A(floata=10,floatb=20)x=a; y=b; A()voidPrint(void)coutxtyendl; ;voidmain(void)Aa1;Aa2(3.0,30.0);两个函数均为缺两个函数均为缺省的构造函数省的构造函数两个构造函数均可供调用,构造函数不唯一两个构造函数均可供调用,构造函数不唯一675构造函数与构造函数与new运算符运算符可以使用可以
392、使用new运算符来运算符来动态地动态地建立对象。建立建立对象。建立时时要自动调用构造函数要自动调用构造函数,以便完成初始化对象的数,以便完成初始化对象的数据成员。最后返回这个动态对象的起始地址。据成员。最后返回这个动态对象的起始地址。用用new运算符产生的动态对象,在不再使用这运算符产生的动态对象,在不再使用这种对象时,必须用种对象时,必须用delete运算符来释放对象所占用运算符来释放对象所占用的存储空间。的存储空间。用用new建立类的对象时,可以使用参数初始化建立类的对象时,可以使用参数初始化动态空间。动态空间。676classAfloatx,y;public:A(floata,float
393、b)x=a;y=b;A()x=0;y=0;voidPrint(void)coutxtyPrint();pa2-Print();deletepa1;/用用delete释放空间释放空间deletepa2;/用用delete释放空间释放空间35400677析构函数析构函数析构函数的作用与构造函数正好相反,析构函数的作用与构造函数正好相反,是在对象的生是在对象的生命期结束时,释放系统为对象所分配的空间,即要撤消一命期结束时,释放系统为对象所分配的空间,即要撤消一个对象。个对象。析构函数也是类的成员函数,定义析构函数的格式为:析构函数也是类的成员函数,定义析构函数的格式为:ClassName:Class
394、Name()./函数体函数体;678析构析构函数的特点如下:函数的特点如下:1、析析构构函函数数是是成成员员函函数数,函函数数体体可可写写在在类类体体内内,也可写在类体外。也可写在类体外。2、析析构构函函数数是是一一个个特特殊殊的的成成员员函函数数,函函数数名名必必须须与与类类名名相相同同,并并在在其其前前面面加加上上字字符符“”,以以便便和和构造函数名相区别构造函数名相区别。3、析析构构函函数数不不能能带带有有任任何何参参数数,不不能能有有返返回回值值,不指定函数类型。不指定函数类型。679在程序的执行过程中,当遇到某一对象的生存期结在程序的执行过程中,当遇到某一对象的生存期结束时,系统自动
395、调用析构函数,然后再收回为对象束时,系统自动调用析构函数,然后再收回为对象分配的存储空间。分配的存储空间。4、一一个个类类中中,只只能能定定义义一一个个析析构构函函数数,析析构构函函数数不允许重载。不允许重载。5、析构函数是在撤消对象时由系统自动调用的。、析构函数是在撤消对象时由系统自动调用的。680classAfloatx,y;public:A(floata,floatb)x=a;y=b;cout调用非缺省的构造函数调用非缺省的构造函数n;A() x=0;y=0;cout调用缺省的构造函数调用缺省的构造函数n;A()cout调用析构函数调用析构函数n;voidPrint(void)coutx
396、tyendl; ;voidmain(void)Aa1;Aa2(3.0,30.0);cout退出主函数退出主函数n;调用缺省的构造函数调用缺省的构造函数调用非缺省的构造函数调用非缺省的构造函数退出主函数退出主函数调用析构函数调用析构函数调用析构函数调用析构函数681在在程程序序的的执执行行过过程程中中,对对象象如如果果用用new运运算算符符开开辟辟了了空空间间,则则在在类类中中应应该该定定义义一一个个析析构构函函数数,并并在在析析构构函函数数中中使使用用delete删删除除由由new分分配配的的内内存存空空间间。因因为为在在撤撤消消对对象象时时,系系统统自自动动收收回回为为对对象象所所分分配配的
397、的存存储储空空间间,而而不不能能自自动动收收回回由由new分分配配的的动动态态存存储储空间。空间。682classStrchar*Sp;intLength;public:Str(char*string)if(string)Length=strlen(string);Sp=newcharLength+1;strcpy(Sp,string);elseSp=0;voidShow(void) coutSpendl; Str()if(Sp)deleteSp; ;voidmain(void)Strs1(StudyC+);s1.Show();在构造函数中将在构造函数中将成成员数据指针员数据指针指向动指向动态
398、开辟的内存态开辟的内存用初值为开辟用初值为开辟的内存赋值的内存赋值析构函数,当释析构函数,当释放对象时收回用放对象时收回用new开辟的空间开辟的空间683StudyC+0stringLength=strlen(string);Sp=newcharLength+1;Spnew开辟的空间开辟的空间strcpy(Sp,string);StudyC+0684用用new运算符为对象分配动态存储空间时,调运算符为对象分配动态存储空间时,调用了构造函数,用用了构造函数,用delete删除这个空间时,调用了删除这个空间时,调用了析构函数。析构函数。当使用运算符当使用运算符delete删除一个由删除一个由new
399、动动态产生的对象时,它首先调用该对象的析构函数,态产生的对象时,它首先调用该对象的析构函数,然后再释放这个对象占用的内存空间然后再释放这个对象占用的内存空间。可以用可以用new运算符为对象分配存储空间,如:运算符为对象分配存储空间,如:A*p;p=newA;这时必须用这时必须用delete才能释放这一空间。才能释放这一空间。deletep;685classAfloatx,y;public:A(floata,floatb) x=a;y=b;cout调用了构造函数调用了构造函数n;voidPrint(void)coutxtyendl;A() cout调用了析构函数调用了析构函数n;voidmain
400、(void)coutPrint();deletepa1;/调用析构函数调用析构函数cout退出退出main()函数函数n;进入进入main()函数函数调用了构造函数调用了构造函数35调用了析构函数调用了析构函数退出退出main()函数函数686不同存储类型的对象调用构造函数及析构函数不同存储类型的对象调用构造函数及析构函数1、对对于于全全局局定定义义的的对对象象(在在函函数数外外定定义义的的对对象象),在在程程序序开开始始执执行行时时,调调用用构构造造函函数数;到到程程序序结结束束时时,调用析构函数。调用析构函数。2、对对于于局局部部定定义义的的对对象象(在在函函数数内内定定义义的的对对象象)
401、,当当程程序序执执行行到到定定义义对对象象的的地地方方时时,调调用用构构造造函函数数;在退出对象的作用域时,调用析构函数。在退出对象的作用域时,调用析构函数。3、用用static定定义义的的局局部部对对象象,在在首首次次到到达达对对象象的的定定义时调用构造函数;到程序结束时,调用析构函数义时调用构造函数;到程序结束时,调用析构函数6874、对对于于用用new运运算算符符动动态态生生成成的的对对象象,在在产产生生对对象象时时调调用用构构造造函函数数,只只有有使使用用delete运运算算符符来来释释放放对对象象时时,才才调调用用析析构构函函数数。若若不不使使用用delete来来撤撤消消动动态态生生
402、成成的的对对象象,程程序序结结束束时时,对对象象仍仍存存在在,并并占占用用相相应应的的存存储储空空间间,即即系系统统不不能能自自动动地地调调用用析析构构函函数来撤消动态生成的对象。数来撤消动态生成的对象。688classAfloatx,y;public:A(floata,floatb)x=a;y=b;cout初始化自动局部对象初始化自动局部对象n;A() x=0;y=0;cout初始化静态局部对象初始化静态局部对象n;A(floata) x=a;y=0;cout初始化全局对象初始化全局对象n;A()cout“调用析构函数调用析构函数”endl;Aa0(100.0);/定义全局对象定义全局对象v
403、oidf(void)cout进入进入f()函数函数n;Aab(10.0,20.0);/定义局部自动对象定义局部自动对象staticAa3;/初始化局部静态对象初始化局部静态对象voidmain(void)cout进入进入main函数函数n;f();f();初始化全局对象初始化全局对象进入进入main函数函数初始化自动局部对象初始化自动局部对象进入进入f()函数函数初始化静态局部对象初始化静态局部对象进入进入f()函数函数初始化自动局部对象初始化自动局部对象调用析构函数调用析构函数调用析构函数调用析构函数调用析构函数调用析构函数调用析构函数调用析构函数689举例:建立一个类举例:建立一个类NUM
404、,求指定数据范围内的所有素数。,求指定数据范围内的所有素数。如:如:定义类定义类NUM的对象的对象test,查找范围为,查找范围为100200,正,正确的输出结果:确的输出结果:num=21101103107109113127131690动态构造及析构对象数组动态构造及析构对象数组用用new运算符来动态生成对象数组时,自动调用构运算符来动态生成对象数组时,自动调用构造函数,而用造函数,而用delete运算符来运算符来释放释放p1所指向的对象所指向的对象数组数组占用的存储空间时,在指针变量的前面必须加占用的存储空间时,在指针变量的前面必须加上上,才能将数组元素所占用的空间全部释放。才能将数组元素
405、所占用的空间全部释放。否则,只释放第否则,只释放第0个元素所占用的空间。个元素所占用的空间。pa1=newA3;.deletepa1;691classAfloatx,y;public:A(floata=0,floatb=0)x=a;y=b;cout调用了构造函数调用了构造函数n;voidPrint(void)coutxtyendl;A()cout调用了析构函数调用了析构函数n;voidmain(void)cout进入进入main()函数函数n;A*pa1;pa1=newA3;/开辟数组空间开辟数组空间coutn完成开辟数组空间完成开辟数组空间nn;deletepa1;/必须用必须用删除开辟的空
406、间删除开辟的空间cout退出退出main()函数函数n;进入进入main()函数函数调用了构造函数调用了构造函数调用了构造函数调用了构造函数调用了构造函数调用了构造函数完成开辟数组空间完成开辟数组空间调用了析构函数调用了析构函数调用了析构函数调用了析构函数调用了析构函数调用了析构函数退出退出main()函数函数692缺省的析构函数若若在在类类的的定定义义中中没没有有显显式式地地定定义义析析构构函函数数时时,则则编编译器自动地产生一个缺省的析构函数,其格式为:译器自动地产生一个缺省的析构函数,其格式为:ClassName:ClassName();任何对象都必须有构造函数和析构函数,但在撤消任何对
407、象都必须有构造函数和析构函数,但在撤消对象时,对象时,要释放对象的数据成员用要释放对象的数据成员用new运算符分配运算符分配的动态空间时,必须显式地定义析构函数的动态空间时,必须显式地定义析构函数。693实现类型转换的构造函数实现类型转换的构造函数同类型的对象可以相互赋值,相当于类中的数据同类型的对象可以相互赋值,相当于类中的数据成员相互赋值;成员相互赋值;如果如果直接将数据赋给对象直接将数据赋给对象,所赋入的数据需要强,所赋入的数据需要强制类型转换,制类型转换,这种转换需要调用构造函数这种转换需要调用构造函数。694classAfloatx,y;public:A(floata,floatb)
408、x=a;y=b;cout调用构造函数调用构造函数n;A()cout调用析构函数调用析构函数n;voidPrint(void)coutxtyendl; ;voidmain(void)Aa1(1.0,10.0);a1.Print();a1=A(3.0,30.0);a1.Print();cout退出主函数退出主函数n;调用构造函数调用构造函数产生临时对象,产生临时对象,初始化并赋值后初始化并赋值后立即释放立即释放110调用构造函数调用构造函数调用析构函数调用析构函数330退出主函数退出主函数调用析构函数调用析构函数695注意:当构造函数只有一个参数时,可以用注意:当构造函数只有一个参数时,可以用=强
409、制赋值强制赋值。classBfloatx;public:B(floata)x=a;cout调用构造函数调用构造函数n;B()cout调用析构函数调用析构函数n;voidPrint(void)coutxendl;voidmain(void)Bb1(1.0);b1.Print();Bb2=100;b2.Print();b1=10;b1.Print();cout退出主函数退出主函数n;调用构造函数调用构造函数单参数可以这样赋值单参数可以这样赋值1调用构造函数调用构造函数100调用构造函数调用构造函数调用析构函数调用析构函数10退出主函数退出主函数调用析构函数调用析构函数调用析构函数调用析构函数b1=
410、B(10)产生一个产生一个临时对象临时对象696完成拷贝功能的构造函数完成拷贝功能的构造函数可以在定义一个对象的时候用另一个对象为其初始可以在定义一个对象的时候用另一个对象为其初始化,化,即构造函数的参数是另一个对象的引用即构造函数的参数是另一个对象的引用,这种这种构造函数常为完成拷贝功能的构造函数。构造函数常为完成拷贝功能的构造函数。完成拷贝功能的构造函数的一般格式为:完成拷贝功能的构造函数的一般格式为:ClassName:ClassName(ClassName&)./函数体完成对应数据成员的赋值函数体完成对应数据成员的赋值697classAfloatx,y;public:A(floata=
411、0,floatb=0)x=a;y=b;A(A&a)x=a.x;y=a.y;;voidmain(void)Aa1(1.0,2.0);Aa2(a1);形参形参必须必须是同类型对象的引用是同类型对象的引用实参是同类型的对象实参是同类型的对象698classAfloatx,y;public:A(floata=0,floatb=0)x=a;y=b;cout调用了构造函数调用了构造函数n;A(A&a)x=a.x;y=a.y;cout“调用了完成拷贝功能的构造函数调用了完成拷贝功能的构造函数n”;voidPrint(void)coutxtyendl;A()cout调用了析构函数调用了析构函数n;voidma
412、in(void)Aa1(1.0,2.0);Aa2(a1);a1.Print();a2.Print();调用了构造函数调用了构造函数调用了完成拷贝功能的构造函数调用了完成拷贝功能的构造函数1212调用了析构函数调用了析构函数调用了析构函数调用了析构函数用已有的对象中的数据为新创建的对象赋值用已有的对象中的数据为新创建的对象赋值699如如果果没没有有定定义义完完成成拷拷贝贝功功能能的的构构造造函函数数,编编译译器器自自动动生生成成一一个个隐隐含含的的完完成成拷拷贝贝功功能能的的构构造函数造函数,依次完成类中对应数据成员的拷贝依次完成类中对应数据成员的拷贝。A:A(A&a)x=a.x;y=a.y;隐
413、含的构隐含的构造函数造函数700classAfloatx,y;public:A(floata=0,floatb=0)x=a;y=b;cout调用了构造函数调用了构造函数n;voidPrint(void)coutxtyendl;A()cout调用了析构函数调用了析构函数n;voidmain(void)Aa1(1.0,2.0);Aa2(a1);Aa3=a1;/可以这样赋值可以这样赋值a1.Print();a2.Print();a3.Print();调用了构造函数调用了构造函数121212调用了析构函数调用了析构函数调用了析构函数调用了析构函数调用了析构函数调用了析构函数隐含了拷贝隐含了拷贝的构造函
414、数的构造函数701由由编编译译器器为为每每个个类类产产生生的的这这种种隐隐含含的的完完成成拷拷贝贝功功能能的的构构造造函函数数,依依次次完完成成类类中中对对应应数数据据成员的拷贝。成员的拷贝。但但是是,当当类类中中的的数数据据成成员员中中使使用用new运运算算符符,动动态态地地申申请请存存储储空空间间进进行行赋赋初初值值时时,必必须须在在类类中中显显式式地地定定义义一一个个完完成成拷拷贝贝功功能能的的构构造造函函数,以便正确实现数据成员的复制数,以便正确实现数据成员的复制。702classStrintLength;char*Sp;public:Str(char*string)if(string
415、)Length=strlen(string);Sp=newcharLength+1;strcpy(Sp,string);elseSp=0;voidShow(void)coutSpendl;Str()if(Sp) deleteSp;voidmain(void)Strs1(StudyC+);Strs2(s1);s1.Show();s2.Show();隐含的拷贝构造函数为:隐含的拷贝构造函数为:Str:Str(Str&s)Length=s.Length;Sp=s.Sp;“StudyC+”s1.Sps2.Spnew开辟开辟的空间的空间同一空间释放两次,造成运同一空间释放两次,造成运行错误。行错误。70
416、3在这种情况下,在这种情况下,必须必须要定义完成拷贝功能的构造函数。要定义完成拷贝功能的构造函数。Str:Str(Str&s)if(s.Sp)Length=s.Length;Sp=newcharLength+1;strcpy(Sp,s.Sp);elseSp=0;Strs2(s1);“StudyC+”s1.Sp原来原来s1开开辟的空间辟的空间“StudyC+”s2.Sp拷贝函数中用拷贝函数中用new开辟的空间开辟的空间704构造函数与对象成员构造函数与对象成员对类对类A的对象初始化的同时还要对其的对象初始化的同时还要对其成员数成员数据类据类B的对象的对象进行初始化,所以,进行初始化,所以,类类A
417、的构造的构造函数中要调用类函数中要调用类B的构造函数的构造函数。classB.;classAintx,y;Bb1,b2;;在类在类A中包含中包含类类B的对象的对象705classAfloatx,y;public:A(inta,intb)x=a;y=b;voidShow()coutx=xty=yn;classCfloatz;Aa1;/类类C的数据成员为类的数据成员为类A的对象的对象a1public:C(inta,intb,intc):a1(b,c)z=a;/类类C的对象初始化的对象初始化voidShow()cout“z=an;a1.Show();voidmain(void)Cc1(1,2,3);
418、/对类对类C的对象初始化的对象初始化c1.Show();在类在类C中调用类中调用类A的成员函数的成员函数利用类利用类A的构造函数对类的构造函数对类A的对象初始化的对象初始化706xyA()Show()za1.xa1.ya1.A()a1.Show()C()Show()a1ACa1(b,c)707ClassName:ClassName(args):c1(args1),.,cn(agrsn)./对其它成员的初始化对其它成员的初始化初初始始化化对对象象成成员员的的参参数数(实实参参)可可以以是是表表达达式式。,也可以仅对部分对象成员进行初始化。也可以仅对部分对象成员进行初始化。708classAflo
419、atx,y;public:A(inta,intb) x=a;y=b;voidShow()coutx=xty=yn;classBfloatx1,y1;public:B(inta,intb)x1=a;y1=b;voidShow()cout“x1=“x1t“y=“yn;classCfloatz;Aa1;Bb1;public:C(inta,intb,intc,intd,inte):a1(a+b,c),b1(a,d)z=e;voidShow()cout“z=an;a1.Show();b1.Show();voidmain(void)Cc1(1,2,3,4,5);/对类对类C的对象初始化的对象初始化对象初始
420、化的参数可以是表达式对象初始化的参数可以是表达式709对对对对象象成成员员的的构构造造函函数数的的调调用用顺顺序序取取决决于于这这些些对对象象成成员员在在类类中中说说明明的的顺顺序序,与与它它们们在在成成员初始化列表中的顺序无关。员初始化列表中的顺序无关。当当建建立立类类ClassName的的对对象象时时,先先调调用用各各个个对对象象成成员员的的构构造造函函数数,初初始始化化相相应应的的对对象象成成员员,然然后后才才执执行行类类ClassName的的构构造造函函数数,初初始始化化类类ClassName中中的的其其它它成成员员。析析构构函函数的调用顺序与构造函数正好相反。数的调用顺序与构造函数正
421、好相反。710classAfloatx;public:A(inta)x=a;cout“调用了调用了A的构造函数的构造函数n”;A()cout“调用了调用了A的析构函数的析构函数n”;classBfloaty;public:B(inta)y=a;cout“调用了调用了B的构造函数的构造函数n”;B()cout“调用了调用了B的析构函数的析构函数n”;classCfloatz;Bb1;Aa1;public:C(inta,intb,intc):a1(a),b1(b)z=c;cout“调用了调用了C的构造函数的构造函数n”;C()cout“调用了调用了C的析构函数的析构函数n”;voidmain(vo
422、id)Cc1(1,2,3);调用了调用了B的构造函数的构造函数调用了调用了A的构造函数的构造函数调用了调用了C的构造函数的构造函数调用了调用了C的析构函数的析构函数调用了调用了A的析构函数的析构函数调用了调用了B的析构函数的析构函数711第十一章 继承和派生类712继承性是面向对象程序设计中最重要的机制。继承性是面向对象程序设计中最重要的机制。这种机制这种机制提供了无限重复利用程序资源的一提供了无限重复利用程序资源的一种途径种途径。通过。通过C+语言中的继承机制,语言中的继承机制,可以可以扩充和完善旧的程序设计以适应新的需求。扩充和完善旧的程序设计以适应新的需求。这样不仅可以节省程序开发的时间
423、和资源,这样不仅可以节省程序开发的时间和资源,并且为未来程序增添了新的资源。并且为未来程序增添了新的资源。713classStudentintnum;charname30;charsex;public:voiddisplay()/对成员函数对成员函数display的定义的定义coutnum:numendl;coutname:nameendl;coutsex:sexendl;714classStudend1intnum;/此行原来己有此行原来己有charname20;/此行原来己有此行原来己有charsex;/此行原来己有此行原来己有intage;charaddr20;public:voiddi
424、splay();/此行原来己有此行原来己有coutnum:numendl;/此行原来己有此行原来己有coutname:nameendl;/此行原来己有此行原来己有coutsex:sexendl;/此行原来己有此行原来己有coutage:ageendl;coutaddress:addrendl;715利用原来定义的类利用原来定义的类StudentStudent作为基础,再加上新的作为基础,再加上新的内容即可,以减少重复的工作量。内容即可,以减少重复的工作量。 C+C+提供的继承提供的继承机制就是为了解决这个问题。机制就是为了解决这个问题。在在C+中所谓中所谓“继承继承”就是在一个已存在的类的基就
425、是在一个已存在的类的基础上建立一个新的类。础上建立一个新的类。已存在的类称为已存在的类称为“基类基类(baseclass)”或或“父类父类(fatherclass)”。新建立的。新建立的类称为类称为“派生类派生类(derivedclass)”或或“子类子类(sonclass)”。716classStudent1:publicStudent/声明基类是声明基类是Studentprivate:intage;/新增加的数据成员新增加的数据成员stringaddr;/新增加的数据成员新增加的数据成员public:voiddisplay_1()/新增加的成员函数新增加的成员函数coutage:ageen
426、dl;coutaddress:addrendl;717类类A派生类派生类B:类:类A为基类,类为基类,类B为派生类。为派生类。AB新增加的成员数新增加的成员数据和成员函数据和成员函数718在在C+语言中,语言中,一个派生类可以从一个基类一个派生类可以从一个基类派生,也可以从多个基类派生。派生,也可以从多个基类派生。从一个基类从一个基类派生的继承称为单继承;从多个基类派生的派生的继承称为单继承;从多个基类派生的继承称为多继承。继承称为多继承。719通过继承机制,可以利用已有的数据类型来通过继承机制,可以利用已有的数据类型来定义新的数据类型。定义新的数据类型。所定义的新的数据类型所定义的新的数据类
427、型不仅拥有新定义的成员,而且还同时拥有旧不仅拥有新定义的成员,而且还同时拥有旧的成员。的成员。我们称已存在的用来派生新类的类我们称已存在的用来派生新类的类为基类,又称为父类。为基类,又称为父类。由已存在的类派生出由已存在的类派生出的新类称为派生类,又称为子类。的新类称为派生类,又称为子类。720在建立派生类的过程中,基类不会做任何改在建立派生类的过程中,基类不会做任何改变,变,派生类则除了继承基类的所有可引用的派生类则除了继承基类的所有可引用的成员变量和成员函数外,还可另外定义本身成员变量和成员函数外,还可另外定义本身的成员变量和处理这些变量的函数,的成员变量和处理这些变量的函数,由于派由于派
428、生类可继承基类的成员变量和成员函数,因生类可继承基类的成员变量和成员函数,因此在基类中定义好的数据和函数等的程序代此在基类中定义好的数据和函数等的程序代码可重复使用,这样可以提高程序的可靠性。码可重复使用,这样可以提高程序的可靠性。721当当从从已已有有的的类类中中派派生生出出新新的的类类时时,可可以以对对派派生生类类做做以以下下几几种变化:种变化:1、可以继承基类的成员数据或成员函数。可以继承基类的成员数据或成员函数。2、可以增加新的成员变量。、可以增加新的成员变量。3、可以增加新的成员函数。、可以增加新的成员函数。4、可以重新定义已有的成员函数。、可以重新定义已有的成员函数。5、可以改变现
429、有的成员属性。、可以改变现有的成员属性。在在C+中中有有二二种种继继承承:单单一一继继承承和和多多重重继继承承。当当一一个个派派生生类类仅仅由由一一个个基基类类派派生生时时,称称为为单单一一继继承承;而而当当一一个个派派生生类类由二个或更多个基类所派生时,称为多重继承。由二个或更多个基类所派生时,称为多重继承。722类类A派生类派生类B:类:类A为基类,类为基类,类B为派生类。为派生类。AB但派生并不是简单的扩充,有可能改变基类的性质。但派生并不是简单的扩充,有可能改变基类的性质。有三种派生方式:公有派生、保护派生、私有派生。有三种派生方式:公有派生、保护派生、私有派生。classB:publ
430、icA.;classB:protectedA.;classB:privateA.;默认的是私有派生。默认的是私有派生。classB:A.;A为私有派生为私有派生723从一个基类派生一个类的一般格式为:从一个基类派生一个类的一般格式为:classClassName:BaseClassNameprivate:.;/私有成员说明私有成员说明public:.;/公有成员说明公有成员说明protected:.;/保护成员说明保护成员说明派生类名派生类名基类名基类名继承方式继承方式public:表示公有基类表示公有基类private:表示私有基类表示私有基类(默认默认)protected:表示保护基类表示
431、保护基类派生类中新增加的成员派生类中新增加的成员724公有派生class ClassName: public BaseClassName公有派生时,公有派生时,基类中所有成员在派生类中保持各个成员的访问权限基类中所有成员在派生类中保持各个成员的访问权限。公有派生,派生类中保持基类的成员特性公有派生,派生类中保持基类的成员特性基类成员属性基类成员属性派生类中派生类中派生类外派生类外公有公有可以引用可以引用可以引用可以引用保护保护可以引用可以引用不可引用不可引用私有私有不可引用不可引用不可引用不可引用基类:基类:public:在派生类和类外可以使用在派生类和类外可以使用protected:在派生类
432、中使用在派生类中使用private:不能在派生类中使用不能在派生类中使用725x(私有私有)y(保护保护)z(公有公有)A()Getx()Gety()ShowA()Ax(私私有私私有)y(保护保护)z(公有公有)A()Getx()Gety()ShowA()Bm(私有私有)n(私有私有)B()Show()Sum()publicx在类在类B新增加的成员中不能直新增加的成员中不能直接调用接调用y在类在类B中可以调用中可以调用z在整个文件中可以调用在整个文件中可以调用对类对类B的对象初始化即是对的对象初始化即是对x,y,z,m,n等全部成员的初始化等全部成员的初始化726classAintx;prot
433、ected:inty;public:intz;A(inta,intb,intc)x=a;y=b;z=c;/基类初始化基类初始化intGetx()returnx;/返回返回xintGety()returny;/返回返回yvoidShowA()coutx=xty=ytz=zn;classB:publicAintm,n;public: B(inta,intb,intc,intd,inte):A(a,b,c)m=d;n=e;voidShow()cout“m=mt“n=nn;coutx=Getx()ty=ytz=zn;intSum()return(Getx()+y+z+m+n);voidmain(voi
434、d)Bb1(1,2,3,4,5);b1.ShowA(); b1.Show();coutSum=b1.Sum()n;coutx=b1.Getx()t;couty=b1.Gety()t;coutz=b1.zn;公有派生公有派生对基类初始化对基类初始化因为因为x是基类私有,所以在派生类和类外中不能直接引用是基类私有,所以在派生类和类外中不能直接引用因为因为y是基类保护,所以在是基类保护,所以在派生类中可以直接引用。而派生类中可以直接引用。而在类外不可直接引用。在类外不可直接引用。因为因为z是基类公有,所是基类公有,所以在派生类中和类外以在派生类中和类外均可直接引用。均可直接引用。727私有派生cla
435、ss ClassName: private BaseClassName私私有有派派生生时时,基基类类中中公公有有成成员员和和保保护护成成员员在在派派生生类类中中均均变变为为私私有有的的,在在派派生生类类中中仍仍可可直直接接使使用用这这些些成成员员,基基类类中中的的私私有有成成员员,在在派派生生类类中不可直接使用。中不可直接使用。私有派生,派生类中基类公有和保护成员成为私有私有派生,派生类中基类公有和保护成员成为私有基类成员属性基类成员属性派生类派生类派生类外派生类外公有公有可以引用可以引用不可引用不可引用保护保护可以引用可以引用不可引用不可引用私有私有不可引用不可引用不可引用不可引用基类:基类
436、:public:(变为私有变为私有)在派生类中使用,类外不可使用在派生类中使用,类外不可使用protected:(变为私有)在派生类中使用,类外不可使用变为私有)在派生类中使用,类外不可使用private:不能在派生类中和类外使用不能在派生类中和类外使用728x(私有私有)y(保护保护)z(公有公有)A()Getx()Gety()ShowA()Ax(私私有私私有)y(私有私有)z(私有私有)A()Getx()Gety()ShowA()Bm(私有私有)n(私有私有)B()Show()Sum()privatex在类在类B新增加的成员中新增加的成员中不能直接调用不能直接调用y在类在类B中可以调用中可
437、以调用z在类在类B中可以调用中可以调用对类对类B的对象初始化即是对的对象初始化即是对x,y,z,m,n等全部成员的初始化等全部成员的初始化均为私有均为私有类类B外不外不能引用能引用729classAintx;protected:inty;public:intz;A(inta,intb,intc)x=a;y=b;z=c;/基类初始化基类初始化intGetx()returnx;/返回返回xintGety()returny;/返回返回yvoidShowA()coutx=xty=ytz=zn;classB:privateAintm,n;public: B(inta,intb,intc,intd,int
438、e):A(a,b,c)m=d;n=e;voidShow()cout“m=mt“n=nn;coutx=Getx()ty=ytz=zn;intSum()return(Getx()+y+z+m+n);voidmain(void)Bb1(1,2,3,4,5);b1.ShowA(); b1.Show();coutSum=b1.Sum()n;coutx=b1.Getx()t;couty=b1.Gety()t;coutz=b1.zn;私有派生私有派生对基类初始化对基类初始化因为因为x是基类私有,所以在派生类和类外中不能直接引用是基类私有,所以在派生类和类外中不能直接引用y是基类保护,所以在派生是基类保护,所
439、以在派生类中可以直接引用。而在类类中可以直接引用。而在类外不可直接引用。外不可直接引用。z是基类公有,私有是基类公有,私有派生变为私有,所以派生变为私有,所以在派生类中可直接引在派生类中可直接引用,用,而在类外不可。而在类外不可。这些函数都是基类公有,这些函数都是基类公有,在类外不可使用。在类外不可使用。Aa1(1,2,3);a1.ShowA();730保护派生class ClassName: protected BaseClassName保保护护派派生生时时,基基类类中中公公有有成成员员和和保保护护成成员员在在派派生生类类中中均均变变为为保保护护的的和和私私有有的的,在在派派生生类类中中仍仍
440、可可直直接接使使用用这这些些成成员员,基基类类中中的的私私有有成成员员,在派生类中不可直接使用。在派生类中不可直接使用。保护派生,派生类中基类公有和保护成员降级使用保护派生,派生类中基类公有和保护成员降级使用基类成员属性基类成员属性派生类派生类派生类外派生类外公有公有可以引用可以引用不可引用不可引用保护保护可以引用可以引用不可引用不可引用私有私有不可引用不可引用不可引用不可引用基类:基类:public:(变为保护变为保护)在派生类中使用,类外不可使用在派生类中使用,类外不可使用protected:(变为私有)在派生类中使用,类外不可使用变为私有)在派生类中使用,类外不可使用private:不能
441、在派生类中和类外使用不能在派生类中和类外使用731x(私有私有)y(保护保护)z(公有公有)A()Getx()Gety()ShowA()Ax(私私有私私有)y(私有私有)z(保护保护)A()Getx()Gety()ShowA()Bm(私有私有)n(私有私有)B()Show()Sum()protectedx在类在类B新增加的成员新增加的成员中不能直接调用中不能直接调用y在类在类B中可以调用中可以调用z在类在类B中可以调用中可以调用对类对类B的对象初始化即是对的对象初始化即是对x,y,z,m,n等全部成员的初始化等全部成员的初始化均为保护均为保护类类B外不外不能引用能引用732protected成
442、员是一种具有血缘关系内外成员是一种具有血缘关系内外有别的成员。它对派生类的对象而言,有别的成员。它对派生类的对象而言,是公开成员,可以访问,对是公开成员,可以访问,对血缘外部而血缘外部而言,与私有成员一样被隐蔽言,与私有成员一样被隐蔽。733抽象类与保护的成员函数抽象类与保护的成员函数当定义了一个类,当定义了一个类,这个类这个类只能用作基类只能用作基类来派来派生出新的类,而不能用这种类来定义对象时,生出新的类,而不能用这种类来定义对象时,称这种类为抽象类。称这种类为抽象类。当对某些特殊的对象要当对某些特殊的对象要进行很好地封装时,需要定义抽象类。进行很好地封装时,需要定义抽象类。将类的构造函数
443、或析构函数的访问权限将类的构造函数或析构函数的访问权限定义为定义为保护保护的时,这种类为的时,这种类为抽象类抽象类。734当把类中的构造函数或析构函数说明为当把类中的构造函数或析构函数说明为私有私有的时,所定义的类通常是没有任何的时,所定义的类通常是没有任何实用意义的,一般情况下,不能用它来实用意义的,一般情况下,不能用它来产生对象,也不能用它来产生派生类。产生对象,也不能用它来产生派生类。735x(私有私有)y(私有私有)A()(保护保护)ShowA()(公有公有)Ax(私私有私私有)y(私私有私私有)A()(保护保护)ShowA()Bm(私有私有)B()Show()public在类在类B中
444、不能定义中不能定义A的对象的对象在任何时候都不能定义在任何时候都不能定义A的对象的对象但可以在初始化类但可以在初始化类B的对象时初始化的对象时初始化原类原类A中的成员中的成员,因为因为A()在类在类B中是可以被调用的。中是可以被调用的。736classAintx,y;protected:A(inta,intb)x=a;y=b;/基类初始化基类初始化public:voidShowA()coutx=xty=yn;classB:publicAintm;Aa1; /在派生类中也不可以定义在派生类中也不可以定义A的对象,实际上还是类外调用的对象,实际上还是类外调用public:B(inta,intb,i
445、ntc):A(a,b)/可以在派生类中调用可以在派生类中调用A的构造函数的构造函数m=c;voidShow()cout“m=mn;ShowA();voidmain(void)Bb1(1,2,3);/可以定义派生类对象可以定义派生类对象b1.Show();Aaa;/不可定义不可定义A的对象的对象a1(4,5)737多重继承多重继承可以用多个基类来派生一个类。可以用多个基类来派生一个类。ABCD多重继承是单多重继承是单一继承的扩展一继承的扩展派生类中新定派生类中新定义的成员义的成员738格式为:格式为:class类名类名:类名类名1,.,类名类名nprivate:.;/私有成员说明私有成员说明;p
446、ublic:.;/公有成员说明公有成员说明;protected:.;/保护的成员说明保护的成员说明;继承方式继承方式classD:publicA,protectedB,privateC./派生类中新增加成员派生类中新增加成员;739classA intx1,y1;public: A(inta,intb)x1=a;y1=b;voidShowA(void)coutA.x=x1tA.y=y1endl;classBintx2,y2;public: B(inta,intb)x2=a;y2=b;voidShowB(void)coutB.x=x2tB.y=y2endl;classC:publicA,priv
447、ateBintx,y;public: C(inta,intb,intc,intd,inte,intf):A(a,b),B(c,d)x=e;y=f;voidShowC(void)coutC.x=xtC.y=yendl;ShowA();ShowB();voidmain(void)Cc(1,2,3,4,5,6);c.ShowC();c.ShowA();c.ShowB();公有派生公有派生私有派生私有派生仍为公有仍为公有成为私有成为私有非法,私有类外不可调用非法,私有类外不可调用Bb1(10,20);b1.ShowB();740初始化基类成员初始化基类成员构造函数不能被继承构造函数不能被继承,派生类的
448、构造函数派生类的构造函数必须调用基类的构造函数必须调用基类的构造函数来初始化基类来初始化基类成员基类成员基类子对象子对象。派生类构造函数的调用顺序如下:派生类构造函数的调用顺序如下:基类的构造函数基类的构造函数子对象类的构造函数子对象类的构造函数派生类的构造函数派生类的构造函数741classB:publicAinty;Aa1;public:B(inta,intb):A(a),a1(3)y=b;.;当撤销派生类对象时,析当撤销派生类对象时,析构函数的调用正好相反。构函数的调用正好相反。基类的构造函数基类的构造函数子对象类的构造函数子对象类的构造函数派生类的构造函数派生类的构造函数742clas
449、sBase1 intx;public:Base1(inta)x=a;cout调用基类调用基类1的构造函数的构造函数!n;Base1()cout调用基类调用基类1的析构函数的析构函数!n;classBase2 inty;public:Base2(inta) y=a;cout调用基类调用基类2的构造函数的构造函数!n;Base2()cout调用基类调用基类2的析构函数的析构函数!n;classDerived:publicBase2,publicBase1intz;public:Derived(inta,intb):Base1(a),Base2(20)z=b;cout调用派生类的构造函数调用派生类的
450、构造函数!n;Derived()cout调用派生类的析构函数调用派生类的析构函数!n;voidmain(void)Derivedc(100,200);调用基类调用基类2的构造函数的构造函数调用基类调用基类1的构造函数的构造函数调用派生类的构造函数调用派生类的构造函数调用派生类的析构函数调用派生类的析构函数调用基类调用基类1的析构函数的析构函数调用基类调用基类2的析构函数的析构函数先说明基类先说明基类2743classDerived:publicBase2,publicBase1intz;Base1b1,b2;public:Derived(inta,intb):Base1(a),Base2(20
451、),b1(200),b2(a+b)z=b;cout调用派生类的构造函数调用派生类的构造函数!n;Derived()cout调用派生类的析构函数调用派生类的析构函数!n;voidmain(void)Derivedc(100,200);基类子对象基类子对象基类成员构造基类成员构造基类子对象构造基类子对象构造基类成员构造用基类名,基类成员构造用基类名,基类子对象构造用对象名基类子对象构造用对象名744classBase1 intx;public:Base1(inta)x=a;cout调用基类调用基类1的构造函数的构造函数!n;Base1()cout调用基类调用基类1的析构函数的析构函数!n;clas
452、sBase2 inty;public:Base2(inta) y=a;cout调用基类调用基类2的构造函数的构造函数!n;Base2()cout调用基类调用基类2的析构函数的析构函数!n;classDerived:publicBase2,publicBase1intz; Base1b1,b2;public:Derived(inta,intb):Base1(a),Base2(20),b1(200),b2(a+b)z=b;cout调用派生类的构造函数调用派生类的构造函数!n;Derived()cout调用派生类的析构函数调用派生类的析构函数!n;voidmain(void)Derivedc(100
453、,200);745调用基类调用基类2的构造函数的构造函数调用基类调用基类1的构造函数的构造函数调用派生类的构造函数调用派生类的构造函数调用派生类的析构函数调用派生类的析构函数调用基类调用基类1的析构函数的析构函数调用基类调用基类2的析构函数的析构函数调用基类调用基类1的构造函数的构造函数调用基类调用基类1的构造函数的构造函数调用基类调用基类1的析构函数的析构函数调用基类调用基类1的析构函数的析构函数说明基类说明基类1的对象的对象b1,b2746classBase1intx;public:Base1(inta);Base1();classBase2inty;public:Base2(inta);
454、Base2();classDerived:publicBase2,publicBase1intz; Base1b1,b2;public:Derived(inta,intb);Derived();xBase1()Base1()Base1yBase2()Base2()Base2DerivedxBase1()Base1()yBase2()Base2()xBase1()Base1()b1xBase1()Base1()b2zDerived()Derived747冲突冲突ABCxA()xB()xC()DA()xB()xC()xD()dDv;v.x=5;public派生类对象派生类对象产生了冲突产生了冲突A
455、:v.x=5;用类作用符限定用类作用符限定748classApublic:intx;voidShow()coutx=xn;A(inta=0)x=a;classBpublic:intx;voidShow()coutx=xn;B(inta=0)x=a;classC:publicA,publicBinty;public:voidSetx(inta)x=a;/c1对象中有两个对象中有两个x成员成员voidSety(intb)y=b;intGety()returny;voidmain(void)Cc1; c1.Show();/c1对象中有两个对象中有两个Show()函数函数这时,可以利用这时,可以利用类
456、作用类作用域符域符:来指明数据或函来指明数据或函数的来源。数的来源。如:如:A:x=a;c1.B:Show();749支配规则支配规则AxA()DpublicxA()xD()基类成员基类成员派生类新增成员派生类新增成员Dv;v.x=5;当派生类中新增加的数据或当派生类中新增加的数据或函数与基类中原有的同名时,函数与基类中原有的同名时,若不加限制,则若不加限制,则优先调用派优先调用派生类中的成员生类中的成员。5750classApublic: intx;voidShow()coutx=xn;classBpublic: inty;voidShow()couty=yn;classC:publicA,
457、publicBpublic: inty;/类类B和类和类C均有均有y的成员的成员;voidmain(void)Cc1; c1.x=100;c1.y=200;/给派生类中的给派生类中的y赋值赋值c1.B:y=300; /给基类给基类B中的中的y赋值赋值c1.A:Show();c1.B:Show(); /用作用域运算符限定调用的函数用作用域运算符限定调用的函数couty=c1.yn;/输出派生类中的输出派生类中的y值值couty=c1.B:yn;/输出基类输出基类B中的中的y值值当派生类中新增加的当派生类中新增加的数据或函数与基类中数据或函数与基类中原有的同名时,若不原有的同名时,若不加限制,则加
458、限制,则优先调用优先调用派生类中的成员派生类中的成员。751classApublic: intx;A(inta=0)x=a;classBpublic: inty;B(inta=0)y=a;classC:publicAintz;Bb1; Aa1;public: C(inta,intb,intm):A(a),b1(b),a1(a+b)z=m;voidShow()coutx=xt;couty=b1.yt;coutx=zn;couta1.x=a1.xendl;voidmain(void)Cc1(100,200,500);c1.Show();xzShow()a1.xb1.yC的对象所占空间的对象所占空间
459、从基类从基类A中继承中继承在类在类C中新说明中新说明在类在类C中新说明中新说明在类在类C中新说明中新说明在类在类C中新说明中新说明从基类从基类A中继承中继承新说明类新说明类A对象中的对象中的x752基类与对象成员基类与对象成员任一基类在派生类中只能继承一次,否则,会造任一基类在派生类中只能继承一次,否则,会造成成员名的冲突成成员名的冲突若在派生类中,确实要有二个以上基类的成员,若在派生类中,确实要有二个以上基类的成员,则可用基则可用基类的二个对象作为派生类的成员。类的二个对象作为派生类的成员。把把一一个个类类作作为为派派生生类类的的基基类类或或把把一一个个类类的的对对象象作作为为一一个个类类的
460、的成成员员,在在使使用用上上是是有有区区别别的的:在在派派生生类类中中可可直直接接使使用用基基类类的的成成员员(访访问问权权限限允允许许的的话话),但但要要使使用用对对象象成成员员的的成成员员时时,必必须须在在对对象象名名后后加加上上成成员员运运算算符符“.”和和成员名成员名。753在平面上作两个点,连一直线,求直线的长度和直在平面上作两个点,连一直线,求直线的长度和直线中点的坐标。线中点的坐标。基类为基类为Dot,有两个公有数据成员,即平面上的坐,有两个公有数据成员,即平面上的坐标(标(x,y),同时有构造函数及打印函数。,同时有构造函数及打印函数。派生类为派生类为Line,有,有两个基类两
461、个基类Dot对象对象,分别存放两,分别存放两点的坐标,同时,从点的坐标,同时,从基类继承了一个基类继承了一个Dot数据数据,存,存放直线中点的坐标。放直线中点的坐标。754xyDot(x,y)(构造构造)Dot(&dot)(拷贝拷贝)Show()Dot的对象空间的对象空间x(中点中点)y(中点中点)Dot(x,y)Dot(&dot)Show()d1xyDot(x.y)Dot(&dot)Show()d2xyDot(x,y)Dot(&dot)Show()Line(dot1,dot2)Showl()Line对象对象空间空间从基类从基类继承继承基类基类对象对象755classDotpublic: fl
462、oatx,y;Dot(floata=0,floatb=0)x=a;y=b;voidShow(void)coutx=xty=yendl;classLine:publicDotDotd1,d2;public: Line(Dotdot1,Dotdot2):d1(dot1),d2(dot2)x=(d1.x+d2.x)/2;y=(d1.x+d2.y)/2;voidShowl(void)coutDot1:;d1.Show();coutDot2:;d2.Show();coutLength=sqrt(d1.x-d2.x)*(d1.x-d2.x)+(d1.y-d2.y)*(d1.y-d2.y)endl;cout
463、Center:x=xty=yendl;voidmain(void)floata,b;coutab;Dotdot1(a,b);/调用调用Dot的构造函数的构造函数coutab;Dotdot2(a,b);Lineline(dot1,dot2);line.Showl();用坐标初始化用坐标初始化Dot对象对象在在Line中新说明的成员中新说明的成员对成员初始化对成员初始化x,y是继承基类的成员是继承基类的成员打印坐标打印坐标756赋值兼容规则赋值兼容规则基类基类对象对象派生类派生类对象对象相互之间能否赋值?相互之间能否赋值?可以将派生类对象的值赋给基类对象。可以将派生类对象的值赋给基类对象。反之不行
464、反之不行Baseb;Derived;b=d;只是将从基类只是将从基类继承来的成员继承来的成员赋值。赋值。757Show()Dot(&dot)Dot(x,y)yxDot的对象空间的对象空间Show()Dot(&dot)Dot(x,y)Show()Dot(&dot)Dot(x,y)yDot(&dot)Show()Dot(x.y)yxxShowl()Line()d2d1yxLine的对的对象空间象空间从基类从基类继承继承基类基类对象对象Dotdot;Lineline;dot=line;line=dot;非法非法758可以将一个派生类对象的地址赋给基类的指针变量。可以将一个派生类对象的地址赋给基类的指
465、针变量。基类对象基类对象派生类对象派生类对象Baseb;Derived;Base*basep;basepbasep=&b;basepbasep=&dbasep只能引用只能引用从基类继承来从基类继承来的成员。的成员。基类指针基类指针派生类对象派生类对象基类对象基类对象759派生类对象可以初始化基类的引用。派生类对象可以初始化基类的引用。Derived;Basebasei=&d;基类对象基类对象派生类对象派生类对象Baseb;Derived;别名别名baseibasei只能引用只能引用从基类继承来从基类继承来的成员。的成员。基类引用基类引用派生类对象派生类对象760classApublic: in
466、tx;A(inta=0)x=a;classBpublic: inty;B(inta=0)y=a;classC:publicA,publicBintz;public: C(inta,intb,intm):A(a),B(b) z=m;voidShow()coutx=xt;couty=yt;coutz=zn;voidmain(void)Aa1(100);Bb1(200);Cc1(10,20,50);couta1.x=a1.xendl;coutb1.y=b1.yendl;c1.Show();a1=c1; b1=c1;/派生类对象向基类对象赋值派生类对象向基类对象赋值couta1.x=a1.xendl;
467、coutb1.y=b1.yShow();xA()yB()zC()Show()102050a1.x=100b1.y=200x=10y=20z=50a1.x=10b1.y=20c1xA()a1yB()b11002001020错误!错误!761虚基类虚基类类类B是类是类A的派生类的派生类xA()xA()yB()xA()zC()A类类B类类C类类dxD()xA()zC()yB()A()xD类类类类A拷贝拷贝类类C是类是类A的派生类的派生类类类D是类是类B和类和类C的派生类的派生类这样,类这样,类D中就有两份类中就有两份类A的拷贝的拷贝B类类C类类类类A拷贝拷贝762这种同一个公共的基类这种同一个公共的
468、基类在派生类中产生多个拷在派生类中产生多个拷贝,不仅多占用了存储贝,不仅多占用了存储空间,空间,而且可能会造成而且可能会造成多个拷贝中的数据不一多个拷贝中的数据不一致致和模糊的引用和模糊的引用。Dd;d.x=10;/模糊引用模糊引用dxD()xA()zC()yB()A()xD类类类类A拷贝拷贝B类类C类类类类A拷贝拷贝763classApublic: intx;A(inta=0)x=a;classB:publicApublic: inty;B(inta=0,intb=0):A(a)y=b;classC:publicApublic: intz;C(inta,intc):A(a)z=c;class
469、D:publicB,publicCpublic: intdx;D(inta1,intb,intc,intd,inta2):B(a1,b),C(a2,c)dx=d;voidmain(void)Dd1(10,20,30,40,50);coutd1.xendl;dxD()xA()zC()yB()A()xD类类a1=10b=20a2=50c=30dx=40模糊引用,错误!模糊引用,错误!764在多重派生的过程中,若使公共基类在派生类中只在多重派生的过程中,若使公共基类在派生类中只有一个拷贝,则可将这种基类说明为有一个拷贝,则可将这种基类说明为虚基类虚基类。classB:publicvirtualApu
470、blic:inty;B(inta=0,intb=0):A(b)y=a;在派生类的定义中,只要在基类的类名前加上关键在派生类的定义中,只要在基类的类名前加上关键字字virtual,就可以将基类说明为虚基类,就可以将基类说明为虚基类。765xA()xA()yB()xA()zC()A类类B类类C类类xA()yB()zC()dxD()D类类一份拷贝,在一份拷贝,在D()的构造函数中直的构造函数中直接调用接调用A()由虚基类派生出的对象初始由虚基类派生出的对象初始化时,化时,直接调用直接调用虚基类的构虚基类的构造函数。因此,若将一个类造函数。因此,若将一个类定义为虚基类,定义为虚基类,则一定有正则一定有
471、正确的构造函数可供所有派生确的构造函数可供所有派生类调用。类调用。766classApublic: intx;A(inta=0)x=a;classB:publicvirtualApublic: inty;B(inta=0,intb=0):A(a)y=b;classC:publicvirtualApublic: intz;C(inta=0,intc=0):A(a)z=c;classD:publicB,publicCpublic: intdx;D(inta1,intb,intc,intd,inta2):B(a1,b),C(a2,c)dx=d;voidmain(void)Dd1(10,20,30,4
472、0,50);coutd1.xendl;d1.x=400;coutd1.xendl;coutd1.yendl;040020没有对虚基类构造函数的调用,用缺省的构造函数没有对虚基类构造函数的调用,用缺省的构造函数,A(a2)直接在派生类中调用虚基类的构造函数直接在派生类中调用虚基类的构造函数5040020767再次强调,用虚基类进行多重派生时,再次强调,用虚基类进行多重派生时,若虚若虚基类没有缺省的构造函数基类没有缺省的构造函数,则在每一个派生,则在每一个派生类的构造函数中类的构造函数中都必须有对虚基类构造函数都必须有对虚基类构造函数的调用的调用(且首先调用)。(且首先调用)。768第十二章第十二
473、章类的其它特性类的其它特性769友元函数友元函数类中私有和保护的成员在类外不能被访问。类中私有和保护的成员在类外不能被访问。友元函数是一种定义在类外部的友元函数是一种定义在类外部的普通函普通函数数,其特点是,其特点是能够访问类中私有成员和能够访问类中私有成员和保护成员保护成员,即类的访问权限的限制对其,即类的访问权限的限制对其不起作用。不起作用。770友元函数需要在友元函数需要在类体内类体内进行说明,在前面加进行说明,在前面加上关键字上关键字friend。一般格式为:一般格式为:friendFuncName();friendfloatVolume(A&a);关键字关键字返回值类型返回值类型函数
474、名函数名函数参数函数参数771友友元元函函数数不不是是成成员员函函数数,用用法法也也与与普普通通的的函函数数完完全全一一致致,只只不不过过它它能能访访问问类类中中所所有有的的数数据据。友友元元函函数数破破坏坏了了类类的的封封装装性性和和隐隐蔽蔽性性,使使得得非非成成员员函函数数可可以以访访问问类的私有成员类的私有成员。一个类的友元可以自由地用该类中的所有成员。一个类的友元可以自由地用该类中的所有成员。772classAfloatx,y;public:A(floata,floatb)x=a;y=b;floatSum()returnx+y;friendfloatSum(A&a)returna.x+
475、a.y;voidmain(void)At1(4,5),t2(10,20);coutt1.Sum()endl;coutSum(t2)endl;友元函数友元函数成员函数成员函数友元函数的调用,直接调用友元函数的调用,直接调用成员函数的调用,利用对象名调用成员函数的调用,利用对象名调用友元函数只能用友元函数只能用对象对象名名引用类中的数据。引用类中的数据。私有数据私有数据773有关友元函数的使用,说明如下:有关友元函数的使用,说明如下:友元函数不是类的成员函数友元函数不是类的成员函数友元函数近似于友元函数近似于普通的函数普通的函数,它不带有,它不带有this指指针,针,因此必须将对象名或对象的引用作
476、为友因此必须将对象名或对象的引用作为友元函数的参数元函数的参数,这样才能访问到对象的成员。,这样才能访问到对象的成员。774友元函数与一般函数的不同点在于友元函数与一般函数的不同点在于:1.友元函数必须在类的定义中说明,友元函数必须在类的定义中说明,其其函数体可在类内定义,也可在类外定函数体可在类内定义,也可在类外定义义;2.它可以访问该类中的所有成员(公有它可以访问该类中的所有成员(公有的、私有的和保护的)的、私有的和保护的),而一般函数,而一般函数只能访问类中的公有成员。只能访问类中的公有成员。775classAfloatx,y;public:A(floata,floatb)x=a;y=b
477、;floatGetx()returnx;floatGety()returny;floatSum()returnx+y;friendfloatSum(A&);floatSumxy(A&a)returna.Getx()+a.Gety();floatSum(A&a)returna.x+a.y;voidmain(void)At1(1,2),t2(10,20),t3(100,200);coutt1.Sum()endl;coutSum(t2)endl;coutSumxy(t3)endl;成员函数成员函数友元函数友元函数,可以直接调用类中私有成员可以直接调用类中私有成员普通函数,必须通过公有函数访问私有成员
478、普通函数,必须通过公有函数访问私有成员对象调用成员函数对象调用成员函数调用友元函数调用友元函数调用一般函数调用一般函数友元函数友元函数776友友元元函函数数不不受受类类中中访访问问权权限限关关键键字字的的限限制制,可可以以把把它它放放在在类类的的私私有有部部分分,放放在在类类的的公公有有部部分分或或放放在在类类的的保保护护部部分分,其其作作用用都都是是一一样样的的。换换言言之之,在在类类中中对友元函数指定访问权限是不起作用的对友元函数指定访问权限是不起作用的。友元函数的作用域与一般函数的作用域相同。友元函数的作用域与一般函数的作用域相同。谨慎使用友元函数谨慎使用友元函数通常使用友元函数来通常使
479、用友元函数来取取对象中的数据成员值,而对象中的数据成员值,而不不修改修改对象中的成员值,则肯定是安全的。对象中的成员值,则肯定是安全的。777大大多多数数情情况况是是友友元元函函数数是是某某个个类类的的成成员员函函数数,即即A类类中中的的某某个个成成员员函函数数是是B类类中中的的友友元元函函数数,这这个个成成员员函函数数可可以以直直接接访访问问B类类中中的的私私有有数数据据。这这就就实实现现了类与类之间的沟通了类与类之间的沟通。注意:一个类的成员函数作为另一个类的友元函数时,注意:一个类的成员函数作为另一个类的友元函数时,应应先定义友元函数所在的类。先定义友元函数所在的类。classA.voi
480、dfun(B&);classB.friendvoidfun(B&);既是类既是类A的成员函数的成员函数又是类又是类B的友元函数的友元函数778classB;/先定义类先定义类A,则首先对类,则首先对类B作引用性说明作引用性说明classA./类类A的成员定义的成员定义public:voidfun(B&);/函数的原型说明函数的原型说明;classB.friendvoidA:fun(B&);/定义友元函数定义友元函数;voidA:fun(B&b) /函数的完整定义函数的完整定义./函数体的定义函数体的定义类类A中的成员函数中的成员函数fun()是类是类B的友元函数。的友元函数。即在即在fun()
481、中可以直中可以直接引用类接引用类B的私有成的私有成员。员。779classB;/必须在此进行引用性说明,必须在此进行引用性说明,classAfloatx,y;public:A(floata,floatb)x=a;y=b;floatSum(B&);/说明友元函数的函数原型,是类说明友元函数的函数原型,是类A的一成员函数的一成员函数;classBfloatm,n;public:B(floata,floatb)m=a;n=b;friendfloatA:Sum(B&);/说明类说明类A的成员函数是类的成员函数是类B的友元函数的友元函数floatA:Sum(B&b)/定义该友元函数定义该友元函数x=b.
482、m+b.n;y=b.m-b.n;voidmain(void)Aa1(3,5);Bb1(10,20);a1.Sum(b1); /调用该函数,调用该函数,因是类因是类A的成员函数,故用类的成员函数,故用类A的对象调用的对象调用a1.x=30a1.y=-10直接引用类直接引用类B的私有成员的私有成员类类A中有一个函数可以直中有一个函数可以直接引用类接引用类B的私有成员的私有成员780友元类友元类classA.friendclassB;classB.类类B是类是类A的友元的友元类类B可以自由使用可以自由使用类类A中的成员中的成员对于类对于类B而言,类而言,类A是透明的是透明的类类B必须通过必须通过类类
483、A的对象的对象使用类使用类A的成员的成员781constfloatPI=3.1415926;classAfloatr;floath;public: A(floata,floatb)r=a;h=b;floatGetr()returnr;floatGeth()returnh;friendclassB;/定义类定义类B为类为类A的友元的友元;classBintnumber;public: B(intn=1)number=n;voidShow(A&a)coutPI*a.r*a.r*a.h*numberendl;/求类求类A的某个对象的某个对象*n的体积的体积;voidmain(void)Aa1(25,
484、40),a2(10,40);Bb1(2);b1.Show(a1); b1.Show(a2);直接引用类直接引用类A的私有成员的私有成员类类B中的任何函数都中的任何函数都能使用类能使用类A中的所有中的所有私有成员。私有成员。782不管是按哪一种方式派生,基类的私有成员不管是按哪一种方式派生,基类的私有成员在派生类中都是不可见的。在派生类中都是不可见的。如果在一个派生类中要访问基类中的私有成如果在一个派生类中要访问基类中的私有成员,可以将这个员,可以将这个派生类声明为基类的友元派生类声明为基类的友元。classBasefriendclassDerive;.classDerive.直接使用直接使用B
485、ase中的私有成员中的私有成员783#includeclassMfriendclassN;/N为为M的友元,可以直接使用的友元,可以直接使用M中的私有成员中的私有成员private:inti,j;voidshow(void)couti=itj=jt;public:M(inta=0,intb=0)i=a;j=b;classN:publicM/N为为M的派生类的派生类public:N(inta=0,intb=0):M(a,b)voidPrint(void)show();couti+j=i+jendl;voidmain(void)Nn1(10,20);Mm1(100,200);/m1.show();
486、/私有成员函数,在类外不可调用私有成员函数,在类外不可调用n1.Print();直接引用类直接引用类M的私有成员函数和私有成员的私有成员函数和私有成员784基类对象基类对象M派生类对象派生类对象Nx(私有)私有)Show()(私有私有)x(私私私私有)有)Show()(私私私私有有)y(公有公有)Showy()(公有公有)showy()show();coutiShow();basep-Show()基类指针基类指针派生类对象派生类对象基类对象基类对象787classPointfloatx,y;public: Point()Point(floati,floatj)x=i;y=j;floatarea
487、(void) return0.0;constfloatPi=3.14159;classCircle:publicPoint/类类Point的派生类的派生类floatradius;public: Circle(floatr)radius=r;floatarea(void) returnPi*radius*radius;voidmain(void)Point*pp;/基类指针,可以将派生类对象的地址赋给基类指针基类指针,可以将派生类对象的地址赋给基类指针Circlec(5.4321);pp=&c;coutarea()Show()Base*basep;basep=&b;basep=&d;basep-
488、Show();即指向派生类新增的成员函数即指向派生类新增的成员函数需要将基类中的需要将基类中的Show()说明为虚函数说明为虚函数789若要访问派生类中相同名字的函数,必须将若要访问派生类中相同名字的函数,必须将基类中的基类中的同名函数定义为虚函数同名函数定义为虚函数,这样,将,这样,将不同的派生类对象的地址赋给基类的指针变不同的派生类对象的地址赋给基类的指针变量后,就可以量后,就可以动态地根据这种赋值语句调用动态地根据这种赋值语句调用不同类中的函数不同类中的函数。790classPointfloatx,y;public: Point()Point(floati,floatj)x=i;y=j;
489、virtualfloatarea(void)return0.0;constfloatPi=3.14159;classCircle:publicPoint/类类Point的派生类的派生类floatradius;public: Circle(floatr)radius=r;floatarea(void) returnPi*radius*radius;voidmain(void)Point*pp;/基类指针,可以将派生类对象的地址赋给基类指针基类指针,可以将派生类对象的地址赋给基类指针Circlec(5.4321);pp=&c;coutarea()endl;/调用虚函数调用虚函数将将area()声明
490、为虚函数,编译器对其进行动态聚束,按照实际对象声明为虚函数,编译器对其进行动态聚束,按照实际对象c调用了调用了Circle中的函数中的函数area()。使使Point类中的类中的area()与与Circle类中的类中的area()有一个统一有一个统一的接口。的接口。输出:输出:92.7011声明为虚函数声明为虚函数调用虚函数调用虚函数虚函数再定义虚函数再定义791虚函数的定义和使用虚函数的定义和使用可可以以在在程程序序运运行行时时通通过过调调用用相相同同的的函函数数名名而而实实现不同功能的函数称为虚函数。现不同功能的函数称为虚函数。定义格式为:定义格式为:virtualFuncName();一
491、旦把基类的成员函数定义为虚函数,由基类所派一旦把基类的成员函数定义为虚函数,由基类所派生出来的所有派生类中,该函数均保持虚函数的特生出来的所有派生类中,该函数均保持虚函数的特性。性。在派生类中重新定义基类中的虚函数时,可以不用在派生类中重新定义基类中的虚函数时,可以不用关键字关键字virtual来修饰这个成员函数来修饰这个成员函数。792虚函数是用关键字虚函数是用关键字virtual修饰的某基类中的修饰的某基类中的protected或或public成员函数。它可以在派生成员函数。它可以在派生类中重新定义,以形成不同版本。类中重新定义,以形成不同版本。只有在程只有在程序的执行过程中,依据指针具体
492、指向哪个类序的执行过程中,依据指针具体指向哪个类对象,或依据引用哪个类对象,才能确定激对象,或依据引用哪个类对象,才能确定激活哪一个版本,实现动态聚束活哪一个版本,实现动态聚束。793classAprotected:intx;public: A()x=1000;virtualvoidprint()cout“x=”xt;/虚函数虚函数;classB:publicAinty;public: B()y=2000;voidprint()cout“y=”yt;/派生虚函数派生虚函数;classC:publicAintz;public: C()z=3000;voidprint()cout“z=”zprin
493、t();/调用类调用类A的虚函数的虚函数pa=&b;pa-print();/调用类调用类B的虚函数的虚函数pa=&c;pa-print();/调用类调用类C的虚函数的虚函数794classBasepublic:virtualintSet(inta,intb).;classDerive:publicBasepublic:intSet(intx,inty).;classBasepublic:virtualintSet(inta,intb).;classDerive:publicBasepublic:intSet(intx,inty=0).;intSet(int,int)是虚函数是虚函数两个两个Se
494、t()函数参数函数参数不一致,是重载,不一致,是重载,不是虚函数不是虚函数795关于虚函数,说明以下几点:关于虚函数,说明以下几点:1、当当在在基基类类中中把把成成员员函函数数定定义义为为虚虚函函数数后后,在在其其派派生生类类中中定定义义的的虚虚函函数数必必须须与与基基类类中中的的虚虚函函数数同同名名,参参数数的的类类型型、顺顺序序、参参数数的的个个数数必必须须一一一一对对应应,函函数数的的返返回回的的类类型型也也相相同同。若若函函数数名名相相同同,但但参参数数的的个个数数不不同同或或者者参参数数的的类类型型不不同同时时,则则属属于于函函数数的的重重载载,而而不不是是虚虚函函数数。若若函函数数
495、名名不不同同,显显然然这这是是不不同同的的成成员函数。员函数。7962、实现这种动态的多态性时,必须使用实现这种动态的多态性时,必须使用基类类型基类类型的指针变量的指针变量,并使该指针,并使该指针指向不同的派生类对象指向不同的派生类对象,并通过调用指针所指向的虚函数才能实现动态的多并通过调用指针所指向的虚函数才能实现动态的多态性。态性。xShow()xShow()yShow()xShow()zShow()类类A类类B类类CShow()定义为虚函数定义为虚函数类类B与类与类C均为类均为类A的公有派生。的公有派生。A*p;Bb;Cc;p=&b;p-Show();p=&c;p-Show();即在程序
496、运行时,即在程序运行时,通过赋值语句实通过赋值语句实现多态性现多态性7973、虚函数必须是类的一个成员函数,不能是虚函数必须是类的一个成员函数,不能是友元函数,也不能是静态的成员函数。友元函数,也不能是静态的成员函数。4、在派生类中、在派生类中没有重新定义虚函数没有重新定义虚函数时,与一时,与一般的成员函数一样,当调用这种派生类对象般的成员函数一样,当调用这种派生类对象的虚函数时,的虚函数时,则调用其基类中的虚函数则调用其基类中的虚函数。5、可把析构函数定义为虚函数,但是,不能可把析构函数定义为虚函数,但是,不能将构造函数定义为虚函数将构造函数定义为虚函数。7986、虚虚函函数数与与一一般般的
497、的成成员员函函数数相相比比较较,调调用用时时的的执执行行速速度度要要慢慢一一些些。为为了了实实现现多多态态性性,在在每每一一个个派派生生类类中中均均要要保保存存相相应应虚虚函函数数的的入入口口地地址址表表,函函数数的的调调用用机机制制也也是是间间接接实实现现的的。因因此此,除除了了要要编编写写一一些些通通用用的的程程序序,并并一一定定要要使使用用虚虚函函数数才才能能完完成成其其功功能能要要求外,通常不必使用虚函数。求外,通常不必使用虚函数。7、一个函数如果被定义成虚函数,则不管经历多、一个函数如果被定义成虚函数,则不管经历多少次派生,仍将保持其虚特性,以实现少次派生,仍将保持其虚特性,以实现“
498、一个接口,一个接口,多个形态多个形态”。799虚函数的访问虚函数的访问用基指针访问与用对象名访问用基指针访问与用对象名访问用基指针访问虚函数时,指向其实际派生类用基指针访问虚函数时,指向其实际派生类对象重新定义的函数。实现动态聚束。对象重新定义的函数。实现动态聚束。通过一个通过一个对象名对象名访问时,只能静态聚束。即访问时,只能静态聚束。即由编译器在编译的时候决定调用哪个函数。由编译器在编译的时候决定调用哪个函数。800classPointfloatx,y;public: Point()Point(floati,floatj)x=i;y=j;virtualfloatarea(void)retu
499、rn0.0;/声明为虚函数声明为虚函数;constfloatPi=3.14159;classCircle:publicPoint/类类Point的派生类的派生类floatradius;public: Circle(floatr)radius=r;floatarea(void) returnPi*radius*radius;/虚函数再定义虚函数再定义;voidmain(void)Point*pp;/基类指针,可以将派生类对象的地址赋给基类指针基类指针,可以将派生类对象的地址赋给基类指针Circlec(5.4321);coutc.area()endl;coutc.Point:area()endl;
500、coutc.Circle:area()endl;输出:输出:92.7011092.7011可见,利用对象名进行调用与一般非虚函数没有区别。可见,利用对象名进行调用与一般非虚函数没有区别。用对象名调用用对象名调用area()801classbase0public: voidv(void)coutbase0n;classbase1:publicbase0public: virtualvoidv(void)coutbase1n;classA1:publicbase1public: voidv()coutA1n; ;classA2:publicA1public: voidv(void)coutA2n;
501、 ;classB1:privatebase1public: voidv(void)coutB1n; ;classB2:publicB1public: voidv(void)coutv();A2a2;(pb=&a2)-v();B1b1;(pb=&b1)-v();B2b2;(pb=&b2)-v();base0base0私有派生,在类外私有派生,在类外不能调用基类函数不能调用基类函数802classbase0public: voidv(void)coutbase0n;classbase1:publicbase0public: virtualvoidv(void)coutbase1n;classA1:
502、publicbase1public: voidv()coutA1n; ;classA2:publicA1public: voidv(void)coutA2n; ;classB1:privatebase1public: voidv(void)coutB1n; ;classB2:publicB1public: voidv(void)coutv();A2a2;(pb=&a2)-v();A1A2803纯虚函数纯虚函数在基类中不对虚函数给出有意义的实现在基类中不对虚函数给出有意义的实现,它只是在它只是在派生类中有具体的意义。这时基类中的虚函数只是派生类中有具体的意义。这时基类中的虚函数只是一个入口,具体
503、的目的地由不同的派生类中的对象一个入口,具体的目的地由不同的派生类中的对象决定。这个虚函数称为决定。这个虚函数称为纯虚函数纯虚函数。classvirtual()=0;.;804classAprotected:intx;public: A()x=1000;virtualvoidprint()=0;/定义纯虚函数定义纯虚函数;classB:publicA/派生类派生类private:inty;public: B()y=2000;voidprint()cout“y=”yn;/重新定义纯虚函数重新定义纯虚函数;classC:publicA/派生类派生类intz;public: C()z=3000;vo
504、idprint()cout“z=”zprint(); pa=&c;pa-print();Aa;pa=&a;pa-print();y=2000z=3000抽象类抽象类不能定义抽象类的对象不能定义抽象类的对象8051、在在定定义义纯纯虚虚函函数数时时,不不能能定定义义虚虚函函数数的的实实现部分。现部分。2、把把函函数数名名赋赋于于0,本本质质上上是是将将指指向向函函数数体体的的指指针针值值赋赋为为初初值值0。与与定定义义空空函函数数不不一一样样,空空函函数数的的函函数数体体为为空空,即即调调用用该该函函数数时时,不不执执行行任任何何动动作作。在在没没有有重重新新定定义义这这种种纯纯虚虚函函数之前,
505、是不能调用这种函数的。数之前,是不能调用这种函数的。8063、把至少包含一个纯虚函数的类,称为抽象把至少包含一个纯虚函数的类,称为抽象类。这种类只能作为派生类的基类,不能用类。这种类只能作为派生类的基类,不能用来说明这种类的对象来说明这种类的对象。其理由是明显的:因为虚函数没有实现部分,其理由是明显的:因为虚函数没有实现部分,所以不能产生对象。但可以定义指向抽象类所以不能产生对象。但可以定义指向抽象类的指针,即指向这种基类的指针。当用这种的指针,即指向这种基类的指针。当用这种基类指针指向其派生类的对象时,基类指针指向其派生类的对象时,必须在派必须在派生类中生类中重载重载纯虚函数,否则会产生程序
506、的运纯虚函数,否则会产生程序的运行错误。行错误。8074、在在以以抽抽象象类类作作为为基基类类的的派派生生类类中中必必须须有有纯纯虚虚函函数数的的实实现现部部分分,即即必必须须有有重重载载纯纯虚虚函函数数的的函函数数体体。否否则则,这这样样的的派派生生类类也也是是不不能能产生对象的。产生对象的。综综上上所所述述,可可把把纯纯虚虚函函数数归归结结为为:抽抽象象类类的的唯唯一一用用途途是是为为派派生生类类提提供供基基类类,纯纯虚虚函函数数的的作作用用是是作作为为派派生生类类中中的的成成员员函函数数的的基基础础,并并实现动态多态性。实现动态多态性。808虚基类虚基类多基派生中的多条路径具有公共基类时
507、,在这条路径的汇合处就会多基派生中的多条路径具有公共基类时,在这条路径的汇合处就会因对公共基类产生多个拷贝而产生同名函数调用的二义性。因对公共基类产生多个拷贝而产生同名函数调用的二义性。解决这个问题的办法就是把解决这个问题的办法就是把公共基类定义为虚基类公共基类定义为虚基类,使由它派生的,使由它派生的多条路径的汇聚处只产生一个拷贝。多条路径的汇聚处只产生一个拷贝。classBase;classA:publicBase;classB:publicBase;classC:publicA,publicB;类类C中继承了两个类中继承了两个类Base,即有两个类即有两个类Base的实现部分,的实现部分,
508、在调用时产生了二义性。在调用时产生了二义性。809用虚基类进行多重派生时,用虚基类进行多重派生时,若虚基类没有缺若虚基类没有缺省的构造函数省的构造函数,则在每一个派生类的构造函,则在每一个派生类的构造函数中数中都必须有对虚基类构造函数的调用都必须有对虚基类构造函数的调用(且(且首先调用)。首先调用)。由虚基类派生出的对象初始化时,由虚基类派生出的对象初始化时,直接调用直接调用虚基类的构造函数。因此,若将一个类定义虚基类的构造函数。因此,若将一个类定义为虚基类,则一定有正确的构造函数可供所为虚基类,则一定有正确的构造函数可供所有派生类调用。有派生类调用。810classbasepublic:vi
509、rtualvoida() couta()inbasen;virtualvoidb() coutb()inbasen;virtualvoidc() coutc()inbasen;virtualvoidd() coutd()inbasen;virtualvoide() coute()inbasen;virtualvoidf() coutf()inbasen;classA:publicbasepublic:virtualvoida() couta()inAn;virtualvoidb() coutb()inAn;virtualvoidf() coutf()inAn;classB:publicbase
510、public:virtualvoida() couta()inBn;virtualvoidb() coutb()inBn;virtualvoidc() coutc()inBn;classC:publicA,publicBpublic:virtualvoida() couta()inCn;virtualvoidd() couta();pa-b();pa-c();pa-d();pa-e();pa-f();将类将类C的地址赋的地址赋值时产生歧义值时产生歧义811a()b()c()d()e()f()a()b()c()d()e()f()a()b()f()a()b()c()d()e()f()a()c()a
511、()b()c()d()e()f()a()b()f()a()b()c()d()e()f()a()c()baseABCa()d()AB812classbasepublic:virtualvoida() couta()inbasen;virtualvoidb() coutb()inbasen;virtualvoidc() coutc()inbasen;virtualvoidd() coutd()inbasen;virtualvoide() coute()inbasen;virtualvoidf() coutf()inbasen;classA:publicbasepublic:virtualvoida
512、() couta()inAn;virtualvoidb() coutb()inAn;virtualvoidf() coutf()inAn;classB:publicbasepublic:virtualvoida() couta()inBn;virtualvoidb() coutb()inBn;virtualvoidc() coutc()inBn;classC:publicA,publicBpublic:virtualvoida() couta()inCn;virtualvoidd() couta();pa-b();pa-c();pa-d();pa-e();pa-f();将类将类C的地址赋的地址
513、赋值时产生歧义值时产生歧义类类C中有两个中有两个base,只有一个,只有一个Aa()inCb()inAc()inbased()inCe()inbasef()inA为避免这种情况,将为避免这种情况,将base定义定义为虚基类。为虚基类。813classbasepublic:virtualvoida() couta()inbasen;virtualvoidb() coutb()inbasen;virtualvoidc() coutc()inbasen;virtualvoidd() coutd()inbasen;virtualvoide() coute()inbasen;virtualvoidf()
514、 coutf()inbasen;classA:virtualpublicbasepublic:virtualvoida() couta()inAn;virtualvoidb() coutb()inAn;virtualvoidf() coutf()inAn;classB:virtualpublicbasepublic:virtualvoida() couta()inBn;virtualvoidc() coutc()inBn;classC:publicA,publicBpublic:virtualvoida() couta()inCn;virtualvoidd() couta();pa-b();p
515、a-c();pa-d();pa-e();pa-f();814a()b()c()d()e()f()a()b()c()d()e()f()a()b()f()a()b()c()d()e()f()a()c()a()b()c()d()e()f()a()b()f()a()c()baseABCa()d()AB815classbasepublic:virtualvoida() couta()inbasen;virtualvoidb() coutb()inbasen;virtualvoidc() coutc()inbasen;virtualvoidd() coutd()inbasen;virtualvoide()
516、 coute()inbasen;virtualvoidf() coutf()inbasen;classA:virtualpublicbasepublic:virtualvoida() couta()inAn;virtualvoidb() coutb()inAn;virtualvoidf() coutf()inAn;classB:virtualpublicbasepublic:virtualvoida() couta()inBn;virtualvoidc() coutc()inBn;classC:publicA,publicBpublic:virtualvoida() couta()inCn;v
517、irtualvoidd() couta();pa-b();pa-c();pa-d();pa-e();pa-f();类类C中只有一个中只有一个basea()inCb()inAc()inBd()inCe()inbasef()inA816classbasepublic:voida()couta()inbasen;voidb()coutb()inbasen;voidc()coutc()inbasen;voidd()coutd()inbasen;voide()coute()inbasen;voidf()coutf()inbasen;classA:virtualpublicbasepublic:voida
518、()couta()inAn;voidb()coutb()inAn;voidf()coutf()inAn;classB:virtualpublicbasepublic:voida()couta()inBn;voidc()coutc()inBn;classC:publicA,publicBpublic:voida()couta()inCn;voidd()couta();pa-b();pa-c();pa-d();pa-e();pa-f();类类C中只有一个中只有一个basea()inbaseb()inbasec()inbased()inbasee()inbasef()inbase817下面程序的输出
519、是下面程序的输出是。classAprotected:intx;public:A()x=1000;virtualvoidp()coutx=xn;p2();virtualvoidp2()coutA:p2()endl;classC:publicAintz;public:C()z=3000;voidp()coutz=zn;p2();virtualvoidp2()coutC:p2()p();pa=&c;pa-p();818通通常常,每每当当说说明明一一个个对对象象时时,把把该该类类中中的的有有关关成成员员数数据据拷拷贝贝到到该该对对象象中中,即即同同一一类类的的不不同同对对象象,其其成成员员数数据据之间
520、是互相独立的之间是互相独立的。静态成员静态成员classAintx,y;public:voidSetxy(inta,intb)x=a;y=b;Aa1,a2;a1.xa1.ya2.xa2.y.x=a;y=b;.a1.Setxy()a2.Setxy()a1.Setxy(1,2);a2.Setxy(3,4);this-x=a;this-y=b;819当我们将类的某一个当我们将类的某一个数据成员的存储类型指定为静态类型数据成员的存储类型指定为静态类型时时,则由该类所产生的所有对象,其静态成员均共享,则由该类所产生的所有对象,其静态成员均共享一个一个存储空间存储空间,这个空间是在编译的时候分配的这个空间
521、是在编译的时候分配的。换言之,在。换言之,在说明对象时,并不为静态类型的成员分配空间。说明对象时,并不为静态类型的成员分配空间。在类定义中,用关键字在类定义中,用关键字static修饰的数据成员称为静修饰的数据成员称为静态数据成员。态数据成员。classAintx,y;staticintz;public:voidSetxy(inta,intb)x=a;y=b;Aa1,a2;a1.xa1.ya2.xa2.yza1.za2.z不同对象,同一空间不同对象,同一空间820有关静态数据成员的使用,说明以下几点:有关静态数据成员的使用,说明以下几点:1、类类的的静静态态数数据据成成员员是是静静态态分分配配
522、存存储储空空间间的的,而而其其它它成成员员是是动动态态分分配配存存储储空空间间的的(全全局局变变量量除除外外)。当当类类中中没没有有定定义义静静态态数数据据成成员员时时,在在程程序序执执行行期期间间遇遇到到说说明明类类的的对对象象时时,才才为为对对象象的的所所有有成成员员依依次次分分配配存存储储空空间间,这这种种存存储储空空间间的的分分配配是是动动态态的的;而而当当类类中中定定义义了了静静态态数数据据成成员员时时,在在编编译译时时,就就要要为为类类的的静态数据成员分配存储空间静态数据成员分配存储空间。8212、必须在文件作用域中,对静态数据成员作必须在文件作用域中,对静态数据成员作一次且只能作
523、一次定义性说明一次且只能作一次定义性说明。因为静态数。因为静态数据成员在定义性说明时已分配了存储空间,据成员在定义性说明时已分配了存储空间,所以通过静态数据成员名前加上所以通过静态数据成员名前加上类名和作用类名和作用域运算符域运算符,可直接引用静态数据成员。在,可直接引用静态数据成员。在C+中,静态变量缺省的初值为中,静态变量缺省的初值为0,所以静态,所以静态数据成员总有唯一的初值。当然,数据成员总有唯一的初值。当然,在对静态在对静态数据成员作定义性的说明时,数据成员作定义性的说明时,也可以指定一也可以指定一个初值。个初值。822classAinti,j;staticintx,y;/定义静态成
524、员定义静态成员public: A(inta=0,intb=0,intc=0,intd=0)i=a;j=b;x=c;y=d;voidShow()couti=itj=jt;coutx=xty=yn;intA:x=0;/必须对静态成员作一次定义性说明必须对静态成员作一次定义性说明intA:y=0;voidmain(void)Aa(2,3,4,5);a.Show();Ab(100,200,300,400);b.Show();a.Show();a.x和和b.x在内存中占据一个空间在内存中占据一个空间a.y和和b.y在内存中占据一个空间在内存中占据一个空间i=2j=3x=4y=5i=100 j=200 x
525、=300 y=400i=2j=3x=300 y=400823classAinti,j;public:staticintx;public:A(inta=0,intb=0,intc=0)i=a;j=b;x=c;voidShow()couti=itj=jt;coutx=xn;intA:x=500; /intA:xvoidmain(void)Aa(20,40,10),b(30,50,100);a.Show();b.Show();cout“A:x=”A:xn;/可以直接用类名引用可以直接用类名引用在类外重新定义在类外重新定义8243、静态数据成员具有全局变量和局部变量的一些、静态数据成员具有全局变量和局
526、部变量的一些特性。静态数据成员与全局变量一样都是静态分配特性。静态数据成员与全局变量一样都是静态分配存储空间的,存储空间的,但全局变量在程序中的任何位置都可但全局变量在程序中的任何位置都可以访问它,而静态数据成员受到访问权限的约束。以访问它,而静态数据成员受到访问权限的约束。必须是必须是public权限时,才可能在类外进行访问权限时,才可能在类外进行访问。4、为了保持静态数据成员取值的一致性,通常在、为了保持静态数据成员取值的一致性,通常在构造函数中不给静态数据成员置初值,构造函数中不给静态数据成员置初值,而是在对静而是在对静态数据成员的定义性说明时指定初值态数据成员的定义性说明时指定初值。8
527、25classAinti;staticintcount;public:A(inta=0)i=a;count+;coutNumberofObjects=countn;A()count-;coutNumberofObjects=countn; voidShow()couti=in;coutcount=countn;intA:count;voidmain(void)Aa1(100);Ab2;a1.Show();NumberofObjects=1NumberofObjects=2NumberofObjects=3i=100count=3NumberofObjects=2NumberofObjects=
528、1NumberofObjects=0826静态成员函数静态成员函数可以将类的成员函数定义为静态的成员函数。即使可以将类的成员函数定义为静态的成员函数。即使用关键字用关键字static来修饰成员函数来修饰成员函数。classAfloatx,y;public:A()staticvoidsum(void).;827对静态成员函数的用法说明以下几点:对静态成员函数的用法说明以下几点:1、与静态数据成员一样,在类外的程序代码中,与静态数据成员一样,在类外的程序代码中,通过类名加上作用域操作符,可直接调用静态成员通过类名加上作用域操作符,可直接调用静态成员函数函数。2、静态成员函数只能直接使用本类的静态数
529、据成静态成员函数只能直接使用本类的静态数据成员或静态成员函数员或静态成员函数,但不能直接使用非静态的数据但不能直接使用非静态的数据成员成员(可以引用使用)。这是因为静态成员函数(可以引用使用)。这是因为静态成员函数可被其它程序代码直接调用,所以,可被其它程序代码直接调用,所以,它不包含对象它不包含对象地址的地址的this指针指针。828classTcprivate:intA;staticintB;/静态数据成员静态数据成员public:Tc(inta)A=a;B+=a;staticvoiddisplay(Tcc)/Tc的对象为形参的对象为形参coutA=c.A,B=Bendl;intTc:B=
530、2;voidmain(void)Tca(2),b(4);Tc:display(a);Tc:display(b);非静态成员,用非静态成员,用对象名来引用对象名来引用静态成员,静态成员,直接引用直接引用直接用类名来调用直接用类名来调用静态成员函数静态成员函数A=2,B=8A=4,B=88293、静静态态成成员员函函数数的的实实现现部部分分在在类类定定义义之之外外定定义义时时,其其前前面面不不能能加加修修饰饰词词static。这这是是由由于于关关键键字字static不不是是数数据据类类型型的的组组成成部部分分,因因此此,在在类类外外定定义义静静态态成员函数的实现部分时成员函数的实现部分时,不能使用
531、这个关键字不能使用这个关键字4、不不能能把把静静态态成成员员函函数数定定义义为为虚虚函函数数。静静态态成成员员函函数数也也是是在在编编译译时时分分配配存存储储空空间间,所所以以在在程程序序的的执执行过程中不能提供多态性。行过程中不能提供多态性。5、可可将将静静态态成成员员函函数数定定义义为为内内联联的的(inline),其其定义方法与非静态成员函数完全相同。定义方法与非静态成员函数完全相同。830classTcprivate:intA;staticintB;/静态数据成员静态数据成员public:Tc(inta)A=a;B+=a;staticvoiddisplay(Tcc);/Tc的对象为形参
532、的对象为形参;voidTc:display(Tcc)/不用不用static修饰修饰coutA=c.A,B=Bendl;intTc:B=2;voidmain(void)Tca(2),b(4);Tc:display(a);Tc:display(b);函数原型函数原型类外定义类外定义8319.下述程序的输出结果是下述程序的输出结果是_。#includeclassSamplepublic:Sample()coutConstructorendl;Sample() coutDestructorendl;voidfun(inti)staticSamplec;couti=iendl;voidmain(void
533、)fun(10);fun(20);832const、volatile对象和成员函数用const修饰的对象,只能访问该类中用const修饰的成员函数,而其它的成员函数是不能访问的。用volatile修饰的对象,只能访问该类中用volatile修饰的成员函数,不能访问其它的成员函数。当希望成员函数只能引用成员数据的值,而不允许成员函数修改数当希望成员函数只能引用成员数据的值,而不允许成员函数修改数据成员的值时,可用关键词据成员的值时,可用关键词const修饰成员函数。修饰成员函数。一旦在用const修饰的成员函数中出现修改成员数据的值时,将导致编译错误。833const和和volatile成员函数
534、成员函数在成员函数的前面加上关键字const,则表示这函数返回一个常量,其值不可改变。const成成员员函函数数则则是是指指将将const放放在在参参数数表表之之后后,函函数数体体之之前前,其一般格式为:其一般格式为:FuncName()const;其语义是指明这函数的this指针所指向的对象是一个常量,即规定了const成员函数不能修改对象的数据成员,在函数体内只能调用const成员函数,不能调用其它的成员函数。834用volatile修饰一个成员函数时,其一般格式为:FuncName()volatile;其语义是指明成员函数具有一个易变的this指针,调用这个函数时,调用这个函数时,编译程
535、序把属于此类的所有的数据成员都看作是易变的变量编译程序把属于此类的所有的数据成员都看作是易变的变量,编译器不要对这函数作优化工作。由于关键字const和volatile是属于数据类型的组成部分,因此,若在类定义之外定义const成员函数或volatile成员函数时,则必须用这二个关键字修饰,否则编译器认为是重载函数,而不是定义const成员函数或volatile成员函数。835指向类成员的指针在C+中可以定义一种特殊的指针,它指向类中的成员函数或类中的数据成员。并可通过这样的指针来使用类中的数据成员或调用类中的成员函数。指向类中数据成员的指针变量定义一个指向类中数据成员的指针变量的一般格式为:
536、ClassName:*PointName;其中type是指针PointName所指向数据的类型,它必须是类ClassName中某一数据成员的类型8361、指指向向类类中中数数据据成成员员的的指指针针变变量量不不是是类类中中的的成成员员,这这种种指指针针变变量量应在类外定义应在类外定义。2、与与指指向向类类中中数数据据成成员员的的指指针针变变量量同同类类型型的的任任一一数数据据成成员员,可可将将其地址赋给这种指针变量,赋值的一般格式为:其地址赋给这种指针变量,赋值的一般格式为:PointName=&ClassName:member;这种赋值,是取该成员相对于该类的所在对象中的偏移量,即相对地址(
537、距离开始位置的字节数)如:mptr=&S:y;表示将数据成员y的相对起始地址赋给指针变量mptr。3、用用这这种种指指针针访访问问数数据据成成员员时时,必必须须指指明明是是使使用用那那一一个个对对象象的的数数据成员。当与对象结合使用时,其用法为:据成员。当与对象结合使用时,其用法为:ObjectName.*PointName4、由于这种指针变量并不是类的成员,所以使用它只能访问对象的公有数据成员。若要访问对象的私有数据成员,必须通过成员函数来实现。837指向类中成员函数的指针变量指向类中成员函数的指针变量定义一个指向类中成员函数的指针变量的一般格式为:定义一个指向类中成员函数的指针变量的一般格
538、式为:(ClassName:*PointName)()();其中PointName是指向类中成员函数的指针变量;ClassName是已定义的类名;type是通过函数指针PointName调用类中的成员函数时所返回值的数据类型,它必须与类ClassName中某一成员函数的返回值的类型相一致;是函数的形式参数表。在使用这种指向成员函数的指针前,应先对其赋值PointName=ClassName:FuncName;同样地,只是将指定成员函数的相对地址赋给指向成员函数的指针。838在调用时,用(对象名.指针)()的形式。比较:intmax(inta,intb)return(ab?a:b);若有:int
539、(*f)(int,int);f=max;则调用时(*f)(x,y);所以:(s1.*mptr1)();(s1.*mptr2)(100);或:(ps-*mptr1)( );(ps-*mptr2)(100);839对指向成员函数的指针变量的使用方法说明以下几点:1、指向类中成员函数的指针变量不是类中的成员,这种指针变量应在类外定义。2、不能将任一成员函数的地址赋给指向成员函数的指针变量,只有成员函数的参数个数、参数类型、参数的顺序和函数的类型均与这种指针变量相同时,才能将成员函数的指针赋给这种变量。3、使用这种指针变量来调用成员函数时,必须指明调用那一个对象的成员函数,这种指针变量是不能单独使用的
540、。用对象名引用。4、由于这种指针变量不是类的成员,所以用它只能调用公有的成员函数。若要访问类中的私有成员函数,必须通过类中的其它的公有成员函数。8405、当一个成员函数的指针指向一个虚函数,且通过指向对象的基类指针或对象的引用来访问该成员函数指针时,同样地产生运行时的多态性。6、当用这种指针指向静态的成员函数时,可直接使用类名而不要列举对象名。这是由静态成员函数的特性所确定的。841第十三章第十三章运算符重载运算符重载842函数的重载函数的重载所谓函数的重载是指完成不同功能的函数可以具所谓函数的重载是指完成不同功能的函数可以具有有相同的函数名相同的函数名。C+的编译器是根据的编译器是根据函数的
541、实参函数的实参来确定应该调用来确定应该调用哪一个函数的。哪一个函数的。intfun(inta,intb)returna+b;intfun(inta)returna*a;voidmain(void)coutfun(3,5)endl;coutfun(5)endl;8258431、定定义义的的重重载载函函数数必必须须具具有有不不同同的的参参数数个个数数,或或不不同同的的参参数数类类型型。只只有有这这样样编编译译系系统统才才有有可可能能根据不同的参数去调用不同的重载函数。根据不同的参数去调用不同的重载函数。2、仅返回值不同时,不能定义为重载函数。、仅返回值不同时,不能定义为重载函数。844intsum
542、,a=3,b=2;(int)=(int)+(int)sum=a+b;floatadd,x=3.2,y=2.5;(float)=(float)+(float)add=x+y;charstr4,c12=a,c22=b;(char*)=(char*)+(char*)str=c1+c2;编译系统中的运算符编译系统中的运算符“”本身不能做这种运算,本身不能做这种运算,若使上式可以运算,必须重新定义若使上式可以运算,必须重新定义“”运算符,运算符,这种重新定义的过程成为运算符的重载。这种重新定义的过程成为运算符的重载。系统自动系统自动识别数据识别数据类型类型845classAfloatx,y;public
543、:A(floata=0,floatb=0)x=a;y=b;voidmain(void)Aa(2,3),b(3,4),c;c=a+b;两对象不能使用,必须重新定义两对象不能使用,必须重新定义运算符重载就是赋予已有的运算符多重运算符重载就是赋予已有的运算符多重含义含义。C+通过重新定义运算符,使它通过重新定义运算符,使它能够用于特定类的对象执行特定的功能能够用于特定类的对象执行特定的功能846运算符的重载从另一个方面体现了运算符的重载从另一个方面体现了OOP技术的多技术的多态性,态性,且同一运算符根据不同的运算对象可以完且同一运算符根据不同的运算对象可以完成不同的操作。成不同的操作。为了重载运算符
544、,必须定义一个函数,并告为了重载运算符,必须定义一个函数,并告诉编译器,诉编译器,遇到这个重载运算符就调用该函数,遇到这个重载运算符就调用该函数,由这个函数来完成该运算符应该完成的操作。由这个函数来完成该运算符应该完成的操作。这这种函数称为运算符重载函数,它通常是种函数称为运算符重载函数,它通常是类的成员类的成员函数或者是友元函数函数或者是友元函数。运算符的操作数通常也应运算符的操作数通常也应该是类的对象。该是类的对象。847重载为类的重载为类的成员函数成员函数格式如下:格式如下:operator()函数体函数体Aoperator+(A&);/重载了类重载了类A的的“+”运算运算符符其中:其中
545、:operator是定义运算符重载函数的关键字,是定义运算符重载函数的关键字,它与其后的运算符一起构成函数名。它与其后的运算符一起构成函数名。返回类型返回类型运算的对象运算的对象关键字关键字函数名函数名运算的对象运算的对象848classAinti;public:A(inta=0)i=a; voidShow(void)couti=iendl;voidAddA(A&a,A&b) /利用函数进行类之间的运算利用函数进行类之间的运算i=a.i+b.i;voidmain(void)Aa1(10),a2(20),a3;a1.Show();a2.Show();/a3=a1+a2;/不可直接运算不可直接运算
546、a3.AddA(a1,a2);/调用专门的功能函数调用专门的功能函数a3.Show();没有重载运算符的例子没有重载运算符的例子利用函数完成了加法运算利用函数完成了加法运算用和作对象调用函数用和作对象调用函数849classAinti;public:A(inta=0)i=a;voidShow(void)couti=iendl;voidAddA(A&a,A&b)/利用函数进行类之间的运算利用函数进行类之间的运算i=a.i+b.i;Aoperator+(A&a) /重载运算符重载运算符+At;t.i=i+a.i;returnt;voidmain(void)Aa1(10),a2(20),a3;a1.
547、Show();a2.Show();a3=a1+a2;/重新解释了加法,可以直接进行类的运算重新解释了加法,可以直接进行类的运算a3.AddA(a1,a2);/调用专门的功能函数调用专门的功能函数a3.Show();相当于相当于a3=a1.operator+(a2)850重载运算符与一般函数的比较:重载运算符与一般函数的比较:相同:相同:1)均为类的成员函数;)均为类的成员函数;2)实现同一功能)实现同一功能voidAddA(A&a,A&b)i=a.i+b.i; Aoperator+(A&a)At;t.i=i+a.i;returnt;a3=a1+a2;a3.AddA(a1,a2);返回值返回值函
548、数名函数名形参列表形参列表由对象由对象a3调用调用函数调用:函数调用:返回值返回值函数名函数名形参形参函数调用:函数调用:a3=a1.operator+(a2);由对象由对象a1调用调用851Aoperator+(A&a)At;t.i=i+a.i;returnt;a3=a1+a2;返回值返回值函数名函数名形参形参函数调用:函数调用:a3=a1.operator+(a2);由对象由对象a1调用调用总结:总结:重新定义运算符,重新定义运算符,由左由左操作符调用右操作符操作符调用右操作符。最后将函数返回值赋给最后将函数返回值赋给运算结果的对象。运算结果的对象。852classAinti;public
549、:A(inta=0)i=a;voidShow(void)couti=iendl;voidAddA(A&a,A&b)/利用函数进行类之间的运算利用函数进行类之间的运算i=a.i+b.i;Aoperator+(A&a) /重载运算符重载运算符+At;t.i=i+a.i;returnt;voidmain(void)Aa1(10),a2(20),a3;a1.Show();a2.Show();a3=a1+a2;/重新解释了加法,可以直接进行类的运算重新解释了加法,可以直接进行类的运算a3.AddA(a1,a2);/调用专门的功能函数调用专门的功能函数a3.Show();相当于相当于a3=a1.opera
550、tor+(a2)853当当用用成成员员函函数数实实现现运运算算符符的的重重载载时时,运运算算符符重重载载函函数数的的参参数数只只能能有有二二种种情情况况:没没有有参参数数或或带带有有一一个个参参数数。对对于于只只有有一一个个操操作作数数的的运运算算符符(如如+),在在重重载载这这种种运运算算符符时时,通通常常不不能能有有参参数数;而而对对于于有有二二个个操操作作数数的的运运算算符符,只只能能带带有有一一个个参参数数。这这参参数数可可以以是是对对象象,对对象象的的引引用用,或或其其它它类类型型的的参参数数。在在C+中中不不允许重载有三个操作数的运算符允许重载有三个操作数的运算符8542、在在C+
551、中中,允允许许重重载载的的运运算算符符列列于于表表13.1中。中。3、在、在C+中不允许重载的运算符列于中不允许重载的运算符列于表表13.2。4、只只能能对对C+中中已已定定义义了了的的运运算算符符进进行行重重载载,而而且且,当当重重载载一一个个运运算算符符时时,该该运运算算符符的的优优先级和结合律是不能改变的先级和结合律是不能改变的。855classroomfloatLength;floatWide;public: room(floata=0.0,floatb=0.0)Length=a;Wide=b;voidShow(void)coutLength=LengthtWide=Wideendl;
552、voidShowArea(void) coutArea=Length*Wideendl;roomoperator+(room&);/重载运算符重载运算符+,函数原型,函数原型;roomroom:operator+(room&r)/重载运算符,函数定义重载运算符,函数定义roomrr;rr.Length=Length+r.Length;rr.Wide=Wide+r.Wide;returnrr;voidmain(void)roomr1(3,2),r2(1,4),r3,r4;r1.Show();r2.Show();r3=r1+r2;r3.Show();r4=r1+r2+r3;r4.Show();r4
553、=r1+r2+r3;(r1+r2); (r1+r2)+r3;r4=r1+(r2+r3);(r2+r3);r1+(r2+r3);运算符的优先级和结运算符的优先级和结合律是不能改变的合律是不能改变的856classAinti;public:A(inta=0)i=a;voidShow(void)couti=iendl;Aoperator+(A&a) /重载运算符重载运算符+At;t.i=i+a.i;returnt;voidoperator+=(A&a)i=i+a.i;voidmain(void)Aa1(10),a2(20),a3;a1.Show();a2.Show();a3=a1+a2;a1+=a2
554、;a3.Show();由左操作符调用右操由左操作符调用右操作符作符,没有返回值,没有返回值,故函数类型为故函数类型为void。相当于相当于a3=a1.operator+(a2)相当于相当于a1.operator+=(a2)857单目运算符的重载单目运算符的重载只具有一个操作数的运算符为单目运算符,最常用只具有一个操作数的运算符为单目运算符,最常用的为及。的为及。Aa,b;b=+a;b=a+;Aa;+a;a+;可以看出,虽然运算后对象可以看出,虽然运算后对象a a的值一致,但先自加的值一致,但先自加或后自加的或后自加的重载运算符函数的返回值不一致,重载运算符函数的返回值不一致,必须必须在重载时予
555、以区分在重载时予以区分。858+为前置运算时,为前置运算时,它的运算符重载函数的一般格式为:它的运算符重载函数的一般格式为: operator +( ) operator +( ) . .; +为后置运算时为后置运算时,它的运算符重载函数的一般格式为:,它的运算符重载函数的一般格式为: operator +( operator +(intint) ) . .; Aa,b;b=+a;b=a+;Aoperator+().Aoperator+(int).859classAfloatx,y;public:A(floata=0,floatb=0)x=a;y=b;Aoperator+()At;t.x=+x
556、;t.y=+y;returnt;Aoperator+(int)At;t.x=x+;t.y=y+;returnt;voidmain(void)Aa(2,3),b;b=+a;b=a+;860Aoperator+()At;t.x=+x;t.y=+y;returnt;b=+a;b=a.operator+();返回值返回值函数名函数名23at3344t作为函数值返回赋给作为函数值返回赋给bAoperator+()+x;+y;return*this;将对象本身作为函将对象本身作为函数值返回赋给数值返回赋给b861Aoperator+(int)At;t.x=x+;t.y=y+;returnt;b=a+;b=
557、a.operator+(3);23at3243返回值返回值函数名函数名t作为函数值返回赋给作为函数值返回赋给b862classincountintc1,c2;public:incount(inta=0,intb=0)c1=a;c2=b;voidShow(void)coutc1=c1tc2=c2等等格式为:格式为:friendoperator().c=a+b;/c=operator+(a,b)friendAoperator+(A&a,A&b).867classAinti;public:public:A(inta=0)i=a; voidShow(void)couti=iendl;friendAop
558、erator+(A&,A&);/友元函数,两个参数,为引用友元函数,两个参数,为引用;Aoperator+(A&a,A&b)At;t.i=a.i+b.i;returnt;voidmain(void)Aa1(10),a2(20),a3;a1.Show();a2.Show();a3=a1+a2;/重新解释了加法,可以直接进行类的运算重新解释了加法,可以直接进行类的运算a3.Show();相当于相当于a3=operator+(a1,a2)868+为前置运算时,为前置运算时,它的运算符重载函数的一般格式为:它的运算符重载函数的一般格式为:A operator +(A &a)A operator +(A
559、 &a) . .; +为后置运算时为后置运算时,它的运算符重载函数的一般格式为:,它的运算符重载函数的一般格式为:A operator +(A &a, A operator +(A &a, intint) ) . .; Aa,b;b=+a;b=a+;Aoperator+(Aa).Aoperator+(Aa,int).869classAinti;public:public:A(inta=0)i=a; voidShow(void)couti=iendl;friendAoperator+(A&a)a.i+;retrurna;friendAoperator+(A&a,intn)At;t.i=a.i;a
560、.i+;returnt;voidmain(void)Aa1(10),a2,a3;a2=+a1;a3=a1+;a2.Show();a3.Show();相当于相当于a2=operator+(a1)相当于相当于a3=operator+(a1,int)870classincountintc1,c2;public:incount(inta=0,intb=0)c1=a;c2=b;voidShow(void)coutc1=c1tc2=c2endl;friendincountoperator+(incount&);/前置前置friendincountoperator+(incount&,int);/后置后置;
561、incountoperator+(incount&c)c.c1+; c.c2+; returnc;incountoperator+(incount&c,int)incountcc;cc=c;c.c1+; c.c2+; returncc;voidmain(void)incountic1(10,20),ic2(100,200),ic3,ic4;ic1.Show();ic2.Show();ic3=+ic1;/ic3=operator(ic1)ic4=ic2+;/ic4=operator(ic2,n)ic3.Show();ic4.Show();871classThreeDfloatx,y,z;publ
562、ic: ThreeD(floata=0,floatb=0,floatc=0)x=a;y=b;z=c;friendThreeD&operator+(ThreeD&);/前置前置friendThreeDoperator+(ThreeD&,int);/后置后置voidShow()coutx=xty=ytz=zn;ThreeD&operator+(ThreeD&t)t.x+;t.y+;t.z+;returnt;ThreeDoperator+(ThreeD&t,int)ThreeDtemp=t;t.x+;t.y+;t.z+;returntemp;voidmain(void)ThreeDm1(25,50,
563、100),m2(1,2,3),m3;m1.Show();m3=+m1;m1.Show();m3.Show();m3=m2+;m2.Show();m3.Show();872对双目运算符,重载为成员函数时,仅一个对双目运算符,重载为成员函数时,仅一个参数,另一个被隐含;重载为友元函数时,有两参数,另一个被隐含;重载为友元函数时,有两个参数,没有隐含参数。个参数,没有隐含参数。一般来说,单目运算符最好被重载为成员函一般来说,单目运算符最好被重载为成员函数;对双目运算符最好被重载友元函数。数;对双目运算符最好被重载友元函数。873转换函数转换函数转换函数就是在类中定义一个成员函数,其作用是转换函数就是
564、在类中定义一个成员函数,其作用是将类转换为某种数据类型将类转换为某种数据类型。classAfloatx,y;public:A(floata,floatb)x=a;y=b;voidmain(void)Aa(2,3);coutaendl;错误!类的对象不能直接输出错误!类的对象不能直接输出利用转换函数将利用转换函数将类类A的对象的对象a转换转换成某种数据类型成某种数据类型Afloat874A:operatorfloat()returnx+y;Afloat格式为:格式为:ClassName:operator().类名类名具体的转换算法具体的转换算法欲转换类型欲转换类型关键字关键字转换算法自己定义转换
565、算法自己定义1.转换函数必须是类转换函数必须是类的成员函数。的成员函数。2.转换函数的调用是转换函数的调用是隐含的,没有参数。隐含的,没有参数。875classAinti;public:public:A(inta=0) i=a; voidShow(void)couti=iendl; operatorint() returni;voidmain(void)Aa1(10),a2(20);couta1endl;couta2endl;876classComplexfloatReal,Image;public:Complex(floatreal=0,floatimage=0)Real=real;Imag
566、e=image;voidShow(void)coutReal=RealtImage=Imagefloat;Complex:operatorfloat()returnReal*Real+Image*Image;voidmain(void)Complexc(10,20);c.Show();coutcendl;/可以直接输出可以直接输出c,因为已经进行类型转换,因为已经进行类型转换877注注意意,转转换换函函数数只只能能是是成成员员函函数数,不不能能是是友友元元函函数数。转转换换函函数数的的操操作作数数是是对对象象。转转换换函函数数可可以以被被派派生生类类继继承承,也也可可以以被被说说明明为为虚虚函
567、函数。数。878赋值运算符与赋值运算符重载赋值运算符与赋值运算符重载 “”同类型的对象间可以相互赋值,等同于对象的各个同类型的对象间可以相互赋值,等同于对象的各个成员的一一赋值。成员的一一赋值。A a(2,3), b;A a(2,3), b;b ba;a; 但当对象的成员中使用了动态的数据类型时但当对象的成员中使用了动态的数据类型时(用用new开辟空间),就不能直接相互赋值,否则在程开辟空间),就不能直接相互赋值,否则在程序的执行期间会出现运行错误序的执行期间会出现运行错误。879classAchar*ps;public:A()ps=0;A(char*s)ps=newcharstrlen(s)
568、+1;strcpy(ps,s);A()if(ps)deleteps;voidShow(void)coutpsendl;voidmain(void)As1(China!),s2(Computer!);s1.Show();s2.Show();s2=s1;s1.Show();s2.Show();/相当于相当于s2.ps=s1.ps;s1 ps“China”s2 psComputers2.ps=s1.ps首先析构首先析构s2接着析构接着析构s1出错出错880这时,利用编译系统的默认赋值无法正确运行程序,这时,利用编译系统的默认赋值无法正确运行程序,必须重载赋值运算符必须重载赋值运算符“”,即,即重新定
569、义重新定义“”。格式为:格式为::operator=()赋值运算符必须重载为成员函数。赋值运算符必须重载为成员函数。AA:operator=(A&a)函数返回值类型函数返回值类型成员函数作用域成员函数作用域函数名函数名函数参数函数参数b=a;b.operator=(a);左操作符调左操作符调用右操作符用右操作符881classSampleintx;public:Sample(inti=0)x=i;voiddisp(void)cout“x=“xendl;voidoperator=(Sample&p)x=p.x;voidmain(void)SampleA(20),B;SampleC(A);/使用缺
570、省的拷贝构造函数使用缺省的拷贝构造函数B=A;/使用赋值运算符重载使用赋值运算符重载B.disp();A.disp();882classAchar*ps;public:A()ps=0;A(char*s)ps=newcharstrlen(s)+1;strcpy(ps,s);A()if(ps)deleteps;voidShow(void)coutpsendl;A&operator=(A&b);voidmain(void)As1(China!),s2(Computer!);s1.Show();s2.Show();s2=s1;s1.Show();s2.Show();必须重新定义必须重新定义“=”883
571、A&A:operator=(A&b)/重载赋值运算符重载赋值运算符if(ps)deleteps;if(b.ps)ps=newcharstrlen(b.ps)+1;strcpy(ps,b.ps);elseps=0;return*this;s1 ps“China”s2 ps“Computer”s2=s1;s2.operator=(s1);“China”返回同种类型的引用适合于连等。返回同种类型的引用适合于连等。s3=s2=s1;884classAchar*ps;public: A()ps=0;A(char*s)ps=newcharstrlen(s)+1;strcpy(ps,s);A()if(ps)
572、deleteps;char*GetS()returnps;A&operator=(A&b);/重载赋值运算符重载赋值运算符;A&A:operator=(A&b)/重载赋值运算符重载赋值运算符if(ps)deleteps;if(b.ps)ps=newcharstrlen(b.ps)+1;strcpy(ps,b.ps);elseps=0;return*this;voidmain(void)As1(China!),s2(Computer!);s2=s1;couts1=s1.GetS()t;couts2=s2.GetS()n;s2.ps重新开辟内存,存放重新开辟内存,存放“China”重新开辟内存重新
573、开辟内存885一个字符串类一个字符串类在在C+中中,系系统统提提供供的的字字符符串串处处理理能能力力比比较较弱弱,都都是是通通过过字字符符处处理理函函数数来来实实现现的的,并并且且不不能能直直接接对对字字符符串串进进行行加加法法、减减法法,字字符符串串的的拼拼接接,字字符符串串之之间间的的相相互互赋赋值值等等操操作作。可可以以通通过过应应用用C+提提供供的的运运算算符符重重载载机机制制,可可以以提提供供字字符符串串的的直直接接操操作作能能力力,使使得得字字符符串串的操作与一般的数据一样方便。的操作与一般的数据一样方便。886classStringintLength;/字符串长度字符串长度cha
574、r*Sp;/字符串在内存中的首地址字符串在内存中的首地址public:.可见,字符串类只定义了指针,并没有开辟具体的可见,字符串类只定义了指针,并没有开辟具体的空间以存放字符串的内容,所以,无论是构造、析空间以存放字符串的内容,所以,无论是构造、析构还是加减等,构还是加减等,均需要考虑动态开辟空间的问题均需要考虑动态开辟空间的问题,这也是字符串类的难点。这也是字符串类的难点。887classStringintLength;/字符串的长度字符串的长度char*Sp;/指向字符串的指针指向字符串的指针public: String()Sp=0;Length=0;/缺省的构造函数缺省的构造函数Stri
575、ng(char*s)/以一个字符串常量作为参数以一个字符串常量作为参数Length=strlen(s);Sp=newcharLength+1;strcpy(Sp,s);String()if(Sp)deleteSp;friendStringoperator+(String&,String&);/友元函数重载友元函数重载String&operator=(String&);/成员函数重载赋值成员函数重载赋值String(String&s);/拷贝的构造函数拷贝的构造函数(必须有必须有);voidmain(void)Stringstr1(China);Stringstr2(CCTV);Stringst
576、r3;str3=str1+str2;str2=str1;coutstr3x;coutx;cin.get(ch);内内存存键盘键盘文件文件光笔光笔.输入流输入流显示器显示器文件文件打印机打印机.输出流输出流892输入输出流(输入输出流(I/O StreamI/O Stream)C+C+语语言言的的I/OI/O系系统统向向用用户户提提供供一一个个统统一一的的接接口口,使使得得程程序序的的设设计计尽尽量量与与所所访访问问的的具具体体设设备备无无关关,在在用用户户与与设设备备之之间间提供了一个抽象的界面提供了一个抽象的界面: :输入输出流输入输出流。iosistream(输入流输入流)ostream(
577、输出流输出流)iostream在在“iostream.h”中说明中说明893用标准流进行输入用标准流进行输入/输出时,系统自动地完成输出时,系统自动地完成数据类型的转换。数据类型的转换。对于输入流,要将输入的对于输入流,要将输入的字符序列形式的数据变换成计算机内部形式字符序列形式的数据变换成计算机内部形式的数据(二进制或的数据(二进制或ASCII)后,再赋给变量,)后,再赋给变量,变换后的格式由变量的类型确定。变换后的格式由变量的类型确定。对于输出对于输出流,将要输出的数据变换成字符串形式后,流,将要输出的数据变换成字符串形式后,送到输出流(文件)中。送到输出流(文件)中。894重载输入重载输
578、入(提取提取)和输出和输出(插入插入)运算符运算符classAfloatx,y;public:A(floata=0,floatb=0)x=a;y=b;voidSet(floata,floatb)x=a;y=b;voidShow(void)coutxtya;couta;对象不能直对象不能直接输入输出接输入输出895在在C+中中允允许许用用户户重重载载运运算算符符“”,实实现现对对象象的的输输入入和和输输出出。重重载载这这二二个个运运算算符符时时,在在对对象象所所在在的的类类中中,将将重重载载这这二二个个运运算算符符的的函函数数说说明明该该类的类的友元函数友元函数。重载提取运算符的一般格式为:重载
579、提取运算符的一般格式为:友元函数友元函数friendistream&operater(istream&,ClassName&);返回值类型返回值类型函数名函数名左操作数左操作数右操作数右操作数cina;operator(cin,a)896友元函数友元函数friendistream&operater(istream&,ClassName&);返回值类型返回值类型函数名函数名左操作数左操作数右操作数右操作数cina;operator(cin,a)返回值类型:返回值类型:类类istream的引用,的引用,cin中可以连续使用运算中可以连续使用运算符符“”。cinab;第一个参数:是第一个参数:是“”
580、的左操作数的左操作数cin类型类型,类类istream的引的引用用第二个参数:是第二个参数:是“”的右操作数的右操作数,即欲输入的对象的引即欲输入的对象的引用用.istream&operater(istream&is,ClassName&f);897classAfloatx,y;public:.;.Aa;cina;.friendistream&operater(istream&,A&);istream&operater(istream&is,A&a)cout“Inputa:”a.xa.y;returnis;重新定义输入流重新定义输入流在类中原型说明在类中原型说明在类外定义函数在类外定义函数返回
581、输入流返回输入流898classincountintc1,c2;public:incount(inta=0,intb=0)c1=a; c2=b; voidshow(void)coutc1=c1tc2=c2(istream&,incount&);istream&operator(istream&is,incount&cc)iscc.c1cc.c2;returnis;voidmain(void)incountx1,x2;x1.show();x2.show();cinx1;cinx2;x1.show();x2.show();重载输入函数原型说明重载输入函数原型说明重载输入函数定义重载输入函数定义89
582、9友元函数友元函数friendostream&operater(ostream&,ClassName&);返回值类型返回值类型函数名函数名左操作数左操作数右操作数右操作数couta;operator(istream&,ClassName&);将输入流改为输出流。将输入流改为输出流。900classAfloatx,y;public:.;.Aa(2,3);couta;.friendostream&operater(ostream&,A&);ostream&operater(ostream&os,A&a)cout“Theobjectis:”endl;osa.xta.yendl;returnos;重新
583、定义输出流重新定义输出流在类中原型说明在类中原型说明在类外定义函数在类外定义函数返回输出流返回输出流901classincountintc1,c2;public: incount(inta=0,intb=0) c1=a;c2=b;voidshow(void) coutc1=c1tc2=c2(istream&,incount&);friendostream&operator(istream&is,incount&cc)iscc.c1cc.c2;returnis;ostream&operator(ostream&os,incount&cc) /重载重载coutosc1=cc.c1tc2=cc.c2
584、endl; returnos;voidmain(void)incountx1,x2;coutx1x1;/调用输入函数调用输入函数cinx2;coutx1x;coutx;cin.get(ch);903文件流文件流C+在头文件在头文件fstream.h中定义了中定义了C+的文件流类体的文件流类体系系,当程序中使用文件时,当程序中使用文件时,要包含头文件要包含头文件fstream.h。iosifstream(输入流输入流)ofstream(输出流输出流)fstream在在“fstream.h”中说明中说明当使用文件时,在程序头有:当使用文件时,在程序头有:#include其中定义了各种文件操作运算符
585、及函数。其中定义了各种文件操作运算符及函数。904内存变量内存变量(程序程序)键盘键盘输入文件输入文件屏幕屏幕输出文件输出文件cinxcoutxoutfilexy;myfile1.txt34内存内存infilexy34用用 infile代代 替替 myfile1.txt进行操作。进行操作。911ifstreamoutfile;/定义输出文件类对象定义输出文件类对象infile.open(“myfile2.txt”);/利用函数打开某一文件利用函数打开某一文件floatx3,y4;outfilextyxy;outfilextyendl;infile.close();outfile.close()
586、;infile.close();outfile.close();913voidmain(void)inta10;ifstreaminfile;/定义输入文件类定义输入文件类ofstreamoutfile;/定义输出文件类定义输出文件类infile.open(“file1.txt”);/打开一个输入文件打开一个输入文件“file1.txt”outfile.open(“file2.txt”);/打开一个输出文件打开一个输出文件“file2.out”for(inti=0;iai;/将将“file1.txt”中的十个整型数输入到中的十个整型数输入到ai中中for(i=0;i10;i+)outfilea
587、it;/将将ai中的十个数输出到文件中的十个数输出到文件“file2.txt”中中outfilech;/输入输入pfile2ch;/输出输出pfile1.close();pfile2.close();915在打开文件后,都要判断打开是否成功。若打开成功,则在打开文件后,都要判断打开是否成功。若打开成功,则文件流对象值为非零值;文件流对象值为非零值;若打开不成功,则其值为若打开不成功,则其值为0。ifstreampfile1,pfile2;/定义了两个文件类的对象定义了两个文件类的对象pfile1.open(“file1.txt”,ios:in);pfile2.open(“file2.txt”,
588、ios:out);if(!pfile1)cout”不能打开输入文件:不能打开输入文件:file1.txt”n;exit(1);if(!pfile2)cout”不能打开输出文件:不能打开输出文件:file2.txt”n;exit(1);若为若为0,打开文件操作失败,打开文件操作失败916打开输入文件时,文件必须存在。打开输入文件时,文件必须存在。打开输出文件时,若文件不存在,则建打开输出文件时,若文件不存在,则建立文件;若文件存在,则删除原文件的立文件;若文件存在,则删除原文件的内容,使其成为一个空文件。内容,使其成为一个空文件。917charch,str300;ifstreaminfile(“
589、myfile1.txt”);ofstreamoutfile(“myfiel2.txt”);涉及到字符串的文件读写涉及到字符串的文件读写从键盘输入一个字符:从键盘输入一个字符:cin.get(ch);从文件输入一个字符:从文件输入一个字符:infile.get(ch);向显示器输出一个字符:向显示器输出一个字符:cout.put(ch);向文件输出一个字符:向文件输出一个字符:outfile.put(ch);从键盘输入一行字符:从键盘输入一行字符:cin.getline(str,300);从文件输入一行字符:从文件输入一行字符:infile.getline(ch,300);从文件输入一字符或从文
590、件输入一字符或一行字符,当输入至一行字符,当输入至文件尾时,文件尾时,函数返回函数返回值为值为0,可以据此来判,可以据此来判断循环结束。断循环结束。91814-15.实现两文件的拷贝的程序实现两文件的拷贝的程序voidmain(void)charfilename1256,filename2256;coutfilename1;coutfilename2;ifstreaminfile(filename1);ofstreamoutfile(filename2);charch;while(infile.get(ch)outfile.put(ch);infile.close();outfile.clos
591、e();输入文件输入文件(源文件源文件)名名输出文件输出文件(目的文件目的文件)名名用构造函数打开文件用构造函数打开文件从源文件中读取一个字从源文件中读取一个字符,至文件尾停止循环符,至文件尾停止循环将该字符输出至目的文件将该字符输出至目的文件关闭文件关闭文件919voidmain(void)charfilename1256,filename2256;charbuf300;coutfilename1;coutfilename2;fstreaminfile,outfile;infile.open(filename1,ios:in);outfile.open(filename2,ios:out);
592、while(infile.getline(buf,300)outfilebufendl;outfile.close();infile.close();输入文件输入文件(源文件源文件)名名输出文件输出文件(目的文件目的文件)名名用函数打开文件用函数打开文件从源文件中读取一行字从源文件中读取一行字符,至文件尾停止循环符,至文件尾停止循环将该行字符输出至目的文件将该行字符输出至目的文件关闭文件关闭文件920二进制文件的读写操作二进制文件的读写操作若在文件的打开方式中没有特别说明,打开的文件均为若在文件的打开方式中没有特别说明,打开的文件均为ASCII码文件,码文件,若要打开二进制文件,则要特别说明并
593、若要打开二进制文件,则要特别说明并用特定的读写函数用特定的读写函数。fstreaminfile,outfile;infile.open(“inf1.dat”,ios:in|ios:binary);outfile.open(“outf1.dat”,ios:out|ios:binary);文件名文件名输入方式打开输入方式打开二进制文件二进制文件文件名文件名输出方式打开输出方式打开二进制文件二进制文件921输入函数:输入函数:infile.read(char*,int)输入文件输入文件对象名对象名数据进入的内存地址数据进入的内存地址一次读入的字节数一次读入的字节数文件文件内存内存inta10;inf
594、ile.read(char*)a,10*sizeof(int);/从文件中输入十个整型数到从文件中输入十个整型数到ainti;infile.read(char*)&i,sizeof(int);/从文件中输入一个整型数到从文件中输入一个整型数到i由于二进制文件中的数据不是由于二进制文件中的数据不是ASCII码,故不能直接对码,故不能直接对其读写,其读写,必须要通过特定的函数予以转换。必须要通过特定的函数予以转换。读入读入地址要强制转换成字符型地址要强制转换成字符型922输出函数:输出函数:outfile.write(char*,int)输出文件输出文件对象名对象名要输出的数据在内存中的地址要输出
595、的数据在内存中的地址一次输出的字节数一次输出的字节数文件文件内存内存inta10=0,1,2,3,4,5,6,7,8,9;outfile.write(char*)a,10*sizeof(int);/向文件输出一个整型数组向文件输出一个整型数组ainti=4;outfile.write(char*)&i,sizeof(int);/向文件输出一个整型数向文件输出一个整型数i写出写出地址要强制转换成字符型地址要强制转换成字符型923判断二进制文件是否读到文件尾?判断二进制文件是否读到文件尾?infile.eof()当到达文件结束位置时,该函数返回一个非零值;当到达文件结束位置时,该函数返回一个非零值
596、;否则否则返回零。返回零。fstreaminfile;infile.open(“data1.dat”,ios:in|ios:binary);if(!infile)cout“OpenError!n”;exit(1);charstr300;while(!infile.eof()infile.read(str,300);判断打开是否出错判断打开是否出错判断是否读到文件尾判断是否读到文件尾924voidmain(void)charfilename1256,filename2256;charbuff4096;coutfilename1;coutfilename2;fstreaminfile,outfil
597、e;infile.open(filename1,ios:in|ios:binary);outfile.open(filename2,ios:out|ios:binary);intn;while(!infile.eof()/文件不结束,继续循环文件不结束,继续循环infile.read(buff,4096);/一次读一次读4096个字节个字节n=infile.gcount();/取实际读的字节数取实际读的字节数outfile.write(buff,n);/按实际读的字节数写入文件按实际读的字节数写入文件infile.close();outfile.close();925文件指针文件指针文件内容文
598、件内容文件指针文件指针当一打开文件,文件指针位于文件头,并随着读写当一打开文件,文件指针位于文件头,并随着读写字节数的多少顺序移动。字节数的多少顺序移动。可以利用成员函数随机移动文件指针。可以利用成员函数随机移动文件指针。926随机读取二进制文件随机读取二进制文件infile.seekg(int);/将文件指针移动到由参数指定的字节处将文件指针移动到由参数指定的字节处infile.seekg(100);/将文件指针移动到距离文件头将文件指针移动到距离文件头100个字个字节处节处infile.seekg(int,ios:_dir);移动的字节数移动的字节数相对位置相对位置infile.seekg
599、(100,ios:beg);/移动到距文件头移动到距文件头100个字节个字节_dir:beg:文件头文件头cur:当前位置当前位置end:文件尾文件尾infile.seekg(-100,ios:cur);/移动到距当前位置前移动到距当前位置前100个字节个字节infile.seekg(-500,ios:end);/移动到距文件尾前移动到距文件尾前500个字节个字节927voidmain(void)ofstreamoutfile(“data1.dat”,ios:out|ios:binary);inti;for(i=5;i1000;i+=2)outfile.write(char*)&i,sizeo
600、f(int);/将奇数写入文件将奇数写入文件outfile.close();/关闭文件关闭文件ifstreamf1(“data.dat”,ios:in|ios:binary);intx;f1.seekg(20*sizeof(int);/将文件指针移到第将文件指针移到第20个整数的位置个整数的位置for(i=0;i10;i+)f1.read(char*)&x,sizeof(int);/依次读出第依次读出第2029个奇数到个奇数到xcoutxtmp)sum+=tmp;f1.close();coutsumendl;929如果令如果令A,B,C,D,,X,Y,Z这这26个英文字母,分个英文字母,分别等于百分之别等于百分之1,2,24,25,26个数值,那么我们个数值,那么我们就能得出如下有趣的结论:就能得出如下有趣的结论:HARDWORD8+1+18+4+23+15+18+11=98KNOWLEDGE96%LOVE54%LUCK47%计算一下计算一下MONEYSTUDYATTITUDE930