• 1. C++程序设计 谭浩强编著 清华大学出版社 课件制作:南京理工大学 陈清华 朱红1
  • 2. 第一章C++概述 C++语言发展历史 自从1946年第一台电子数字计算机ENIAC问世以来,随着计算机应用领域的不断扩大,促进了计算机技术的高速发展,尤其是近年来计算机的硬件和软件都是日新月异。作为应用计算机的一种工具—程序设计语言,得到不断的充实和完善。每年都有新的程序设计语言问世,老的程序设计语言不断地更新换代。 2
  • 3. 20世纪60年代,Martin Richards为计算机软件人员在开发系统软件时,作为记述语言使用而开发了BCPL语言(Basic Combined Programming Language)。1970年,Ken Thompson在继承BCPL语言的许多优点的基础上发明了实用的B语言。到了1972年,贝尔实验室的Dennis Ritchie和Brian kernighan在B语言的基础上,作了进一步的充实和完善,设计出了C语言。当时,设计C语言是为了编写UNIX操作系统的。以后,C语言经过多次改进,并开始流行。C++是在C语言的基础上发展和完善的,而C是吸收了其它语言的优点逐步成为实用性很强的语言。3
  • 4. C语言的主要特点是: 1、C语言是一种结构化的程序设计语言,语言本身简洁、使用灵活方便。既适用于设计和编写大的系统程序,又适用于编写小的控制程序,也适用科学计算。2、它既有高级语言的特点,又具有汇编语言的特点。运算符丰富,除了提供对数据的算术逻辑运算外,还提供了二进制的位运算。并且也提供了灵活的数据结构。用C语言编写的程序表述灵活方便,功能强大。用C语言开发的程序,其结构性好,目标程序质量高,程序执行效率高。4
  • 5. 3、程序的可移植性好。用C语言在某一种型号的计算机上开发的程序,基本上可以不作修改,而直接移植到其它型号和不同档次的计算机上运行。4、程序的语法结构不够严密,程序设计的自由度大。这对于比较精通C语言的程序设计者来说,可以设计出高质量的非常通用的程序。但对于初学者来说,要能比较熟练运用C语言来编写程序,并不是一件容易的事情。与其它高级语言相比而言,调试程序比较困难。往往是编好程序输入计算机后,编译时容易通过,而在执行时还会出错。但只要对C语言的语法规则真正领会,编写程序及调试程序还是比较容易掌握的。5
  • 6. 随着C语言应用的推广,C语言存在的一些缺陷或不足也开始流露出来,并受到大家的关注。如:C语言对数据类型检查的机制比较弱;缺少支持代码重用的结构;随着软件工程规模的扩大,难以适应开发特大型的程度等等。6
  • 7. 为了克服C语言本身存在的缺点,并保持C语言简洁、高效,与汇编语言接近的特点,1980年,贝尔实验室的Bjarne Stroustrup博士及其同事对C语言进行了改进和扩充,并把Simula 67中类的概念引入到C中。并在1983年由Rick Maseitti提议正式命名为C++(C Plus Plus)。后来,又把运算符的重载、引用、虚函数等功能加入到C++中,使C++的功能日趋完善。 当前用得较为广泛的C++有:VC++ (Visual C Plus Plus)、 BC++(Borland C Plus Plus)、AT&T C++等。7
  • 8. 简单的C++程序介绍高级语言编译过程源程序 (文本文件) *.CPP目标文件 (二进制文件) *.OBJ可执行文件 (二进制文件) *.EXE库文件 (各种函数)在Vitual C++系统中,可直接从源程序编译连接至可执行程序,但依然要生成*.OBJ及*.EXE这两个文件。F7编译连接compilelink8
  • 9. 一个简单的C++程序#include void main(void ) { cout<<“I am a student.\n”; //输出字符串 }主函数函数体开始函数体结束输出流,在屏幕上打印引号内的字符串分号,一条完整语句的结束符本程序编译执行后,在DOS屏幕上打印出 I am a student.包含文件注释或说明9
  • 10. 编译过程: 1)启动Visual C++,选择“文件”菜单中的“新建”命令,选择“文件”标签中的“C++ Source File”选项。 2)选择源程序存放的目录和输入源程序名,单击“确定”。 3)在编辑器中编写源程序。 4)单击F7或“编译”中的“重建全部”编译源程序,若编译通过,单击“执行”,在DOS屏上看结果,任按一键返回编辑器。10
  • 11. 启动VC++编译系统11
  • 12. VC++编译系统界面单击“File”菜单中“New”命令12
  • 13. 选择“Files”选项卡选择C++源文件命令输入文件名输入文件存放位置单击选择驱动器选择驱动器或目录13
  • 14. C++源文件编辑界面输入C++源代码14
  • 15. 可以将此源代码另起文件名存盘15
  • 16. 选择编译命令,将源文件.cpp生成.obj文件16
  • 17. 如果编译出错,会出现提示信息,指出错误的位置及种类错误所在行错误的原因17
  • 18. 双击错误所在行光标移到该行18
  • 19. 生成可执行文件通过后单击该命令运行程序19
  • 20. 运行结果显示在DOS屏上注意:不可以在软盘上运行程序!应该把保存在软盘中的源文件拷贝到硬盘的目录中再运行!20
  • 21. 源程序所在目录未编译前,只有一个源程序21
  • 22. 编译运行后,出现众多附加文件同时,产生一个子目录Debug22
  • 23. Debug目录中,有obj和EXE文件23
  • 24. #include void main(void) { cout << “i=”; //显示提示符 int i; //说明变量i cin >>i; //从键盘上输入变量i的值 cout << “i的值为:” <
  • 25. 第二章 数据类型、运算符与表达式25
  • 26. 2000H 2001H 2002H 2003H 2004H33+5=?5运算器(2000H)+(2002H)用一个字节表示整数,范围为-128~127;用两个字节表示整数,范围为-32768~ 32767。一般用四个字节表示整数。(举例)内存CPU内存data外存Program8硬盘 软盘26
  • 27. 1514131211109876543210有符号数无符号数0111111111111111327673276701111111111111103276632766…………0000000000000001110000000000000000001111111111111111-1(补码)655351111111111111110-265534…………1000000000000001-32767327691000000000000000-327683276827
  • 28. 常量与变量常量:在程序运行过程中,其值一直保持不变的量为常量。 常量也区分不同的类型:30,40 为整型,30.0,40.0为实型,编辑器只是根据其表面形式来判断其类型。变量:在程序运行过程中,其值可以改变的量为变量。 变量在程序的执行中能够赋值,发生变化。变量有一个名字,并在使用之前要说明其类型,一经说明,就在内存中占据与其类型相应的存储单元。28
  • 29. #include #define PRICE 30 //常量,在程序中保持不变 void main(void) { int num, total; //定义变量,在内存中开辟区间 num=10; //变量赋值,10为常量 total=num*PRICE; cout<<“total=“<
  • 30. C++中有多种数据类型,均有常量与变量之分,各占不同的内存空间,正确定义与使用数据是编写程序的基本前提。30
  • 31. 变量名的命名方法: 变量名、数组名、函数名…称为标识符。 标识符只能由字母、数字、下划线这三种字符组成,且第一个字符必须为字母或下划线,长度不大于247个字符,大小写不通用。(关键字不能作为标识符)。 关键字即是VC++的语法要求中使用的字。 如 int if while 等。 正确的标识符:INT, sum , de12, SUM等。变量必须使用前定义,以分配空间。 举例说明31
  • 32. abc English 2xy x-y if Else b(3) ‘def’ Chine_bb b3y AbsFloat float一般变量都是用匈牙利命名法命名的。int nCount; char chChoice;32
  • 33. 整型数据整型常量: 常量是根据其表面形式来判定,整型量即是没有小数点的整数,范围:-231~(231-1) ,有三种形式: 1)十进制(默认方式) 43 1345 87654 2)八进制 以0开头 043, 056, 011 3)十六进制 以0x开头 0x12 0xa3 0x34 0xdf(举例说明)33
  • 34. #include void main(void) { int int10,int8,int16; //定义3个整型变量 int10=10; //默认为十进制 int8=010; //八进制 int16=0x10; //十六进制 cout<<"int10="<35. 整型变量: 分为有符号型与无符号型。 有符号型: short 在内存中占两个字节,范围为-215~(215-1) int 在内存中占四个字节,范围为-231~(231-1) long在内存中占四个字节,范围为-2-31~231-1无符号型:最高位不表示符号位 unsigned short 在内存中占两个字节,范围为0~216-1 unsigned int 在内存中占四个字节,范围为0~232-1 unsigned long在内存中占四个字节,范围为0~232-135
  • 36. 1)整型常量亦有长短之分,常量中无unsigned型,但一个非负的整型常量可以赋给unsigned型的变量。 2)若一个常量定义为长整型数,则在其后加l或L进行区分。 如:32l 32L 564L等,内存为其分配四个字节存储。 一个数在内存中为1111111111111111当这个数为有符号数时,是-1;为无符号数时,是232-1 内存中的数是以补码的形式存放的。(举例说明)111111111111111136
  • 37. #include void main() { unsigned short a; short int b= -1; a=b; cout<<"a="<
  • 38. 实型数据实型数又称浮点数,有两种表示方式: 1)十进制形式: 23.0 24.5 3.56789 指数形式: 23E1 145e-1 356789e1 e前有数字,后面必须是整数。实型变量分单精度 float 和双精度 double 两种形式: float:占四个字节,提供7~8位有效数字。 double: 占八个字节,提供15~16位有效数字。举例说明38
  • 39. #include void main(void) { float a, b; double c, d; a=0.01; b=3.45678e-2; c=3.45678e-2; d=9.7654e-5; cout<<"a="<40. 如果为实数,则用浮点数的形式在内存存储,表示如下:JtJSfS阶符阶码数符尾数实数是既有整数又有小数的数。 实数可以表示成:N=S×RJ S 称为尾数,尾数决定有效数字,即数字的精度。 J 表示指数(阶码)。 R 是基数,可取2,4,8,16等,对具体机器而言,基数取好后,就不能再变了。 数有正有负, 所以设置数符; 阶码亦有正负, 所以设置阶符40
  • 41. 一般用4个字节表示一个浮点数,也有用8个字节表示的。字长一定,尾数越多,精度越高;阶码越多,范围越大。 当计算机中出现小于机器所能表示的最小数时,机器只能当零来处理,当出现超过机器所能表示的最大数时,出现溢出现象,一旦出现溢出,就会停止运算。定点数,浮点数均会出现溢出现象。41
  • 42. 字符型数据(char)字符型数据实际上是作为整型数据在内存中存储的。 计算机是以字符编码的形式处理字符的,因此,我们在计算机内部是以ASCII码的形式表示所有字符的。所以7位二进制数即可表示出一个字符,我们用一个字节的容量(8位)存储一个字符。例如:字符A的ASCII码为0x41或65,在内存中表示为:01000001在程序中表示为: char grade ;//定义一个字符型的变量空间(1个字节) grade=‘A’; //必须用‘ ’表示,否则易与标识符混同 ‘ ’内括起来的字符表示该字符的ASCII码。42
  • 43. 进一步,由于在内存中的形式与整型数据相同,所以,可以直接用其整型值给变量赋值。char grade; grade=65;以下的赋值形式均是等同的。 grade='A'; grade=65 ; grade=0x41; grade=0101;#include void main(void) { char a,b; a=‘A’; //输入ASCII码 b=65; //输入十进制数 cout<<"a="<44. 非打印字符 有些ASCII的字符代表某些操作,不能打印出来,如回车、退格等,可用两种方式表示这些字符。 1)用ASCII码的形式 char re=13; 2)用转义字符 char re=‘\n’;(p15)44
  • 45. 转义字符含 义 ASCII代码 \a 响铃 7 \n 换行,将当前位置移到下一行开头 10 \t 水平制表(跳到下一个tab位置) 9 \b 退格,将当前位置移到前一列 8 \r 回车,将当前位置移到本行开头 13 \f 换页,将当前位置移到下页开头 12 \ v 竖向跳格 8 \\ 反斜杠字符“\” 92 \′ 单引号(撇号)字符 39 \" 双引号字符 34 \0 空字符 0 \ddd 1到3位8进制数所代表的字符   \xhh 1到2位16进制数所代表的字符   45
  • 46. 转义字符虽然包含2个或多个字符,但它只代表一个字符。编译系统在见到字符“\”时,会接着找它后面的字符,把它处理成一个字符,在内存中只占一个字节。 46
  • 47. 典型转义字符 : ‘\n’换行 ‘\b’ 退格 '\t' 下一个输出区 若输出中包含这些特定格式,则再加一个\输出 c:\tc\tc 表示为cout<<"c:\\tc\\tc";可以用转义字符表示任一一个ASCII字符 ‘\ddd’ (八进制) ‘\xhh‘ (十六进制) '\101' '\x41' '\x61' '\141' 47
  • 48. #include void main(void) { char c1,c2,c3,c4; char n1,n2; c1='a'; //字符常量 c2=97; //十进制 c3='\x61'; //转义字符 c4=0141; //八进制 cout<<"c1="<49. 字符串常量: 用" "表示,在内存中顺序存放,以'\0'结束。 如:"CHINA" 0x430x480x490x550x41\0'a'在内存中占一个字节 "a"占两个字节aa\0实际上内存是对应字符的ASCII码形式010000110100100001001001010101010100000100000000CHINA\001100001011000010000000049
  • 50. 标识符常量 在C++中有二种方法定义标识符常量,一种是使用编译预处理指令;另一种是使用C++的常量说明符const。 例如: #define PRICE 30 //在程序中凡是出现PRICE均用30替代 #define PI 3.1415926 #define S “China”const float pi=3.1415926; //将变量pi定义为常量 (举例说明)50
  • 51. #include #define PI 3.14156 #define S "China" void main(void) { const float pi=3.14156; //变量作为常量使用 cout<<"PI="<52. 下列常量的表示在C++中是否合法?若不合法,指出原因;若合法,则指出常量的数据类型。 32767 35u 1.25e3.4 3L 0.0086e-32 ‘\87’ “Computer System” “a” ‘a’ ‘\96\45’ -0 +0 .5 -.567 52
  • 53. 变量 1) 在程序的执行过程中,其值可以改变的量称为变量。2) 变量名必须用标识符来标识。3) 变量根据其取值的不同值域,分为不同类型的变量:整型变量、实型变量、字符型变量、构造型变量、指针型变量等等。53
  • 54. 4) 对于任一变量,编译程序要为其分配若干个字节(连续的)的内存单元,以便保存变量的取值。5) 当要改变一个变量的值时,就是把变量的新的取值存放到为该变量所分配的内存单元中;用到一个变量的值时,就是从该内存单元中取出数据。6) 不管什么类型的变量,通常均是变量的说明在前,使用变量在后。54
  • 55. int i, j, k; //定义了三个整型变量i,j,k float x,y,z; //定义了三个实型变量x,y,zchar c1,c2; //说明了二个字符型变量c1,c2 double dv1;//说明了一个双精度型变量dv1k四个字节的连续空间j四个字节的连续空间i四个字节的连续空间z四个字节的连续空间y四个字节的连续空间x四个字节的连续空间dv1八个字节的连续空间c21个字节的空间c11个字节的空间开辟空间后, 空间中为随机值55
  • 56. 变量赋初值在定义变量的同时给变量赋值,即在内存中开辟出一个空间后马上给此空间赋值。 但这个空间的值并不是固定不变的,在程序的运行中一样可以改变。 char a='\x64', b='d'; int a1=6, a2=98; a=‘A’; b=‘\n’; a1=011; a2=121; int a=4; //定义语句,在开辟空间后马上为空间赋值 a=6; //重新为该空间赋值a4656
  • 57. 算术运算符和算术表达式一、算术运算符和算术表达式 + - * / % 用算术运算符连接起来的式子是算术表达式两个整数相除结果为整数 1/2=0 5/2=2整数才可求余,余数的符号与左边数的符号相同。 3%2=1 -3%2=-1 3%-2=1 -3%-2=-1 8%4=0二、优先级与结合性 () * / % + —57
  • 58. 三、强制转换类型 (类型名)(表达式) (double) a (int) (x+y) (int) 6.2%4=2 在强制类型运算后原变量不变,但得到一个所需类型的中间变量。如:int x; float y=5.8; x=(int)y;x=5y=5.8y的值没有改变,仍是单精度浮点型58
  • 59. 四、自增、自减运算符 (难点) ++ --i6i37 int i, j; i=3; j = ++i;i=4 j=4 ++在前, 先运算,后赋值 int i, j; i=3; j = i++;i=4 j=3 ++在后, 先赋值,后运算j44i3j34i=6; i++; i=i+1 i=7 ++i; i=i+1 i=7 i=6; i--; i=i-1 i=5 --i ; i=i-1 i=5i6759
  • 60. 1)自增、自减运算符只能用于变量,不可用于常量和表达式 因为表达式在内存内没有具体空间,常量所占的空间不能重新赋值 3++ (x+y)++ (-i)++若i=3, j=2 (i++) +j 等于5i=4, j=22)结合方式自右至左,优先级最高,向右取最大 -i++ -(i++) i+++j (i++) +j60
  • 61. 赋值运算符和赋值表达式bmw=2002"="左边必须是变量名。 若“ = ” 两边变量类型不同,在赋值时要进行类型转换。 转换原则:根据左边变量的类型转换。61
  • 62. 少字节多字节 1)若多字节变量为unsigned ,则转换后多余字节补零。000000001111111111111111unsignedshort int a=-1; unsigned long b; b=a;ab62
  • 63. 111111111111111111111111有符号型,符号扩展short int a=-1; long b; b=a;2)若多字节变量为有符号型,则转换后扩展少字节的最高位。转换后,数据的符号不变。ab63
  • 64. 多字节少字节 低位照搬1111111111111111int a=-1; short int b; b=a;b=-1int a=65535; short int b; b=a;b=-1ba1111111164
  • 65. 赋值表达式 a=b=5 ; b=5 a=5 "="的结合性为自右至左复合的赋值运算符 a+=3 a=a+3 x*=y+3 x=x*(y+3) x/=x-4 x=x/(x-4) x+=y x=x+y i+=j-- i=i+(j--)65
  • 66. a=12; a+=a-=a*a;12a a=a-(a * a) =12-(12*12)=-132 a=a+(-132)=-132-132=-264-132-26466
  • 67. 关系运算符和关系表达式关系运算符(比较运算) < > <= >= = = != = = 与 = a=5; 赋值运算 a= =5;判断是否相等< > <= >= 的优先级大于= = !=3. 算术运算符的优先级大于关系运算符的优先级67
  • 68. 关系表达式:用关系运算符将表达式连接起来称为关系表达式。其值非真即假。在C++语言中,用非0代表真,用0表示假。关系表达式的结果只有两个,真为1,假为0。 a=2 b=3 c=4 a>2 a>b+c a= =2 a= ='a' a>'a' b=a= =2'a'>'A' b= ='a'+1 c-a= =a00100110168
  • 69. 逻辑运算符  运算符 与&& 或 || 非! A B 结果 0 0 0 0 1 0 1 0 0 1 1 1 有0出0,全1出1 A,B同时成立&&A B 结果 0 0 0 0 1 1 1 0 1 1 1 1 有1出1,全0出0 A或B有一个成立| |A 结果 0 1 1 0 有0出1, 有1出0!69
  • 70. 江苏籍的男生 江苏籍的学生和所有男生 非江苏籍的学生江苏籍&&男生例如:两个条件:江苏籍 男生江苏籍||男生!江苏籍注意: 1.优先级:!&&| | !算术关系逻辑赋值逗号70
  • 71. 3.不可写为 13 && 2 || 8<4-!04.当前面的表达式可以得出整个表达式的结果时,不必再求后面的表达式。a&&b&&c 当a为0时,表达式为0,不必求b与c。a||b||c 当a为1时,表达式为1,不必求b与c。71
  • 72. x=4 y=5 i= ++x= =5 || ++y= =6x=5 y=5 i=1i= x++= =5&& y++= =6x=5 y=5 i=0判断某年是否为闰年 1)能被400整除 2)能被4整除,不能被100整除 (2200年不是)year%400= =0year%4= =0&& year%100!=0(year%400= =0) || (year%4= =0&&year%100!=0)72
  • 73. 当c=4时,以下的值各多少? (c=1)&&(c=3)&&(c=5) (c= =1)||(c= =2) || (c= =5) (c!=2) && (c!=4) &&(c>=1)&&(c<=5)10073
  • 74. sizeof()运算符  sizeof()运算符是一个单目运算符,用于计算某一个操作数类型的字节数。其格式为: sizeof(<类型>)sizeof(int) //其值为4 sizeof(float) //其值为4 sizeof(double) //其值为8 sizeof(char) //其值为174
  • 75. 逗号运算符和逗号表达式表达式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
  • 76. 下列语句中表达式中i, j的值各为多少 1、int i=0, j=0; 2、 int i=0, j=1; i=3, (j++)+i ; i+=j*=3; 3、int i=1, j=0; 4、int i=1, j=1; j=i=((i=3)*2); i+=j+=2;i=3,j=1i=3,j=3i=6,j=6i=4,j=376
  • 77. 各类数值型数据间的混合运算整型、实型、字符型数据间可以混合运算。floatdoublelongunsignedintchar10+'a'+1.5-87.65*'b'在进行运算时,不同类型的数据要先转换成同一类型的数据再进行运算。 转换规则如下:77
  • 78. 第三章 简单的输入输出78
  • 79. 输入语句:cin程序在执行期间,接收外部信息的操作称为程序的输入;而把程序向外部发送信息的操作称为程序的输出。在C++中没有专门的输入输出语句,所有输入输出是通过输入输出流来实现的。 79
  • 80. 要使用C++提供的输入输出时,必须在程序的开头增加一行: #include 即包含输入输出流的头文件“iostream.h”。有关包含文件的作用,在编译预处理部分(第五章)作详细介绍。80
  • 81. 输入十进制整数和实数cin >> <变量名1>《 >> <变量名2> ...... 》(举例说明)int a,b; cin>>a>>b; //程序运行至此停下,等待从键盘输入变量值键盘输入:3 5 或:3 5 均可。输入语句自动过滤空白字符。a3键盘b5键盘81
  • 82. 浮点型数据同整型数据一样。float c,d; cin>>c>>d;char ch1,ch2; cin>>ch1>>ch2;若输入:ab 则ch1为a, ch2为b。若输入:a b 则ch1为a, ch2为b。字符型变量过滤空白字符。cin格式过滤空白字符82
  • 83. float a; int i1,i2; char ch1,ch2; cin>>i1>>a>>i2>>ch1>>ch2;输入:34 5.678 1a bi2:1在缺省的情况下,cin自动跳过输入的空格,换言之,cin不能将输入的空格赋给字符型变量,同样地,回车键也是作为输入字符之间的分隔符,也不能将输入的回车键字符赋给字符型变量。 a:5.578i1:34ch1:ach2:b83
  • 84. 若要把从键盘上输入的每一个字符,包括空格和回车键都作为一个输入字符赋给字符型变量时,必须使用函数cin.get()。其格式为: cin.get(<字符型变量>);cin.get()从输入行中取出一个字符,并将它赋给字符型变量。这个语句一次只能从输入行中提取一个字符。char c1; cin.get(c1);84
  • 85. char ch1,ch2,ch3; cin.get(ch1); cin.get(ch2); cin.get(ch3);输入:A B则:ch1:A并且在输入缓冲区中保留回车键。 ch2:空格ch3:B空格的ASCII码为3200100000ch285
  • 86. 输入十六进制或八进制数据 在缺省的情况下,系统约定输入的整型数是十进制数据。当要求按八进制或十六进制输入数据时,在cin中必须指明相应的数据类型:hex为十六进制;oct为八进制;dec为十进制。 86
  • 87. int i,j,k,l; cin>>hex>>i; //指明输入为十六进制数 cin>>oct>>j; //指明输入为八进制数 cin>>k; //输入仍为八进制数 cin>>dec>>l; //指明输入为十进制数 当执行到语句cin时,若输入的数据为: 11 11 12 12结果:i:17j:9k:10l:1287
  • 88. 使用非十进制数输入时,要注意以下几点: 1、八进制或十六进制数的输入,只能适用于整型变量,不适用于字符型变量,实型变量。2、当在cin中指明使用的数制输入后,则所指明的数制一直有效,直到在接着的cin中指明输入时所使用的另一数制为止。如上例中,输入k的值时,仍为八进制。88
  • 89. 3、输入数据的格式、个数和类型必须与cin中所列举的变量类型一一对应。一旦输入出错,不仅使当前的输入数据不正确,而且使得后面的提取数据也不正确。cin>>a,b; cin>>a b; cin>>ab; int a, b;cin>>a>>b; 89
  • 90. 输出数据 cout 与输入cin对应的输出是cout输出流。当要输出一个表达式的值时,可使用cout来实现,其一般格式为: cout << <表达式> 《<< <表达式>......》; 其中运算符“<<”称为插入运算符,它将紧跟其后的表达式的值,输出到显示器当前光标的位置。 90
  • 91. int a=6; float f1=12.4; char s1[ ]=“abcd”; cout<
  • 92. cout将双引号中的字符串常量按其原样输出char ch1=‘a’,ch2=‘b’; cout<<“c1=“<int i1=4,i2=5; float a=3.5; cout<<“a*i1=“<
  • 93. 指定输出项占用的宽度: 在输出的数据项之间进行隔开的另一种办法是指定输出项的宽度。如上面的两个输出语句可改写为: cout <
  • 94. 使用setw()应注意以下三点: 1、在程序的开始位置必须包含头文件iomanip.h,即在程序的开头增加: #include 2、括号中必须给出一个表达式(值为正整数),它指明紧跟其后输出项的宽度。3、该设置仅对其后的一个输出项有效。一旦按指定的宽度输出其后的输出项后,又回到原来的缺省输出方式。94
  • 95. 输出八、十六进制数和科学表示法的实数对于整型数据可指定以十六进制或八进制输出,而对于实型数据可指定以科学表示法形式输出。例如,设有如下一个程序: #include void main(void) { float x=3.14,y=100; cout.setf(ios::scientific,ios::floatfield); //表明浮点数用科学表示法输出 cout << x<<’\t’; cout <
  • 96. 与cin中类同,当在cout中指明以一种进制输出整数时,对其后的输出均有效,直到指明又以另一种进制输出整型数据为止。对实数的输出,也是这样,一旦指明按科学表示法输出实数,则接着的输出均按科学表示法输出,直到指明以定点数输出为止。明确指定按定点数格式输出(缺省的输出方式)的语句为: cout.setf(ios::fixed,ios::floatfield);96
  • 97. 第四章 C++的流程控制语句97
  • 98. 程序的三种基本结构1、顺序AB2、选择条件?真假ABx>y?真假z=xz=y98
  • 99. 3、循环A当P为真当型i++i<10PAYN99
  • 100. 直到P为真A直到型i>=10i++PAYN100
  • 101. if语句判断选择语句,有三种形式: if(表达式) 语句语句条件真假语句2语句1条件真假2) if(表达式) 语句1 else 语句2 if (a>b) cout<b) cout<
  • 102. if(表达式1) 语句1 else if (表达式2) 语句2 ...... else if (表达式n) 语句n else 语句n+1 表达式1语句1真表达式2真语句2表达式3真语句3表达式4真语句4假假假假语句5102
  • 103. 表达式1语句1真表达式2真语句2表达式3真语句3表达式4真语句4假假假假语句5103
  • 104. 注意:1) if 后可跟复合语句。 2) 注意 ;的位置。 3) 注意多重 if else 的搭配。if (a>b) { a=1; b=0; } else { a=0; b=1; } a=0 b=1a=1 b=0a>b真假104
  • 105. if (i >j) i++; if (i>j); i++;i+ +i>j真假if 总是与它上面最近的 else 配对,如要改变,用复合语句{ }。 注意书写格式,相互配对的语句要对齐。i>j真假i+ +105
  • 106. 例:输入两个实数,按代数值由小到大次序输出这两个数。 void main( void ) { float a,b,t; //定义变量 cout<<“ Input 2 Real Number:\n";//在屏幕上的提示信息 cin>>a>>b; //给变量赋值 a:7, b:3 if(a>b) { t=a; a=b; b=t; }//交换数据,用中间变量 cout<
  • 107. 嵌套的条件语句(举例说明)x=100; a=10; b=20; ok1=5; ok2=0; if(a
  • 108. 条件运算符 是C++中的唯一的三目运算符。 表达式1?表达式2 :表达式3表达式3表达式2表达式1真假max=a>b?a:b ; // 求a, b中的大者 当 a=2 b=1 a>b为真,表达式的值等于a, max值为2 当 a=1 b=2 a>b为假,表达式的值等于b, max值为2注意: 条件运算符的优先级比赋值运算符高 x=(x=3) ? x+2 : x-3 2. 结合方向自左至右 a>b?a:c>d?c:d 3. 三个表达式的类型可不同 z=a>b?'A':a+bx=5108
  • 109. x=9, y=6, z=5; x=((x+y)%z>=x%z+y%z)?1:0; cout<<"x= "<y?x++:y++)<
  • 110. void main(void ) { int x=1,y=2,z=3; x+=y+=z; cout<y?x++:y++<=y&&y= =x)?1:0<=y&&y>=x<
  • 111. 执行以下程序段后,变量a,b,c的值分别是: int x=10, y=9; int a,b,c; a=(--x= =y++)?--x:++y; b=x++; c=y;x=8 y=10 a=8b=8 x=9c=10111
  • 112. void main(void ) { int a=5,b=1,c=0; if(a=b+c) cout<<“* * *\n”; else cout<<“$ $ $\n”; }* * *112
  • 113. switch语句多分支选择语句。if语句只有两个分支,而实际问题中常常需要用到多分支的选择。如,成绩分为A(100~85)、B(84~70)、C(69~60)、D(60以下)等。‘A’100~85Y‘B’Y84~70‘C’Y69~60‘D’Yno passNNNN显示出错113
  • 114. cin.get(grade); if(grade= =‘A’) cout<<“100~85\n”; else if (grade= =‘B’) cout<<“84~70\n”; else if (grade= =‘C’) cout<<“69~60\n”; else if (grade= =‘D’) cout<<“no pass\n”; else cout<<“error\n”; 114
  • 115. switch(表达式) { case 常量表达式1:语句1 case 常量表达式2:语句2 … … case 常量表达式n:语句n default:语句n+1 }switch(grade) { case ‘A’:cout<<“100~85\n”; case ‘B’:cout<<“84~70\n”; case ‘C’:cout<<“69~60\n”; case ‘D’:cout<<“no pass\n”; default:cout<<“error\n”; }如果grade为 ‘A’,则结果为100~85 84~70 69~60 no pass error115
  • 116. 其流程为:先计算表达式的值,然后顺序地与case子句中所列出的各个常量进行比较,若表达式的值与常量中的值相等,就开始进入相应的case语句执行程序,遇到case和default也不再进行判断,直至switch语句结束。如果要使其在执行完相应的语句后中止执行下一语句,可以在语句后加break。116
  • 117. switch(grade) { case ‘A’:cout<<“100~85\n”; break; case ‘B’:cout<<“84~70\n”; break; case ‘C’:cout<<“69~60\n”; break; case ‘D’:cout<<“no pass\n”; break; default:cout<<“error\n”; }117
  • 118. 注意: 1、switch与if不同,它仅能判断一种逻辑关系,即表达式是否等于指定的常量,而 if 可以计算并判断各种表达式。2、case子句后必须为常量,常常是整型和字符型。3、default可以省略,这时,不满足条件什么也不执行。118
  • 119. 4、case和default只起标号的作用,顺序可以颠倒,颠倒时注意后面的break语句。5、多个case语句可以共用一组程序。 case ‘A’: case ‘B’: case ‘C’: cout<<“pass!\n”;119
  • 120. void main(void ) { int i=10; switch(i) { case 9: i++; case 10: i++; case 11: i++; default: i++; } cout<<“i=”<
  • 121. int x=1, y=0, a=0, b=0; switch( x ) { case 1: switch( y ) { case 0: a++; break; case 1: b++; break; } case 2: a++; b++; break; case 3: a++; b++; } cout<<“a=“<
  • 122. 有3个整数a,b,c,由键盘输入,输出其中最大的数。 122
  • 123. while语句while ( 表达式) { 语句组1 } {语句组2}表达式语句组1真语句组2假a=3; while(a<100) a=a+5; cout<<“a=“<
  • 124. 求 1+2+3+……+100void main(void) { int i=1,sum=0; //定义变量,初始化 while(i<=100) //构造循环 { sum=sum+i; // 循环体,多次执行 i=i+1; } cout<<“sum=”<
  • 125. 注意: 1、循环体如果为一个以上的语句,用{ }括起。 2、循环体内或表达式中必须有使循环结束的条件,即一定有一个循环变量。 3、while表达式可以成为语句,要特别小心。125
  • 126. k=2; while(k!=0) cout<
  • 127. void main(void) { int num=0; while(num<=2) { num++; cout<1真22真33假无127
  • 128. void main(void) { int y=10; while (y--); cout<<“y=”<
  • 129. k=10; while( k=0 ) k=k-1; cout<< k; k10表达式0输出:0129
  • 130. x=10; while (x!=0) x--; x=10; while (x) x--; x=10; while(x--); x=10; while(--x); 以下语句,循环退出时x为多少?x=0x=0x=-1x=0130
  • 131. #include void main() { char ch; while(cin.get(ch)&&ch!='\n') switch (ch-'2') { case 0: case 1: cout<<(char)(ch+4); case 2: cout<<(char)(ch+4); break; case 3: cout<<(char)(ch+3) ; default : cout<<(char)(ch+2); break; } cout<,则程序的输出结果是:输出:668977131
  • 132. 直到P为真A直到型do—while语句表达式语句组1真语句组2假do { 语句组1} while(表达式); {语句组2}132
  • 133. 求 1+2+3+……+100void main(void) { int i=1,sum=0; //定义变量,初始化 do //构造循环 { sum=sum+i; // 循环体,多次执行 i=i+1; }while (i<=100); cout<<“sum=”<
  • 134. 注意: do—while首先执行循环体,然后再判断表达式,至少执行一次循环体。当第一次循环表达式的值为真时,while与do—while的结果完全一样,否则结果不相同。134
  • 135. x=0,y=0; do { y++; x*=x; } while ((x>0)&&(y>5)); cout<<“y=“<
  • 136. s=7; do s-=2; while(s= =0); cout<<“s=”<
  • 137. for语句for(表达式1;表达式2;表达式3) {语句组1(循环体)} {语句组2}N表达式2语句组1Y语句组2表达式1表达式3for(循环变量赋初值;循环结束条件;循环变量增值)137
  • 138. 求 1+2+3+……+100void main(void) { int i, sum; for (i=1, sum=0; i<=100; i++) sum=sum+i; cout<<“sum=”<
  • 139. 注意: 1、当型循环,条件测试是在循环开始时进行,有可能一次也进入不了循环体。2、for语句中的三个表达式可以部分省略或全部省略, 但;不能省略,若省略表达式2,则表示循环条件为真。3、for语句中三个表达式可以是任何有效的C语言表达式。139
  • 140. void main(void) { char i, j ; for (i=‘a’,j=‘z’ ; i
  • 141. 以下循环结果如何? for ( i=0, k= -1; k=1; i++, k++) cout<<“****\n”;以下循环最多执行_____次,最少执行_____次 for (i=0, x=0; i<=9&&x!=876 ; i++) cin>>x; 101141
  • 142. 循环的嵌套一个循环体内又包含另一个完整的循环体,称为循环的嵌套。注意: 1、循环体内有多个语句要用{}括起来。 2、书写格式要清晰。for ( ; ; ) { ..... for ( ; ; ) { ....... } } 142
  • 143. void main(void) { int i, j, k=0, m=0; for ( i=0; i<2; i++) { for ( j=0; j<3; j++) k++; k- =j; } m=i+j; cout<<“k=“<
  • 144. 几种循环的比较while ( 表达式) { 语句组1 } {语句组2}表达式语句组1真语句组2假do { 语句组1} while(表达式); {语句组2}表达式语句组1真语句组2假144
  • 145. for(表达式1;表达式2;表达式3) {语句组1} {语句组2}假表达式2语句组1真语句组2表达式1表达式3145
  • 146. 最大公约数与最小公倍数 求两自然数m , n的最大公约数 欧几里德算法(m>n) 1、m被n除得到余数r(0≤r ≤n) r=m%nm=6 n=4 r=m%n=6%4=2while ( r=m%n ) { m=n; n=r ; } 最小公倍数为两数之积除以最大公约数。4*6/2=122、若r=0,则算法结束,n为最大公约数,否则做33、mn , nr , 回到1m=4 n=2 r=m%n=4%2=0 所以,公约数=2146
  • 147. 最大公约数:能同时被m和n整除的最大数。r=m>n?n:m for(i=1; i
  • 148. 将 12345 的每位分别打印出来。12345%10=5 12345/10=12341234%10=4 1234/10=123123%10=3 123/10=1212%10=2 12/10=11%10=1 1/10=0while(n) { cout<
  • 149. 求级数公式:首先写出通项,然后再用当前项(第n项)除前一项,得出后一项比前一项大多少倍。通项:t=x*x/((2*n)*(2*n-1))第n项/第n-1项:表明前一项比后一项大t倍,即后一项乘t等于前一项后一项=(-1)×前一项×t149
  • 150. S=0;term=1;n=1;//一定要赋初值 while(fabs(term)>=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))150
  • 151. t=x*x/((2*n)*(2*n-1))第n项/第n-1项:第一项:term=1;第一次循环:S=S+term; term=(-1)*term*t;第二次循环:S=S+term; term=(-1)*term*t;这时左边的term代表第二项,而右边的term为第一项。这时左边的term代表第三项,而右边的term为第二项。term=(-1)*term*t;前一项当前项同样是term,在循环中不断用旧的数值去推导赋值出新的数值。151
  • 152. S=0;term=1;n=1;//一定要赋初值 while(fabs(term)>=1e-5) { S=S+term; term=(-1)*term*x*x/((2*n)*(2*n-1)); n++; }旧的新的152
  • 153. break语句和continue语句break在switch语句中,可以使流程跳过判断体,执行下面的程序。在循环体中,也可以从循环体内跳出循环体,提前结束循环。for ( ; ; ) { cin>>x; if (x= =123) break; } 当输入123时,结束循环。break 只能退出一层循环或switch语句。153
  • 154. a=10 ; y=0; do { a+=2; y+=a; cout<<“a=“<50) break; } while (a=14);第一次:a=12 y=12输出:a=12 , y=12第二次:a=16 y=28输出:a=16 , y=28第三次:a=16 y=44输出:a=16 , y=44第四次:a=16 y=60输出:a=16 , y=60154
  • 155. continue:其作用为结束本次循环,即跳过循环体中下面尚未执行的语句,接着进行下一次是否执行循环的判定。void main(void) { int i; for (i=1 ; i<=5 ; i++ ) { if (i%2) cout<<“*”; else continue; cout<<“#”; } cout<<“ $\n”; }ii<=5i%2输出输出:*#*#*#$1真1*#2真0无3真1*#4真0无5真1*#6假$155
  • 156. void main(void) { int i, j, x=0 ; for (i=0 ; i<2; i++) { x++; for (j=0;j<=3; j++) { if ( j%2 ) continue; x++; } x++; } cout<<“x=“<< x<
  • 157. void main(void ) { int k=0; char c=‘A’; do { switch (c++) { case ‘A’: k++; break; case ‘B’: k--; case ‘C’: k+=2; break; case ‘D’: k=k%2; continue; case ‘E’: k=k*10; break; default: k=k/3; } k++; }while (c<‘G’); cout<<“k=”<< k<
  • 158. 总结:在循环体中,break从循环体内跳出循环体,提前结束循环。for(... ; ... ; ... ) { ........ break; ........ }158
  • 159. continue:其作用为结束本次循环,即跳过循环体中下面尚未执行的语句,接着进行下一次是否执行循环的判定。for(... ; ... ; ... ) { ........ continue; ........ }while( ...... ) { ........ continue; ........ }159
  • 160. 求素数:只可以被1与自身整除的数。判断一个数 t 是否为素数,用2到t-1循环除。for( i=2; i=t/2)160
  • 161. 求范围内的素数(50~100):for(t=50, k=0 ; t<=100; t++) { for( i=2; i
  • 162. 鸡兔共有30只,脚共有90只,问鸡兔各有多少?void main(void) { int i; //i代表鸡,则兔为30-i只 for(i=0; i<=15; i++) if(2*i + 4*(30-i)= =90) { cout<<“鸡”<
  • 163. 一百万富翁 遇到一陌生人,陌生人找他谈一个换钱的计划,该计划如下:我每天给你十万元,而你第一天只需给我一分钱,第二天我仍给你十万元,你给我两分钱,第三天我仍给你十万元,你给我四分钱,....,你每天给我的钱是前一天的两倍,直到满一个月(30天),百万富翁很高兴,欣然接受了这个契约。请编写程序计算陌生人给百万富翁多少钱,百万富翁给陌生人多少钱?163
  • 164. 利用循环语句编程,打印下列图形: * * * * * * * * * * * * * * * *找规律: 上面四行 行号空格星号131222313404 for(i=0;i<4;i++) { for(j=4-i-1;j>0;j--) cout<<" "; for(k=1;k<=i+1;k++) cout<<" * "; cout<
  • 165. void main(void) { int i,j,k; for(i=0;i<4;i++) { for(j=4-i-1;j>0;j--) cout<<" "; for(k=1;k<=i+1;k++) cout<<" * "; cout<0;j--) cout<<" * "; cout<
  • 166. 打印图形: * * * * * * * * * * * * * * * * * * * * * * * * * 行号空格星号031123215307行号:i 空格:3-i 星号:2*i+1如果打印n行行号:0~n-1空格:0~n-1-i166
  • 167. 计算:2+22+222+.....+2222222=?累加和 s=0设通项为tt的初值为222=2*10+2; 222=22*10+2; 2222=222*10+2; t=t*10+2; 所以,通项的循环表示为:前一项当前项循环体为:{ s = s +t t=t*10+2; }167
  • 168. void main(void) { int t,s; s=0; t=2; for(int i=0;i<7;i++) { s=s+t; t=t*10+2; } cout<
  • 169. 满足以下条件三位数n,它除以11所得到的商等于n的各位数字的平方和,且其中至少有两位数字相同。 131 131/11=11 12+32+12=11分析:数字应该从100循环到999将每位数字剥出,判断其是否满足条件169
  • 170. 满足以下条件三位数n,它除以11所得到的商等于n的各位数字的平方和,且其中至少有两位数字相同。 131 131/11=11 12+32+12=11分析:用a,b,c分别代表三位数,a,b,c分别从0循环到9,组成所有可能的三位数,然后找出满足条件的数来。170
  • 171. 求n=1000时π的近似值分析:通项:s=s×t迭代算法:上次迭代的结果本次计算的结果迭代结束条件: 迭代 1000次注意s与t的初始值n从1开始迭代 s=1171
  • 172. 下面程序的功能是用公式求π的近似值,直到最后一项的值小于10-6为止。请填空。void main(void ) { int i=1; ______ pi=0; while (i*i<=10e+6) { pi=______________ ; i++; } pi=sqrt (6.0 *pi) ; cout<<“ pi=”<
  • 173. 有1020个西瓜,第一天卖一半多两个,以后每天卖剩下的一半多两个,问几天以后能卖完?请填空。#include”stdio.h” void main(void ) { int day, x1, x2; day=0; x1=1020; while (________ ) { x2=__________; x1=x2; day++; } cout<<“day=”<
  • 174. 第五章 函数与编译预处理174
  • 175. 概述函数是程序代码的一个自包含单元,用于完成某一特定的任务。C++是由函数构成的,函数是C++的基本模块。有的函数完成某一操作;有的函数计算出一个值。通常,一个函数即能完成某一特定操作,又能计算数值。175
  • 176. 为什么要使用函数?1、避免重复的编程。 2、使程序更加模块化,便于阅读、修改。参数(多个)函数值(唯一)函数体所编写的函数应尽量少与主调函数发生联系,这样便于移植。176
  • 177. 说明:1、一个源程序文件由一个或多个函数组成,编译程序以文件而不是以函数为单位进行编译的。2、一个程序可以由多个源文件组成,可以分别编译,统一执行。3、一个程序必须有且只有一个main( )函数,C++从main( )函数开始执行。4、C++语言中,所有函数都是平行独立的,无主次、相互包含之分。函数可以嵌套调用,不可嵌套定义。5、从使用角度来说,分标准函数和用户自定义函数;从形式来说,分无参函数和有参函数。177
  • 178. 库函数是C++编译系统已预定义的函数,用户根据需要可以直接使用这类函数。库函数也称为标准函数。 为了方便用户进行程序设计,C++把一些常用数学计算函数(如sqrt()、exp()等)、字符串处理函数、标准输入输出函数等,都作为库函数提供给用户,用户可以直接使用系统提供的库函数。 库函数有很多个,当用户使用任一库函数时,在程序中必须包含相应的头文件。 如 #include等。178
  • 179. 用户在设计程序时,可以将完成某一相对独立功能的程序定义为一个函数。用户在程序中,根据应用的需要,由用户自己定义函数,这类函数称为用户自定义的函数。 根据定义函数或调用时是否要给出参数,又可将函数分为:无参函数和有参函数。 179
  • 180. 函数定义的一般形式一、无参函数主调函数并不将数据传给被调函数。类型说明 函数名(void) { 函数体 } 无参函数主要用于完成某一操作。不传递参数参数(多个)函数值(唯一)函数体180
  • 181. void main(void ) { printstar ( ); print_message ( ); printstar( ); }void printstar (void ) { cout<<“* * * * * * * * * * *\n”; } void print_message (void) { cout<<“ How do you do! \n”; } 调用函数调用函数调用函数函数类型函数名函数体两个被调函数主要用于完成打印操作。181
  • 182. 输出: * * * * * * * * * * * How do you do! * * * * * * * * * * * 182
  • 183. 二、有参函数主调函数和被调函数之间有数据传递。主调函数可以将参数传递给被调函数,被调函数中的结果也可以带回主调函数。类型说明 函数名(形式参数列表说明 ) { 函数体 } 183
  • 184. int max (int x,int y) { int z; z=(x>y)? x : y ; return z; } void main (void ) { int a,b,c; cin>>a>>b; c=max (a , b) ; cout<<“The max is”<< c<
  • 185. int max (int x,int y) { int z; z=(x>y)? x : y ; return z; } void main (void ) { int a,b,c; cin>>a>>b; c=max (a , b) ; cout<<“The max is”<< c<
  • 186. 函数参数和函数的值形参是被调函数中的变量;实参是主调函数赋给被调函数的特定值。实参可以是常量、变量或复杂的表达式,不管是哪种情况,在调用时实参必须是一个确定的值。形参与实参类型相同,一一对应。形参必须要定义类型,因为在定义被调函数时,不知道具体要操作什么数,而定义的是要操作什么类型的数。186
  • 187. int max (int x,int y) { int z; z=(x>y)? x : y ; return z; } void main (void ) { int a,b,c; cin>>a>>b; c=max (a+b , a*b) ; cout<<“The max is”<
  • 188. 说明:1、在未出现函数调用时,形参并不占内存的存储单元,只有在函数开始调用时,形参才被分配内存单元。调用结束后,形参所占用的内存单元被释放。2、实参对形参变量的传递是“值传递”,即单向传递。在内存中实参、形参分占不同的单元。3、形参只作用于被调函数,可以在别的函数中使用相同的变量名。5a8b实参xy形参58188
  • 189. void fun(int a, int b) { a=a*10; b=b+a; cout<
  • 190. void fun(int x, int y) { x=x*10; y=y+x; cout<
  • 191. 形参必须要定义类型,因为在定义被调函数时,不知道具体要操作什么数,而定义的是要操作什么类型的数。形参是被调函数中的变量;实参是主调函数赋给被调函数的特定值。在函数调用语句中,实参不必定义数据类型,因为实参传递的是一个具体的值(常量),程序可依据这个数值的表面形式来判断其类型,并将其赋值到对应的形参变量中。191
  • 192. 函数的返回值函数的返回值通过return语句获得。函数只能有唯一的返回值。函数返回值的类型就是函数的类型。return语句可以是一个表达式,函数先计算表达式后再返回值。return语句还可以终止函数,并将控制返回到主调函数。一个函数中可以有一个以上的return语句,执行到哪一个return语句,哪一个语句起作用。 192
  • 193. int add ( int a, int b) { return (a+b); } int max ( int a, int b) { if (x>y) return x ; else return y; } 若函数体内没有return语句,就一直执行到函数体的末尾,然后返回到主调函数的调用处。先计算,后返回可以有多个return语句193
  • 194. 不带返回值的函数可说明为void型。函数的类型与函数参数的类型没有关系。double blink ( int a, int b)如果函数的类型和return表达式中的类型不一致,则以函数的类型为准。函数的类型决定返回值的类型。对数值型数据,可以自动进行类型转换。 既然函数有返回值,这个值当然应属于某一个确定的类型,应当在定义函数时指定函数值的类型。 int max (float a, float b) // 函数值为整型 函数返回值的类型,也是函数的类型194
  • 195. 参数(多个)函数值(唯一)函数体int max ( int a, int b) { int z; z=x>y?x:y; return z; } 如果有函数返回值,返回值就是函数值,必须惟一。如果有函数返回值, 函数的类型就是返回值的类型函数体的类型、形式参数的类型必须在函数的定义中体现出来。195
  • 196. 函数的调用函数调用的一般形式函数名(实参列表);形参与实参类型相同,一一对应。 i=2; f (i, ++i);函数调用的方式作为语句 printstar( );作为表达式 c=max (a,b);作为另一个函数的参数 cout<
  • 197. 1) 被调用的函数必须是已存在的函数2) 如果使用库函数,必须用 #include < math.h>在一个函数中调用另一函数(即被调用函数)需要具备哪些条件呢?3) 函数调用遵循先定义、后调用的原则,即被调函数应出现在主调函数之前。197
  • 198. float max(float x, float y) { float z; z=(x>y)? x : y ; return z; } void main (void) { float a,b, c; cin>>a>>b; c=max (a+b , a*b) ; cout<<“The max is”<
  • 199. 4) 如果使用用户自己定义的函数,而该函数与调用它的函数(即主调函数)在同一个程序单位中且位置在主调函数之后,则必须在调用此函数之前对被调用的函数作声明。 199
  • 200. float max (float x, float y) { float z; z=(x>y)? x : y ; return z; } void main (void) { float a,b, c; float max (float,float); cin>>a>>b; c=max (a,b) ; cout<<“The max is”<
  • 201. void main(void) { int i=2, x=5, j=7; void fun(int,int); fun ( j, 6); cout<
  • 202. void main(void ) { int x=2,y=3, z=0;void add(int,int,int); cout<<“(1) x=“<
  • 203. 编写程序,分别计算下列函数的值(x从键盘输入)203
  • 204. float f1(float x) { float y; y=3*x*x*x+2*x*x-1; return y; } void main(void) { float x, y; cin>>x; y=f1(x); cout<<“x=“<
  • 205. 编写程序,分别计算下列函数的值(x从键盘输入)当最后一项小于0.00001时,累加结束。205
  • 206. float fun(float x) { float s=1, t=1; do { t=t/x; s+=t; }while (t>0.00001); return s; }void main(void) { float x; cin>>x; cout<<“s=“<
  • 207. 计算100~200之间的素数,用函数prime( )判断一个数是否是素数,若是该函数返回1,否则返回0。void main(void) { for(int i=100;i<=200; i++) if(prime(i)==1) cout<
  • 208. 计算输入两个数的最大公约数void main(void) { int x, y; cin>>x>>y; cout<
  • 209. 计算输入三个数的最大公约数void main(void) { int x, y, z; cin>>x>>y>>z; cout<c?r:c; for(int i=r-1;i>=1;i--) { if(a%i==0&&b%i==0&&c%i==0) break; } return i; } 209
  • 210. 写一个函数验证哥德巴赫猜想;一个不小于6的偶数可以表示为两个素数之和,如6=3+3, 8=3+5, 10=3+7……。在主函数中输入一个不小于6的偶数n,函数中输出以下形式的结果∶ 34=3+31 210
  • 211. 函数的嵌套调用C语言中,所有函数都是平行独立的,无主次、相互包含之分。函数可以嵌套调用,不可嵌套定义。int max ( int a, int b) { int c; int min ( int a, int b) { return ( ab? a : b); } int max ( int a, int b) { int c; c=min(a,b); return ( a>b? a : b); } int min ( int a, int b) { return ( a
  • 212. 调用 b 函数a 函数b 函数⑴main 函数调用 a 函数结束(2)(3)(4)(5)(6)(7)(8)(9)在main函数中调用a函数,在a函数中又调用b函数。212
  • 213. int power(int m,int n) //m^n { int i,product=m; for(i=1;i>k>>m; cout<<"f("<
  • 214. 函数的递归调用在调用一个函数的过程中直接或间接地调用函数本身,称为函数的递归调用。int f(int x) { int y,z ; ..... z=f(y); .... return (2*z); }int f1(int x) { int y,z ; ..... z=f2(y); .... return (2*z); }int f2(int t) { int a, c ; ..... c=f1(a); .... return (3+c); }214
  • 215. 有5个人坐在一起,问第5个人多少岁,他说比第4个人大2岁。问第4个人多少岁,他说比第3个人大2岁。问第3个人多少岁,他说比第2个人大2岁。问第2个人多少岁,他说比第1个人大2岁。问第1个人多少岁,他说是10岁。请问第5个人多大?age(5)=age(4)+2age(4)=age(3)+2age(3)=age(2)+2age(2)=age(1)+2age(1)=10age(n)=10 n=1age(n-1)+2 n>1int age ( int n ) { int c; c=age(n-1)+2; return c; }void main(void) { int age(int); cout<
  • 216. int age ( int n ) { int c; if (n= =1) c=10; else c=age(n-1)+2; return c; }void main(void) { int age(int); cout<
  • 217. 用递归方法求n!n!=1 n=0,1n*(n-1)! n>1float fac (int n) { float y; if ((n= =0)|| (n= =1) y=1; else y=n*fac(n-1); return y; }void main (void) { float y; int n; cout<<“Input n:\n”; cin>>n ; cout<
  • 218. int sub(int); void main (void) { int i=5; cout<
  • 219. void main (void) { int i=5; cin>>i; f(i); }void f(int n ) {if(n= =0) return; else {cout<
  • 220. void recur(char c) { cout<
  • 221. void f(int n) { if(n>=10) f(n/10); cout<
  • 222. 作用域和存储类作用域是指程序中所说明的标识符在哪一个区间内有效,即在哪一个区间内可以使用或引用该标识符。在C++中,作用域共分为五类:块作用域、文件作用域、函数原型作用域、函数作用域和类的作用域。 222
  • 223. 块作用域 我们把用花括号括起来的一部分程序称为一个块。在块内说明的标识符,只能在该块内引用,即其作用域在该块内,开始于标识符的说明处,结束于块的结尾处。 在一个函数内部定义的变量或在一个块中定义的变量称为局部变量。 223
  • 224. 在函数内或复合语句内部定义的变量,其作用域是从定义的位置起到函数体或复合语句的结束。形参也是局部变量。float f1( int a) { int b,c; ..... }float f2( int x, int y) { int i, j; ..... }void main(void ) { int m, n; ..... }x,y,i,j 有效a,b,c有效m,n有效224
  • 225. 主函数main中定义的变量,也只在主函数中有效,同样属于局部变量。不同的函数可以使用相同名字的局部变量,它们在内存中分属不同的存储区间,互不干扰。void main(void) { int x=10; { int x=20; cout<
  • 226. 注意: 具有块作用域的标识符在其作用域内,将屏蔽其作用块包含本块的同名标识符,即 变量名相同,局部更优先。 226
  • 227. void main(void) { int a=2, b=3, c=5; cout<
  • 228. void main(void) { int a=1,b=2,c=3; ++a; c+=++b; { int b=4, c; c=b*3; a+=c; cout<<“first:”<
  • 229. 文件作用域 在函数外定义的变量称为全局变量。 全局变量的作用域称为文件作用域,即在整个文件中都是可以访问的。 其缺省的作用范围是:从定义全局变量的位置开始到该源程序文件结束。当在块作用域内的变量与全局变量同名时,局部变量优先。 229
  • 230. p,q有效int p=1, q=5; float f1( int a) { int b,c; ..... }char c1,c2; main( ) { int m, n; ..... }a,b,c有效m,n有效c1,c2有效全局变量局部变量全局变量增加了函数间数据联系的渠道,在函数调用时可以得到多于一个的返回值。230
  • 231. 4int min; int max (int x, int y) { int z; min=(xy)? x : y ; return z; } void main (void) { int a,b,c; cin>>a>>b; c=max (a , b) ; cout<<“The max is”<
  • 232. 在同一个源文件中,外部变量与局部变量同名,则在局部变量的作用范围内,外部变量不起作用。int a=3, b=5; int max(int a, int b) { int c; c=a>b? a:b; return c; } void main(void) { int a=8; cout<
  • 233. int x; void cude(void) { x=x*x*x ; } void main (void) { x=5; cude ( ); cout<
  • 234. 在块作用域内可通过作用域运算符“::”来引用与局部变量同名的全局变量。 #include int i= 100; void main(void) { int i , j=50; i=18; //访问局部变量i ::i= ::i+4; //访问全部变量i j= ::i+i; //访问全部变量i和局部变量j cout<<”::i=”<<::i<<’\n’; cout<<”i=”<
  • 235. 函数原型作用域 在函数原型的参数表中说明的标识符所具有的作用域称为函数原型作用域,它从其说明处开始,到函数原型说明的结束处结束。 float tt(int x , float y); //函数tt的原型说明 由于所说明的标识符与该函数的定义及调用无关,所以,可以在函数原型说明中只作参数的类型说明,而省略参量名。 float tt (int , float); 235
  • 236. int i=0; int workover(int i) { i=(i%i)*((i*i)/(2*i)+4); cout<<“i=“<
  • 237. 存储类 外存内存程序程序区静态存储区动态存储区存放程序代码存放变量需要区分变量的存储类型237
  • 238. 作用域全局变量局部变量生存期动态存储变量静态存储变量静态存储:在文件运行期间有固定的存储空间,直到文件运行结束。动态存储:在程序运行期间根据需要分配存储空间,函数结束后立即释放空间。若一个函数在程序中被调用两次,则每次分配的单元有可能不同。程序区静态存储区动态存储区全局变量静态局部变量动态局部变量238
  • 239. 局部变量的分类动态变量(auto):默认,存储在动态区寄存器变量(register):在cpu内部存储静态局部变量(static):存储在静态区动态局部变量未被赋值时,其值为随机值。其作用域的函数或复合语句结束时,空间被程序收回。程序执行到静态局部变量时,为其在静态区开辟存储空间,该空间一直被保留,直到程序运行结束。由于存储在静态区,静态局部变量或全局变量未赋初值时,系统自动使之为0。239
  • 240. int fun(int a) { int c; static int b=3; c=a+ b++; return c; } void main(void) { int x=2, y; y=fun(x); cout<
  • 241. int f (int a) { int b=0; static int c=3; b=b+1; c=c+1; return a+b+c; }void main(void) { int a=2,i; for (i=0;i<3;i++) cout<
  • 242. int func (int a, int b) { static int m=0, i=2; i+=m+1; m=i+a+b; return m; } void main(void) { int k=4, m=1, p; p=func(k, m); cout<
  • 243. int q(int x) { int y=1; static int z=1; z+=z+y++; return x+z; } void main(void) { cout<
  • 244. 全局变量的存储方式(extern static)全局变量的默认方式,当在一个文件中要引用另一个文件中的全局变量或在全局变量定义之前要引用它时,可用extern作说明,相当于扩大全局变量的作用域。2、静态(static)存储类别1、extern 存储类别全局变量是在函数的外部定义的,编译时分配在静态存储区,如果未赋初值,其值为0。它仅能在本文件中引用,即使在其它文件中用extern说明也不能使用。相当于限制了全局变量的作用域范围。244
  • 245. 程序的作用是:给定b的值,输入a和m,求a×b和am的值。文件file1.c中的内容为: int a; void main(void) { extern int power (int); int b=3, c, d, m; cin>>a>>m; c=a*b; cout<
  • 246. 静态局部变量:static 在函数内部定义,存储在静态存储区,与auto对应,在别的函数中不能引用。全局静态变量:static 在函数外部定义,只限在本文件中使用,与extern对应。当变量名相同致使作用域相重时,起作用的是最近说明的那个变量。全局变量静态 static 外部 extern自动 auto局部变量静态 static 寄存器 register 246
  • 247. 主调函数调用处被调函数主调函数调用处被调函数内联函数 将被调函数体的代码直接插到调用处内联函数247
  • 248. 内联函数的实质是用存储空间(使用更多的存储空间)来换取时间(减少执行时间). 内联函数的定义方法是,在函数定义时,在函数的类型前增加修饰词inline。 248
  • 249. inline int max (int x, int y) { int z; z=(x>y)? x : y ; return z; } void main (void ) { int a,b,c; cin>>a>>b; c=max (a+b , a*b) ; cout<<“The max is”<
  • 250. 使用内联函数时应注意以下几点: 1、C++中,除在函数体内含有循环,switch分支和复杂嵌套的if语句外,所有的函数均可定义为内联函数。 2、内联函数也要定义在前,调用在后。形参与实参之间的关系与一般的函数相同。 3、对于用户指定的内联函数,编译器是否作为内联函数来处理由编译器自行决定。说明内联函数时,只是请求编译器当出现这种函数调用时,作为内联函数的扩展来实现,而不是命令编译器要这样去做。 4、正如前面所述,内联函数的实质是采用空间换取时间,即可加速程序的执行,当出现多次调用同一内联函数时,程序本身占用的空间将有所增加。如上例中,内联函数仅调用一次时,并不增加程序占用的存储间。250
  • 251. 具有缺省参数值和参数个数可变的函数在C++中定义函数时,允许给参数指定一个缺省的值。在调用函数时,若明确给出了这种实参的值,则使用相应实参的值;若没有给出相应的实参,则使用缺省的值。(举例说明) 251
  • 252. int fac(int n=2) { int t=1; for(int i=1;i<=n;i++) t=t*i; return t; } void main(void) { cout<< fac(6) <
  • 253. int area(int long=4 , int width=2) { return long* width; }void main(void ) { int a=8, b=6; cout<< area(a,b) <
  • 254. 使用具有缺省参数的函数时,应注意以下几点: 1.不可以靠左边缺省 2.函数原型说明时可以不加变量名 float v(float,float=10,float=20);int area(int long , int width=2)int area(int long =4, int width)3.只能在前面定义一次缺省值,即原型说明时定义了缺省值,后面函数的定义不可有缺省值。错误!254
  • 255. 参数个数可变的函数到目前为止,在定义函数时,都明确规定了函数的参数个数及类型。在调用函数时,实参的个数必须与形参相同。在调用具有缺省参数值的函数时,本质上,实参的个数与形参的个数仍是相同的,由于参数具有缺省值,因此,在调用时可省略。在某些应用中,在定义函数时,并不能确定函数的参数个数,参数的个数在调时才能确定。在C++中允许定义参数个数可变的函数。 255
  • 256. 首先,必须包含头文件“stdarg.h”,因为要用到里面的三个库函数 va_start( )、va_arg( )和va_end( )。其次,要说明一个va_list类型的变量。va_list与int,float类同,它是C++系统预定义的一个数据类型(非float),只有通过这种类型的变量才能从实际参数表中取出可变有参数。如:va_list ap;ab...ap (va_list)变量(可变参数)va_start(ap,b):初始化 va_arg(ap,int):依次取参数 va_end(ap):正确结束256
  • 257. va_start():有两个参数,va_start(ap,b); b即为可变参数前的最后一个确定的参数。va_arg():有两个参数,va_arg(ap,int) int即为可变参数的数据类型名。 int temp; temp=va_arg(ap,int);va_end():完成收尾工作。va_end(ap);在调用参数个数可变的函数时,必定有一个参数指明可变参数的个数或总的实参个数。如第一个参数值为总的实际参数的个数。257
  • 258. 使用参数数目可变的函数时要注意以下几点: 1、在定义函数时,固定参数部分必须放在参数表的前面,可变参数在后面,并用省略号“...”表示可变参数。在函数调用时,可以没有可变的参数。 2、必须使用函数va_start()来初始化可变参数,为取第一个可变的参数作好准备工作;使用函数va_arg()依次取各个可变的参数值;最后用函数va_end()做好结束工作,以便能正确地返回。 3、在调用参数个数可变的函数时,必定有一个参数指明可变参数的个数或总的实参个数。258
  • 259. 函数的重载所谓函数的重载是指完成不同功能的函数可以具有相同的函数名。 C++的编译器是根据函数的实参来确定应该调用哪一个函数的。 int fun(int a, int b) { return a+b; }int fun (int a) { return a*a; }void main(void) { cout<
  • 260. 1、定义的重载函数必须具有不同的参数个数,或不同的参数类型。只有这样编译系统才有可能根据不同的参数去调用不同的重载函数。2、仅返回值不同时,不能定义为重载函数。 即仅函数的类型不同,不能定义为重载函数 int fun(int a, int b) { return a+b; }float fun (int a,int b) { return (float) a*a; }void main(void) { cout<
  • 261. double sin(double x1,double x2) { return x1*x2;} double sin(double x,int a) { return a+x;} void main(void) { double x; cin>>x; cout<
  • 262. int add(int a,int b,int c) { return a+b+c; } int add(int a,int b) { return a+b; } void main(void) { cout<<"3+5="<263. 高级语言编译过程源程序 (文本文件) *.CPP目标文件 (二进制文件) *.OBJ可执行文件 (二进制文件) *.EXE库文件 (各种函数)编译连接编译预处理C语言提供的编译预处理的功能有以下三种:宏定义文件包含条件编译编译预处理 263
  • 264. 宏定义不带参数的宏定义用一个指定的标识符(即名字)来代表一个字符串,以后凡在程序中碰到这个标识符的地方都用字符串来代替。这个标识符称为宏名,编译前的替代过程称为“宏展开”。# define 标识符 字符串264
  • 265. #define PRICE 30 void main(void) { int num, total; /*定义变量*/ num=10; /*变量赋值*/ total=num*PRICE; cout<<"total=“<
  • 266. 1、宏展开只是一个简单的“物理”替换,不做语法检查,不是一个语句,其后不加分号“;”注意:2、#define命令出现在函数的外面,其有效范围为定义处至本源文件结束。可以用# undef命令终止宏定义的作用域。#define G 9.8 void main(void ) {.....} # undef G int max(int a,int b) {...... }266
  • 267. 3、对程序中用双引号括起来的字符串内容,即使与宏名相同,也不进行置换。4、在进行宏定义中,可以用已定义的宏名,进行层层置换。267
  • 268. # define R 3.0 # define PI 3.1415926 # define L 2*PI*R # define S PI*R*R void main(void) { cout<<“L=“<
  • 269. 带参数的宏定义#define 宏名(参数表) 字符串#define S(a, b) a*b .... float x, y,area; cin>>x>>y; area=S(x, y); /* area=x*y; */形式参数实际参数宏定义宏调用定义的宏实参代入后还原269
  • 270. 按#define命令行中指定的字符串从左至右进行置换宏名,字符串中的形参以相应的实参代替,字符串中的非形参字符保持不变。#define S(a, b) a*barea=S(3,2)3*2机械地将实参代入宏定义的形参形式S(a,b)等同于 a*bS(3,2)等同于 3*2270
  • 271. #define PI 3.1415926 #define S(r) PI*r*r void main(void) { float a, area, b; a=3.6; b=4.0; area=S(a); cout<<“r=“<
  • 272. #define PI 3.1415926 #define S(r) PI*r*r void main(void) { float a, area, b; a=1; b=2; area=S(a+b); cout<<“r=“<
  • 273. 定义宏时在宏名与带参数的括弧间不能有空格。#define S_ (r) P*r*r 带参数的宏与函数调用的区别相同:有实参、形参,代入调用。不同之处:1、函数调用先求表达式的值,然后代入形参,而宏只是机械替换。2、函数调用时形参、实参进行类型定义,而宏不需要,只是作为字符串替代。3、函数调用是在运行程序时进行的,其目标代码短,但程序执行时间长。而宏调用是在编译之前完成的,运行时已将代码替换进程序中,目标代码长,执行时间稍快。一般用宏表示实时的、短小的表达式。273
  • 274. #define A 3 #define B(a) ((A+1)*a) 执行 x=3*(A+B(7)); 后, x的值为:93#define neg(x) ((-x)+1) int neg( int x) {return x+1; } void main(void) { int y; y=neg(1); cout<<“y=“<
  • 275. 文件包含一个源文件可以将另外一个源文件的全部内容包含进来,即将另外的文件包含到本文件之中。# include “文件名”file1.cppBA#include “file2.cpp”ABfile1.cppfile2.cpp275
  • 276. 注意:1、文件名是C的源文件名,是文本文件,后缀名可以任选。*.cpp *.h2、一个#include语句只能指定一个被包含文件。3、文件名用双引号或尖括号括起来。4、包含后所有源文件编译为一个可执行文件。276
  • 277. 条件编译C语言允许有选择地对程序的某一部分进行编译。也就是对一部分源程序指定编译条件。源程序可以将部分源程序不转换为机器码277
  • 278. 条件编译有以下几种形式:1、 # ifdef 标识符 程序段1 # else 程序段2 # end if当标识符已被定义过(用#define定义),则对程序段1进行编译,否则编译程序段2.# define DEBUG ...... # ifdef DEBUG cout<
  • 279. 2、 # ifndef 标识符 程序段1 # else 程序段2 # endif与形式1相反,当标识符没有被定义过(用#define定义),则对程序段1进行编译,否则编译程序段2。# define DEBUG ...... # ifndef DEBUG cout<
  • 280. 3、 # if 表达式 程序段1 # else 程序段2 # endif当表达式为真(非零),编译程序段1,表达式为零,编译程序段2。# define DEBUG 1 ...... # if DEBUG cout<
  • 281. 以下程序的运行结果是:#define DEBUG void main(void) { int a=14, b=15, c; c=a/b; # ifdef DEBUG cout<<“a=“<
  • 282. 程序的多文件组织 而在设计一个功能复杂的大程序时,为了便于程序的设计和调试,通常将程序分成若干个模块,把实现一个模块的程序或数据放在一个文件中。当一个完整的程序被存放在多于一个文件中时,称为程序的多文件组织。 282
  • 283. 内部函数和外部函数内部函数:函数只限于在本文件中调用,其它文件不能调用,用static 定义该函数。static float fac( int n) { ...... }外部函数:函数的默认形式,可以被其它文件调用,用extern 定义该函数。调用时,在文件中用extern 说明。void main(void) { extern enter_string( ); char str[80]; enter_string(str); .......... }说明外部函数283
  • 284. 补充算法方程求解1、牛顿切线法 只有为数不多的方程有精确解,一般都是用迭代方法近似求方程的解。方程f(x)=0的实数解实际上是曲线f (x)在x轴上交点的值。f(x)xyx0284
  • 285. 1、任选一x值x1,在y1=f(x1)处做切线与x轴相交于x2处。f(x)xyx0f(x1)x1x22、若|x2-x1|或|f(x2)|小于指定的精度,则令x1=x2,继续做1。当其满足所需的精度时,x2就是方程的近似解。x1x2根据已知点求其切线的公式为:这就是牛顿切线法。牛顿切线法收敛快,适用性强,缺陷是必须求出方程的导数。285
  • 286. 已知方程为f(x)=x*x-a时,用牛顿切线法求方程的解。给定初值x0,精度10-6,算法编程如下。cin>>x1; //从键盘输入x0 do { x0=x1; x1=x0-(x0*x0-a)/(2*x0) ; // } while (fabs(x1-x0)>=1e-6) ; cout>>”x=”>>x1>>endl;旧值算本次循环的新值上一循环的新值成为本次循环的旧值286
  • 287. 2、弦截法f(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,则方程的解应在x1与x0之间,令x2=x0,继续做2。同理,若f(x0)*f(x1)>0,则方程的解应在x2与x0之间,令x1=x0,继续做2 ,直至满足精度为止。287
  • 288. 用两分法求方程的根。 x3-5x2+16x-80=0#include float f (float x) {return x*x*x-5*x*x+16*x-80; }float xpoint(float x1,float x2) { float x0; x0=(x1*f(x2)-x2*f(x1))/(f(x2)-f(x1)); return x0; }void main(void ) { float x1,x2, x0, f0, f1, f2; do { cout<<“Input x1, x2\n”; cin>>x1>>x2; f1=f(x1); f2=f(x2); } while (f1*f2>0); do { x0=xpoint(x1,x2); f0=f(x0); if ((f0*f1) >0) { x1=x0;f1=f0;} else { x2=x0; f2=f0;} }while (fabs(f0)>=0.0001); cout<<”x=”<< x0<
  • 289. 3、两分法f(x)xyx1、在x轴上取两点x1和x2, 要确保x1与x2之间有且只有方程唯一的解。x1x22、求出x1,x2的中点x0。x0x2x03、若|f(x0)|满足给定的精度,则x0即是方程的解,否则,若f(x0)*f(x1)<0,则方程的解应在x1与x0之间,令x2=x0,继续做2。同理,若f(x0)*f(x1)>0,则方程的解应在x2与x0之间,令x1=x0,继续做2 ,直至满足精度为止。x0=(x1+x2)/2289
  • 290. 用两分法求方程的根。 x3-5x2+16x-80=0#include float f (float x) {return x*x*x-5*x*x+16*x-80; }void main(void ) { float x1,x2, x0, f0, f1, f2; do { cout<<“Input x1, x2\n”; cin>>x1>>x2; f1=f(x1); f2=f(x2); } while (f1*f2>0); do { x0=(x1+x2)/2; f0=f(x0); if ((f0*f1) >0){ x1=x0;f1=f0;} else { x2=x0;f2=f0;} }while (fabs(f0)>=0.0001); cout<<”x=”<< x0<
  • 291. int q(int x) { int y=1; static int z=1; z+=z+y++; return x+z; } void main(void) { cout<
  • 292. 下面函数pi的功能是:根据以下公式,返回满足精度(0.0005)要求的π的值,请填空。#include “math.h” double pi(double eps) { double s, t; int n; for ( ___________; t>eps; n++) { s+=t; t=n*t/(2*n+1); } return ___________ ; }main( ) { double x; cout<<“\nInput a precision:”; cin>>x; cout<< “π=“<
  • 293. void f(int n) { if(n>=10) f(n/10); cout<
  • 294. void main(void) { char s; cin.get(s); while(s!=‘\n’) { switch(s-’2’) { case 0: case 1: cout<545455555657294
  • 295. 第六章 数组 295
  • 296. 一维数组的定义和引用 数组是同一类型的一组值(10个 char 或15个 int) ,在内存中顺序存放。 整个数组共用一个名字,而其中的每一项又称为一个元素。一、定义方式:类型说明符 数组名[常量表达式]; int a[4]; // 表明a数组由4个int型元素组成 定义类型数组名称元素个数296
  • 297. int a[4]; // 表明a数组由4个int型元素组成 其元素分别为:a[0], a[1], a[2], a[3] 其序号从0开始。若存放首地址为2000H,则在内存中为:a[3]a[2]a[1]a[0]2010H200CH2008H2004H2000HC++不允许对数组的大小作动态的定义,即数组的大小不能是变量,必须是常量。必须是常数297
  • 298. 如果要根据不同的数值改变数组的大小,可用常量表达式。如:#define SIZE 50 void main(void) { int art[SIZE]; ...... }298
  • 299. 二、一维数组元素的引用数组必须先定义,具体引用时(赋值、运算、输出)其元素等同于变量。void main(void ) { int i, a[10]; for ( i=0; i<10; i++) a[i]=i; for ( i=9; i>=0 ; i--) cout<
  • 300. 三、一维数组的初始化在定义数组的同时给数组元素赋值。注意: 1、对数组中的一部分元素列举初值,未赋值的部分是0。int a[10]= {0,1, 2, 3, 4, 5};2、不能给数组整体赋值,只能一个一个地赋值。 int a[10]= {0,1,2,.....,9}; 非法int a[10]= {0,1, 2, 3, 4, 5,6,7,8,9};int a[10]= {0,1, 2, 3, 4, 5, 0, 0, 0, 0};300
  • 301. 3、可以用 int a[ ]= {0,1, 2, 3, 4, 5, 6, 7, 8, 9}; 给数组赋值,编译器会自动计算出内的元素项数,并将数组定义为该长度。4、用局部static 或全局定义的数组不赋初值,系统均默认其为‘\0’。static int a[10];(即存储在静态数据区中的数组其元素默认为0)数组在内存中顺序存放,第一个元素位于地址的最低端。0000000000a301
  • 302. 求Fibonacci数列:1,1,2,3,5,8,......的前20个数,即 F1=1 (n=1) F2=1 (n=2) Fn=Fn-1+Fn-2 (n>=3) 2113853211....f[7]f[6]f[5]f[5]f[4]f[3]f[2]f[1]f[0]f [i]=f [i-1]+f [i-2]void main (void) { int i; int f [20]={1,1}; for (i=2 ; i<20 ; i++ ) f [i]=f [i-1]+f [i-2]; for ( i=0; i<20; i++) { if (i%5= =0) cout<<“\n”; cout<
  • 303. 下面程序的运行结果是:void main(void) { int a[6], i; for (i=1; i<6; i++) { a[i]=9*(i-2+4*(i>3))%5 ; cout<
  • 304. 排序算法用起泡法对6个数排序(由小到大)将相邻的两个数两两比较,将小的调到前头。985420895420859420854920854290854209第一趟 循环5次584209548209542809第二趟 循环4次854209543089543089453089435089430589第三趟 循环3次304
  • 305. 430589340589304589304589第四趟 循环2次034589第五趟 循环1次总结:n次数趟数j(1~n-1)54321n-j12345共有6个数for (j=1; j<=n-1; j++) for (i=1; i<=n-j ; i++) { if (a[i]>a[i+1]) { t=a[i]; a[i]=a[i+1]; a[i+1]=t; } } 305
  • 306. 一般,元素的序号从0开始,因此,程序可以变动如下:for (j=0; ja[i+1]) { t=a[i]; a[i]=a[i+1]; a[i+1]=t; } } 306
  • 307. 二维数组的定义和引用一、定义方式: 类型说明符 数组名[常量表达式][常量表达式];int a[3][4]; 其元素分别为:a[0][0], a[0][1], a[0][2], a[0][3], a[1][0], a[1][1], a[1][2], a[1][3], a[2][0], a[2][1], a[2][2], a[2][3] 表明a数组由3×4个int型元素组成 定义类型数组名行数列数307
  • 308. 其行列的序号均从0开始。若存放首地址为2000H,则在内存中为:a[0][0]a[0][1]a[0][2]a[0][3]a[1][0]a[1][1]a[1][2]a[1][3]a[2][0]a[2][1]a[2][2]a[2][3]2000H2008H2010H2014H201cH2020H2028H202cH即在内存中,多维数组依然是直线顺序排列的,第一个元素位于最低地址处。其元素分别为:a[0][0], a[0][1], a[0][2], a[0][3], a[1][0], a[1][1], a[1][2], a[1][3], a[2][0], a[2][1], a[2][2], a[2][3] 308
  • 309. 二、二维数组的引用与一维数组一样,二维数组必须先定义,其维数必须是常量。具体引用时(赋值、运算、输出)其元素等同于变量。void main(void) { int a[2][3], i, j; cout<<“Input 2*3 numbers\n”; for (i=0; i<2; i++) /* 输入 */ for(j=0; j<3; j++) cin>>a[i][j]; for (i=0; i<2; i++) /* 输出 */ { for(j=0; j<3; j++) cout<输出: _ _ _1_ _ _2_ _ _3 _ _ _4_ _ _5_ _ _6定义赋值输出309
  • 310. 三、二维数组的初始化在定义数组的同时给数组元素赋值。即在编译阶段给数组所在的内存赋值。1、分行赋值int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};2、顺序赋值int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12}; //依次赋值 310
  • 311. 3、部分赋值int a[3][4]={{1},{5},{9}}; /* a[0][0]=1, a[1][0]=5, a[2][0]=9 其余元素为0 */int a[3][4]={{0,1},{5}}; /* a[0][0]=0, a[0][1]=1, a[1][0]=5 */ 100050009000010050000000311
  • 312. 4、分行或全部赋值时,可以省略第一维,第二维不可省。int a[ ][4]={{1,2},{5,6,7,8,}{9,10,11,12}}; 5、不能给数组整体赋值,只能一个一个地赋值。 6、用static 定义的数组不赋初值,系统均默认其为‘\0’。static int a[2][3];int a[2][3]={1,2,3,.....,12};312
  • 313. void main(void) { int a[3][3], i, j; for (i=0; i<3; i++) { for (j=0; j<3; j++) if (i= =2) a[i][j]=a[i-1][a[i-1][j]]+1; else a[i][j]=j; cout<
  • 314. 有一个3×4的矩阵,要求编程序求出其中值最大的那个元素的值,以及其所在的行号和列号。 先考虑解此问题的思路。从若干个数中求最大者的方法很多,我们现在采用“打擂台”算法。如果有若干人比武,先有一人站在台上,再上去一人与其交手,败者下台,胜者留台上。第三个人再上台与在台上者比,同样是败者下台,胜者留台上。如此比下去直到所有人都上台比过为止。最后留在台上的就是胜者。314
  • 315. 程序模拟这个方法,开始时把a[0][0]的值赋给变量max,max就是开始时的擂主,然后让下一个元素与它比较,将二者中值大者保存在max中,然后再让下一个元素与新的max比,直到最后一个元素比完为止。max最后的值就是数组所有元素中的最大值。315
  • 316. max=a[0][0]; //使max开始时取a[0][0]的值 for (i=0;i<=2;i++) //从第0行到第2行 for (j=0;j<=3;j++) //从第0列到第3列 if (a[i][j]>max)//如果某元素大于max { max=a[i][j]; //max将取该元素的值 row=i; //记下该元素的行号i colum=j; //记下该元素的列号j } cout<
  • 317. 将数组行列式互换。1 2 3 5 6 7 8 91 4 7 2 5 8 3 6 9for (i=0; i<3; i++) for (j=0; j<3; j++) { t=a[i][j]; a[i][j]=a[j][i]; a[j][i]=t; } for (i=0; i<3; i++) for (j=0; j
  • 318. 打印杨辉三角形 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1a[i][j]=a[i-1][j-1]+a[i-1][j]318
  • 319. void main(void) { static int n[2],i,j,k; for(i=0;i<2;i++) n[j++]=n[i]+i+1; cout<
  • 320. 以下程序用于从键盘上输入若干个学生的成绩,统计出平均成绩,并输出低于平均成绩的学生成绩。输入负数结束void main() { float x[100],sum=0, ave,a; int n=0,i; cout<<“Input score\n”; _________; while(__________) { x[n]=a; _______; _________ cin>>a; }ave=sum/n; cout<<“ave=“<>aa>=0sum+=an++i
  • 321. 输入一个十进制数,输出它对应的八进制数。725/2=362 余数=1=K0 362/2=181 余数=0=K1 181/2=90 余数=1=K2 90/2=45 余数=0=K3 45/2=22 余数=1=K4 22/2=11 余数=0=K5 11/2=5 余数=1=K6 5/2=2 余数=1=K7 2/2=1 余数=0=K8 1/2=0 余数=1=K9不断地除8,求其余数,直到被除数为0,最后余数倒序排列。321
  • 322. void main(void) { int x , i, n ; int a[100]; cin>>x; i=0; while(x) { a[i]=x%8; x=x/8; i++; } n=i;for(i=n-1;i>=0;i--) cout<
  • 323. 已有一个已排好序的数组,今输入一个数,要求按原来排序的规律将它插入数组中。 36913345678输入:cin>>x; 25369132534567836913345678x25y253434323
  • 324. 36913345678x25y25343436913255678x3434y345656324
  • 325. void main(void) { int a[6]={1,4,7,10,12}; int x; for(int i=0;i<5;i++) cout<>x; for(i=0;i<5;i++) { if(a[i]>x) break; } for(int j=i;j<=5;j++) { int y=a[j]; a[j]=x; x=y; } for( i=0;i<6;i++) cout<
  • 326. 36913345678ab输入:cin>>x; 253691325345678326
  • 327. void main(void) { int a[6]={1,4,7,10,12}; int b[6]; int x; for(int i=0;i<5;i++) cout<>x; for(i=0;i<5;i++) if(a[i]
  • 328. 36913345678a输入:cin>>x; 2578563425for(i=n-1;i>=0;i--)从后向前循环328
  • 329. void main(void) { int a[6]={2,5,8,10,12}; int x; for(int i=0;i<5;i++) cout<>x; for(i=4;i>0;i--) { if(a[i]>x) a[i+1]=a[i]; else break; } a[i+1]=x; for(i=0;i<6;i++) cout<
  • 330. 用筛选取法求出2~200之间的所有素数。 筛法:首先将1~n个数为数组置初值。2的倍数不是素数,置0; 3的倍数不是素数,置0;5的倍数不是素数,置0;....,依次类推,最后将数组中不是0的元素输出。23456789101112131415161718192023050709011013015017019023050700011013000170190330
  • 331. 数组作为函数参数一、数组元素作函数参数数组元素作函数实参,用法与一般变量作实参相同,是“值传递”。331
  • 332. 有两个数据系列分别为: int a[8]={26,1007,956,705,574,371,416,517}; int b[8]={994,631,772,201,262,763,1000,781}; 求第三个数据系列 c ,要求c中的数据是a b中对应数的最大公约数。 int a[8]={26, 1007, 956, 705, 574, 371, 416, 517}; int b[8]={994, 631, 772, 201, 262, 763, 1000, 781}; c[8]={2, 1, 4, 3 , 2 , 7 , 8, 11}332
  • 333. int gys(int m,int n) { int r; if(m
  • 334. 二、用数组名作函数参数用数组名作函数参数,实参与形参都应用数组名。 这时,函数传递的是数组在内存中的地址。在C++中,数组名被认为是数组在内存中存放的首地址。实参中的数组地址传到形参中,实参形参共用同一段内存。334
  • 335. void fun(int a[2]) { for(int i=0;i<2;i++) a[i]=a[i]*a[i]; } void main(void) { int b[2]={2,4}; cout<
  • 336. void sort(int x[ ], int n) { int t,i,j; for( i=0;ix[j+1]) { t=x[j]; x[j]=x[j+1]; x[j+1]=t;} } void main(void) { int a[5]={20,4,16,8,10}; sort(a, 5 ); for(int i=0;i<5;i++) cout<
  • 337. 有一个一维数组,内放10个学生成绩,求平均成绩。void main(void) { static float score[10]={ 100, 90, ...}; float aver; aver=average(score); cout<<“aver=“<
  • 338. 注意:1、用数组名作函数参数,应在主调函数和被调函数中分别定义数组,且类型一致。2、需指定实参数组大小,形参数组的大小可不指定。数组名作实参实际上是传递数组的首地址。338
  • 339. 3、C++语言规定,数组名代表数组在内存中存储的首地址,这样,数组名作函数实参,实际上传递的是数组在内存中的首地址。实参和形参共占一段内存单元,形参数组中的值发生变化,也相当于实参数组中的值发生变化。 score[8]score[6]score[4]score[2]score[0]array[8]array[6]array[4]array[2]array[0]scorearray339
  • 340. 程序中的函数p( )用于计算:主函数利用函数完成计算int p(int a, int x[], int b, int y[], int n) { int i, s; for(________; i
  • 341. int a[10], i; void sub1(void) { for(i=0;i<10;i++) a[i]=i+i; } void sub2(void) { int a[10], max,i; max=5; for(i=0;i
  • 342. 编写程序,在被调函数中删去一维数组中所有相同的数,使之只剩一个,数组中的数已按由小到大的顺序排列,被调函数返回删除后数组中数据的个数。 例如: 原数组:2 2 2 3 4 4 5 6 6 6 6 7 7 8 9 9 10 10 10 删除后:2 3 4 5 6 7 8 9 10 342
  • 343. 用多维数组名作函数参数同样,实参向形参传递的是数组的首地址。如果实参、形参是二维数组,则形参可以省略第一维,不可省略第二维,且第二维必须与实参中的维数相等。int array[ ][10]int score[5][10]int array[3][10]int score[5][10]int array[ ][8]int score[5][10]错误343
  • 344. 有一个3×4的矩阵,求其中的最大元素。int max_value (int array[ ][4]) { int i, j, k, max; max=array[0][0]; for (i=0; i<3; i++) for (j=0; j<4; j++) if (array[i][j]>max) max=array[i][j]; return (max); } void main (void) { static int a[3][4]={{1,3,5,7}, {2,4,6,8},{15,17,34,12}}; cout<<“max is ”<
  • 345. 字符数组用来存放字符数据的数组是字符数组,字符数组中的一个元素存放一个字符。一、字符数组的定义char 数组名[常量表达式];char c[4]; /*每个元素占一个字节 */c[0]=‘I’; c[1]=‘m’; c[2]=‘_’;类型数组名数组大小345
  • 346. 二、字符数组的初始化与数值数组的初始化相同,取其相应字符的ASCII值。char c[10]={‘I’, ‘ ’, ‘a’, ‘m’, ‘ ’, ‘a’, ‘ ’ , ‘b’, ‘o’, ‘y’}; 随机‘y’‘o’‘b’‘ ’‘a’‘ ’‘m’‘a’‘ ’‘I’cc[0]c[9]346
  • 347. 如果字符个数大于数组长度,做错误处理;如果数值个数小于数组长度,后面的字节全部为‘\0’。如果省略数组长度,则字符数即为数组长度。static char c[ ]={‘I’, ‘ ’, ‘a’, ‘m’, ‘ ’, ‘a’, ‘ ’ , ‘g’, ‘i’, ‘r’,’l’}; 同理,也可定义和初始化一个二维或多维的字符数组。分层或省略最后一维。char st1[ ]={65, 66, 68};‘A’‘B’‘D’347
  • 348. 三、字符数组的引用void main(void) { char c[10]={‘I’, ‘ ’, ‘a’, ‘m’, ‘ ’, ‘a’, ‘ ’ , ‘b’, ‘o’, ‘y’}; int i; for (i=0; i<10; i++) cout<
  • 349. 四、字符串和字符串结束标志C++语言将字符串作为字符数组来处理。 字符串常量:“CHINA”,在机内被处理成一个无名的字符型一维数组。CHINA‘\0’C++语言中约定用‘\0’作为字符串的结束标志,它占内存空间,但不计入串长度。有了结束标志‘\0’后,程序往往依据它判断字符串是否结束,而不是根据定义时设定的长度。349
  • 350. 字符串与字符数组的区别:char a[ ]={‘C’,’H’,’I’,’N’,’A’};char c[ ]=“CHINA”; 随机随机ANIHC长度占5个字节随机‘\0’ANIHC长度占6个字节字符数组字符串350
  • 351. 可以用字符串的形式为字符数组赋初值char c[ ]={“I am a boy”}; /*长度11字节,以‘\0’结尾 */char a[ ]={‘I’, ‘ ’, ‘a’, ‘m’, ‘ ’, ‘a’, ‘ ’ , ‘b’, ‘o’, ‘y’}; /* 长度10字节 */如果数组定义的长度大于字符串的长度,后面均为‘\0’。char c[10]=“CHINA”; ‘\0’‘\0’‘\0’‘\0’‘\0’ANIHCc‘\0’的ASCII为0,而‘ ’(空格)的ASCII为32。351
  • 352. char w[ ]={‘T’, ‘u’, ‘r’, ‘b’, ‘o’, ‘\0’};Turbo‘\0’char w[ ]={“Turbo\0”};Turbo‘\0’char w[ ]=“Turbo\0”;Turbo‘\0’char w[ ]=‘Turbo\0’;非法352
  • 353. char a[2][5]={“abcd”, “ABCD”};abcd‘\0’ABCD‘\0’在语句中字符数组不能用赋值语句整体赋值。char str[12]; str=“The String”;str为字符数组在内存中存储的地址,一经定义,便成为常量,不可再赋值。char str[12]=“The String”;非法,在语句中赋值定义数组,开辟空间时赋初值353
  • 354. 字符数组的输入输出 逐个字符的输入输出。这种输入输出的方法,通常是使用循环语句来实现的。如: char str[10]; cout<<“输入十个字符:”; for(int i=0;i<10;i++) cin>>str[i]; //A ...... A行将输入的十个字符依次送给数组str中的各个元素。定义赋值354
  • 355. 把字符数组作为字符串输入输出。对于一维字符数组的输入,在cin中仅给出数组名;输出时,在cout中也只给出数组名。void main (void ) {char s1[50],s2[60]; cout << “输入二个字符串:”; cin >> s1; cin >> s2; cout << “\n s1 = “ << s1; cout << “\n s2 = “ << s2 << “\n”;  }输入:abcd stringcin只能输入一个单词,不能输入一行单词。数组名数组名输出到‘\0’为止355
  • 356. 当要把输入的一行作为一个字符串送到字符数组中时,则要使用函数cin.getline( )。这个函数的第一个参数为字符数组名,第二个参数为允许输入的最大字符个数。 cin.getline(数组名, 数组空间数);char s1[80]; ....... cin.getline(s1, 80);首先开辟空间参数是数组名356
  • 357. void main (void ) { char s3[81]; cout<<”输入一行字符串:”; cin.getline(s3,80); //A cout<<”s3=”<
  • 358. 从键盘输入一行字符,统计其中分别有多少大小写字母,以$号结束输入。从键盘输入一行字符,统计其中分别有多少大小写字母。从键盘输入一行字符,其中的大写变小写,小写变大写。358
  • 359. 从键盘接收一行字符,统计有多少个单词数?we are students.weares字母字母空格空格字母字母字母空格字母不能用字母数或空格数来判断,只能用字母和空格状态变化的次数来判断。设状态变量word , 判别到字母时word为1,判别到非字母时word为0。word的初始值为0,当从0变为1时,单词数加1。0110011101359
  • 360. void main(void) {char s[80]; int i=0, word=0,num=0; cin.getline (s,80); while(s[i]!='\0') { if((s[i]>='a'&&s[i]<='z'||s[i]>='A'&&s[i]<='Z')&&word==0) { word=1; num++; } else if(s[i]==' '||s[i]=='\t') word=0; i++; } cout<<"num="<
  • 361. 六、字符串处理函数C++中没有对字符串变量进行赋值、合并、比较的运算符,但提供了许多字符串处理函数,用户可以调用 #include “string.h”所有字符串处理函数的实参都是字符数组名361
  • 362. 1、合并两个字符串的函数 strcat (str1, str2)static char str1[20]={“I am a ”}; static char str2[ ]={“boy”}; strcat (str1, str2);Iama'\0''\0'boy‘\0’Iamaboy'\0'将第二个字符串 str2 接到第一个字符串 str1 后。注意:第一个字符串要有足够的空间。空间足够大362
  • 363. 2、复制两个字符串的函数 strcpy (str1, str2)static char str1[20]={“I am a ”}; static char str2[ ]={“boy”}; strcpy (str1, str2);'\0''\0'amaIstr1'\0'yobstr2'\0''\0'a'\0'yobstr1strcpy ( str1, “CHINA”);'\0'ANIHCstr1strcpy (“CHINA”, str1);str1=str2; str1=“CHINA”; 字符串正确赋值均为非法363
  • 364. 3、比较两个字符串的函数 strcmp (str1, str2)此函数用来比较str1和str2中字符串的内容。函数对字符串中的ASCII字符逐个两两比较,直到遇到不同字符或‘\0’为止。函数值由两个对应字符相减而得。该函数具有返回值,返回值是两字符串对应的第一个不同的ASCII码的差值。若两个字符串完全相同,函数值为0。 if ( strcmp (str1, str2)==0) { ........ }用来判断两字符串是否相等364
  • 365. static char str1[20]={“CHINA”}; static char str2[ ]={“CHINB”}; cout<< strcmp (str1, str2)<
  • 366. 4、求字符串长度的函数 strlen (str1)长度不包括‘\0’。函数参数为数组名,返回值为数组首字母到‘\0’的长度。并非数组在内存中空间的大小。char s[80]; strcpy(s, “abcd”); cout<
  • 367. char str1[20]={“CHINA”}; cout<
  • 368. 5、 strlwr (str1)将str1中的大写字母转换成小写字母。6、 strupr (str1)将str1中的小写字母转换成大写字母。368
  • 369. 7、函数strncmp(字符串1,字符串2 , maxlen) 函数原型为: int strncmp(char str1[ ], char str2[ ],int m)第三个参数为正整数,它限定了至多比较的字符个数若字符串1或字符串2的长度小于maxlen的值时,函数的功能与strcmp( )相同。当二个字符串的长度均大于maxlen的值时,maxlen为至多要比较的字符个数。cout<
  • 370. 第三个参数为正整数,它限定了至多拷贝的字符个数若字符串2的长度小于maxlen的值时,函数的功能与strcpy( )相同。当字符串2的长度大于maxlen的值时,maxlen为至多要拷贝的字符个数。8、函数strncpy(字符数组名1, 字符串2, maxlen) 函数原型为: void strncmp(char str1[ ], char str2[ ],int m)370
  • 371. char s[90],s1[90]; strncpy(s,"abcdssfsdfk",3); //A strncpy(s1,"abcdef " , 90); //B cout<
  • 372. 输入三个字符串按大小输出。输入n个字符串按大小输出。372
  • 373. void changed(char str1[],char str2[]) {char str3[80]; strcpy(str3,str1); strcpy(str1,str2); strcpy(str2,str3); }void main(void) {char s1[80],s2[80],s3[80]; cout<<"Input 3 strings:\n"; cin.getline(s1); cin.getline(s2); cin.getline(s3); if(strcmp(s1,s2)>0) changed(s1,s2); if(strcmp(s1,s3)>0) changed(s1,s3); if(strcmp(s2,s3)>0)changed(s2,s3); cout<<"sorted:"<
  • 374. void changed(char str1[],char str2[]) {char str3[80]; strcpy(str3,str1); strcpy(str1,str2); strcpy(str2,str3); }void main(void) {char ss[10][80]; int i,j; cout<<"Input 10 strings:\n"; for(i=0;i<10;i++) cin.getline (ss[i],80); for(i=0;i<9;i++) for(j=0;j<9-i;j++) if(strcmp(ss[j],ss[j+1])>0) changed(ss[j],ss[j+1]); cout<<"sorted:"<
  • 375. 用选择法对6个数排序(由小到大)设定一个变量,放入数组中的最小数的序号,然后将其与最上面的数比较交换。024589a[6]a[5]a[4]a[3]a[2]a[1]2、a[min]与a[2]比较1min1、min=13、min=22min4、 a[min]与a[3]比较024589a[6]a[5]a[4]a[3]a[2]a[1]即9与8比较假定元素序号为1的数是最小的数这时,最小数的序号变为2即8与5比较375
  • 376. 024589a[6]a[5]a[4]a[3]a[2]a[1]a[min]与a[4]比较3min min=3 min=44mina[min]与a[5]比较024589a[6]a[5]a[4]a[3]a[2]a[1]024589a[6]a[5]a[4]a[3]a[2]a[1]a[min]与a[6]比较5min min=5 min=66mina[min]与a[1]交换924580a[6]a[5]a[4]a[3]a[2]a[1]第一趟,循环5次这时,最小数的序号变为3即5与4比较这时,最小数的序号变为4即4与2比较这时,最小数的序号变为5第一趟比较完毕,最小数是a[6],最小数的序号为6376
  • 377. 924580a[6]a[5]a[4]a[3]a[2]a[1]a[min]与a[3]比较2min min=2 min=33mina[min]与a[4]比较924580a[6]a[5]a[4]a[3]a[2]a[1]924580a[6]a[5]a[4]a[3]a[2]a[1]a[min]与a[5]比较4min min=4 min=55mina[min]与a[6]比较924580a[6]a[5]a[4]a[3]a[2]a[1]从第二个数开始比较,假定最小数的序号为2377
  • 378. 984520a[6]a[5]a[4]a[3]a[2]a[1]a[min]与a[2]交换5min min=5第二趟,循环4次第二趟比较完毕,最小数是a[5],最小数的序号为5378
  • 379. 984520a[6]a[5]a[4]a[3]a[2]a[1]a[min]与a[4]比较3min min=3 min=44mina[min]与a[5]比较984520a[6]a[5]a[4]a[3]a[2]a[1]984520a[6]a[5]a[4]a[3]a[2]a[1]a[min]与a[6]比较4min min=4 min=44mina[min]与a[3]交换985420a[6]a[5]a[4]a[3]a[2]a[1]第三趟,循环3次379
  • 380. 985420a[6]a[5]a[4]a[3]a[2]a[1]a[min]与a[5]比较4min min=4 min=44mina[min]与a[6]比较985420a[6]a[5]a[4]a[3]a[2]a[1]985420a[6]a[5]a[4]a[3]a[2]a[1]a[min]与a[4]交换4min min=4第四趟,循环2次380
  • 381. 985420a[6]a[5]a[4]a[3]a[2]a[1]a[min]与a[6]比较5min min=5 min=55mina[min]与a[5]交换985420a[6]a[5]a[4]a[3]a[2]a[1]第五趟,循环1次总结:n次数趟数i(1~n-1)54321n-i12345共有6个数for (i=1; i<=n-1; i++) { min=i ; for (j=i; j<=n; j++) if (a[min]>a[j]) min=j ; t=a[min]; a[min]=a[i]; a[i]=t; } 381
  • 382. 一般,元素的序号从0开始,因此,程序可以变动如下:for (i=0; ia[j]) min=j ; t=a[min]; a[min]=a[i]; a[i]=t; } 小循环,找最小数的序号,从 i 找起大循环,找到后与 i 交换每一次循环前设置最小数的序号382
  • 383. 调试程序的方法: 1)单步调试:以行为单位,每运行一步,程序就会中断,可以实时查询目前各变量的状态及程序的走向。可以选择是否进入子函数。 2)运行到光标处,可以直接使程序运行到光标处再进行单步调试,这种方法可以不必运行正确的循环而直接到有疑问的地方。383
  • 384. 在a数组中查找与x值相同的元素所在的位置,数据从a[1]元素开始存放,请填空:#define MAX 10 void main(void) { int a[MAX+1], x, i; for(i=1;i<=MAX;i++) cin>>__________; cout<<“Enter x:”; cin>>x; a[0]=x; i=MAX;while(x!=___________) ____________________; if(___________) cout<
  • 385. void main(void) { char str[ ]=“SSSWILTECH1\1\11W\1WALLMP1”; char c; int k; for(k=2; (c=str[k])!=‘\0’;k++) { switch(c) { case ‘A’ : cout<<‘a’; continue; case ‘1’: break; case 1: while((c=str[++k])!=‘\1’&&c!=‘\0’); case 9: cout<<‘#’; case ‘E’ : case ‘L’: continue; default: cout<
  • 386. 以下程序分别在a数组和b数组中放入an+1和bn+1个由小到大的有序数,程序把两个数组中的数按由小到大的顺序归并到c数组中,请填空: void main(void) { int a[10]={1,2,5,8,9,10},an=5; int b[10]={1,3,4,8,12,18}, bn=5; int i,j,k, c[20], max=9999; a[an+1]=b[an+1]=max; i=j=k=0; while( a[i]!=max||b[j]!=max) { if(a[i]
  • 387. 编写程序,在被调函数中删去一维数组中所有相同的数,使之只剩一个,数组中的数已按由小到大的顺序排列,被调函数返回删除后数组中数据的个数。 例如: 原数组:2 2 2 3 4 4 5 6 6 6 6 7 7 8 9 9 10 10 10 删除后:2 3 4 5 6 7 8 9 10 387
  • 388. 第七章 结构体、共同体和枚举类型 388
  • 389. 定义:将不同种类型的数据有序地组合在一起,构造出一个新的数据类型,这种形式称为结构体。结构体是多种类型组合的数据类型。389
  • 390. struct 结构体名 { 成员列表 };struct student { int num; char name[20]; char sex; char addr[30]; };结构体名关键字不同数据类型组成的成员分号不能少390
  • 391. 定义结构体类型变量的方法一、先定义结构体类型再定义变量名struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; };struct student student1, student2;结构体类型名变量1变量2结构体类型只是一种数据类型,不占内存空间,只有定义结构体类型变量时才开辟内存空间。391
  • 392. # define STUDENT struct student STUDENT { int num; char name[20]; char sex; int age; float score; char addr[30]; }; STUDENT student1,student2;凡是STUDENT的地方都用struct student 机械替换。392
  • 393. 二、在定义类型的同时定义变量struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; } student1, student2;struct 结构体名 { 成员列表 }变量名列表; 紧接着定义变量393
  • 394. 三、直接定义结构体类型变量struct { int num; char name[20]; char sex; int age; float score; char addr[30]; } student1, student2;struct { 成员列表 }变量名列表; 不出现结构体名。394
  • 395. 2、在编译时,仅对变量分配空间,不对类型分配空间。1、结构体类型的变量在内存依照其成员的顺序顺序排列,所占内存空间的大小是其全体成员所占空间的总和。3、对结构体中各个成员可以单独引用、赋值,其作用与变量等同。格式:变量名 . 成员名 student1 . num395
  • 396. 4、结构体的成员可以是另一个结构体类型。struct date { int month; int day; int year; };struct student { int num; char name[20]; struct date birthday; };成员类型成员名5、成员名可以与程序中的变量名相同,二者分占不同的内存单元,互不干扰。例如,在程序中仍可以定义变量 int num;396
  • 397. 结构体类型变量的引用1、不能对结构体变量整体赋值或输出,只能分别对各个成员引用。cin>>student1;cin>>student1.num; student1.num=100;可以将一个结构体变量整体赋给另外一个相同类型的结构体变量。 student2=student1;2、嵌套的结构体变量必须逐层引用。student1.birthday.day=25;3、结构体变量中的成员可以同一般变量一样进行运算。student1.birthday.day++; student1.score+=60;错误必须用成员名引用397
  • 398. 对局部变量类型的结构体变量初始化void main(void) { struct student { long int num; char name[20]; char sex; char addr[30]; } student1={901031, “Li Lin”, ‘M’, “123 Beijing Road”}; cout<
  • 399. 关于结构类型变量的使用,说明以下几点: 1、同类型的结构体变量之间可以直接赋值。这种赋值等同于各个成员的依次赋值。 2、结构体变量不能直接进行输入输出,它的每一个成员能否直接进行输入输出,取决于其成员的类型,若是基本类型或是字符数组,则可以直接输入输出。 3、结构体变量可以作为函数的参数,函数也可以返回结构体的值。当函数的形参与实参为结构体类型的变量时,这种结合方式属于值调用方式,即属于值传递。(举例说明)399
  • 400. 结构体数组结构体数组中的每个元素都是一个结构体类型的变量,其中包括该类型的各个成员。数组各元素在内存中连续存放。400
  • 401. 一、结构体数组的定义struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; } ; struct student stu[30];struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; } stu[30];直接定义401
  • 402. 二、结构体数组的初始化struct student { int num; char name[20]; char sex; } stu[3]={ {1011, "Li Lin",'M'}, {1012,"Wang Lan",'F'}, {1013,"Liu Fang",'F'};402
  • 403. struct student { int num; char name[20]; char sex; } stu[ ]={ {1011,"Li Lin",'M'}, {1012,"Wang Lan",'F'}, {1013,"Liu Fang",'F'}};403
  • 404. 以下程序的结果是:void main(void) { struct date { int year, month, day; } today; cout<
  • 405. 根据下面的定义,能打印出字母M的语句是:struct person { char name[9]; int age; }; struct person class[10]={ “Jone”,17, “Paul”,19, “Mary”,18, “Adam”,16 }; cout<
  • 406. 结构体类型的静态成员 当把结构体类型中的某一个成员的存储类型定义为静态时,表示在这种结构类型的所有变量中,编译程序为这个成员只分配一个存储空间,即这种结构体类型的所有变量共同使用这个成员的存储空间。<类型> <结构体类型名>::<静态成员名>; 其中类型要与在结构体中定义该成员的类型一致,结构体类型名指明静态成员属于哪一个结构体。 struct s{ static int id; int eng; }; int s::id=50; 这时,未定义结构体变量,但已将静态成员的空间安排好。数据类型结构体类型若有定义:s s1,s2; 则变量s1,s2的id成员占用同一存储空间(静态区)。406
  • 407. 在结构体中说明的静态成员属于引用性说明,必须在文件作用域中的某一个地方对静态的成员进行定义性说明,且仅能说明一次。 int s::id; 说明id的初值为0(静态变量的缺省初值均为0) 407
  • 408. 共用体C++语言中,允许不同的数据类型使用同一存储区域,即同一存储区域由不同类型的变量共同表示。这种数据类型就是共用体。union 共用体名 { 成员表列; } 变量表列;union data { int i; char ch; float f; } a, b, c;union data a, b, c;这几个成员在共用体变量中存放在同一地址,相互覆盖,其长度为最长的成员的长度。408
  • 409. 共用体变量的引用不能整体引用共用体变量,只能引用变量中的成员。a.i 表示为整型 a.ch 表示为字符型 a.f 表示为符点型409
  • 410. 共用体变量的特点1、共用体的空间在某一时刻只有一个成员在起作用。2、共用体变量中的成员是最后一次放入的成员。3、共用体变量不能在定义时赋初值。4、共用体变量不能作为函数的参数或函数值,但可使用指向共用体的指针变量。5、共用体可以作为结构的成员,结构体也可以作为共用体的成员。410
  • 411. union un { int i; double y; }; struct st { char a[10]; union un b; }; cout<
  • 412. union un { short int a; char c[2]; } w; w.c[0]=‘A’; w.c[1]=‘a’; cout<
  • 413. void main(void) { union EXAMPLE { struct { int x, int y;} in; int a,b; }e; e.a=1; e.b=2; e.in.x=e.a*e.a; e.in.y=e.b+e.b; cout<
  • 414. 枚举类型如果一个变量只有几种可能的值,可以定义为枚举类型。枚举类型就是将变量的值一一列举出来,变量的值仅限于列举出来的值的范围内。414
  • 415. enum weekday {sun, mon, tue, wed, thu, fri, sat};enum weekday workday, weekend ;workday 和 weekend 值只能是sun 到 sat 其中之一。enum {sun, mon, tue, wed, thu, fri, sat} workday, weekend ;其中sun, mon,....,sat称为枚举元素或枚举常量,为用户定义的标识符,所代表的意义由用户决定,在程序中体现出来。数据类型可能取的值变量另一种定义变量的方法415
  • 416. 1、枚举元素为常量,不可赋值运算。 sun=0; mon=1;2、在定义枚举类型的同时,编译程序按顺序给每个枚举元素一个对应的序号,序号从0开始,后续元素依次加1。enum weekday {sun, mon, tue, wed, thu, fri, sat}; 0 , 1, 2, 3, 4, 5, 6 3、可以在定义时人为指定枚举元素的序号值。enum weekday {sun=9, mon=2, tue, wed, thu, fri, sat}; 9 , 2, 3, 4, 5, 6 , 7 4、只能给枚举变量赋枚举值,若赋序号值必须进行强制类型转换。day=mon ; day=1; day=(enum weekday)1;416
  • 417. 5、枚举元素可以用来进行比较判断。if (workday= = mon) if (workday>sun)6、枚举值可以进行加减一个整数n的运算,得到其前后第n个元素的值。workday=sun; workday=(week)(workday+2);workday= = tue7、枚举值可以按整型输出其序号值。workday=tue; cout<
  • 418. void main(void) { enum team{ qiaut, cubs=4, pick, dodger=qiaut-2;}; cout<
  • 419. 第八章 指针和引用 419
  • 420. 指针的概念数据在内存中是如何存取的?系统根据程序中定义变量的类型,给变量分配一定的长度空间。字符型占1个字节,整型数占4个字节.....。内存区的每个字节都有编号,称之为地址。2000H 2001H 2002H 2003H 2004H35内存内存单元的地址内存单元的内容420
  • 421. 1、直接访问按变量地址存取变量的值。cin>>i; 实际上放到定义 i 单元的地址中。2、间接访问将变量的地址存放在另一个单元p中,通过 p 取出变量的地址,再针对变量操作。一个变量的地址称为该变量的指针。如果在程序中定义了一个变量或数组,那么,这个变量或数组的地址(指针)也就确定为一个常量。ii2000H2000H3000Hp421
  • 422. 变量的指针和指向变量的指针变量变量的指针就是变量的地址,当变量定义后,其指针(地址)是一常量。 可以定义一个变量专门用来存放另一变量的地址,这种变量我们称之为指针变量。在编译时同样分配一定字节的存储单元,未赋初值时,该存储单元内的值是随机的。指针变量定义的一般形式为:类型标识符 *变量名int *i_point;i2000Hint i; &i :2000H 指针类型变量名422
  • 423. 指针变量同样也可以赋值:int i, *i_point; i_point=&i;也可以在定义指针变量时赋初值:int i; int *i_point=&i; * 在定义语句中只表示变量的类型是指针,没有任何计算意义。 * 在语句中表示“指向”。&表示“地址”。一个指针变量只能指向同一类型的变量。即整型指针变量只能放整型数据的地址,而不能放其它类型数据的地址。3000H i_point2000H i2000H423
  • 424. 2000H2000H3000H i_pointint i; int *i_point=&i; *i_point=3;表示指向表示类型i3424
  • 425. 指针变量的引用指针变量只能存放地址,不要将非地址数据赋给指针变量。int *p, i; p=100; p=&i;void main(void) { int a=10, b=100; int *p1, *p2; p1=&a; p2=&b; cout<
  • 426. void main(void) { int a, b; int *p1, *p2; p1=&a; p2=&b; *p1=10; *p2=100; cout<
  • 427. void main(void) { int a, b; int *p1, *p2; *p1=10; *p2=100; cout<
  • 428. 输入a, b两个整数,按大小输出这两个数。void main(void) { int *p1, *p2, *p, a,b; cin>>a>>b; p1=&a; p2=&b; if (a
  • 429. int a=3, *p; p=&a;++, - -, * 优先级相同,都是右结合性。相当于a++。表达式为3, a=47532008H2004H2000Ha&ap(*p)++; 4429
  • 430. int a=3, *p; p=&a;++, - -, * 优先级相同,都是右结合性。7532008H2004H2000Ha&ap2004H*(p++)首先*p ,然后p=p+1,指针指向下一个int单元 表达式为3, p=2004H。*p++; 430
  • 431. int a=3, *p; p=&a;++, - -, * 优先级相同,都是右结合性。7532008H2004H2000Ha&ap4++(*p) *p=*p+1 a=4++*p431
  • 432. int a=3, *p; p=&a;++, - -, * 优先级相同,都是右结合性。7532008H2004H2000Ha&ap2004H*(++p),首先:p=p+1, 然后取*p。即取p所指的下一个int单元的内容。 表达式为5 p=2004H*++p 432
  • 433. 指针变量作为函数参数: 函数的参数可以是指针类型,它的作用是将一个变量的地址传送到另一个函数中。指针变量作为函数参数与变量本身作函数参数不同,变量作函数参数传递的是具体值,而指针作函数参数传递的是内存的地址。433
  • 434. 输入a, b两个整数,按大小输出这两个数。void main(void) { int *point1, *point2, a,b; cin>>a>>b; point1=&a; point2=&b; if (a
  • 435. 输入a, b两个整数,按大小输出这两个数。void main(void) { int *point1, *point2, a,b; cin>>a>>b; point1=&a; point2=&b; if (a
  • 436. 用指针变量作函数参数,在被调函数的执行过程中,应使指针变量所指向的参数值发生变化,这样,函数在调用结束后,其变化值才能保留回主调函数。用指针变量作函数参数,可以得到多个变化了的值。函数调用不能改变实参指针变量的值,但可以改变实参指针变量所指向变量的值。436
  • 437. void grt(int *x , int *y , int *z) { cout<< ++*x<<‘,’<< ++*y<<‘,’<<*(z++)<
  • 438. void main(void) { int a=0, i, *p, sum; for (i=0; i<=2; i++) { p=&a; cin>>*p; sum=s(p); cout<<“sum=”<sum=11sum=13sum=15p&aa1p&asum10sumint s( int *p) { int sum=10; sum=sum + *p; return sum; }1111438
  • 439. sub( int *s) { static int t=0; t=*s + t; return t; } void main(void) { int i, k; for (i=0; i<4; i++) { k=sub(&i); cout<<“sum=“<
  • 440. int *p; void main(void) { int a=1, b=2, c=3; p=&b; pp(a+c, &b); cout<<“(1)”<
  • 441. 举例:最大最小值、方程根441
  • 442. 数组的指针和指向数组的指针变量数组与变量一样,在内存中占据单元,有地址,一样可以用指针来表示。C++规定:数组名就是数组的起始地址;又规定:数组的指针就是数组的起始地址。数组元素的指针就是数组元素的地址。442
  • 443. 一、指向数组元素的指针变量的定义与赋值int a[10], *p; p=&a[0]; p=a;p是变量,a为常量。2024H2020H201CH2018H2014H2010H200CH2008H2004H2000Ha[9]a[8]a[7]a[6]a[5]a[4]a[3]a[2]a[1]a[0]ap&a[0]若数组元素为int型,则指向其的指针变量也应定义为int型。int a[10]; int *p=a; int *p=&a[0];数组第一个元素的地址直接用数组名赋值这两种情况均为赋初值443
  • 444. 二、通过指针引用数组元素int a[10]; int *p=a; 2024H2020H201CH2018H2014H2010H200CH2008H2004H2000Ha[9]a[8]a[7]a[6]a[5]a[4]a[3]a[2]a[1]a[0]ap&a[0]*p=1; a[0]=1; 1C++规定,p+1指向数组的下一个元素,而不是下一个字节。*(p+1)=2;a[1]=2;2*++p=2;p=p+1; *p=2; p=2004H为指针变量赋初值通过指针变量为数组元素赋值指针变量也重新赋值444
  • 445. *(a+1)=2;*(a+1)与a[1]等同。*++a=2;a为常量,不可赋值。p+i 或 a+i 均表示 a[i] 的地址 &a[i]2024H2020H201CH2018H2014H2010H200CH2008H2004H2000Ha[9]a[8]a[7]a[6]a[5]a[4]a[3]a[2]a[1]a[0]ap&a[0]12*(p+1)=2;a[1]=2;*++p=2;错误*(a+i)a[i]*(p+i)p[i]p=p+1; *p=2; p=2004H445
  • 446. 用指向数组的指针变量输出数组的全部元素void main(void) { int a[10], i; int *p; for (i=0; i<10; i++) cin>>a[i]; for (p=a; p>a[i]; for (i=0; i<10; i++) cout<<*p++<<‘\t’; }输入数组元素指针变量赋初值指向下一元素输出指针指向的数据*p, p=p+1输出数据后指针加1446
  • 447. void main(void) { int x[ ]={1,2,3}; int s, i, *p; s=1; p=x; for (i=0; i<3; i++) s*=*(p+i); cout<
  • 448. static int a[ ]={1, 3,5, 7, 11, 13}; main( ) { int *p; p=a+3; cout<<*p<<'\t'<<(*p++)<
  • 449. 三、数组名作函数参数数组名可以作函数的实参和形参,传递的是数组的地址。这样,实参、形参共同指向同一段内存单元,内存单元中的数据发生变化,这种变化会反应到主调函数内。在函数调用时,形参数组并没有另外开辟新的存储单元,而是以实参数组的首地址作为形参数组的首地址。这样形参数组的元素值发生了变化也就使实参数组的元素值发生了变化。449
  • 450. void main(void) { int array[10]; ...... f(array, 10); ..... }f(int arr[ ], int n) { ...... }实参数组形参数组,必须进行类型说明用数组名作形参,因为接收的是地址,所以可以不指定具体的元素个数。1、形参实参都用数组名450
  • 451. 2028H2024H2020H201CH2014H2010H200CH2008H2004H2000Harray[9]array[8]array[7]array[6]array[5]array[4]array[3]array[2]array[1]array[0]array,arrarr[0]指向同一存储区间451
  • 452. 2、实参用数组名,形参用指针变量void main(void) { int a [10]; ...... f(a, 10); ..... }f(int *x, int n ) { ...... }实参数组形参指针452
  • 453. 3、形参实参都用指针变量void main(void) { int a [10],*p; p=a; ...... f(p, 10); ..... }f(int *x, int n ) { ...... }实参指针形参指针实参指针变量调用前必须赋值453
  • 454. 4、实参为指针变量,形参为数组名void main(void) { int a [10],*p; p=a; ...... f(p, 10); ..... }f(int x[ ], int n ) { ...... }实参指针形参数组454
  • 455. 将数组中的n个数按相反顺序存放。void inv(int x[ ], int n) { int t, i, j, m=(n-1)/2; for (i=0;i<=m; i++) { j=n-1-i; t=x[i]; x[i]=x[j]; x[j]=t; } } void main(void) { int i, a[10]={3,7,9,11,0,6,7,5,4,2}; inv(a,10); for (i=0;i<10; i++) cout<
  • 456. void inv(int *x, int n) { int *p, t, *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; } } void main(void) { int i, a[10]={3,7,9,11,0,6,7,5,4,2}; inv(a,10); for (i=0;i<10; i++) cout<
  • 457. 输入10个整数,将其中最小的数与第一个数对换,把最大的数与最后一个数对换。写3个函数:①输入10个数;②进行处理;③输出10个数。457
  • 458. 编写函数 int fun(int x, int *pp),其功能是,求出能整除x且不是偶数的各整数,并按照从小到大的顺序放在pp指向的内存中,函数返回值为这些整数的个数。若x的值为30, 数组中的数为1,3,5,15,函数返回4。458
  • 459. int fun(int x, int *pp) { int k=0; for(int i=1;i>x; n=fun(x,a); for(int i=0;i
  • 460. 输入一行字符串,将字符串中所有下标为奇数位置上的字母转换为大写(若不是小写字符则不必转换)。460
  • 461. void change(char *pchar) { while(*pchar) { if(*pchar>='a'&&*pchar<='z') *pchar=*pchar-32; pchar++; if(*pchar==0) break; pchar++; } }void main(void) { char str[100]; cin.getline(str,100); change(str); cout<
  • 462. 数组名作函数参数数组名可以作函数的实参和形参,传递的是数组的地址。这样,实参、形参共同指向同一段内存单元,内存单元中的数据发生变化,这种变化会反应到主调函数内。在函数调用时,形参数组并没有另外开辟新的存储单元,而是以实参数组的首地址作为形参数组的首地址。这样形参数组的元素值发生了变化也就使实参数组的元素值发生了变化。462
  • 463. 既然数组做形参没有开辟新的内存单元,接受的只是实参数组的首地址,那么,这个首地址也可以在被调函数中用一个指针变量来接受,通过在被调函数中对这个指针变量的指向进行操作而使实参数组发生变化。ap实参,在主调函数开辟的空间形参,用指针变量来接受地址实际上在被调函数中只开辟了p的空间,里面放的是a的值。463
  • 464. 四、指向多维数组的指针和指针变量用指针变量也可以指向多维数组,表示的同样是多维数组的首地址。int a[3][4]; //首地址为2000H a[2][3]a[2][2]a[2][1]a[2][0]a[1][3]a[1][2]a[1][1]a[1][0]a[0][3]a[0][2]a[0][1]a[0][0]200CH2008H2004H2000Haa[2]a[1]a[0]2000H2010H2020H可以将a数组看作一个一维数组,这个一维数组的每个元素又是一个具有4个int型数据的一维数组,这样,我们就可以利用一维数组的概念来标记一些写法。a[0][0]a[0][1]a[0][2]a[0][3]a[1][0]a[1][1]a[1][2]a[1][3]a[2][0]a[2][1]a[2][2]a[2][3]2000H2008H2010H2014H201cH2020H2028H202cH464
  • 465. a[0]=*(a+0)a+0为a[0]的地址&a[0],其值为2000H。a[1]=*(a+1)a+1为a[1]的地址&a[1],其值为2010H。a[2]=*(a+2)a+2为a[2]的地址&a[2],其值为2020H。a[2][3]a[2][2]a[2][1]a[2][0]a[1][3]a[1][2]a[1][1]a[1][0]a[0][3]a[0][2]a[0][1]a[0][0]200CH2008H2004H2000Haa[2]a[1]a[0]2000H2010H2020H a[0]为一维数组名,其数组有四个int型的元素: a[0][0],a[0][1],a[0][2],a[0][3] 同样,a[0]代表一维数组的首地址,所以,a[0]为&a[0][0]。465
  • 466. a[2][3]a[2][2]a[2][1]a[2][0]a[1][3]a[1][2]a[1][1]a[1][0]a[0][3]a[0][2]a[0][1]a[0][0]200CH2008H2004H2000H2020H2010H2000Haa[2]a[1]a[0]a[0]代表一维数组的首地址,也就是一维数组名,a[0]为&a[0][0]。a[0]为&a[0][0]a[0][0]=*(a[0]+0)b[0] = *(b+0)a[0]+1为&a[0][1]a[0][1]=*(a[0]+1)b[1] = *(b+1)a[0]+2为&a[0][2]a[0][2]=*(a[0]+2)b[2] = *(b+2)a[0]+3为&a[0][3]a[0][3]=*(a[0]+3)b[3] = *(b+3)a[1]+2为&a[1][2]a[1][2]=*(a[1]+2)行列把a[0]看成一维数组ba[i][j]=*(a[i]+j)466
  • 467. a为二维数组名,a+1为a[1]的地址,也就是数组第一行的地址,所以a为行指针。a[1]为一维数组名,a[1]+1为a[1][1]的地址,也就是数组第一行第一列的地址,所以a[1]为列指针。a[2][3]a[2][2]a[2][1]a[2][0]a[1][3]a[1][2]a[1][1]a[1][0]a[0][3]a[0][2]a[0][1]a[0][0]200CH2008H2004H2000H2020H2010H2000Haa[2]a[1]a[0]a[1]+2为&a[1][2]a[1][2]=*(a[1]+2)行列a[i][j]=*(a[i]+j)467
  • 468. 可以看到:a, a+0 , *(a+0), a[0], &a[0][0]表示的都是2000H,即二维数组的首地址。 实际上,a[0], a[1], a[2]并不是实际的元素,它们在内存并不占具体的存储单元,只是为了我们表示方便起见而设计出的一种表示方式。a为行指针,加1移动一行。*a或a[0]为列指针,加1移动一列。a[2][3]a[2][2]a[2][1]a[2][0]a[1][3]a[1][2]a[1][1]a[1][0]a[0][3]a[0][2]a[0][1]a[0][0]200CH2008H2004H2000H2020H2010H2000Haa[2]a[1]a[0]468
  • 469. a[1]=*(a+1)*(a+1)+2=&a[1][2]*(*(a+1)+2)=a[1][2]**(a+1)=*(a[1])=*(*(a+1)+0)=a[1][0](*(a+1))[1]=*(*(a+1)+1)=a[1][1]*(a+1)[1]=*((a+1)[1])=*(*((a+1)+1))=**(a+2)=a[2][0]注意二维数组的各种表示法,a为常量。a[2][3]a[2][2]a[2][1]a[2][0]a[1][3]a[1][2]a[1][1]a[1][0]a[0][3]a[0][2]a[0][1]a[0][0]200CH2008H2004H2000H2020H2010H2000Haa[2]a[1]a[0]469
  • 470. int a[3][4]={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)为_____________ (a+1)[1]为_____________ 1908H1900H1920H1900H1918H1191920Ha[2][3]a[2][2]a[2][1]a[2][0]a[1][3]a[1][2]a[1][1]a[1][0]a[0][3]a[0][2]a[0][1]a[0][0]190CH1908H1904H1900H1920H1910H1900Haa[2]a[1]a[0]470
  • 471. void main(void) { static int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23}; int *p; for(p=a[0]; p
  • 472. a[0][0]a[0][1]a[0][2]a[0][3]a[1][0]a[1][1]a[1][2]a[1][3]a[2][0]a[2][1]a[2][2]a[2][3]pint a[3][4],*p; 如何用p表示二维数组中的任一元素?p=a[0]*p *(a[0]+0) a[0][0]p+1*(a[0]+1) a[0][1]p+2*(a[0]+2) a[0][2]p+3*(a[0]+3) a[0][3]p+4*(a[0]+4) a[1][0] *(p+4*1+0)p+5*(a[0]+5) a[1][1] *(p+4*1+1)a[i][j]*(p+4*i+j) *(p+m*i+j)m为第二维的维数。是个常数p+2p+4472
  • 473. fun(int *q1, int *q2, int *q3) { *q3=*q2+*q1; } void main ( void) { int i , j, a[3][3]={1,1},*p1,*p2,*p3; p1=a[0], p2=a[0]+1,p3=a[0]+2; for(i=2;i<9;i++) fun(p1++, p2++, p3++); for(i=0;i<3; i++) for(j=0;j<3;j++) { cout<
  • 474. 指向由m个整数组成的一维数组的指针变量int (*p)[m]; int (*p)[4], a[4];app+1指针加16个字节。a+1指针加4个字节。a+1p+1指向下一行474
  • 475. int (*p)[4], a[3][4];a[2][3]a[2][2]a[2][1]a[2][0]a[1][3]a[1][2]a[1][1]a[1][0]a[0][3]a[0][2]a[0][1]a[0][0]200CH2008H2004H2000Hpp+1p+2p为行指针,可以直接将二维数组名a赋给p。这样,a与p等同。a[2][3] *(*(a+2)+3) p[2][3] *(*(p+2)+3) ap=a两种表示完全等价a为常量p为变量475
  • 476. 若有以下的定义和语句,则下面各个符号的正确含义是: int a[3][4] , (*p)[4]; p=a; p+1 *(p+2) *(p+1)+2 *(*p+2) a[2][3]a[2][2]a[2][1]a[2][0]a[1][3]a[1][2]a[1][1]a[1][0]a[0][3]a[0][2]a[0][1]a[0][0]200CH2008H2004H2000Hpp+1p+2aa数组第一行元素的首地址为行指针a数组第二行元素的首地址为列指针&a[2][0]&a[1][2]为列指针数据元素*(*(p+0)+2)=a[0][2]476
  • 477. 若有以下的定义和语句,则对a数组元素的非法引用是:int a[2][3], (*pt)[3]; pt=a;pt[0][0] 2) *(pt+1)[2] 3) *(pt[1]+2) 3) *(a[0]+2)*(pt+1)[2] 右结合性=*((pt+1)[2])=*(*(pt+1+2))=*(*(pt+3))=pt[3][0]477
  • 478. 多维数组的指针作函数参数主要注意的是函数的实参究竟是行指针还是列指针,从而决定函数形参的类型。要求实参、形参一一对应,类型一致。(举例)478
  • 479. 求二维数组a[3][4]的平均值。void main(void) { float score[3][4] = { {65,67,70 ,60}, {80,87,90,81}, {90,99,100,98} }; float sum=0; for(int i=0;i<3;i++) for(int j=0;j<4;j++) sum=sum+score[i][j]; cout<<“aver=“<
  • 480. void main(void) { float score[3][4] = { {65,67,70 ,60}, {80,87,90,81}, {90,99,100,98} }; float aver; aver=fun1(score, 3); aver=fun2(*score, 12); p 161 8.15480
  • 481. 字符串的指针和指向字符串的指针变量字符串的表示形式1、用字符数组实现void main(void ) { char string[ ]=“I love China”; cout<
  • 482. char string[20]; string=“I love China”;strcpy(string, “I love China”);cin.getline(string); //从键盘输入\0anihCevolI string错误!常量不能赋值正确赋值形式482
  • 483. 2、用字符指针表示字符串void main(void) { char *string=“I love China”; cout<
  • 484. void main(void) { char *string; string=“I love China”; }*string=“I love China”;char *string; cin.getline(string);指针变量赋值,合法具体字符指针未赋值就作指向运算484
  • 485. 将字符串a复制到字符串b。void main(void) { char a[ ]=“I am a boy”, b[20]; int i; for(i=0; *(a+i)!=‘\0’; i++) *(b+i)=*(a+i); *(b+i)=‘\0’; cout<
  • 486. void main(void) { char a[ ]=“I am a boy”, b[20]; char *p1, *p2; int i; p1=a; p2=b; for(; *p1!=‘\0’; p1++,p2++) *p2=*p1; *p2=‘\0’; cout<
  • 487. void main(void) { char a[ ]=“I am a boy”, b[20]; char *p1, *p2; int i; p1=a; p2=b; for(; *p1!=‘\0’; p1++,p2++) *p2=*p1; *p2=‘\0’; cout<
  • 488. 以下程序判断输入的字符串是否“回文”,若是回文,输出YES。 void main(void) { char s[81], cr, *pi, *pj; int i, j, n; cin.getline(s); n=strlen(s); pi=________; pj=________;//pi指向串开始,pj指向最后 while(*pi==‘ ‘) _________; while(*pj==‘ ‘) ________; while( ( ___________) &&(*pi==*pj) ) { pi++; _______; } if((pi
  • 489. 字符串指针作函数参数将一个字符串从一个函数传递到另一个函数,可以用地址传递的办法。即用字符数组名作参数或用指向字符串的指针变量作参数。在被调函数中可以改变原字符串的内容。489
  • 490. 将字符串a复制到字符串b。void main(void) { char a[ ]={“I am a teacher”}; char b[ ]={“You are a student”}; copy_string(a , b); cout<
  • 491. 将字符串a复制到字符串b。void main(void) { char a[ ]={“I am a teacher”}; char b[ ]={“You are a student”}; copy_string(a,b); cout<
  • 492. 字符指针变量与字符数组字符数组和字符指针变量都可以实现字符串的存储和运算,区别在于:字符数组名是常量,定义时必须指明占用的空间大小。字符指针变量是变量,里面存储的是字符型地址,可以整体赋值,但字符串必须以‘\0’结尾。492
  • 493. void main(void) { char str[80]= “hcance”; fun(str); cout<
  • 494. void swap(char *s1, char *s2) { char t; t=*s1; *s1=*s2; *s2=t; }void main(void) { char *s1=“BD”, *s2=“BC”, *s3=“AB”; if(strcmp(s1,s2)>0) swap(s1,s2); if(strcmp(s2,s3)>0) swap(s2,s3); if(strcmp(s1,s2)>0) swap(s1,s2); cout<
  • 495. 有一字符串,包含n个字符。写一函数,将此字符串中从第m个字符开始的全部字符复制成为另一个字符串。void main(void) { char str1[100]={“I am a student”},str2[100]; int m; cin>>m; fun(str1,str2,m); cout<
  • 496. void fun(char *p1, char *p2, int m) { int n=strlen(p1); if(n
  • 497. 函数的指针和指向函数的指针变量可以用指针变量指向变量、字符串、数组,也可以指向一个函数。函数在编译时被分配给一个入口地址。这个入口地址就称为函数的地址,也是函数的指针。像数组一样,C++语言规定,函数名就代表函数的入口地址一个存放地址的指针变量空间可以存放数据的地址(整型、字符型),也可以存放数组、字符串的地址,还可以存放函数的地址。497
  • 498. p=max;直接用函数名为指针变量赋值。int max (int x, int y) { return x>y?x:y; }这时,指针变量p中放的是max函数在内存中的入口地址。函数类型 (*指针变量名)(参数类型 );int (*p)( int, int);专门存放函数地址的指针变量称为指向函数的指针变量。p空间的内容只能放函数的地址且该函数的返回值为整型数同时该函数具有两个整型形参498
  • 499. 函数名max代表函数在内存中的入口地址,是一个常量,不可被赋值。而指向函数的指针变量 p 可以先后指向不同的同种类型的函数。但不可作加减运算。p=max;p=min;int (*p)( int , int);定义赋值499
  • 500. 如何用指向函数的指针变量调用函数?int max(int x, int y) { return x>y?x:y; } void main(void) { int a, b, c; cin>>a>>b; c=max(a,b); cout<y?x:y; } void main(void) { int a, b, c,max(int,int); int (*p)(int, int ); p=max ; cin>>a>>b; c=p(a,b); cout<
  • 501. 用二分法求方程的解。f1(x)=x2-3指向函数的指针变量作函数参数(实现通用函数)501
  • 502. 二分法求解方程f(x)xyx01、在x轴上取两点x1和x2, 要确保x1与x2之间有且只有方程唯一的解。x1x2x02、做x0=(x1+x2)/2。3、若|f(x0)|满足给定的精度,则x0即是方程的解,否则,若f(x0)*f(x1)<0,则方程的解应在x1与x0之间,令x2=x0,继续做2。同理,若f(x0)*f(x1)>0,则方程的解应在x2与x0之间,令x1=x0,继续做2 ,直至满足精度为止。x2x0x2= x0x0=(x1+x2)/2502
  • 503. 用二分法求方程的解。f1(x)=x2-3void main(void) { float x1, x2, x0; do { cout<<“Input two real number\n”; cin>>x1>>x2; }while (f1(x1)*f1(x2)>0);float f1(float x) {return x*x-3;}do { x0=(x1+x2)/2; if ( (f1(x1)*f1(x0)) <0 ) x2=x0; else x1=x0; }while (fabs (f1(x0))>=1e-6); cout<
  • 504. 当求解方程f2(x)=3x2-5x-3时,同样main( ) { float x1, x2, x0; do { cout<<“Input two real number\n”; cin>>x1>>x2; }while (f2(x1)*f2(x2)>0);float f2(float x) {return 3*x*x-5*x-3;}do { x0=(x1+x2)/2; if ( (f2(x1)*f2(x0)) <0 ) x2=x0; else x1=x0; }while (fabs (f2(x0))>=1e-6); cout<
  • 505. float devide(float (*fun)(float )) { float x1, x2, x0; do { cout<<“Input two number\n”; cin>>x1>>x2; }while ( fun(x1) * fun(x2) >0); do { x0=(x1+x2)/2; if ( fun(x1) * fun(x0) <0 ) x2=x0; else x1=x0; }while (fabs ( fun(x0) )>=1e-6); return x0; }float f1(float x) {return x*x-3;}float f2(float x) {return 3*x*x-5*x-3;}main( ) { float y1,y2; y1=devide(f1); y2=devide(f2); cout<
  • 506. 实参:实际的函数名(函数地址)形参:指向函数的指针变量 与实参函数的类型完全一致(返回值、参数)通用函数:所有的内部函数调用都用函数指针调用506
  • 507. 梯形法求定积分的公式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)507
  • 508. S=[ (f(a)+f(b))/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;i
  • 509. float jifen(float (*pf)(float ), float a, float b) { y=(pf(a)+pf(b))/2; h=(b-a)/2; for(i=1;i
  • 510. 返回指针值的函数被调函数返回的不是一个数据,而是一个地址。所以函数的类型为指针类型。类型标识符 *函数名(参数表)指出返回是什么类型的地址int *max(x, y)510
  • 511. void main(void) { int a, b , *p; cin>>a>>b; p=max(&a,&b); cout<<*p<*y) pt=x; else pt=y; return pt; }返回类型是指针用指针类型接收ab随机p&ax24&bypt&b&b输出:4该指针所指向的空间是在主调函数中开辟的。511
  • 512. char *strc(char *str1, char *str2) { char *p; for(p=str1;*p!=‘\0’; p++); do {*p++=*str2++; }while (*str2!=‘\0’); *p=‘\0’; return (str1); } void main(void) {char s1[80]=“computer”, s2[ ]=“language”, *pt; pt=strc(s1, s2); cout<
  • 513. computer‘\0’s1str1pcomputer‘\0’s2str2pstr2computer‘\0’p513
  • 514. 已知函数int *f(int *),有以下说明语句: int *p, *s, a; 函数正确的调用形式是: A) a=*f(s) B) *p=f(s) C) s=f(*p) D) p=f(&a)514
  • 515. 指针数组和指向指针的指针指针数组的概念一个数组,其元素均为指针类型的数据,称为指针数组。也就是说,指针数组中的每一个元素都是指针变量,可以放地址。类型标识 *数组名[数组长度说明]int *p[4]; int (*p)[4]; pp[3]p[2]p[1]p[0]地址地址地址地址p为数组名,内有四个元素,每个元素可以放一个int型数据的地址 p为指向有四个int型元素的一维数组的行指针 515
  • 516. void main(void) { float a[]={100,200,300,400,500}; float *p[]={&a[0],&a[1],&a[2],&a[3],&a[4]}; int i; for(i=0;i<5;i++) cout<<*p[i]<<'\t'; cout<
  • 517. void main(void) { int a[12]={1,2,3,...11,12}; int *p[4], i; for(i=0; i<4;i++) p[i]=&a[i*3]; cout<
  • 518. 常用字符指针数组,数组中的元素指向字符串首地址,这样比字符数组节省空间。char *str[ ]={“China”, “Japan”, “America”};3090H3000H2000Hstrstr[2]str[1]str[0]“America”“Japan”“China”str[1][4]*(*(str+1)+4)*str[2]*(*(str+2)+0)**str*(*(str+0)+0)nAC518
  • 519. 将若干字符串按字母顺序(由小到大)输出。void main(void) { void sort( ); void print( ); char *alpha[ ]={“Follow me”, “Basic”, “Great Wall”, “FORTRAN”, “Computer design”}; int n=5; sort (alpha, n); print(alpha, n); }519
  • 520. void sort(char *alpha[ ], int n) { char *temp; int i, j, k; for(i=0;i0) k=j; if (k!=i) { temp=alpha[i]; alpha[i]=alpha[k]; alpha[k]=temp; } } } void print(char *alpha[ ], int n) { int i; for(i=0;i
  • 521. 指向指针的指针变量int i,*p; p=&i;i2000H2000Hp3000H3000Hprt5000H同样,p也有地址,可以再引用一个指针变量指向它。prt=&p; p=&iint i, *p, **prt;称prt为指向指针的指针变量。其基类型是指向整型数据的指针变量,而非整型数据。521
  • 522. prt=p;p=&i;prt=&p;prt=&i;*p=i;**prt=i;非法,基类型不符i2000H2000Hp3000H3000Hprt5000H522
  • 523. void main(void) { a[5]={1,3,5,7,9}; int *num[5]={&a[0],&a[1],&a[2],&a[3],&a[4]}; int **p, i; p=num; for(i=0;i<5;i++) { cout<<**p<<‘\t’; p++; } } 97531a&a[4]&a[3]&a[2]&a[1]&a[0]numnumpp=p+1;指向num数组下一个元素1 3 5 7 9p=&num[0]523
  • 524. void main(void) {char *alpha[ ]={“Follow me”, “Basic”, “Great Wall”, “FORTRAN”, “Computer design”}; char **p; int i; for(i=0; i<5; i++) { p=alpha+i; cout<<*p<
  • 525. void main(void) { char *n[4]={“China”, “Japan”, “England”, “Germany”}; char **p; int i; p=n; for(i=0; i<4;i++,p++) cout<<(char) (*(*p+2)+1)<
  • 526. 以下程序的输出结果是:char *alpha[6]={“ABCD”,”EFGH”,”IJKL”,”MNOP”, ”QRST”,”UVWX”}; char **p; main( ) { int i; p=alpha; for(i=0;i<4;i++) cout<<*(p[i]); cout<
  • 527. 以下程序的输出结果是:char *alpha[6]={“ABCD”,”EFGH”,”IJKL”,”MNOP”, ”QRST”,”UVWX”}; char **p; main( ) { int i; p=alpha; for(i=0;i<4;i++) cout<<(*p)[i]; cout<
  • 528. 若有以下定义,则下列哪种表示与之等价。char s[3][5]={“aaaa”,”bbbb”,”cccc”}; char **s1= {“aaaa”,”bbbb”,”cccc”}; char *s2[3]= {“aaaa”,”bbbb”,”cccc”}; char s3[ ][3]= {“aaaa”,”bbbb”,”cccc”}; char s4[ ][4]= {“aaaa”,”bbbb”,”cccc”};528
  • 529. 以下程序调用函数swap_p将指针s和t所指单元(a和b)中的内容交换,请填空。void swap_p (______ss, ______tt) { int term; term=_________; **ss=_________; **tt=term; } main( ) { int a=10, b=20, *s,*t; s=&a; t=&b; swap_p(&s,&t); printf(“%d %d”,a,b); }int **int ****ss **tt10a&as20b&bt&sss&tttterm529
  • 530. 假设有说明: char *argv[ ]={“hello”, “nanjing”, “jiangsu”}; char **pargv=argv; 以下语句的输出结果如何? cout<<*(pargv+1)<
  • 531. void main() { char *s[]={“1995”,”1996”,”1997”,”1998”}; char **sp[ ]={s+3,s+2,s+1,s}; char ss[5]; ss[0]=**sp[0]; ss[1]=*(*sp[1]+1); ss[2]=*(*sp[2]+2); ss[3]=*sp[3][3]+6; ss[4]=‘\0’; cout<
  • 532. 总结:通过行指针引用二维数组元素int a[3][4], *p[3], (*pp)[4], **prt; for(i=0;i<3;i++) p[i]=a[i]; pp=a; prt=p;8a[2]a[1]a[0]pp+2pp+1pp8p[2]p[1]p[0]apprtprt+1prt+2a[2][3] *(*(pp+2)+3)a[2][3] *(*(p+2)+3)a[2][3] *(*(a+2)+3)a[2][3] *(*(prt+2)+3)a[2][3] pp[2][3] p[2][3] prt[2][3]532
  • 533. int a[3][4], *p[3], (*pp)[4], **prt; for(i=0;i<3;i++) p[i]=a[i]; pp=a; prt=p;8p[2]p[1]p[0]apprtprt+1prt+2a:二维数组名,常量p:指针数组名,常量pp:指向具有四个元素的一维数组的指针变量prt :指向指针的指针变量533
  • 534. 指针数组作main( )函数的形参程序是由main( )函数处向下执行的。main函数也可以带参数。 其它函数由main函数调用的,即在程序中调用的,但main函数却是由DOS系统调用的,所以main函数实参的值是在DOS命令行中给出的,是随着文件的运行命令一起给出的。可执行文件名 实参1 实参2 ...... 实参nS9_16 CHINA JAPAN AMERICAN可执行文件S9_16.EXE三个形参534
  • 535. main函数形参的形式:main( int argc, char * argv[ ]) main( int argc, char **argv)argc为命令行中参数的个数(包括文件名); argv为指向命令行中参数(字符串)的指针数组。S9_16 CHINA JAPAN AMERICAN文件名实参1实参2实参3argc=4argv[3]argv[2]argv[1]argv[0]“AMERICAN”“JAPAN”“CHINA”“S9_16.EXE”argvargv535
  • 536. main( int argc, char *argv[ ]) { while (argc>1) { cout<<*argv<文件名实参1实参2实参3536
  • 537. B9_1 Beijing Chinamain(int argc, char **argv ) { while (argc-- >1) cout<< *(++argv)<
  • 538. 小结1、指针变量可以有空值,即指针变量不指向任何地址。int *p; p=0;#include “iostream.h” int *p; p=NULL;#define NULL 02、两指针可以相减,不可相加。若要进行相减运算,则两指针必须指向同一数组,相减结果为相距的数组元素个数int a[10],*p1,*p2; p1=a; p2=a+9;p2-p1 : 9 3、指向同一数组的两个指针变量可以比较大小:p2>p1538
  • 539. 在内存动态分配存储空间在定义变量或数组的同时即在内存为其开辟了指定的固定空间。int n, a[10]; char str[100]; 在程序内我们有时需要根据实际需要开辟空间,如输入学生成绩,但每个班的学生人数不同,一般将人数定得很大,这样占用内存。一经定义,即为固定地址的空间,在内存不能被别的变量所占用。539
  • 540. #define N 100 ...... float score[N][5]; cin>>n; for(int i=0;i>score[i][j]; ......无论班级中有多少个学生,程序均在内存中开辟100×5个实型数空间存放学生成绩,造成内存空间的浪费。540
  • 541. 如何根据需要在程序的运行过程中动态分配存储内存空间?int n; cin>>n; float score[n][5]; 错误!数组的维数必须是常量利用 new 运算符可以在程序中动态开辟内存空间。new 数据类型[单位数];new int[4];在内存中开辟了4个int型的数据空间,即16个字节541
  • 542. new 相当于一个函数,在内存开辟完空间后,返回这个空间的首地址,这时,这个地址必须用一个指针保存下来,才不会丢失。int *p;pp=new int;new开辟的空间*p=6;6可以用*p对这个空间进行运算。new int;在内存中开辟出四个字节的空间542
  • 543. int n,* p; cin>>n; p=new int[n];p指向新开辟空间的首地址。p同样,利用new运算符也可以开辟连续的多个空间(数组)。for(int i=0;i>p[i];可以用p[i]的形式来引用新开辟的内存单元。543
  • 544. 注意:用new开辟的内存单元没有名字,指向其首地址的指针是引用其的唯一途径,若指针变量重新赋值,则用new开辟的内存单元就在内存中“丢失”了,别的程序也不能占用这段单元,直到重新开机为止。int * p, a[4]; p=new int[4]; p=a;anew开辟的单元p该段内存由于失去了“名字”,再也无法引用544
  • 545. 用 new 运算符分配的空间,不能在分配空间时进行初始化。 delete运算符用来将动态分配到的内存空间归还给系统,使用格式为: delete p;同样,用new开辟的内存单元如果程序不“主动”收回,那么这段空间就一直存在,直到重新开机为止。545
  • 546. delete也可以收回用new开辟的连续的空间。int *point; cin>>n; point=new int[n]; ....... delete [ ]point;int *point; point=new int; ...... delete point;注意:在此期间,point指针不能重新赋值,只有用new开辟的空间才能用delete收回。当内存中没有足够的空间给予分配时,new 运算符返回空指针NULL(0)。546
  • 547. 以下程序求两个数的大者,请填空。void main(void ) { int *p1, *p2; p1=___________; p2=___________; cin>>_______________; if (*p2>*p1) *p1=*p2; delete p2; cout<<“max=”<< _______<>*p2547
  • 548. main( ) { int *s1, *s2; sub1(&s1,&s2); sub2(&s1,&s2); cout<<*s1<<‘\t’<<*s2<
  • 549. 引用对变量起另外一个名字 (外号),这个名字称为该变量的引用。<类型> &<引用变量名> = <原变量名>; 其中原变量名必须是一个已定义过的变量。如: int max ; int &refmax=max;refmax并没有重新在内存中开辟单元,只是引用max的单元。max与refmax在内存中占用同一地址,即同一地址两个名字。549
  • 550. maxrefmax510int max ; int &refmax=max;max=5 ;20refmax=10;refmax=max+refmax;max与refmax同一地址550
  • 551. 对引用类型的变量,说明以下几点: 1、引用在定义的时候要初始化。2、对引用的操作就是对被引用的变量的操作。 int &refmax; int &refmax=max;错误,没有具体的引用对象max是已定义过的变量3、 引用类型变量的初始化值不能是一个常数。 如:int &ref1 = 5; // 是错误的。 int &ref=i;551
  • 552. 4、引用同变量一样有地址,可以对其地址进行操作,即将其地址赋给一指针。int a, *p; int &m=a;apm10p=&m; *p=10;&m&是变量的引用&是变量的地址552
  • 553. 5、可以用动态分配的内存空间来初始化一个引用变量。float &reff = * new float ; //用new开辟一个空间,取一个别名reff reff= 200; //给空间赋值 cout << reff ; //输出200 delete &reff; //收回这个空间 这个空间只有别名,但程序可以引用到。float *p, a; p=new float;float a=* new float;错误!553
  • 554. 指针与引用的区别: 1、指针是通过地址间接访问某个变量,而引用是通过别名直接访问某个变量。 2、引用必须初始化,而一旦被初始化后不得再作为其它变量的别名。554
  • 555. 当&a的前面有类型符时(如int &a),它必然是对引用的声明;如果前面无类型符(如cout<<&a),则是取变量的地址。 555
  • 556. 以下的声明是非法的 1、企图建立数组的引用 int & a[9]; 2、企图建立指向引用的指针 int & *p; 3、企图建立引用的引用 int & &px;int m=10;int &y=10;int &z;float &t=&m;int &x=m;556
  • 557. void main(void) { const int &r=8; //说明r为常量,不可赋值 cout<<"r="<558. 引用与函数 引用的用途主要是用来作函数的参数或函数的返回值。引用作函数的形参,实际上是在被调函数中对实参变量进行操作。void change(int &x, int &y)//x,y是实参a,b的别名 { int t; t=x; x=y; y=z; } void main(void) { int a=3,b=5; change(a,b); //实参为变量 cout<
  • 559. 引用作为形参,实参是变量而不是地址,这与指针变量作形参不一样。void change(int &x, int &y) { int t; t=x; x=y; y=z; } void main(void) { int a=3,b=5; change(a,b); //实参为变量 cout<
  • 560. void dd(int &x, int &y, int z) { x=x+z; y=y-x; z=10; cout<<“(2)”<
  • 561. void f1( int *px) { *px+=10;} void f2(int &xx) { xx+=10;} void main(void) { int x=0; cout<<"x="<562. 函数的返回值为引用类型可以把函数定义为引用类型,这时函数的返回值即为某一变量的引用(别名),因此,它相当于返回了一个变量,所以可对其返回值进行赋值操作。这一点类同于函数的返回值为指针类型 。562
  • 563. 先调用,再赋值 int a=4; int &f(int x) { a=a+x; return a; } void main(void) { int t=5; cout<
  • 564. 一个函数返回引用类型,必须返回某个类型的变量。 语句:getdata()=8; 就相当于 int &temp=8; temp=8 ; 注意:由于函数调用返回的引用类型是在函数运行结束后产生的,所以函数不能返回自动变量和形参。 返回的变量的引用,这个变量必须是全局变量或静态局部变量,即存储在静态区中的变量。 564
  • 565. 我们都知道,函数作为一种程序实体,它有名字、类型、地址和存储空间,一般说来函数不能作为左值(即函数不能放在赋值号左边)。但如果将函数定义为返回引用类型,因为返回的是一个变量的别名,就可以将函数放在左边,即给这个变量赋值。565
  • 566. int &f(int &x) { static int t=2; t=x++; return t; } void main(void) { int a=3; cout<
  • 567. const类型变量当用const限制说明标识符时,表示所说明的数据类型为常量类型。可分为const型常量和const型指针。 可用const限制定义标识符量,如: const int MaxLine =1000; const float Pi=3.1415926 用const定义的标识符常量时,一定要对其初始化。在说明时进行初始化是对这种常量置值的唯一方法 ,不能用赋值运算符对这种常量进行赋值。如: MaxLine =35; 567
  • 568. const 型指针 1)禁写指针 声明语句格式为: 数据类型 * const 指针变量名如:int r=6; int * const pr=&r; 则指针pr被禁写,即pr将始终指向一个地址,成为一个指针常量。它将不能再作为左值而放在赋值号的左边。(举例说明)虽然指针被禁写,但其间接引用并没有被禁写。即可以通过pr对r赋值。*pr=8;同样,禁写指针一定要在定义的时候赋初值。568
  • 569. void main(void) { int a,b; int *const pa=&a; //一定要赋初值,pa是常量,不能在程序中 //被改变 *pa=10; //可以间接引用 pa=&b; //非法,pa为常量 }ab&apa10569
  • 570. 2)禁写间接引用 声明语句格式如下: const 数据类型 *指针变量名; 所声明的指针指向一禁写的实体,即间接引用不能被改写。如: const int *p; 所以程序中不能出现诸如 *p= 的语句,但指针p并未被禁写,因而可对指针p进行改写。570
  • 571. void main(void) { int a=3,b=5; const int *pa=&b; //可以不赋初值 pa=&a; //指针变量可以重新赋值 cout<<*pa<
  • 572. 3)禁写指针又禁写间接引用 将上面两种情况结合起来,声明语句为下面的格式 const 数据类型 *const 指针变量名 如:const int *const px=&x 说明:px是一个指针常量,它指向一禁写的实体,并且指针本身也被禁写,诸如:px= *px= 此类的语句都是非法的。在定义时必须赋初值。572
  • 573. 用指针处理链表一、链表概述3000HA2000H3000H3050HB3050H6000HC6000H2090HD2090H‘\0’B2000Hhead链表是由一个个结点组成,每一个结点是一个结构体类型的变量,各个结点的类型相同,但其地址不一定连续。具体结点的个数根据需要动态开辟。每个结点由两部分组成,第一部分放若干数据,第二部分是指针变量,放下一结点的地址。链表头是一指针变量,放第一个结点的地址,若结点的第二部分的值为NULL,表示此链表结束。573
  • 574. 二、如何处理链表struct student { int num; float score; struct student *next; } ;#define STU struct student STU { int num; float score; STU *next; } ; 链表结点的结构:指向同一结构体类型的指针变量指向同一结构体类型的指针变量1、建立链表574
  • 575. struct student { int num; float score; struct student *next; } ;struct student *p; //定义了结构体类型的指针 p=new student; //用new开辟一结构体空间,将地址赋给p p->num=10; //为新开辟的结构体空间中的num成员赋值 p->score=90;nextscorenump1090 用指针引用结构体内的成员(*p).num575
  • 576. 1、首先定义两个结构体类型的指针 STU *p1, *p2;2、用new在内存中开辟一个结构体变量的空间,将地址赋给p1。p1=new student; /* STU struct student */3、将数据赋给刚开辟的变量空间。cin>>p1->num>>p1->score;4、若输入的数据有效,将首地址作为链表头,head=p1; 令p2=p1,p1继续用new开辟新的内存空间。5、将下一个数据赋给新开辟的变量空间。p1=new student; /* STU struct student */cin>>p1->num>>p1->score;6、若输入的数据有效,将p2与p1连接起来,p2->next=p1 再令p2=p1,p1继续用new开辟新的内存空间。做5。若输入的数据无效,p2就是链表的尾,则p2->next=NULL。headp2A2000Hp13000HBp13000Hp22090HCp12090Hp26000HDp1‘\0’ABC576
  • 577. headp2A2000Hp13000HBp13000Hp22090HCp12090Hp26000HDp1‘\0’ABC577
  • 578. STU *p1, *p2, *head; head=NULL; p1=p2=new student; cin>>p1->num>>p1->score; if (p1->num!=0) head=p1;p1=new student; cin>>p1->num>>p1->score; if (p1->num!=0) { p2->next=p1; p2=p1;}p1=new student; cin>>p1->num>>p1->score; if (p1->num!=0) { p2->next=p1; p2=p1; }p1=new student; cin>>p1->num>>p1->score; if (p1->num= =0) p2->next=NULL; return (head);第一结点第二结点第三结点最后结点返回链表头578
  • 579. STU *creat( ) { STU *head, *p1,*p2; n=0; head=NULL; p1=p2=new student; cin>>p1->num>>p1->score; while (p1->num!=0) { n=n+1; if (n= =1) head=p1; else p2->next=p1; p2=p1; p1=new student; cin>>p1->num>>p1->score; } p2->next=NULL; return(head); } n为全局变量,表示结点数开辟新结点向新结点输入数据不满足输入条件,结束579
  • 580. 2、输出链表void print(STU * head) { STU *p; p=head; while(p!=NULL) { cout<num<<‘\t’<score<<‘\n’; p=p->next; } } A3000H2000H3000HB3050H3050HC6000H6000HD2090H2090HB‘\0’head输出数据p指向下一结点580
  • 581. 3、删除链表A3000H2000H3000HB6000H6000HD2090H2090HB‘\0’head1、首先定义两个结构体类型的指针 STU *p1, *p2;2、将链表的表头赋给p1, p1=head;3、判断p1所指向的结点是否是要删除的结点 p1->num a1。4、若p1->num!=a1, p2=p1; p1指向下一个结点p1=p1->next,继续判断下一个结点是否是要删除的结点。继续做3。5、若p1->num= =a1,则p1当前指向的结点就是要删除的结点,将p2的指针成员指向p1所指的下一个结点。p2->next=p1->next;这样就删除了一个结点。p2p1p1p1p22090H581
  • 582. 特殊情况:1、若链表为空链表,返回空指针。2、删除的结点为头结点时,head指向下一个结点3、链表内没有要删除的结点,返回提示信息。582
  • 583. struct student *del(struct student * head, int num) { struct student *p1,*p2; if (head= =NULL) { cout<<“list null\n”; return NULL;} p1=head; while (num!=p1->num&&p1->next!=NULL) { p2=p1; p1=p1->next; } if(num= =p1->num) { if (num= =head->num) head=p1->next; else p2->next=p1->next; n=n-1; } else cout<<“Not found\n”; return head; }链表为空未找到结点,循环结点为第一个循环结束,没有要找的结点找到结点583
  • 584. 4、插入结点:要插入结点的链表是排序的链表。插入10。33000H2000H3000H76000H6000H122090H2090H28‘\0’head1、定义三个结构体指针变量 STU *p1,*p2,*p0; p0指向要插入的结点。p1=head;107000Hp0p12、比较p1->num 与p0->num,若p1->numnum,p2=p1; p1=p1->next; 继续比较。3、若p1->num> =p0->num,p0应插在p1与p2之间,则p2->next=p0 ; p0->next=p1;p2p1p17000H6000Hp2584
  • 585. 特殊情况:1、若链表为空链表,将插入结点作为唯一的结点,head=p0;返回。2、若插入结点中的数据最小,则插入的结点作为头结点。3、插入到链尾,插入结点为最后一个结点。p2->next=p0; p0->next=NULL;p0->next=head; head=p0; 585
  • 586. STU *insert(STU * head, STU * stud) { STU *p0,*p1,*p2; p1=head; p0=stud; if (head= =NULL) { head=p0; p0->next=NULL;} else while((p0->num>p1->num)&&(p1->next!=NULL)) { p2=p1; p1=p1->next; } if (p0->num<=p1->num) { if (head= =p1) head=p0; else p2->next=p0; p0->next=p1; } else {p1->next=p0; p0->next=NULL;} n=n+1; return (head); }链表为空未找到结点,循环找到结点插入在第一个结点前插入在最后一个后586
  • 587. void main(void) { STU *head, stu; int del_num; head=creat( ); print(head); cout<<“Input the deleted number:\n”; cin>>del_num; head=del(head,del_num); print(head); cout<<“Input the inserted record:\n”; cin>>stu.num>>stu.score; head=insert(head, &stu); print(head); }建立链表打印链表删除结点插入结点cout<<“Input the inserted record:\n”; cin>>stu.num>>stu.score; head=insert(head, &stu); print(head);变量,固定空间587
  • 588. 33000H2000H3000H76000H6000H122090H2090H28‘\0’head107000Hstu70006000H588
  • 589. void main(void) { STU *head,*stu; int num; ...... cout<<“Input the inserted record:\n”; stu=new student; cin>>stu->num>>stu->score; while (stu->num!=0) { head=insert(head, stu); print(head); cout<<“Input the inserted record:\n”; stu=new student; cin>>stu->num>>stu->score; } } 如果要插入结点,动态开辟新结点指针,可以赋值重新开辟空间589
  • 590. 用typedef定义类型typedef定义新的类型来代替已有的类型。typedef 已定义的类型 新的类型typedef float REALREAL x, y;1、typedef可以定义类型,但不能定义变量。2、tyoedef只能对已经存在的类型名重新定义一个类型名,而不能创建一个新的类型名。typedef struct student { int i; int *p; } REC;REC x, y, *pt;struct student x, y, *pt;float x, y;590
  • 591. typedef char *CHARP; CHARP p1,p2;char *p1, *p2;typedef char STRING[81]; STRING s1, s2, s3;char s1[81], s2[81],s3[81];1、先按定义变量的方法写出定义体char s[81];2、把变量名换成新类型名char STRING[81];3、在前面加typedeftypedef char STRING[81];4、再用新类型名定义变量STRING s;#define REAL float 编译前简单替换typedef:编译时处理,定义一个类型替代原有的类型。591
  • 592. 第九章 类和对象 面向对象的程序设计592
  • 593. 按钮对象: 按钮的内容、大小,按钮的字体、图案等等 针对按钮的各种操作,创建、单击、双击、拖动等班级对象: 班级的静态特征,所属的系和专业、班级的人数,所在的教室等。这种静态特征称为属性; 班级的动态特征,如学习、开会、体育比赛等,这种动态特征称为行为。 593
  • 594. 任何一个对象都应当具有这两个要素,一是属性(attribute);二是行为(behavior),即能根据外界给的信息进行相应的操作。对象是由一组属性和一组行为构成的。 面向对象的程序设计采用了以上人们所熟悉的这种思路。使用面向对象的程序设计方法设计一个复杂的软件系统时,首要的问题是确定该系统是由哪些对象组成的,并且设计这些对象。在C++中,每个对象都是由数据和函数(即操作代码)这两部分组成的。 594
  • 595. 我们可以对一个对象进行封装处理,把它的一部分属性和功能对外界屏蔽,也就是说从外界是看不到的、甚至是不可知的。 使用对象的人完全可以不必知道对象内部的具体细节,只需了解其外部功能即可自如地操作对象。 把对象的内部实现和外部行为分隔开来。 595
  • 596. 传统的面向过程程序设计是围绕功能进行的,用一个函数实现一个功能。所有的数据都是公用的,一个函数可以使用任何一组数据,而一组数据又能被多个函数所使用。程序设计者必须考虑每一个细节,什么时候对什么数据进行操作 。面向对象程序设计采取的是另外一种思路。它面对的是一个个对象。实际上,每一组数据都是有特定的用途的,是某种操作的对象。也就是说,一组操作调用一组数据。 596
  • 597. 程序设计者的任务包括两个方面:一是设计所需的各种类和对象,即决定把哪些数据和操作封装在一起;二是考虑怎样向有关对象发送消息,以完成所需的任务。各个对象的操作完成了,整体任务也就完成了。 因此人们设想把相关的数据和操作放在一起,形成一个整体,与外界相对分隔。这就是面向对象的程序设计中的对象。 597
  • 598. 程序=算法+数据结构在面向过程的结构化程序设计中,人们常使用这样的公式来表述程序∶ 598
  • 599. 对象 = 算法 + 数据结构 程序=(对象+对象+对象+……)+ 消息 消息的作用就是对对象的控制。 程序设计的关键是设计好每一个对象以及确定向这些对象发出的命令,使各对象完成相应的操作。 面向对象的程序组成:599
  • 600. 每一个实体都是对象。有一些对象是具有相同的结构和特性的。 每个对象都属于一个特定的类型。 在C++中对象的类型称为类(class)。类代表了某一批对象的共性和特征。类是对象的抽象,而对象是类的具体实例(instance)。 600
  • 601. 类是一种复杂的数据类型,它是将不同类型的数据和与这些数据相关的运算封装在一起的 集合体。类的定义类将一些数据及与数据相关的函数封装在一起,使类中的数据得到很好的“保护”。在大型程序中不会被随意修改。601
  • 602. 类的定义格式: class 类名 { private : 成员数据; 成员函数; public : 成员数据; 成员函数; protected: 成员数据; 成员函数; };关键字类名私有公有保护class Student { private : char Name[20]; float Math; float Chiese; public : float average; void SetName(char *name); void SetMath(float math); void SetChinese(float ch); float GetAverage(void); };分号不能少602
  • 603. 用关键字priviate限定的成员称为私有成员,对私有成员限定在该类的内部使用,即只允许该类中的成员函数使用私有的成员数据,对于私有的成员函数,只能被该类内的成员函数调用;类就相当于私有成员的作用域。 603
  • 604. 用关键字public限定的成员称为公有成员,公有成员的数据或函数不受类的限制,可以在类内或类外自由使用;对类而言是透明的。604
  • 605. 而用关键字protected所限定的成员称为保护成员,只允许在类内及该类的派生类中使用保护的数据或函数。即保护成员的作用域是该类及该类的派生类。605
  • 606. 私有成员公有成员保护成员类内函数可以调用可以调用可以调用类外函数不可调用可以调用不可调用私有函数公有函数保护函数类内函数可以调用可以调用可以调用类外函数不可调用可以调用不可调用606
  • 607. 每一个限制词(private等)在类体中可使用多次。一旦使用了限制词,该限制词一直有效,直到下一个限制词开始为止。如果未加说明,类中成员默认的访问权限是private,即私有的。607
  • 608. class Student { char Name[20]; float Math; float Chiese; public : float average; void SetName(char *name); void SetMath(float math); void SetChinese(float ch); float GetAverage(void); };均为私有权限均为公有权限608
  • 609. class A { float x, y; public: void Setxy(float a,float b) { x=a; y=b; } void Print(void) { cout<
  • 610. 成员函数与成员数据的定义不分先后,可以先说明函数原型,再在类体外定义函数体。class A { float x, y; public: void Setxy(float a,float b) { x=a; y=b; } void Print(void) { cout<
  • 611. class A { float x, y; public: void Setxy(float a,float b); void Print(void); }; void A::Setxy(float a,float b) { x=a; y=b; } void A::Print(void) { cout<
  • 612. < class_name > :: < func_name > (<参数表>) { ...... //函数体 }在类体外定义成员函数的格式:void A::Setxy(float a,float b) { x=a; y=b; } 函数类型类名函数名形参列表函数体612
  • 613. 在定义一个类时,要注意如下几点: 1、类具有封装性,并且类只是定义了一种结构(样板),所以类中的任何成员数据均不能使用关键字extern,auto或register限定其存储类型。 2、在定义类时,只是定义了一种导出的数据类型,并不为类分配存储空间,所以,在定义类中的数据成员时,不能对其初始化。如: class Test { int x=5,y=6; //是不允许的 extern float x; //是不允许的 }613
  • 614. 在C++语言中,结构体类型只是类的一个特例。结构体类型与类的唯一的区别在于:在类中,其成员的缺省的存取权限是私有的;而在结构体类型中,其成员的缺省的存取权限是公有的。 614
  • 615. 内联成员函数 当我们定义一个类时,可以在类中直接定义函数体。这时成员函数在编译时是作为内联函数来实现的。 同时,我们也可以在类体外定义类的内联成员函数,在类体内说明函数,在类体外定义时,在成员函数的定义前面加上关键字inline。 class A { float x, y; public: void Setxy(float a,float b); void Print(void); }; inline void A::Setxy(float a,float b) { x=a; y=b; } inline void A::Print(void) { cout<
  • 616. 对象只有在定义了属于类的变量后,系统才会为类的变量分配空间。在定义类时,只是定义了一种数据类型,即说明程序中可能会出现该类型的数据,并不为类分配存储空间。类的变量我们称之为对象。对象是类的实例,定义对象之前,一定要先说明该对象的类。616
  • 617. 不同对象占据内存中的不同区域,它们所保存的数据各不相同,但对成员数据进行操作的成员函数的程序代码均是一样的。 《存储类型》类名 对象1,对象2《,......》;Student st1,st2; 对象的定义格式:类名对象名在建立对象时,只为对象分配用于保存数据成员的内存空间,而成员函数的代码为该类的每一个对象所共享。 617
  • 618. 对象的定义方法同结构体定义变量的方法一样,也分三种,当类中有数据成员的访问权限为私有时,不允许对对象进行初始化。class A { float x,y; public: void Setxy( float a, float b ){ x=a; y=b; } void Print(void) { cout<
  • 619. 对象的使用一个对象的成员就是该对象的类所定义的成员,有成员数据和成员函数,引用时同结构体变量类似,用“.”运算符。619
  • 620. class A { float x,y; public: float m,n; void Setxy( float a, float b ){ x=a; y=b; } void Print(void) { cout<
  • 621. 用成员选择运算符“.”只能访问对象的公有成员,而不能访问对象的私有成员或保护成员。若要访问对象的私有的数据成员,只能通过对象的公有成员函数来获取。 621
  • 622. class A { float x,y; public: float m,n; void Setxy( float a, float b ){ x=a; y=b; } void Print(void) { cout<
  • 623. 同类型的对象之间可以整体赋值,这种赋值与对象的成员的访问权限无关。class A { float x,y; public: float m,n; void Setxy( float a, float b ){ x=a; y=b; } void Print(void) { cout<
  • 624. 对象可以作函数的入口参数(实参、形参),也可以作函数的出口参数。这与一般变量作为函数的参数是完全相同的。 可以定义类类型的指针,类类型的引用,对象数组,指向类类型的指针数组和指向一维或多维数组的指针变量 一个类的对象,可作为另一个类的成员 624
  • 625. 类体的区域称为类作用域。类的成员函数与成员数据,其作用域都是属于类的作用域,仅在该类的范围内有效,故不能在主函数中直接通过函数名和成员名来调用函数。 类作用域、类类型的作用域和对象的作用域 625
  • 626. class A { float x,y; public: float m,n; void Setxy( float a, float b ){ x=a; y=b; } void Print(void) { cout<
  • 627. 类类型的作用域:在函数定义之外定义的类,其类名的作用域为文件作用域;而在函数体内定义的类,其类名的作用域为块作用域 。对象的作用域与前面介绍的变量作用域完全相同 , 全局对象、局部对象、局部静态对象等。627
  • 628. class A { float x,y; public: float m,n; void Setxy( float a, float b ){ x=a; y=b; } void Print(void) { cout<
  • 629. 类的嵌套在定义一个类时, 在其类体中又包含了一个类的完整定义,称为类的嵌套 。类是允许嵌套定义的 。629
  • 630. class A { class B{ int i,j; public : void Setij(int m, int n){ i=m; j=n; } }; float x,y; public: B b1,b2; void Setxy( float a, float b ){ x=a; y=b; } void Print(void) { cout<
  • 631. 类的对象如何引用私有数据成员1、通过公有函数为私有成员赋值class Test{ int x , y; public: void Setxy(int a, int b){x=a; y=b;} void Printxy(void) {cout<<"x="<
  • 632. 2、利用指针访问私有数据成员class Test{ int x,y; public: void Setxy(int a, int b) {x=a; y=b;} void Getxy(int *px, int *py) {*px=x;*py=y;} //提取x,y值 void Printxy(void){cout<<"x="<
  • 633. 3、利用函数访问私有数据成员class Test{ int x,y; public: void Setxy(int a, int b) {x=a; y=b;} int Getx(void) { return x;} //返回x值 int Gety(void) { return y;} //返回y值 void Printxy(void){cout<<"x="<
  • 634. 4、利用引用访问私有数据成员class Test{ int x,y; public: void Setxy(int a, int b){ x=a; y=b;} void Getxy(int &px, int &py) { px=x; py=y; } //提取x,y值 void Printxy(void){cout<<"x="<
  • 635. 类引用举例(三角形类:三角形的三边及与三边相关的运算)class Triangle{ private: float a,b,c; //三边为私有成员数据 public: void Setabc(float x, float y, float z);//置三边的值 void Getabc(float &x, float &y, float &z);//取三边的值 float Perimeter(void);//计算三角形的周长 float Area(void);//计算三角形的面积 void Print(void);//打印相关信息 };635
  • 636. void Triangle::Setabc (float x,float y,float z) {a =x; b=y; c=z; } //置三边的值 void Triangle::Getabc (float &x,float &y,float &z) //取三边的值 {x=a; y=b; z=c;} float Triangle::Perimeter (void) {return (a+b+c)/2;} //计算三角形的周长 float Triangle::Area (void) //计算三角形的面积 {float area,p; p= Perimeter(); area=sqrt((p-a)*(p-b)*(p-c)*p); return area; } void Triangle::Print(void) //打印相关信息 {cout<<"Peri="<
  • 637. void main(void) { Triangle Tri1; //定义三角形类的一个实例(对象) Tri1.Setabc (4,5,6); //为三边置初值 float x,y,z; Tri1.Getabc (x,y,z); //将三边的值为x,y,z赋值 cout<
  • 638. 类引用举例(学生类:学生的姓名成绩及相关的运算)class Stu { char Name[20]; //学生姓名 float Chinese; //语文成绩 float Math; //数学成绩 public: float Average(void); //计算平均成绩 float Sum(void); //计算总分 void Show(void); //打印信息 void SetStudent(char*,float,float);//为对象置姓名、成绩 void SetName(char *); //为对象置姓名 char *GetName(void); //取得学生姓名 };638
  • 639. float Stu::Average(void){ return (Chinese+Math)/2;}//平均成绩 float Stu::Sum(void){ return Chinese+Math; }//总分 void Stu::Show(void) //打印信息 { cout<<"Name: "<
  • 640. void main(void) { Stu p1,p2; p1.SetStudent(“Li qing”,98,96);//对象置初值 p2.SetStudent("Wang Gang",90,88); //对象置初值 p1.Show();//打印信息 p2.Show();//打印信息 p1.SetName (“Zhao jian”);//重新置p1对象的名字 p1.Show (); cout<<“p1.Name: ”<
  • 641. 成员函数的重载 类中的成员函数与前面介绍的普通函数一样,成员函数可以带有缺省的参数,也可以重载成员函数 。重载时,函数的形参必须在类型或数目上不同。641
  • 642. class Test{ int x , y; int m, n; public: void Setxy(int a, int b){x=a; y=b;} void Setxy(int a,int b,int c,int d){ x=a;y=b;m=c;n=d;} void Printxy(int x){cout<< “m="<643. class Stu { char Name[20]; float Chinese; float Math; float English; float Physical; public: float Average(void);//语文、数学平均成绩 float Average(int n);//四门课的平均成绩 float Sum(void);//语文、数学总分 float Sum(int n);//四门课总分 void Show(void); void SetStudent(char*,float,float);//置姓名、语文、数学初值 void SetStudent(char *, float,float,float,float);//置姓名、成绩 void SetName(char *); char *GetName(void); };643
  • 644. 可以有缺省参数的成员函数,若形参不完全缺省,则必须从形参的右边开始缺省。644
  • 645. 缺省参数的成员函数class A{ float x,y; public: float Sum(void) { return x+y; } void Set(float a,float b=10.0) { x=a; y=b;} void Print(void) { cout<<"x="<646. 定义类的指针及如何用指针来引用对象class A{ float x,y; public: float Sum(void) { return x+y; } void Set(float a,float b) { x=a; y=b;} void Print(void) { cout<<"x="<Set(2.0, 3.0); //通过指针引用对象的成员函数 p->Print(); cout<Sum()<
  • 647. 定义类的数组及数组中元素的引用void main(void) { Stu stu[3]; //定义类的数组 Stu *pstu; //定义类的指针 pstu=stu; //为指针赋值 int i; stu[0].SetStudent (“A”,90,90);//通过数组元素的引用赋值 stu[1].SetStudent ("B",80,80); stu[2].SetStudent ("C",70,70); for(i=0;i<3;i++) { pstu->Show ();//指针变量指向数组元素 pstu++; //指针变量加一,指向下一元素 } }stupstupstu647
  • 648. 返回引用类型的成员函数(可以返回私有数据成员的引用)class A{ float x,y; public: float &Getx(void ) { return x; } //返回x的引用 void Set(float a,float b) { x=a; y=b; } void Print(void) { cout<
  • 649. 线性表的应用线性表用来存放若干个整数,用一个指针指向其存放整数的首地址。当存放的数据大于原先开辟的空间时,线性表自动动态开辟空间,储存所有的整数。线性表有三个参数来描述:指向线性表存储空间首地址的指针变量List;无符号整数nMax,指示表的最大长度;无符号整数nElem,指示表中实际所放的数据个数。实际上,线性表相当于一个整型数组,List为数组的首地址,nMax为数组在内存开辟的空间数,nElem为数组中实际存放的元素个数。只不过数组的空间是动态开辟的。649
  • 650. class ListClass { int *List; //指向线性表的指针 unsigned nMax; //表的最大长度 unsigned nElem; //表中当前的元素个数 ....... };37924ListnElemnMax空间是动态开辟的650
  • 651. class ListClass { int *List; //指向线性表的指针 unsigned nMax; //表的最大长度 unsigned nElem; //表中当前的元素个数 public: void Init(int n=10); //初始化针表,最大长度的缺省值为10 void Elem(int); //在线性表尾增加一个元素 int & Elem(unsigned n); //返回线性表中第n个元素的引用 unsigned Elem(void); //返回当前线性表中元素的个数 unsigned Max(void); //返回线性表的长度(占用空间数) void Print(void); //输出线性表中所有的元素 int GetElem(int i); //返回线性表中第i个元素的值 void Destroy(void); //收回线性表占用的存储空间 };651
  • 652. void ListClass::Elem (int elem) //在线性表尾增加一个元素 { nElem=nElem+1; if(nElem>nMax) //空间不够,动态开辟存储空间 { int *list; list=new int[nMax+1]; //开辟一较大的空间 for(int i=0;i
  • 653. this 指针不同对象占据内存中的不同区域,它们所保存的数据各不相同,但对成员数据进行操作的成员函数的程序代码均是一样的。class A{ int x,y; public: void Setxy(int a, int b) { x=a; y=b;} }; A a1, 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;系统自动将对象的指针带到成员函数中653
  • 654. 当对一个对象调用成员函数时,编译程序先将对象的地址赋给this指针,然后调用成员函数,每次成员函数存取数据成员时,也隐含使用this指针。this指针具有如下形式的缺省说明: Stu *const this; 类名即 this 指针里的地址是一个常量654
  • 655. class S{public : char *strp; int length; void Ini(char *s); void Print(void); void Copy(S &s); }; void main(void) { S s1,s2; s1.Ini(“China”); s2.Ini(“”); s1.Print(); s2.Copy(s1); s2.Print(); s1.Copy(s1); }void S::Ini(char *s) { length=strlen(s); strp=new char[length+1]; strcpy(strp, s); } void S::Print(void) { cout<
  • 656. void S::Ini(char *s) { length=strlen(s); strp=new char[length+1]; strcpy(strp, s); } void S::Copy(S &s) { if(strp) delete [ ]strp; length= s.length; strp=new char[length+1]; strcpy(strp, s.strp); } *strplengthIni( )Print( )Copy( )S字符串首址字符串长度s1.Ini(“China”);求长度对象动态开辟空间空间赋值length=5strpChina\0s2.Copy(s1);\0strpChina\0656
  • 657. void S::Copy(S &s) { if(strp) delete [ ]strp; length= s.length; strp=new char[length+1]; strcpy(strp, s.strp); } s1.Copy(s1);strpChina\0length=5随机随机随机随机随机随机失去了原来的内容,不能正确复制657
  • 658. void S::Copy(S &s) { if(&s==this) cout<<“不能复制本身\n”; else { if(strp) delete [ ]strp; length= s.length; strp=new char[length+1]; strcpy(strp, s.strp); } } 判断是否是自身复制this为正在调用该函数的对象的地址s2.Copy(s1);s1.Copy(s1);if(s==*this)658
  • 659. 第十章 构造函数和析构函数659
  • 660. 构造函数和析构函数是在类体中说明的两种特殊的成员函数。构造函数是在创建对象时,使用给定的值来将对象初始化。析构函数的功能正好相反,是在系统释放对象前,对对象做一些善后工作。660
  • 661. 构造函数是类的成员函数,系统约定构造函数名必须与类名相同。构造函数提供了初始化对象的一种简单的方法。构造函数可以带参数、可以重载,同时没有返回值。661
  • 662. class A{ float x,y; public: A(float a,float b){ x=a; y=b;}//构造函数,初始化对象 float Sum(void) { return x+y; } void Set(float a,float b) { x=a; y=b;} Print(void) { cout<<"x="<
  • 663. 对构造函数,说明以下几点: 1.构造函数的函数名必须与类名相同。构造函数的主要作用是完成初始化对象的数据成员以及其它的初始化工作。 2. 在定义构造函数时,不能指定函数返回值的类型,也不能指定为void类型。 3. 一个类可以定义若干个构造函数。当定义多个构造函数时,必须满足函数重载的原则。663
  • 664. 4.构造函数可以指定参数的缺省值。5.若定义的类要说明该类的对象时,构造函数必须是公有的成员函数。如果定义的类仅用于派生其它类时,则可将构造函数定义为保护的成员函数。由于构造函数属于类的成员函数,它对私有数据成员、保护的数据成员和公有的数据成员均能进行初始化。664
  • 665. class A{ float x,y; public: A(float a, float b=10) { x=a; y=b; } A() { x=0; y=0;} void Print(void) { cout<
  • 666. 每一个对象必须要有相应的构造函数若没有显式定义构造函数,系统默认缺省的构造函数。class A{ float x,y; public: A() {} void Print(void) { cout<
  • 667. 对局部对象,静态对象,全局对象的初始化对于局部对象,每次定义对象时,都要调用构造函数。 对于静态对象,是在首次定义对象时,调用构造函数的,且由于对象一直存在,只调用一次构造函数。 对于全局对象,是在main函数执行之前调用构造函数的。667
  • 668. class A { int x,y; public: A(int a){ x=a; cout<<“1\n”;} A(int a, int b) { x=a,y=b;cout<<“2\n”;} }; A a1(3); void f(void) { A b(2,3);} void main(void) { A a2(4,5); f(); f(); }1222668
  • 669. class A{ float x,y; public: A(float a, float b){x=a;y=b;cout<<"初始化自动局部对象\n";} A(){ x=0; y=0; cout<<"初始化静态局部对象\n";} A(float a){ x=a; y=0; cout<<"初始化全局对象\n"; } void Print(void){ cout<
  • 670. 缺省的构造函数 在定义类时,若没有定义类的构造函数,则编译器自动产生一个缺省的构造函数,其格式为: className::className() { } 缺省的构造函数并不对所产生对象的数据成员赋初值;即新产生对象的数据成员的值是不确定的。 670
  • 671. class A{ float x,y; public: A(){ }//缺省的构造函数,编译器自动产生,可以不写 float Sum(void) { return x+y; } void Set(float a,float b) { x=a; y=b;} void Print(void) { cout<<"x="<672. 关于缺省的构造函数,说明以下几点: 1、在定义类时,只要显式定义了一个类的构造函数,则编译器就不产生缺省的构造函数2、所有的对象在定义时,必须调用构造函数不存在没有构造函数的对象!672
  • 673. class A{ float x,y; public: A(float a,float b) { x=a; y=b; } void Print(void){ cout<
  • 674. 3、在类中,若定义了没有参数的构造函数,或各参数均有缺省值的构造函数也称为缺省的构造函数,缺省的构造函数只能有一个。4、产生对象时,系统必定要调用构造函数。所以任一对象的构造函数必须唯一。674
  • 675. class A{ float x,y; public: A(float a=10,float b=20){ x=a; y=b; } A(){ } void Print(void){ cout<
  • 676. 构造函数与new运算符 可以使用new运算符来动态地建立对象。建立时要自动调用构造函数,以便完成初始化对象的数据成员。最后返回这个动态对象的起始地址。用new运算符产生的动态对象,在不再使用这种对象时,必须用delete运算符来释放对象所占用的存储空间。 用new建立类的对象时,可以使用参数初始化动态空间。 676
  • 677. class A{ float x,y; public: A(float a, float b) { x=a;y=b; } A() { x=0; y=0; } void Print(void) { cout<Print(); pa2->Print(); delete pa1; //用delete释放空间 delete pa2; //用delete释放空间 }5 0 0677
  • 678. 析构函数 析构函数的作用与构造函数正好相反,是在对象的生命期结束时,释放系统为对象所分配的空间,即要撤消一个对象。析构函数也是类的成员函数,定义析构函数的格式为: ClassName::~ClassName( ) { ...... // 函数体; }678
  • 679. 析构 函数的特点如下: 1、析构函数是成员函数,函数体可写在类体内,也可写在类体外。2、析构函数是一个特殊的成员函数,函数名必须与类名相同,并在其前面加上字符“~”,以便和构造函数名相区别。3、析构函数不能带有任何参数,不能有返回值,不指定函数类型。679
  • 680. 在程序的执行过程中,当遇到某一对象的生存期结束时,系统自动调用析构函数,然后再收回为对象分配的存储空间。4、一个类中,只能定义一个析构函数,析构函数不允许重载。5、析构函数是在撤消对象时由系统自动调用的。680
  • 681. class A{ float x,y; public: A(float a,float b) { x=a;y=b;cout<<"调用非缺省的构造函数\n";} A() { x=0; y=0; cout<<"调用缺省的构造函数\n" ;} ~A() { cout<<"调用析构函数\n";} void Print(void) { cout<
  • 682. 在程序的执行过程中,对象如果用new运算符开辟了空间,则在类中应该定义一个析构函数,并在析构函数中使用delete删除由new分配的内存空间。因为在撤消对象时,系统自动收回为对象所分配的存储空间,而不能自动收回由new分配的动态存储空间。682
  • 683. class Str{ char *Sp; int Length; public: Str(char *string) { if(string){ Length=strlen(string); Sp=new char[Length+1]; strcpy(Sp,string); } else Sp=0; } void Show(void){ cout<
  • 684. ‘S’‘t’‘u’‘d’‘y’‘ ’‘C’‘+’‘+’‘\0’stringLength=strlen(string);Sp=new char[Length+1];Spnew开辟的空间strcpy(Sp,string);‘S’‘t’‘u’‘d’‘y’‘ ’‘C’‘+’‘+’‘\0’684
  • 685. 用new运算符为对象分配动态存储空间时,调用了构造函数,用delete删除这个空间时,调用了析构函数。当使用运算符delete删除一个由new动态产生的对象时,它首先调用该对象的析构函数,然后再释放这个对象占用的内存空间。可以用new运算符为对象分配存储空间,如:A *p; p=new A;这时必须用delete才能释放这一空间。delete p;685
  • 686. class A{ float x,y; public: A(float a, float b){ x=a; y=b; cout<<"调用了构造函数\n";} void Print(void){ cout<Print(); delete pa1; //调用析构函数 cout<<"退出main()函数\n"; }进入main()函数调用了构造函数3 5调用了析构函数退出main()函数686
  • 687. 不同存储类型的对象调用构造函数及析构函数 1、对于全局定义的对象(在函数外定义的对象),在程序开始执行时,调用构造函数;到程序结束时,调用析构函数。2、对于局部定义的对象(在函数内定义的对象),当程序执行到定义对象的地方时,调用构造函数;在退出对象的作用域时,调用析构函数。3、用static定义的局部对象,在首次到达对象的定义时调用构造函数;到程序结束时,调用析构函数687
  • 688. 4、对于用new运算符动态生成的对象,在产生对象时调用构造函数,只有使用delete运算符来释放对象时,才调用析构函数。若不使用delete来撤消动态生成的对象,程序结束时,对象仍存在,并占用相应的存储空间,即系统不能自动地调用析构函数来撤消动态生成的对象。688
  • 689. class A{ float x,y; public: A(float a, float b){x=a;y=b;cout<<"初始化自动局部对象\n";} A(){ x=0; y=0; cout<<"初始化静态局部对象\n";} A(float a){ x=a; y=0; cout<<"初始化全局对象\n"; } ~A(){ cout<<“调用析构函数”<
  • 690. 举例:建立一个类NUM,求指定数据范围内的所有素数。 如: 定义类NUM的对象test,查找范围为100~200,正确的输出结果: num=21 101 103 107 109 113 127 131 ……690
  • 691. 动态构造及析构对象数组 用new运算符来动态生成对象数组时,自动调用构造函数,而用delete运算符来释放p1所指向的对象数组占用的存储空间时,在指针变量的前面必须加上[ ], 才能将数组元素所占用的空间全部释放。否则,只释放第0个元素所占用的空间。pa1=new A[3]; ..... delete [ ]pa1; 691
  • 692. class A{ float x,y; public: A(float a=0, float b=0){x=a; y=b;cout<<"调用了构造函数\n";} void Print(void){ cout<
  • 693. 缺省的析构函数若在类的定义中没有显式地定义析构函数时,则编译器自动地产生一个缺省的析构函数,其格式为: ClassName::~ClassName() { };任何对象都必须有构造函数和析构函数,但在撤消对象时,要释放对象的数据成员用new运算符分配的动态空间时,必须显式地定义析构函数。 693
  • 694. 实现类型转换的构造函数同类型的对象可以相互赋值,相当于类中的数据成员相互赋值; 如果直接将数据赋给对象,所赋入的数据需要强制类型转换,这种转换需要调用构造函数。694
  • 695. class A{ float x,y; public: A(float a,float b) {x=a;y=b;cout<<"调用构造函数\n";} ~A() { cout<<"调用析构函数\n";} void Print(void) { cout<
  • 696. 注意:当构造函数只有一个参数时,可以用= 强制赋值。class B{ float x; public: B(float a) {x=a; cout<<"调用构造函数\n";} ~B() { cout<<"调用析构函数\n";} void Print(void) { cout<
  • 697. 完成拷贝功能的构造函数 可以在定义一个对象的时候用另一个对象为其初始化,即构造函数的参数是另一个对象的引用,这种构造函数常为完成拷贝功能的构造函数。完成拷贝功能的构造函数的一般格式为: ClassName::ClassName(ClassName &<变量名>) { ...... // 函数体完成对应数据成员的赋值 }697
  • 698. class A{ float x,y; public: A(float a=0, float b=0){x=a; y=b;} A(A &a) { x=a.x; y=a.y;} };void main(void) { A a1(1.0,2.0); A a2(a1); }形参必须是同类型对象的引用实参是同类型的对象698
  • 699. class A{ float x,y; public: A(float a=0, float b=0){x=a; y=b; cout<<"调用了构造函数\n";} A(A &a) { x=a.x;y=a.y;cout<<“调用了完成拷贝功能的构造函数\n”; } void Print(void){ cout<
  • 700. 如果没有定义完成拷贝功能的构造函数,编译器自动生成一个隐含的完成拷贝功能的构造函数,依次完成类中对应数据成员的拷贝。 A::A(A &a) { x=a.x; y=a.y; } 隐含的构造函数700
  • 701. class A{ float x,y; public: A(float a=0, float b=0){x=a; y=b; cout<<"调用了构造函数\n";} void Print(void){ cout<
  • 702. 由编译器为每个类产生的这种隐含的完成拷贝功能的构造函数,依次完成类中对应数据成员的拷贝。但是,当类中的数据成员中使用new运算符,动态地申请存储空间进行赋初值时,必须在类中显式地定义一个完成拷贝功能的构造函数,以便正确实现数据成员的复制。702
  • 703. class Str{ int Length; char *Sp; public: Str(char *string){ if(string){Length=strlen(string); Sp=new char[Length+1]; strcpy(Sp,string); } else Sp=0; } void Show(void){cout<
  • 704. 在这种情况下,必须要定义完成拷贝功能的构造函数。Str::Str(Str &s){ if(s.Sp){ Length=s.Length ; Sp=new char[Length+1]; strcpy(Sp,s.Sp); } else Sp=0; } Str s2(s1);“Study C++”s1.Sp原来s1开辟的空间“Study C++”s2.Sp拷贝函数中用new开辟的空间704
  • 705. 构造函数与对象成员对类A的对象初始化的同时还要对其成员数据类B的对象进行初始化,所以,类A的构造函数中要调用类B的构造函数。class B{ .... };class A{ int x , y; B b1,b2; };在类A中包含类B的对象705
  • 706. class A { float x,y; public: A(int a,int b) { x=a;y=b; } void Show(){ cout<< "x="<707. xyA()Show()za1.xa1.ya1.A()a1.Show()C( )Show( )a1ACa1(b, c)707
  • 708. ClassName::ClassName(args):c1(args1),..,cn(agrsn) { ...... //对其它成员的初始化 } 初始化对象成员的参数(实参)可以是表达式。,也可以仅对部分对象成员进行初始化。708
  • 709. class A { float x,y; public: A(int a,int b) { x=a;y=b; } void Show(){ cout<< "x="<710. 对对象成员的构造函数的调用顺序取决于这些对象成员在类中说明的顺序,与它们在成员初始化列表中的顺序无关。 当建立类ClassName的对象时,先调用各个对象成员的构造函数,初始化相应的对象成员,然后才执行类ClassName的构造函数,初始化类ClassName中的其它成员。析构函数的调用顺序与构造函数正好相反。710
  • 711. class A{ float x; public: A(int a){ x=a; cout<<“调用了A的构造函数\n”;} ~A(){cout<<“调用了A的析构函数\n”;} }; class B{ float y; public: B(int a){ y=a; cout<<“调用了B的构造函数\n”;} ~B(){cout<<“调用了B的析构函数\n”;} }; class C{ float z; B b1; A a1; public: C(int a,int b,int c): a1(a),b1(b){z=c;cout<<“调用了C的构造函数\n”;} ~C(){cout<<“调用了C的析构函数\n”;} }; void main(void) { C c1(1,2,3); }调用了B的构造函数调用了A的构造函数调用了C的构造函数调用了C的析构函数调用了A的析构函数调用了B的析构函数711
  • 712. 第十一章 继承和派生类712
  • 713. 继承性是面向对象程序设计中最重要的机制。这种机制提供了无限重复利用程序资源的一种途径。通过C++语言中的继承机制,可以扩充和完善旧的程序设计以适应新的需求。这样不仅可以节省程序开发的时间和资源,并且为未来程序增添了新的资源。713
  • 714. class Student { int num; char name[30]; char sex; public: void display( ) //对成员函数display的定义 {cout<<"num: "<
  • 715. class Studend1 { int num; //此行原来己有 char name[20]; //此行原来己有 char sex; //此行原来己有 int age; char addr[20]; public: void display( ) ; //此行原来己有 {cout<<"num: "<
  • 716. 利用原来定义的类Student作为基础,再加上新的内容即可,以减少重复的工作量。 C++提供的继承机制就是为了解决这个问题。 在C++中所谓“继承”就是在一个已存在的类的基础上建立一个新的类。已存在的类称为“基类(base class)”或“父类(father class)”。新建立的类称为“派生类(derived class)”或“子类(son class)”。 716
  • 717. class Student1: public Student//声明基类是Student {private: int age; //新增加的数据成员 string addr; //新增加的数据成员 public: void display_1( ) //新增加的成员函数 { cout<<"age: "<
  • 718. 类A派生类B:类A为基类,类B为派生类。AB新增加的成员数据和成员函数718
  • 719. 在C++语言中,一个派生类可以从一个基类派生,也可以从多个基类派生。从一个基类派生的继承称为单继承;从多个基类派生的继承称为多继承。719
  • 720. 通过继承机制,可以利用已有的数据类型来定义新的数据类型。所定义的新的数据类型不仅拥有新定义的成员,而且还同时拥有旧的成员。我们称已存在的用来派生新类的类为基类,又称为父类。由已存在的类派生出的新类称为派生类,又称为子类。720
  • 721. 在建立派生类的过程中,基类不会做任何改变,派生类则除了继承基类的所有可引用的成员变量和成员函数外,还可另外定义本身的成员变量和处理这些变量的函数,由于派生类可继承基类的成员变量和成员函数,因此在基类中定义好的数据和函数等的程序代码可重复使用,这样可以提高程序的可靠性。721
  • 722. 当从已有的类中派生出新的类时,可以对派生类做以下几种变化: 1、 可以继承基类的成员数据或成员函数。 2、可以增加新的成员变量。 3、可以增加新的成员函数。 4、可以重新定义已有的成员函数。 5、可以改变现有的成员属性。 在C++中有二种继承:单一继承和多重继承。当一个派生类仅由一个基类派生时,称为单一继承;而当一个派生类由二个或更多个基类所派生时,称为多重继承。722
  • 723. 类A派生类B:类A为基类,类B为派生类。AB但派生并不是简单的扩充,有可能改变基类的性质。有三种派生方式:公有派生、保护派生、私有派生。class B:public A{...}; class B:protected A{...}; class B:private A{...}; 默认的是私有派生。class B: A {...}; A为私有派生723
  • 724. 从一个基类派生一个类的一般格式为: class ClassName:BaseClassName { private: ......; //私有成员说明 public: ......; //公有成员说明 protected: ......; //保护成员说明 }派生类名基类名继承方式public: 表示公有基类 private:表示私有基类(默认) protected:表示保护基类派生类中新增加的成员724
  • 725. 公有派生 class ClassName: public BaseClassName 公有派生时,基类中所有成员在派生类中保持各个成员的访问权限。公有派生,派生类中保持基类的成员特性基类成员属性派生类中派生类外公有可以引用可以引用保护可以引用不可引用私有不可引用不可引用基类:public: 在派生类和类外可以使用 protected: 在派生类中使用 private: 不能在派生类中使用725
  • 726. x(私有)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等全部成员的初始化726
  • 727. class A { int x; protected: int y; public: int z; A(int a,int b,int c){x=a;y=b;z=c;}//基类初始化 int Getx(){return x;} //返回x int Gety(){return y;} //返回y void ShowA(){cout<< "x="<728. 私有派生 class ClassName: private BaseClassName 私有派生时,基类中公有成员和保护成员在派生类中均变为私有的,在派生类中仍可直接使用这些成员,基类中的私有成员,在派生类中不可直接使用。私有派生,派生类中基类公有和保护成员成为私有基类成员属性派生类派生类外公有可以引用不可引用保护可以引用不可引用私有不可引用不可引用基类:public: (变为私有)在派生类中使用,类外不可使用 protected: (变为私有)在派生类中使用,类外不可使用 private: 不能在派生类中和类外使用728
  • 729. x(私有)y(保护)z(公有)A( )Getx()Gety()ShowA()Ax(私私有)y(私有)z(私有)A( )Getx()Gety()ShowA()Bm(私有)n(私有)B()Show()Sum()privatex在类B新增加的成员中不能直接调用y在类B中可以调用z在类B中可以调用对类B的对象初始化即是对x,y,z,m,n等全部成员的初始化均为私有类B 外不能引用729
  • 730. class A { int x; protected: int y; public: int z; A(int a,int b,int c){x=a;y=b;z=c;}//基类初始化 int Getx(){return x;} //返回x int Gety(){return y;} //返回y void ShowA(){cout<< "x="<731. 保护派生 class ClassName: protected BaseClassName 保护派生时,基类中公有成员和保护成员在派生类中均变为保护的和私有的,在派生类中仍可直接使用这些成员,基类中的私有成员,在派生类中不可直接使用。保护派生,派生类中基类公有和保护成员降级使用基类成员属性派生类派生类外公有可以引用不可引用保护可以引用不可引用私有不可引用不可引用基类:public: (变为保护)在派生类中使用,类外不可使用 protected: (变为私有)在派生类中使用,类外不可使用 private: 不能在派生类中和类外使用731
  • 732. x(私有)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 外不能引用732
  • 733. protected 成员是一种具有血缘关系内外有别的成员。它对派生类的对象而言,是公开成员,可以访问,对血缘外部而言,与私有成员一样被隐蔽。733
  • 734. 抽象类与保护的成员函数 当定义了一个类,这个类只能用作基类来派生出新的类,而不能用这种类来定义对象时,称这种类为抽象类。当对某些特殊的对象要进行很好地封装时,需要定义抽象类。将类的构造函数或析构函数的访问权限定义为保护的时,这种类为抽象类。 734
  • 735. 当把类中的构造函数或析构函数说明为私有的时,所定义的类通常是没有任何实用意义的,一般情况下,不能用它来产生对象,也不能用它来产生派生类。 735
  • 736. x(私有)y(私有)A( )(保护)ShowA()(公有)Ax(私私有)y(私私有)A( )(保护)ShowA()Bm(私有)B()Show()public在类B中不能定义A的对象在任何时候都不能定义A的对象但可以在初始化类B的对象时初始化原类A中的成员,因为A()在类B中是可以被调用的。736
  • 737. class A { int x, y; protected: A(int a,int b){x=a;y=b;}//基类初始化 public: void ShowA(){cout<< "x="<738. 多重继承 可以用多个基类来派生一个类。ABCD多重继承是单一继承的扩展派生类中新定义的成员738
  • 739. 格式为: class 类名:类名1,..., 类名n { private: ...... ; //私有成员说明; public: ...... ; //公有成员说明; protected: ...... ; //保护的成员说明; };继承方式class D: public A, protected B, private C { ....//派生类中新增加成员 };739
  • 740. class A{ int x1,y1; public: A(int a,int b) { x1=a; y1=b; } void ShowA(void){ cout<<"A.x="<741. 初始化基类成员构造函数不能被继承,派生类的构造函数必须调用基类的构造函数来初始化基类成员基类子对象。派生类构造函数的调用顺序如下: 基类的构造函数 子对象类的构造函数 派生类的构造函数741
  • 742. class B:public A{ int y; A a1; public: B(int a, int b):A(a),a1(3){y=b;} ....... };当撤销派生类对象时,析构函数的调用正好相反。基类的构造函数 子对象类的构造函数 派生类的构造函数742
  • 743. class Base1 { int x; public: Base1(int a){ x=a;cout<<"调用基类1的构造函数!\n"; } ~Base1( ){ cout<<"调用基类1的析构函数!\n"; } }; class Base2 { int y; public: Base2(int a){ y=a;cout<<"调用基类2的构造函数!\n"; } ~Base2( ){ cout<<"调用基类2的析构函数!\n"; } }; class Derived:public Base2, public Base1{ int z; public: Derived(int a,int b):Base1(a),Base2(20) {z=b; cout<<"调用派生类的构造函数!\n";} ~Derived( ){cout<<"调用派生类的析构函数!\n";} }; void main(void) { Derived c(100,200); }调用基类2的构造函数调用基类1的构造函数调用派生类的构造函数调用派生类的析构函数调用基类1的析构函数调用基类2的析构函数先说明基类2743
  • 744. class Derived:public Base2, public Base1{ int z; Base1 b1,b2; public: Derived(int a,int b):Base1(a),Base2(20), b1(200),b2(a+b) {z=b; cout<<"调用派生类的构造函数!\n";} ~Derived( ){cout<<"调用派生类的析构函数!\n";} }; void main(void) { Derived c(100,200); }基类子对象基类成员构造基类子对象构造基类成员构造用基类名, 基类子对象构造用对象名744
  • 745. class Base1 { int x; public: Base1(int a){ x=a;cout<<"调用基类1的构造函数!\n"; } ~Base1( ){ cout<<"调用基类1的析构函数!\n"; } }; class Base2 { int y; public: Base2(int a){ y=a;cout<<"调用基类2的构造函数!\n"; } ~Base2( ){ cout<<"调用基类2的析构函数!\n"; } }; class Derived:public Base2, public Base1{ int z; Base1 b1,b2; public: Derived(int a,int b):Base1(a),Base2(20), b1(200),b2(a+b) {z=b; cout<<"调用派生类的构造函数!\n";} ~Derived( ){cout<<"调用派生类的析构函数!\n";} }; void main(void) { Derived c(100,200); }745
  • 746. 调用基类2的构造函数调用基类1的构造函数调用派生类的构造函数调用派生类的析构函数调用基类1的析构函数调用基类2的析构函数调用基类1的构造函数调用基类1的构造函数调用基类1的析构函数调用基类1的析构函数说明基类1的对象b1,b2746
  • 747. class Base1 { int x; public: Base1(int a); ~Base1( ); }; class Base2 { int y; public: Base2(int a); ~Base2( ); }; class Derived:public Base2, public Base1{ int z; Base1 b1,b2; public: Derived(int a,int b); ~Derived( ); };xBase1()~Base1()Base1yBase2()~Base2()Base2DerivedxBase1()~Base1()yBase2()~Base2()xBase1()~Base1()b1xBase1()~Base1()b2zDerived()~Derived747
  • 748. 冲突ABCxA()xB()xC()DA()xB()xC()xD()dD v;v.x=5;public派生类对象产生了冲突A::v.x=5;用类作用符限定748
  • 749. class A{ public: int x; void Show(){cout <<"x="<750. 支配规则AxA()DpublicxA()xD()基类成员派生类新增成员D v;v.x=5;当派生类中新增加的数据或函数与基类中原有的同名时,若不加限制,则优先调用派生类中的成员。5750
  • 751. class A{ public: int x; void Show(){cout <<"x="<752. class A{ public: int x; A(int a=0) { x=a;} }; class B{ public: int y; B(int a=0) { y=a;} }; class C:public A{ int z; B b1; A a1; public: C(int a,int b,int m):A(a),b1(b),a1(a+b){ z=m; } void Show( ){ cout<<"x="<753. 基类与对象成员 任一基类在派生类中只能继承一次,否则,会造成成员名的冲突 若在派生类中,确实要有二个以上基类的成员,则可用基类的二个对象作为派生类的成员。把一个类作为派生类的基类或把一个类的对象作为一个类的成员,在使用上是有区别的:在派生类中可直接使用基类的成员(访问权限允许的话),但要使用对象成员的成员时,必须在对象名后加上成员运算符“.”和成员名。753
  • 754. 在平面上作两个点,连一直线,求直线的长度和直线中点的坐标。 基类为Dot,有两个公有数据成员,即平面上的坐标(x,y),同时有构造函数及打印函数。 派生类为Line,有两个基类Dot对象,分别存放两点的坐标,同时,从基类继承了一个Dot数据,存放直线中点的坐标。754
  • 755. xyDot(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对象空间从基类继承基类对象755
  • 756. class Dot{ public: float x,y; Dot(float a=0,float b=0){ x=a; y=b;} void Show(void){cout<<"x="<>a>>b; Dot dot1(a,b);//调用Dot的构造函数 cout<<"Input Dot2: \n"; cin>>a>>b; Dot dot2(a,b); Line line(dot1,dot2); line.Showl();}用坐标初始化Dot对象在Line中新说明的成员对成员初始化x,y是继承基类的成员打印坐标756
  • 757. 赋值兼容规则基类对象派生类对象 相互之间能否赋值? 可以将派生类对象的值赋给基类对象。反之不行Base b;Derive d; b = d; 只是将从基类继承来的成员赋值。757
  • 758. Show()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的对象空间从基类继承基类对象Dot dot; Line line; dot=line; line=dot;非法758
  • 759. 可以将一个派生类对象的地址赋给基类的指针变量。基类对象派生类对象Base b;Derive d;Base *basep;basepbasep=&b;basepbasep = &dbasep只能引用从基类继承来的成员。基类指针派生类对象基类对象759
  • 760. 派生类对象可以初始化基类的引用。Derive d;Base basei=&d;基类对象派生类对象Base b;Derive d;别名baseibasei只能引用从基类继承来的成员。基类引用派生类对象760
  • 761. class A{ public: int x; A(int a=0) { x=a;} }; class B{ public: int y; B(int a=0) { y=a;} }; class C:public A,public B{ int z; public: C(int a,int b,int m): A(a), B(b) { z=m; } void Show( ){ cout<<"x="<762. 虚基类 类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
  • 763. 这种同一个公共的基类在派生类中产生多个拷贝,不仅多占用了存储空间,而且可能会造成多个拷贝中的数据不一致 和模糊的引用。D d; d.x=10; //模糊引用dxD()xA()zC()yB()A()xD类类A拷贝B类C类类A拷贝763
  • 764. class A{ public: int x; A(int a=0) { x=a;} }; class B:public A{ public: int y; B(int a=0,int b=0):A(a) { y=b;} }; class C:public A{ public: int z; C(int a,int c):A(a){ z=c; } }; class D:public B,public C{ public: int dx; D(int a1,int b,int c,int d,int a2):B(a1,b),C(a2,c) { dx=d;} }; void main(void) { D d1(10,20,30,40,50); cout<
  • 765. 在多重派生的过程中,若使公共基类在派生类中只有一个拷贝,则可将这种基类说明为虚基类。class B:public virtual A{ public: int y; B(int a=0, int b=0 ):A(b) { y=a;} };在派生类的定义中,只要在基类的类名前加上关键字virtual,就可以将基类说明为虚基类。765
  • 766. xA()xA()yB()xA()zC()A类B类C类xA()yB()zC()dxD()D类一份拷贝,在D( )的构造函数中直接调用A()由虚基类派生出的对象初始化时,直接调用虚基类的构造函数。因此,若将一个类定义为虚基类,则一定有正确的构造函数可供所有派生类调用。766
  • 767. class A{ public: int x; A(int a=0) { x=a;} }; class B:public virtual A{ public: int y; B(int a=0,int b=0): A(a) {y=b;} }; class C:public virtual A{ public: int z; C(int a=0,int c=0):A(a){z=c; } }; class D:public B,public C{ public: int dx; D(int a1,int b,int c,int d,int a2):B(a1,b),C(a2,c) { dx=d;} };void main(void) { D d1(10,20,30,40,50); cout<
  • 768. 再次强调,用虚基类进行多重派生时,若虚基类没有缺省的构造函数,则在每一个派生类的构造函数中都必须有对虚基类构造函数的调用 (且首先调用)。768
  • 769. 第十二章 类的其它特性 769
  • 770. 友元函数类中私有和保护的成员在类外不能被访问。友元函数是一种定义在类外部的普通函数,其特点是能够访问类中私有成员和保护成员,即类的访问权限的限制对其不起作用。770
  • 771. 友元函数需要在类体内进行说明,在前面加上关键字friend。 一般格式为: friend FuncName();friend float Volume(A &a);关键字返回值类型函数名函数参数771
  • 772. 友元函数不是成员函数,用法也与普通的函数完全一致,只不过它能访问类中所有的数据。友元函数破坏了类的封装性和隐蔽性,使得非成员函数可以访问类的私有成员。一个类的友元可以自由地用该类中的所有成员。772
  • 773. class A{ float x,y; public: A(float a, float b){ x=a; y=b;} float Sum(){ return x+y; } friend float Sum(A &a){ return a.x+a.y; } }; void main(void) { A t1(4,5),t2(10,20); cout<
  • 774. 有关友元函数的使用,说明如下:友元函数不是类的成员函数友元函数近似于普通的函数,它不带有this指针,因此必须将对象名或对象的引用作为友元函数的参数,这样才能访问到对象的成员。774
  • 775. 友元函数与一般函数的不同点在于: 友元函数必须在类的定义中说明,其函数体可在类内定义,也可在类外定义; 它可以访问该类中的所有成员(公有的、私有的和保护的),而一般函数只能访问类中的公有成员。775
  • 776. class A{ float x,y; public: A(float a, float b){ x=a; y=b;} float Getx(){ return x; } float Gety(){ return y; } float Sum(){ return x+y; } friend float Sum(A &); }; float Sumxy(A &a){ return a.Getx()+a.Gety(); } float Sum(A &a){ return a.x+a.y; } void main(void) { A t1(1,2),t2(10,20), t3(100,200); cout<
  • 777. 友元函数不受类中访问权限关键字的限制,可以把它放在类的私有部分,放在类的公有部分或放在类的保护部分,其作用都是一样的。换言之,在类中对友元函数指定访问权限是不起作用的。友元函数的作用域与一般函数的作用域相同。谨慎使用友元函数 通常使用友元函数来取对象中的数据成员值,而不修改对象中的成员值,则肯定是安全的。777
  • 778. 大多数情况是友元函数是某个类的成员函数,即A类中的某个成员函数是B类中的友元函数,这个成员函数可以直接访问B类中的私有数据。这就实现了类与类之间的沟通。注意:一个类的成员函数作为另一个类的友元函数时,应先定义友元函数所在的类。class A{ ... void fun( B &); };class B{ ... friend void fun( B &); };既是类A的成员函数又是类B的友元函数778
  • 779. class B ; //先定义类A,则首先对类B作引用性说明 class A{ ...... //类A的成员定义 public: void fun( B & );//函数的原型说明 }; class B{ ...... friend void A::fun( B & );//定义友元函数 }; void A::fun ( B &b) //函数的完整定义 { ...... //函数体的定义 }类A中的成员函数fun()是类B的友元函数。即在fun()中可以直接引用类B的私有成员。779
  • 780. class B; //必须在此进行引用性说明, class A{ float x,y; public: A(float a, float b){ x=a; y=b;} float Sum(B &); //说明友元函数的函数原型,是类A的一成员函数 }; class B{ float m,n; public: B(float a,float b){ m=a;n=b; } friend float A::Sum(B &);//说明类A的成员函数是类B的友元函数 } float A::Sum( B &b) //定义该友元函数 { x=b.m+b.n; y=b.m-b.n; } void main(void) { A a1(3,5); B b1(10,20); a1.Sum(b1); //调用该函数,因是类A的成员函数,故用类A的对象调用 }a1.x=30 a1.y=-10直接引用类B的私有成员类A中有一个函数可以直接引用类B的私有成员780
  • 781. 友元类class A{ ..... friend class B; }class B{ ..... }类B是类A的友元类B可以自由使用类A中的成员对于类B而言,类A是透明的类B必须通过类A的对象使用类A的成员781
  • 782. const float PI =3.1415926; class A{ float r ; float h; public: A(float a,float b){r=a; h=b;} float Getr(){return r;} float Geth(){return h;} friend class B;//定义类B为类A的友元 }; class B { int number; public: B(int n=1) {number=n;} void Show(A &a) { cout<
  • 783. 不管是按哪一种方式派生,基类的私有成员在派生类中都是不可见的。 如果在一个派生类中要访问基类中的私有成员,可以将这个派生类声明为基类的友元。class Base { friend class Derive; ..... }class Derive { ..... }直接使用Base中的私有成员783
  • 784. #include class M { friend class N; //N为M的友元,可以直接使用M中的私有成员 private: int i , j; void show(void){cout<<"i="<785. 基类对象 M派生类对象 Nx(私有)Show( )(私有)x(私私有)Show( )(私私有)y(公有)Showy( )(公有)showy( ){ show(); cout<
  • 786. 虚函数多态性:调用同一个函数名,可以根据需要但实现不同的功能。多态性是面向对象的程序设计的关键技术。编译时的多态性(函数重载) 运行时的多态性(虚函数)多态性运行时的多态性是指在程序执行之前,根据函数名和参数无法确定应该调用哪一个函数,必须在程序的执行过程中,根据具体的执行情况来动态地确定786
  • 787. 可以将一个派生类对象的地址赋给基类的指针变量。基类对象派生类对象Base b;Derive d;Base *basep;basepbasep=&b;basepbasep = &d;basep只能引用从基类继承来的成员。xShow()xShow()yShow()basep ->Show();basep->Show()基类指针派生类对象基类对象787
  • 788. class Point{ float x,y; public: Point(){} Point(float i,float j){ x=i; y=j; } float area(void) { return 0.0; } }; const float Pi=3.14159; class Circle:public Point{ //类Point的派生类 float radius; public: Circle(float r){ radius=r; } float area(void) { return Pi*radius*radius; } }; void main(void) { Point *pp; //基类指针,可以将派生类对象的地址赋给基类指针 Circle c(5.4321); pp=&c; cout<area ()<
  • 789. 基类对象派生类对象Base b;Derive d;basepbasepxShow()xShow()yShow()basep->Show()Base *basep;basep=&b;basep = &d;basep ->Show();即指向派生类新增的成员函数需要将基类中的Show()说明为虚函数789
  • 790. 若要访问派生类中相同名字的函数,必须将基类中的同名函数定义为虚函数,这样,将不同的派生类对象的地址赋给基类的指针变量后,就可以动态地根据这种赋值语句调用不同类中的函数。790
  • 791. class Point{ float x,y; public: Point(){} Point(float i,float j){ x=i; y=j; } virtual float area(void) { return 0.0; } }; const float Pi=3.14159; class Circle:public Point{ //类Point的派生类 float radius; public: Circle(float r){ radius=r; } float area(void) { return Pi*radius*radius;} }; void main(void) { Point *pp; //基类指针,可以将派生类对象的地址赋给基类指针 Circle c(5.4321); pp=&c; cout<area ()<
  • 792. 虚函数的定义和使用 可以在程序运行时通过调用相同的函数名而实现不同功能的函数称为虚函数。定义格式为: virtual FuncName();一旦把基类的成员函数定义为虚函数,由基类所派生出来的所有派生类中,该函数均保持虚函数的特性。 在派生类中重新定义基类中的虚函数时,可以不用关键字virtual来修饰这个成员函数 。792
  • 793. 虚函数是用关键字virtual修饰的某基类中的protected或public成员函数。它可以在派生类中重新定义,以形成不同版本。只有在程序的执行过程中,依据指针具体指向哪个类对象,或依据引用哪个类对象,才能确定激活哪一个版本,实现动态聚束。793
  • 794. class A{ protected: int x; public: A(){x =1000;} virtual void print(){ cout <<“x=”<print();//调用类A的虚函数 pa=&b; pa->print();//调用类B的虚函数 pa=&c; pa->print();}//调用类C的虚函数794
  • 795. class Base { public : virtual int Set(int a, int b) { ..... } .... };class Derive:public Base{ public : int Set(int x, int y) { ..... } ..... };class Base { public : virtual int Set(int a, int b) { ..... } .... };class Derive:public Base{ public : int Set(int x, int y=0) { ..... } ..... };int Set(int ,int )是虚函数两个Set()函数参数不一致,是重载,不是虚函数795
  • 796. 关于虚函数,说明以下几点: 1、当在基类中把成员函数定义为虚函数后,在其派生类中定义的虚函数必须与基类中的虚函数同名,参数的类型、顺序、参数的个数必须一一对应,函数的返回的类型也相同。若函数名相同,但参数的个数不同或者参数的类型不同时,则属于函数的重载,而不是虚函数。若函数名不同,显然这是不同的成员函数。796
  • 797. 2、实现这种动态的多态性时,必须使用基类类型的指针变量,并使该指针指向不同的派生类对象,并通过调用指针所指向的虚函数才能实现动态的多态性。xShow()xShow()yShow()xShow()zShow()类A类B类CShow()定义为虚函数类B与类C均为类A的公有派生。A *p; B b; C c; p=&b ; p->Show();p=&c ; p->Show();即在程序运行时,通过赋值语句实现多态性797
  • 798. 3、虚函数必须是类的一个成员函数,不能是友元函数,也不能是静态的成员函数。4、在派生类中没有重新定义虚函数时,与一般的成员函数一样,当调用这种派生类对象的虚函数时,则调用其基类中的虚函数。5、可把析构函数定义为虚函数,但是,不能将构造函数定义为虚函数。798
  • 799. 6、虚函数与一般的成员函数相比较,调用时的执行速度要慢一些。为了实现多态性,在每一个派生类中均要保存相应虚函数的入口地址表,函数的调用机制也是间接实现的。因此,除了要编写一些通用的程序,并一定要使用虚函数才能完成其功能要求外,通常不必使用虚函数。7、一个函数如果被定义成虚函数,则不管经历多少次派生,仍将保持其虚特性,以实现“一个接口,多个形态”。799
  • 800. 虚函数的访问 用基指针访问与用对象名访问 用基指针访问虚函数时,指向其实际派生类对象重新定义的函数。实现动态聚束。 通过一个对象名访问时,只能静态聚束。即由编译器在编译的时候决定调用哪个函数。800
  • 801. class Point{ float x,y; public: Point(){} Point(float i,float j){ x=i; y=j; } virtual float area(void) { return 0.0; }//声明为虚函数 }; const float Pi=3.14159; class Circle:public Point{ //类Point的派生类 float radius; public: Circle(float r){ radius=r; } float area(void) { return Pi*radius*radius;}//虚函数再定义 }; void main(void) { Point *pp; //基类指针,可以将派生类对象的地址赋给基类指针 Circle c(5.4321); cout<
  • 802. class base0{ public: void v(void){ cout<<"base0\n"; } }; class base1:public base0{ public: virtual void v(void){ cout<<"base1\n"; } }; class A1:public base1{ public: void v(){ cout<<"A1\n"; } }; class A2:public A1{ public: void v(void){ cout<<"A2\n"; } }; class B1:private base1{ public: void v(void){ cout<<"B1\n"; } }; class B2:public B1{ public: void v(void){ cout<<"B2\n"; } };void main(void) { base0 *pb; A1 a1; (pb=&a1)->v(); A2 a2; (pb=&a2)->v(); B1 b1; (pb=&b1)->v(); B2 b2; (pb=&b2)->v(); }base0 base0私有派生,在类外不能调用基类函数802
  • 803. class base0{ public: void v(void){ cout<<"base0\n"; } }; class base1:public base0{ public: virtual void v(void){ cout<<"base1\n"; } }; class A1:public base1{ public: void v(){ cout<<"A1\n"; } }; class A2:public A1{ public: void v(void){ cout<<"A2\n"; } }; class B1:private base1{ public: void v(void){ cout<<"B1\n"; } }; class B2:public B1{ public: void v(void){ cout<<"B2\n"; } };void main(void) { base1 *pb; A1 a1; (pb=&a1)->v(); A2 a2; (pb=&a2)->v(); }A1 A2803
  • 804. 纯虚函数 在基类中不对虚函数给出有意义的实现,它只是在派生类中有具体的意义。这时基类中的虚函数只是一个入口,具体的目的地由不同的派生类中的对象决定。这个虚函数称为纯虚函数。class <基类名> { virtual <类型><函数名>(<参数表>)=0; ...... };804
  • 805. class A{ protected: int x; public: A(){x =1000;} virtual void print()=0; //定义纯虚函数 }; class B:public A{ //派生类 private: int y; public: B(){ y=2000;} void print(){cout <<“y=”<print(); pa=&c; pa->print(); A a; pa=&a; pa->print( ); }y=2000 z=3000抽象类不能定义抽象类的对象805
  • 806. 1、在定义纯虚函数时,不能定义虚函数的实现部分。 2、把函数名赋于0,本质上是将指向函数体的指针值赋为初值0。与定义空函数不一样,空函数的函数体为空,即调用该函数时,不执行任何动作。在没有重新定义这种纯虚函数之前,是不能调用这种函数的。806
  • 807. 3、把至少包含一个纯虚函数的类,称为抽象类。这种类只能作为派生类的基类,不能用来说明这种类的对象。 其理由是明显的:因为虚函数没有实现部分,所以不能产生对象。但可以定义指向抽象类的指针,即指向这种基类的指针。当用这种基类指针指向其派生类的对象时,必须在派生类中重载纯虚函数,否则会产生程序的运行错误。807
  • 808. 4、在以抽象类作为基类的派生类中必须有纯虚函数的实现部分,即必须有重载纯虚函数的函数体。否则,这样的派生类也是不能产生对象的。 综上所述,可把纯虚函数归结为:抽象类的唯一用途是为派生类提供基类,纯虚函数的作用是作为派生类中的成员函数的基础,并实现动态多态性。808
  • 809. 虚基类 多基派生中的多条路径具有公共基类时,在这条路径的汇合处就会因对公共基类产生多个拷贝而产生同名函数调用的二义性。 解决这个问题的办法就是把公共基类定义为虚基类,使由它派生的多条路径的汇聚处只产生一个拷贝。class Base{ }; class A : public Base{ }; class B: public Base{ }; class C: public A, public B{ };类C中继承了两个类Base,即有两个类Base的实现部分,在调用时产生了二义性。809
  • 810. 用虚基类进行多重派生时,若虚基类没有缺省的构造函数,则在每一个派生类的构造函数中都必须有对虚基类构造函数的调用 (且首先调用)。由虚基类派生出的对象初始化时,直接调用虚基类的构造函数。因此,若将一个类定义为虚基类,则一定有正确的构造函数可供所有派生类调用。810
  • 811. class base{ public: virtual void a(){ cout<<"a() in base\n";} virtual void b(){ cout<<"b() in base\n";} virtual void c(){ cout<<"c() in base\n";} virtual void d(){ cout<<"d() in base\n";} virtual void e(){ cout<<"e() in base\n";} virtual void f(){ cout<<"f() in base\n";} }; class A:public base{ public: virtual void a(){ cout<<"a() in A\n";} virtual void b(){ cout<<"b() in A\n";} virtual void f(){ cout<<"f() in A\n";} }; class B:public base{ public: virtual void a(){ cout<<"a() in B\n";} virtual void b(){ cout<<"b() in B\n";} virtual void c(){ cout<<"c() in B\n";} };class C:public A,public B{ public: virtual void a(){ cout<<"a() in C\n";} virtual void d(){ cout<<"d() in C\n";} }; void main(void) { C cc; base *pbase=&cc;//错误 A *pa=&cc; pa->a(); pa->b(); pa->c(); pa->d(); pa->e(); pa->f(); }将类C的地址赋值时产生歧义811
  • 812. a( )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( )b( )c( )d( )e( )f( )a( )c( )baseABCa( )d( )AB812
  • 813. class base{ public: virtual void a(){ cout<<"a() in base\n";} virtual void b(){ cout<<"b() in base\n";} virtual void c(){ cout<<"c() in base\n";} virtual void d(){ cout<<"d() in base\n";} virtual void e(){ cout<<"e() in base\n";} virtual void f(){ cout<<"f() in base\n";} }; class A:public base{ public: virtual void a(){ cout<<"a() in A\n";} virtual void b(){ cout<<"b() in A\n";} virtual void f(){ cout<<"f() in A\n";} }; class B:public base{ public: virtual void a(){ cout<<"a() in B\n";} virtual void b(){ cout<<"b() in B\n";} virtual void c(){ cout<<"c() in B\n";} };class C:public A,public B{ public: virtual void a(){ cout<<"a() in C\n";} virtual void d(){ cout<<"d() in C\n";} }; void main(void) { C cc; base *pbase=&cc;//错误 A *pa=&cc; pa->a(); pa->b(); pa->c(); pa->d(); pa->e(); pa->f(); }将类C的地址赋值时产生歧义类C中有两个base,只有一个Aa() in Cb() in Ac() in based() in Ce() in basef() in A为避免这种情况,将base定义为虚基类。813
  • 814. class base{ public: virtual void a(){ cout<<"a() in base\n";} virtual void b(){ cout<<"b() in base\n";} virtual void c(){ cout<<"c() in base\n";} virtual void d(){ cout<<"d() in base\n";} virtual void e(){ cout<<"e() in base\n";} virtual void f(){ cout<<"f() in base\n";} }; class A:virtual public base{ public: virtual void a(){ cout<<"a() in A\n";} virtual void b(){ cout<<"b() in A\n";} virtual void f(){ cout<<"f() in A\n";} }; class B:virtual public base{ public: virtual void a(){ cout<<"a() in B\n";} virtual void c(){ cout<<"c() in B\n";} };class C:public A,public B{ public: virtual void a(){ cout<<"a() in C\n";} virtual void d(){ cout<<"d() in C\n";} }; void main(void) { C cc; base *pa=&cc; pa->a(); pa->b(); pa->c(); pa->d(); pa->e(); pa->f(); }814
  • 815. a( )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( )AB815
  • 816. class base{ public: virtual void a(){ cout<<"a() in base\n";} virtual void b(){ cout<<"b() in base\n";} virtual void c(){ cout<<"c() in base\n";} virtual void d(){ cout<<"d() in base\n";} virtual void e(){ cout<<"e() in base\n";} virtual void f(){ cout<<"f() in base\n";} }; class A:virtual public base{ public: virtual void a(){ cout<<"a() in A\n";} virtual void b(){ cout<<"b() in A\n";} virtual void f(){ cout<<"f() in A\n";} }; class B:virtual public base{ public: virtual void a(){ cout<<"a() in B\n";} virtual void c(){ cout<<"c() in B\n";} };class C:public A,public B{ public: virtual void a(){ cout<<"a() in C\n";} virtual void d(){ cout<<"d() in C\n";} }; void main(void) { C cc; base *pa=&cc; pa->a(); pa->b(); pa->c(); pa->d(); pa->e(); pa->f(); }类C中只有一个basea() in Cb() in Ac() in Bd() in Ce() in basef() in A816
  • 817. class base{ public: void a(){cout<<"a() in base\n";} void b(){cout<<"b() in base\n";} void c(){ cout<<"c() in base\n";} void d(){cout<<"d() in base\n";} void e(){ cout<<"e() in base\n";} void f(){ cout<<"f() in base\n";} }; class A:virtual public base{ public: void a(){cout<<"a() in A\n";} void b(){cout<<"b() in A\n";} void f(){ cout<<"f() in A\n";} }; class B:virtual public base{ public: void a(){cout<<"a() in B\n";} void c(){ cout<<"c() in B\n";} };class C:public A,public B{ public: void a(){ cout<<"a() in C\n";} void d(){ cout<<"d() in C\n";} }; void main(void) { C cc; base *pa=&cc; pa->a(); pa->b(); pa->c(); pa->d(); pa->e(); pa->f(); }类C中只有一个basea() in baseb() in basec() in based() in basee() in basef() in base817
  • 818. 下面程序的输出是 。 class A{ protected:int x; public:A(){x =1000;} virtual void p(){cout <<"x="<p(); pa=&c;pa->p();}818
  • 819. 通常,每当说明一个对象时,把该类中的有关成员数据拷贝到该对象中,即同一类的不同对象,其成员数据之间是互相独立的。静态成员 class A{ int x,y; public: void Setxy(int a, int b) { x=a; y=b;} }; A a1, 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
  • 820. 当我们将类的某一个数据成员的存储类型指定为静态类型时,则由该类所产生的所有对象,其静态成员均共享一个存储空间,这个空间是在编译的时候分配的。换言之,在说明对象时,并不为静态类型的成员分配空间。 在类定义中,用关键字static修饰的数据成员称为静态数据成员。class A{ int x,y; static int z; public: void Setxy(int a, int b) { x=a; y=b;} }; A a1, a2;a1.xa1.ya2.xa2.yza1. za2. z不同对象,同一空间820
  • 821. 有关静态数据成员的使用,说明以下几点: 1、类的静态数据成员是静态分配存储空间的,而其它成员是动态分配存储空间的(全局变量除外)。当类中没有定义静态数据成员时,在程序执行期间遇到说明类的对象时,才为对象的所有成员依次分配存储空间,这种存储空间的分配是动态的;而当类中定义了静态数据成员时,在编译时,就要为类的静态数据成员分配存储空间。821
  • 822. 2、必须在文件作用域中,对静态数据成员作一次且只能作一次定义性说明。因为静态数据成员在定义性说明时已分配了存储空间,所以通过静态数据成员名前加上类名和作用域运算符,可直接引用静态数据成员。在C++中,静态变量缺省的初值为0,所以静态数据成员总有唯一的初值。当然,在对静态数据成员作定义性的说明时,也可以指定一个初值。822
  • 823. class A{ int i,j; static int x,y;//定义静态成员 public: A(int a=0,int b=0,int c=0, int d=0){ i=a;j=b;x=c;y=d; } void Show(){cout << "i="<
  • 824. class A{ int i,j; public: static int x; public: A(int a=0,int b=0,int c=0){ i=a ; j=b ; x=c; } void Show(){ cout << "i="<
  • 825. 3、静态数据成员具有全局变量和局部变量的一些特性。静态数据成员与全局变量一样都是静态分配存储空间的,但全局变量在程序中的任何位置都可以访问它,而静态数据成员受到访问权限的约束。必须是public权限时,才可能在类外进行访问。4、为了保持静态数据成员取值的一致性,通常在构造函数中不给静态数据成员置初值,而是在对静态数据成员的定义性说明时指定初值。 825
  • 826. class A{ int i; static int count; public: A(int a=0) { i=a; count++; cout <<"Number of Objects="<
  • 827. 静态成员函数 可以将类的成员函数定义为静态的成员函数。即使用关键字static来修饰成员函数 。class A { float x, y; public : A( ){ } static void sum(void) { ..... } };827
  • 828. 对静态成员函数的用法说明以下几点: 1、与静态数据成员一样,在类外的程序代码中,通过类名加上作用域操作符,可直接调用静态成员函数。 2、静态成员函数只能直接使用本类的静态数据成员或静态成员函数,但不能直接使用非静态的数据成员 (可以引用使用)。这是因为静态成员函数可被其它程序代码直接调用,所以,它不包含对象地址的this指针。 828
  • 829. class Tc { private:int A; static int B;//静态数据成员 public:Tc(int a){A=a; B+=a;} static void display(Tc c)//Tc的对象为形参 { cout<<"A="<
  • 830. 3、静态成员函数的实现部分在类定义之外定义时,其前面不能加修饰词static。这是由于关键字static不是数据类型的组成部分,因此,在类外定义静态成员函数的实现部分时,不能使用这个关键字 4、不能把静态成员函数定义为虚函数。静态成员函数也是在编译时分配存储空间,所以在程序的执行过程中不能提供多态性。 5、可将静态成员函数定义为内联的(inline),其定义方法与非静态成员函数完全相同。830
  • 831. class Tc { private:int A; static int B;//静态数据成员 public:Tc(int a){A=a; B+=a;} static void display(Tc c);//Tc的对象为形参 }; void Tc::display(Tc c)//不用static修饰 { cout<<"A="<
  • 832. 9. 下述程序的输出结果是________。 #include class Sample{ public: Sample(){ cout<<"Constructor"<833. const 、volatile对象和成员函数 用const修饰的对象,只能访问该类中用const修饰的成员函数,而其它的成员函数是不能访问的。用volatile修饰的对象,只能访问该类中用volatile修饰的成员函数,不能访问其它的成员函数。 当希望成员函数只能引用成员数据的值,而不允许成员函数修改数据成员的值时,可用关键词const修饰成员函数。一旦在用const修饰的成员函数中出现修改成员数据的值时,将导致编译错误。 833
  • 834. const和volatile成员函数 在成员函数的前面加上关键字const,则表示这函数返回一个常量,其值不可改变。 const成员函数则是指将const放在参数表之后,函数体之前,其一般格式为: FuncName() const ; 其语义是指明这函数的this指针所指向的对象是一个常量,即规定了const成员函数不能修改对象的数据成员,在函数体内只能调用const成员函数,不能调用其它的成员函数。834
  • 835. 用volatile修饰一个成员函数时,其一般格式为: FuncName() volatile; 其语义是指明成员函数具有一个易变的this指针,调用这个函数时,编译程序把属于此类的所有的数据成员都看作是易变的变量,编译器不要对这函数作优化工作。 由于关键字const和volatile是属于数据类型的组成部分,因此,若在类定义之外定义const成员函数或volatile成员函数时,则必须用这二个关键字修饰,否则编译器认为是重载函数,而不是定义const成员函数或volatile成员函数。835
  • 836. 指向类成员的指针 在C++中可以定义一种特殊的指针,它指向类中的成员函数或类中的数据成员。并可通过这样的指针来使用类中的数据成员或调用类中的成员函数。 指向类中数据成员的指针变量 定义一个指向类中数据成员的指针变量的一般格式为: ClassName:: *PointName; 其中type是指针PointName所指向数据的类型,它必须是类ClassName中某一数据成员的类型 836
  • 837. 1、指向类中数据成员的指针变量不是类中的成员,这种指针变量应在类外定义。 2、与指向类中数据成员的指针变量同类型的任一数据成员,可将其地址赋给这种指针变量,赋值的一般格式为: PointName = &ClassName::member; 这种赋值,是取该成员相对于该类的所在对象中的偏移量,即相对地址(距离开始位置的字节数) 如:mptr = &S::y; 表示将数据成员y的相对起始地址赋给指针变量mptr。 3、用这种指针访问数据成员时,必须指明是使用那一个对象的数据成员。当与对象结合使用时,其用法为: ObjectName.* PointName4、由于这种指针变量并不是类的成员,所以使用它只能访问对象的公有数据成员。若要访问对象的私有数据成员,必须通过成员函数来实现。837
  • 838. 指向类中成员函数的指针变量 定义一个指向类中成员函数的指针变量的一般格式为: (ClassName:: *PointName)(); 其中PointName是指向类中成员函数的指针变量;ClassName是已定义的类名;type是通过函数指针PointName调用类中的成员函数时所返回值的数据类型,它必须与类ClassName中某一成员函数的返回值的类型相一致;是函数的形式参数表。 在使用这种指向成员函数的指针前,应先对其赋值 PointName= ClassName::FuncName; 同样地,只是将指定成员函数的相对地址赋给指向成员函数的指针。838
  • 839. 在调用时,用(对象名.指针)( )的形式。 比较 :int max( int a,int b) { return (a>b?a:b); } 若有:int (*f)( int, int ); f=max; 则调用时 (*f)(x,y); 所以:(s1.*mptr1)( ); (s1.*mptr2)(100); 或: (ps->*mptr1)( ); (ps-*mptr2)(100); 839
  • 840. 对指向成员函数的指针变量的使用方法说明以下几点: 1、指向类中成员函数的指针变量不是类中的成员,这种指针变量应在类外定义。 2、不能将任一成员函数的地址赋给指向成员函数的指针变量,只有成员函数的参数个数、参数类型、参数的顺序和函数的类型均与这种指针变量相同时,才能将成员函数的指针赋给这种变量。 3、使用这种指针变量来调用成员函数时,必须指明调用那一个对象的成员函数,这种指针变量是不能单独使用的。用对象名引用。 4、由于这种指针变量不是类的成员,所以用它只能调用公有的成员函数。若要访问类中的私有成员函数,必须通过类中的其它的公有成员函数。840
  • 841. 5、当一个成员函数的指针指向一个虚函数,且通过指向对象的基类指针或对象的引用来访问该成员函数指针时,同样地产生运行时的多态性。 6、当用这种指针指向静态的成员函数时,可直接使用类名而不要列举对象名。这是由静态成员函数的特性所确定的。841
  • 842. 第十三章 运算符重载842
  • 843. 函数的重载所谓函数的重载是指完成不同功能的函数可以具有相同的函数名。 C++的编译器是根据函数的实参来确定应该调用哪一个函数的。 int fun(int a, int b) { return a+b; }int fun (int a) { return a*a; }void main(void) { cout<
  • 844. 1、定义的重载函数必须具有不同的参数个数,或不同的参数类型。只有这样编译系统才有可能根据不同的参数去调用不同的重载函数。2、仅返回值不同时,不能定义为重载函数。 844
  • 845. int sum,a=3,b=2;(int)=(int) + (int)sum=a+b; float add, x=3.2, y=2.5;(float)=(float) + (float)add=x+y; char str[4], c1[2]="a", c2[2]="b";(char *)=(char *) + (char *)str=c1+c2; 编译系统中的运算符“+”本身不能做这种运算,若使上式可以运算,必须重新定义“+”运算符,这种重新定义的过程成为运算符的重载。系统自动识别数据类型845
  • 846. class A { float x,y; public: A(float a=0, float b=0){ x=a; y=b; } } void main(void) { A a(2,3), b(3,4), c; c=a+b; }两对象不能使用+,必须重新定义+运算符重载就是赋予已有的运算符多重含义。C++通过重新定义运算符,使它能够用于特定类的对象执行特定的功能846
  • 847. 运算符的重载从另一个方面体现了OOP技术的多态性,且同一运算符根据不同的运算对象可以完成不同的操作。 为了重载运算符,必须定义一个函数,并告诉编译器,遇到这个重载运算符就调用该函数,由这个函数来完成该运算符应该完成的操作。这种函数称为运算符重载函数,它通常是类的成员函数或者是友元函数。运算符的操作数通常也应该是类的对象。847
  • 848. 重载为类的成员函数格式如下: <类名> operator<运算符>(<参数表>) { 函数体 }A operator + (A &);//重载了类A的“+”运算符其中:operator是定义运算符重载函数的关键字,它与其后的运算符一起构成函数名。返回类型运算的对象关键字函数名运算的对象848
  • 849. class A { int i; public:A(int a=0) { i=a; } void Show(void){ cout<<"i="<
  • 850. class A { int i; public:A(int a=0){ i=a; } void Show(void){ cout<<"i="<
  • 851. 重载运算符与一般函数的比较:相同:1)均为类的成员函数;2)实现同一功能void AddA(A &a, A &b) { i=a.i+b.i; }A operator +(A &a) { A t; t.i=i+a.i; return t; }a3=a1+a2; a3.AddA(a1,a2);返回值函数名形参列表由对象a3调用函数调用:返回值函数名形参函数调用:a3=a1.operator+(a2);由对象a1调用851
  • 852. A operator +(A &a) { A t; t.i=i+a.i; return t; }a3=a1+a2; 返回值函数名形参函数调用:a3=a1.operator+(a2);由对象a1调用总结:重新定义运算符,由左操作符调用右操作符。最后将函数返回值赋给运算结果的对象。852
  • 853. class A { int i; public:A(int a=0){ i=a; } void Show(void){ cout<<"i="<
  • 854. 当用成员函数实现运算符的重载时,运算符重载函数的参数只能有二种情况:没有参数或带有一个参数。对于只有一个操作数的运算符(如++),在重载这种运算符时,通常不能有参数;而对于有二个操作数的运算符,只能带有一个参数。这参数可以是对象,对象的引用,或其它类型的参数。在C++中不允许重载有三个操作数的运算符854
  • 855. 2、在C++中,允许重载的运算符列于表13.1中。 3、在C++中不允许重载的运算符列于表13.2。 4、只能对C++中已定义了的运算符进行重载,而且,当重载一个运算符时,该运算符的优先级和结合律是不能改变的。855
  • 856. class room{ float Length; float Wide; public: room(float a=0.0,float b=0.0){ Length=a; Wide=b; } void Show(void){cout<<"Length="<857. class A { int i; public:A(int a=0){ i=a; } void Show(void){ cout<<"i="<
  • 858. 单目运算符的重载只具有一个操作数的运算符为单目运算符,最常用的为++及--。A a, b; b=++a; b=a++;A a; ++a; a++;可以看出,虽然运算后对象a的值一致,但先自加或后自加的重载运算符函数的返回值不一致,必须在重载时予以区分。858
  • 859. ++为前置运算时,它的运算符重载函数的一般格式为: operator ++( ) { ......;} ++为后置运算时,它的运算符重载函数的一般格式为: operator ++(int) { ......;}A a, b; b=++a; b=a++;A operator ++( ){ .... }A operator ++(int){ .... }859
  • 860. class A { float x, y; public: A(float a=0, float b=0){ x=a; y=b; } A operator ++( ){A t; t.x=++ x; t.y=++y; return t;} A operator ++(int) { A t; t.x=x++; t.y=y++; return t;} }; void main(void) { A a(2,3), b; b=++a; b=a++; }860
  • 861. A operator ++( ) { A t; t.x=++ x; t.y=++y; return t; } b=++a; b=a.operator++( );返回值函数名23at3344t作为函数值返回赋给bA operator ++( ) { ++ x; ++y; return *this; }将对象本身作为函数值返回赋给b861
  • 862. A operator ++(int) { A t; t.x=x++; t.y=y++; return t; }b=a++; b=a.operator++(3);23at3243返回值函数名t作为函数值返回赋给b862
  • 863. class incount { int c1,c2; public: incount(int a=0,int b=0){ c1=a; c2=b; } void Show(void){cout<<"c1="<
  • 864. 用成员函数实现运算符的重载时,运算符的左操作数为当前对象,并且要用到隐含的this指针。运算符重载函数不能定义为静态的成员函数,因为静态的成员函数中没有this指针。864
  • 865. 运算符重载为友元函数运算符重载为成员函数时,是由一个操作数调用另一个操作数。A a ,b , c; c=a+b;实际上是c=a.operator+(b);c=++a;实际上是c=a.operator++( );即函数的实参只有一个或没有。c+=a;实际上是c.operator+=( a );重载+=865
  • 866. 友元函数是在类外的普通函数,与一般函数的区别是可以调用类中的私有或保护数据。将运算符的重载函数定义为友元函数,参与运算的对象全部成为函数参数。A a ,b , c; c=a+b;实际上是 c=operator+(a, b);c=++a;实际上是 c=operator++(a);c+=a;实际上是 operator+=( c, a );866
  • 867. 对双目运算符,友元函数有2个参数,对单目运算符,友元函数有一个参数。有些运算符不能重载为友元函数,它们是:=,(),[ ],->等格式为: friend <类型说明> operator<运算符>(<参数表>) {......}c=a+b; // c=operator+( a, b) friend A operator + (A &a, A &b) {.....}867
  • 868. class A { int i; public:public: A(int a=0) { i=a; } void Show(void) { cout<<"i="<
  • 869. ++为前置运算时,它的运算符重载函数的一般格式为: A operator ++(A &a) { ......;} ++为后置运算时,它的运算符重载函数的一般格式为: A operator ++(A &a, int) { ......;}A a, b; b=++a; b=a++;A operator ++( A a ){ .... }A operator ++(A a, int){ .... }869
  • 870. class A { int i; public:public: A(int a=0) { i=a; } void Show(void) { cout<<"i="<
  • 871. class incount { int c1,c2; public: incount(int a=0,int b=0){ c1=a; c2=b; } void Show(void){cout<<"c1="<
  • 872. class ThreeD{ float x,y,z; public: ThreeD(float a=0,float b=0, float c=0){x=a;y=b;z=c;} friend ThreeD & operator ++(ThreeD &);//前置 friend ThreeD operator ++(ThreeD & ,int);//后置 void Show(){cout << "x="<
  • 873. 对双目运算符,重载为成员函数时,仅一个参数,另一个被隐含;重载为友元函数时,有两个参数,没有隐含参数。 一般来说,单目运算符最好被重载为成员函数;对双目运算符最好被重载友元函数。873
  • 874. 转换函数转换函数就是在类中定义一个成员函数,其作用是将类转换为某种数据类型。class A { float x, y; public: A(float a, float b){ x=a; y=b; } }; void main(void) { A a(2,3); cout<
  • 875. A :: operator float ( ) { return x+y; }Afloat格式为: ClassName :: operator ( ) {.........}类名具体的转换算法欲转换类型关键字转换算法自己定义1. 转换函数必须是类的成员函数。2. 转换函数的调用是隐含的,没有参数。875
  • 876. class A { int i; public:public: A(int a=0) { i=a; } void Show(void) { cout<<"i="<
  • 877. class Complex{ float Real,Image; public: Complex(float real=0,float image=0) { Real=real; Image=image; } void Show(void) {cout<<"Real="<float }; Complex::operator float () { return Real*Real+Image*Image;} void main(void) { Complex c(10,20); c.Show (); cout<
  • 878. 注意,转换函数只能是成员函数,不能是友元函数。转换函数的操作数是对象。转换函数可以被派生类继承,也可以被说明为虚函数。878
  • 879. 赋值运算符与赋值运算符重载 “=”同类型的对象间可以相互赋值,等同于对象的各个成员的一一赋值。A a(2,3), b; b=a; 但当对象的成员中使用了动态的数据类型时(用new开辟空间),就不能直接相互赋值,否则在程序的执行期间会出现运行错误。879
  • 880. class A{ char *ps; public: A( ){ ps=0;} A(char *s ){ ps =new char [strlen(s)+1]; strcpy(ps,s);} ~A( ){ if (ps) delete ps;} void Show(void) { cout<
  • 881. 这时,利用编译系统的默认赋值无法正确运行程序,必须重载赋值运算符“=”,即重新定义“=”。 格式为: <函数类型> ::operator=(<参数表>) 赋值运算符必须重载为成员函数。A A:: operator = (A &a)函数返回值类型成员函数作用域函数名函数参数b=a;b.operator=(a);左操作符调用右操作符881
  • 882. class Sample{ int x; public: Sample(int i=0){x=i;} void disp(void){ cout<<“x=“<
  • 883. class A{ char *ps; public: A( ){ ps=0;} A(char *s ){ ps =new char [strlen(s)+1]; strcpy(ps,s);} ~A( ){ if (ps) delete ps;} void Show(void) { cout<
  • 884. A &A::operator = ( A &b)//重载赋值运算符 { if ( ps ) delete [ ] ps; if ( b.ps) { ps = new char [ strlen(b.ps)+1]; strcpy( ps, b.ps); } else ps =0; return *this; }s1ps“China”s2ps“Computer”s2=s1;s2.operator=(s1);“China”返回同种类型的引用适合于连等。s3=s2=s1;884
  • 885. class A{ char *ps; public: A( ){ ps=0;} A(char *s ){ ps =new char [strlen(s)+1]; strcpy(ps,s); } ~A( ){ if (ps) delete ps;} char *GetS( ) {return ps;} A & operator = ( A &b);//重载赋值运算符 }; A &A::operator = ( A &b)//重载赋值运算符 { if ( ps ) delete [ ] ps; if ( b.ps) { ps = new char [ strlen(b.ps)+1]; strcpy( ps, b.ps); } else ps =0; return *this; } void main(void ) { A s1("China!"),s2("Computer!"); s2=s1; cout <<"s1= "<< s1.GetS()<<'\t'; cout <<"s2= "<< s2.GetS()<<'\n'; }s2.ps重新开辟内存,存放“China”重新开辟内存885
  • 886. 一个字符串类 在C++中,系统提供的字符串处理能力比较弱,都是通过字符处理函数来实现的,并且不能直接对字符串进行加法、减法,字符串的拼接,字符串之间的相互赋值等操作。可以通过应用C++提供的运算符重载机制,可以提供字符串的直接操作能力,使得字符串的操作与一般的数据一样方便。886
  • 887. class String { int Length;//字符串长度 char *Sp; //字符串在内存中的首地址 public: ..... }可见,字符串类只定义了指针,并没有开辟具体的空间以存放字符串的内容,所以,无论是构造、析构还是加减等,均需要考虑动态开辟空间的问题,这也是字符串类的难点。887
  • 888. class String{ int Length; //字符串的长度 char *Sp; //指向字符串的指针 public: String(){Sp=0;Length=0;} //缺省的构造函数 String( char *s) //以一个字符串常量作为参数 { Length = strlen(s); Sp=new char[Length+1]; strcpy(Sp,s); } ~String(){ if(Sp) delete [ ] Sp; } friend String operator +(String &,String &);//友元函数重载+ String & operator =(String &);//成员函数重载赋值= String (String &s); //拷贝的构造函数(必须有) }; void main(void) { String str1("China"); String str2("CCTV"); String str3; str3=str1+str2; str2=str1; cout<
  • 889. String & String:: operator =(String &str) { if (Sp) delete []Sp; Length=str.Length ; Sp =new char[Length +1]; strcpy(Sp,str.Sp); return *this; } String operator +(String &str1,String &str2) { String str; str.Length=str1.Length+str2.Length; str.Sp=new char[str.Length +1]; strcpy(str.Sp,str1.Sp); strcat(str.Sp,str2.Sp); return str; }重新定义字符串赋值B=A重新定义字符串连接C=A+B889
  • 890. 若不定义字符串的析构函数,则可以不定义它的拷贝的构造及赋值函数,若定义了析构函数,必须重新定义这两个成员函数。原则:每个对象都有自己的独立空间。890
  • 891. 第十四章 输入/输出流类库 891
  • 892. 编译系统已经以运算符或函数的形式做好了对标准外设(键盘、屏幕、打印机、文件)的接口,使用时只需按照要求的格式调用即可。cin>>x; cout<
  • 893. 输入输出流(I/O Stream) C++语言的I/O系统向用户提供一个统一的接口,使得程序的设计尽量与所访问的具体设备无关,在用户与设备之间提供了一个抽象的界面:输入输出流。iosistream(输入流)ostream(输出流)iostream在“iostream.h”中说明893
  • 894. 用标准流进行输入/输出时,系统自动地完成数据类型的转换。对于输入流,要将输入的字符序列形式的数据变换成计算机内部形式的数据(二进制或ASCII)后,再赋给变量,变换后的格式由变量的类型确定。对于输出流,将要输出的数据变换成字符串形式后,送到输出流(文件)中。 894
  • 895. 重载输入(提取)和输出(插入)运算符class A { float x, y; public: A(float a=0, float b=0){ x=a; y=b; } void Set(float a, float b){ x=a; y=b; } void Show(void){ cout<>a;cout<
  • 896. 在C++中允许用户重载运算符“<<”和“>>”,实现对象的输入和输出。重载这二个运算符时,在对象所在的类中,将重载这二个运算符的函数说明该类的友元函数。重载提取运算符的一般格式为:友元函数friend istream & operater >>(istream &, ClassName &);返回值类型函数名左操作数右操作数cin>>a;operator>>(cin, a)896
  • 897. 友元函数friend istream & operater >>(istream &, ClassName &);返回值类型函数名左操作数右操作数cin>>a;operator>>(cin, a)返回值类型:类istream的引用,cin中可以连续使用运算符“>>”。cin>>a>>b;第一个参数:是“>>”的左操作数cin类型,类istream的引用第二个参数:是“>>”的右操作数,即欲输入的对象的引用.istream & operater >>(istream &is, ClassName &f);897
  • 898. class A { float x, y; public: ..... }; ..... A a; cin>>a; ....friend istream & operater >>(istream &, A &);istream & operater >>(istream &is, A &a) { cout<<“ Input a:”<>a.x>>a.y; return is; }重新定义输入流在类中原型说明在类外定义函数返回输入流898
  • 899. class incount{ int c1,c2; public:incount(int a=0,int b=0) { c1=a; c2=b; } void show(void){cout<<"c1="<>(istream &,incount &); }; istream & operator>>(istream &is, incount &cc) { is>>cc.c1>>cc.c2; return is; } void main(void) { incount x1,x2; x1.show (); x2.show (); cin>>x1; cin>>x2; x1.show (); x2.show (); }重载输入函数原型说明重载输入函数定义899
  • 900. 友元函数friend ostream & operater <<(ostream &, ClassName &);返回值类型函数名左操作数右操作数cout<>(istream &, ClassName &);将输入流改为输出流。900
  • 901. class A { float x, y; public: ..... }; ..... A a(2,3); cout<
  • 902. class incount{ int c1,c2; public: incount(int a=0,int b=0) { c1=a; c2=b; } void show(void) {cout<<"c1="<>(istream &,incount &); friend ostream & operator<<(ostream &,incount &); }; istream & operator>>(istream &is,incount &cc) { is>>cc.c1>>cc.c2; return is;} ostream &operator<<(ostream &os,incount &cc) //重载cout<< {os<<"c1="<>x1; //调用输入函数 cin>>x2; cout<
  • 903. 内存键盘文件光笔....输入流显示器文件打印机...输出流编译系统已经以运算符或函数的形式做好了对标准外设(键盘、屏幕、打印机、文件)的接口,使用时只需按照要求的格式调用即可。cin>>x; cout<
  • 904. 文件流 C++在头文件fstream.h中定义了C++的文件流类体系 ,当程序中使用文件时,要包含头文件fstream.h 。iosifstream(输入流)ofstream(输出流)fstream在“fstream.h”中说明当使用文件时,在程序头有:#include 其中定义了各种文件操作运算符及函数。904
  • 905. 内存变量 (程序)键盘输入文件屏幕输出文件cin>>xcout<>xoutfile<
  • 906. 文件的操作文件文本文件:以ASCII表示的文件:记事本,*.cpp等二进制文件:用二进制形式表示的文件:可执行程序*.EXE等56:ASCII表示为 00110101 00110110,占两字节56:二进制表示为 111000,占六个二进制位不同的文件操作的函数、格式不同906
  • 907. 文本文件的打开与关闭 在文件操作前,需要将程序与被操作的文件联系起来,使程序可以“引用”文件。在程序内定义一个文件类的对象,由该对象与文件发生联系,程序内所有的与文件的操作都是对该对象的操作。fstream infile , outfile; ifstream infile; ofstream outfile;两个对象,可以联系两个输入输出文件对象只能联系输入文件对象只能联系输出文件907
  • 908. iosifstream(输入流)ofstream(输出流)fstream在“fstream.h”中说明定义用于输入的文件对象定义用于输出的文件对象定义用于输入输出的文件对象908
  • 909. 如何使文件类的对象与欲操作的文件发生联系?用对象打开文件:ifstream infile; //定义输入文件类对象 infile.open(“myfile1.txt”);//利用函数打开某一文件打开文件的作用是,使文件流对象与要使用的文件名之间建立联系。ofstream outfile; //定义输出文件类对象 outfile.open(“myfile1.txt”);//打开某一文件供输出909
  • 910. infile.open(“myfile1.txt”);打开文件“myfile1.txt”用于输入,并将这个文件与输入文件类对象infile建立联系,今后,在程序中,用到这个文件“myfile1.txt”的地方就用infile来代替。outfile.open(“myfile2.txt”);打开文件“myfile2.txt”用于输出,并将这个文件与输出文件类对象outfile建立联系,今后,在程序中,用到这个文件“myfile2.txt”的地方就用outfile来代替。910
  • 911. 如何从文件中输入输出数据?将文件类对象看成键盘和显示器即可。ifstream infile; //定义输入文件类对象 infile.open(“myfile1.txt”);//利用函数打开某一文件 float x , y; infile>>x>>y;myfile1.txt3 4内存infilexy34用infile代替myfile1.txt进行操作。911
  • 912. ifstream outfile; //定义输出文件类对象 infile.open(“myfile2.txt”);//利用函数打开某一文件 float x=3 , y=4; outfile<
  • 913. 4)用完文件后,使用成员函数关闭文件.如:myfile1.txt3 4内存infilexy34myfile2.txtoutfile34ifstream infile; ofstream outfile infile.open(“myfile1.txt”); outfile.open(“myfile2.txt”); float x,y; infile>>x>>y; outfile<
  • 914. void main(void) { int a[10]; ifstream infile; //定义输入文件类 ofstream outfile; //定义输出文件类 infile.open(“file1.txt”); //打开一个输入文件“file1.txt” outfile.open(“file2.txt”); //打开一个输出文件“file2.out” for(int i=0;i<10;i++) infile>>a[i];//将“file1.txt”中的十个整型数输入到a[i]中 for(i=0;i<10;i++) outfile<
  • 915. 当用类fstream定义文件对象时,该对象即能定义输入文件对象,又能定义输出文件对象,所以打开文件时,必须在成员函数open()中的参数中给出打开方式(读或写)。fstream pfile1,pfile2;//定义了两个文件类的对象 pfile1.open(“file1.txt”, ios::in);//pfile1联系到“file1.txt”,用于输入 pfile2.open(“file2.txt”, ios::out);//pfile2联系到“file2.txt”,用于输出 char ch; pfile1>>ch; //输入 pfile2<
  • 916. 在打开文件后,都要判断打开是否成功。若打开成功,则文件流对象值为非零值;若打开不成功,则其值为0。 ifstream pfile1,pfile2;//定义了两个文件类的对象 pfile1.open(“file1.txt”, ios::in); pfile2.open(“file2.txt”, ios::out); if (!pfile1) {cout <<”不能打开输入文件:file1.txt”<<’\n’; exit(1);} if (!pfile2) {cout <<”不能打开输出文件:file2.txt”<<’\n’; exit(1);}若为0,打开文件操作失败916
  • 917. 打开输入文件时,文件必须存在。 打开输出文件时,若文件不存在,则建立文件;若文件存在,则删除原文件的内容,使其成为一个空文件。917
  • 918. char ch, str[300]; ifstream infile(“myfile1.txt”); ofstream outfile(“myfiel2.txt”);涉及到字符串的文件读写从键盘输入一个字符:cin.get(ch);从文件输入一个字符:infile.get(ch);向显示器输出一个字符:cout.put(ch);向文件输出一个字符:outfile.put(ch);从键盘输入一行字符:cin.getline(str,300);从文件输入一行字符:infile.getline(ch,300);从文件输入一字符或一行字符,当输入至文件尾时,函数返回值为0,可以据此来判断循环结束。918
  • 919. 14-15. 实现两文件的拷贝的程序void main(void) { char filename1[256],filename2[256]; cout<<"Input source file name: "; cin>>filename1; cout<<"Input destination: "; cin>>filename2; ifstream infile(filename1); ofstream outfile(filename2); char ch; while(infile.get(ch)) outfile.put(ch); infile.close(); outfile.close(); }输入文件(源文件)名输出文件(目的文件)名用构造函数打开文件从源文件中读取一个字符,至文件尾停止循环将该字符输出至目的文件关闭文件919
  • 920. void main(void) { char filename1[256],filename2[256]; char buf[300]; cout<<"Input source file name: "; cin>>filename1; cout<<"Input destination: "; cin>>filename2; fstream infile,outfile; infile.open(filename1,ios::in); outfile.open(filename2,ios::out); while(infile.getline(buf,300)) outfile<
  • 921. 二进制文件的读写操作若在文件的打开方式中没有特别说明,打开的文件均为ASCII码文件,若要打开二进制文件,则要特别说明并用特定的读写函数。fstream infile,outfile; infile.open(“inf1.dat”, ios::in| ios::binary);outfile.open(“outf1.dat”, ios::out| ios::binary); 文件名 输入方式打开 二进制文件 文件名 输出方式打开 二进制文件921
  • 922. 输入函数: infile.read( char *, int )输入文件对象名 数据进入的内存地址 一次读入的字节数文件内存int a[10]; infile.read((char *)a, 10*sizeof(int));//从文件中输入十个整型数到aint i; infile.read((char *)&i, sizeof(int));//从文件中输入一个整型数到i由于二进制文件中的数据不是ASCII码,故不能直接对其读写,必须要通过特定的函数予以转换。读入地址要强制转换成字符型922
  • 923. 输出函数: outfile.write( char *, int )输出文件对象名 要输出的数据在内存中的地址 一次输出的字节数文件内存int a[10]={0,1,2,3,4,5,6,7,8,9}; outfile.write((char *)a, 10*sizeof(int));//向文件输出一个整型数组aint i=4; outfile.write((char *)&i, sizeof(int));//向文件输出一个整型数i写出地址要强制转换成字符型923
  • 924. 判断二进制文件是否读到文件尾?infile.eof( ) 当到达文件结束位置时,该函数返回一个非零值;否则返回零。fstream infile; infile.open(“data1.dat”,ios::in|ios::binary); if(!infile) { cout<<“Open Error!\n”; exit(1); } char str[300]; while(!infile.eof()) infile.read(str, 300); 判断打开是否出错 判断是否读到文件尾924
  • 925. void main(void ) {char filename1[256],filename2[256]; char buff[4096]; cout <<”输入源文件名:”; cin >>filename1; cout <<”输入目的文件名:”; cin >>filename2; fstream infile,outfile; infile.open(filename1,ios::in | ios::binary); outfile.open(filename2,ios::out | ios::binary); int n; while (!infile.eof()){ //文件不结束,继续循环 infile.read(buff,4096); //一次读4096个字节 n=infile.gcount(); //取实际读的字节数 outfile.write(buff,n); //按实际读的字节数写入文件 } infile.close(); outfile.close(); } 925
  • 926. 文件指针文件内容文件指针当一打开文件,文件指针位于文件头,并随着读写字节数的多少顺序移动。可以利用成员函数随机移动文件指针。926
  • 927. 随机读取二进制文件infile.seekg(int);//将文件指针移动到由参数指定的字节处infile.seekg(100);//将文件指针移动到距离文件头100个字节处infile.seekg(int, ios::_dir); 移动的字节数 相对位置infile.seekg(100, ios::beg);//移动到距文件头100个字节_dir: beg: 文件头 cur: 当前位置 end: 文件尾infile.seekg(-100, ios::cur);//移动到距当前位置前100个字节infile.seekg(-500, ios::end);//移动到距文件尾前500个字节927
  • 928. void main(void ) { ofstream outfile(“data1.dat”,ios::out| ios::binary); int i; for(i=5;i< 1000;i+=2 ) outfile.write((char*)&i,sizeof(int)); //将奇数写入文件 outfile.close();//关闭文件 ifstream f1(“data.dat”,ios::in| ios::binary); int x; f1.seekg(20*sizeof(int));//将文件指针移到第20个整数的位置 for(i=0;i<10;i++) {f1.read((char *)&x,sizeof(int)); //依次读出第20~29个奇数到x cout<< x<< ‘\t’; } f1.close(); }以读的方式打开原文件928
  • 929.    设在缺省目录下有文件file1.txt,文件中内容为: 1 2 3 4 5 6 执行下述程序后,程序的输出是__________。 void main(void) { fstream f1; int tmp, sum=0; f1.open(“file1.txt”,ios::in); while(f1>>tmp) sum+=tmp; f1.close( ); cout<
  • 930. 如果令A,B,C,D,……,X,Y,Z这26个英文字母,分别等于百分之1,2,……,24,25,26个数值,那么我们就能得出如下有趣的结论: HARD WORD 8+1+18+4+23+15+18+11=98% KNOWLEDGE 96% LOVE 54% LUCK 47% 计算一下MONEY STUDY ATTITUDE930