玩魔兽弹出寄存器状态标志寄存器

广西隆林县物流
广西隆林县物流
(C)2017 列表网&琼ICP备号-12&增值电信业务经营许可证B2-&拒绝访问 | www.ggdoc.com | 百度云加速
请打开cookies.
此网站 (www.ggdoc.com) 的管理员禁止了您的访问。原因是您的访问包含了非浏览器特征(e43e3-ua98).
重新安装浏览器,或使用别的浏览器当前位置: >>
C++讲稿(清华吕凤翥 zhù版) 詹胜 周三 14 信管 7、8 11 机房 周五 3、4 11 机房16:00―17:5010:00―12:00第一章 c++概述C++,外国人叫做 C Plus Plus 就是 C 语言的增强版的。 中国人直接叫 c 加加,省略了好多音符,舌头少拐了好几个弯。 C 语言里面有前自增和后自增操作符。 C++就是说是 C 语言的增加之外,也兼容 C 语言的语法、特性,也保留了 C 语言的内容。一、为什么学习计算机语言计算机语言是人类和计算机相互交流的语言,是桥梁,是工具。 计算机的语言,像汉语、英语等语言一样也是一种语言,只是交流的对象 是计算机,不是传统意义上的说不同种语言的人。要想了解计算机,让计算机 为我们服务,必须学会使用计算机的语言。 我们利用某一种计算机语言编写计算机能够处理并执行的指令序列,通常1 我们把这些指令序列叫做程序,编写程序的过程简称为编程。把程序以及程序 开发、使用和维护所需要的所有文档整合在一起叫做软件。现在通常把软件分 成两大类,一类是系统软件,如操作系统,另一类是应用软件,如 office。 计算机程序的两大组成部分 数据 指令,数据的运算 计算机能够识别的数据都是二进制形式的,能够执行的程序也不例外,也 是用二进制代码表示指令序列。用二进制代码表示机器指令的语言叫做机器语 言。最早的计算机,程序员使用机器语言编写程序,计算机执行起来非常快, 效率高,但写程序非常麻烦,而且难懂。 例如:使用机器语言计算 1+1。 00 00 为了解决机器语言编程的困难,人们编写了专门的程序设计语言的程序, 这个程序提供一套符合人的思维逻辑的语言规范,能够把人按照语言规范写的 程序翻译成计算机能够识别的机器语言。其中最早期的程序设计语言叫汇编语 言。 例如使用汇编语言计算 1+1。2 movax,1 addax,1 汇编语言屏蔽了枯燥的二进制代码,用人类易懂的符号代替二进制,使得 编程技术前进了一大步。但汇编语言与机器语言比较接近,多数符号还是和二 进制直接对应的,编程难度也比较大,通常人们习惯把机器语言和汇编语言成 为低级语言。 把汇编语言之后出现的程序设计语言叫做高级语言。高级语言更接近自然 语言和数学语言,更接近人类的习惯。C++语言也是高级语言的一种。 例用 C++语言计算 1+1。 #include&iostream.h& Void main(){ cout&&1+1; } 高级语言虽然迎合了程序员的方便,但是用高级语言编写的程序仍然需要 转化为机器语言,让计算机执行,效率较低,因此目前在单片机,硬件编程方 面,用汇编语言等低级语言的还比较多。 根据计算机的特点,cpu 的主频是确定的,内存空间也是确定的,所以为了 使得程序有良好的运行状态,我们需要在这两者之间做出平衡。那么,不论你是 用什么语言来编写程序(指令序列)驱动计算机,在编写程序中始终要注意的 两个问题,一是充分的利用计算机的时间,二是谨慎的使用计算机的空间。计 算机的时间就是 cpu 的利用,空间就是内存储器的利用。3 二、为什么学习 C++语言C++、VisualBasic 和 Java 是众多公司产品体系的首选语言。对 100 家公司 的调查显示, C/C++、 VisualBasic 和 Java 在产品体系中的使用比例分别是 59%、 61%和 66%。 《魔兽世界》等几乎所有的网络游戏,百度搜索引擎(Baidu.com) ,我们 所用的大多数软件都是用 C++写的。 我们可能都听说过 C 语言,它可以称为影响最大、寿命最长的语言之一。 有人说必须先学习才 c,再学习 c++。我们说,学过 c 当然好,但是就目前学习 C++而言,你可以认为他是一门独立的语言;认为他并不依赖 C 语言,我们完全 可以直接学习 C++。在大多数场合 C++完全可以取代 C 语言(然而我们在单片机 等需要谨慎利用空间、直接操作硬件的地方还是要使用 C 语言)。三、c++课程我们学什么在本学期,主要是学习 词法规则,语句,数据类型,函数,简单对象。四、怎么才能学好 c++读程序、写程序、上机调试程序。五、c++程序结构的特点Page9 例 1.1c++语言的一个示范程序(一) 1.c++程序的组成部分 注释 //This isa C++ program4 多行注释/**/2.预处理命令 #include&iostream.h&预处理命令有三种:宏定义命令、文件包含命令、条件编译命令 iostream.h 是一个头文件,位于 C:\Program Files (x86)\Microsoft Visual Studio\VC98\Include 文件夹下,该文件包含了已经定义好的 cout,cin,提取 符&&,和插入符&&。3.函数void main(){???}C++程序------文件-------函数 在组成一个程序的若干个函数中,必须有一个并且只能有一个主函数 main() 在 vc++6.0 里面,一个 c++程序称为一个工程,那么,每个工程下面必须有一个 并且只能有一个主函数。 函数有返回值和参数 我们用到的函数有两大类,一类是库函数,就是专家定义好的函数。另一类就 是我们程序员自己定义定的函数。4.语句语句是组成程序的基本单元。函数是由若干条语句组成的。空函数中可以没有 语句。 语句有单词组成,中间用空格分隔。一条语句结束要是用分号。 语句有表达式语句、复合语句、分支语句、循环语句和转向语句等。5.变量变量是有类型的 int abc(0);属于复制初始化5 int abc=0;属于直接初始化 摘自 C++Primer 第 4 版 42 页。 这两种方式对于基本类型来说差别不大,但是对于后面讲到的类类型就大不相6.输入和输出库函数中定义好的键盘输入流对象名为 cin,预定义的提取符为&& 库函数中定义好的标准输出流对象名为 cout,预定义的插入符是&&使用时注意 表达式中运算符的优先级和编译系统的差异。7. (二)常量两种定义方式 #definePI3.14 程序的书写格式constdoublePI=3.14一般一行写一条语句 良好的缩进 声明变量的时候,望文生义六、c++程序的实现(一)c++程序的编辑----编译(连接)----运行 编辑是将编写好的 c++源程序输入到计算机中 A、 打开 IDE(Integrated Development,集成开发环境) :开始――程序―― Microsoft Visual Studio 6.0――Microsoft Visual c++ 6.01.6 B、文件――新建――工程 确定输入工程名称:Test,可以选择工程所在位置。点击7 C、选择一个空的工程,点击 完成,然后 确定此时,对应的文件夹下就会生成相应的工程文件,打开来看,就能够看到 和工程相关的一些自动生成的文件 .dsp 在 VC 中,应用程序是以 Project 的形式存在的,Project 文件的扩展名为.dsp .dsw .ncb 这种类型的文件在 VC 中是级别最高的,称为 Workspace 文件 无编译浏览文件(no compile browser)。当自动完成功能出问题时可以删除此文件。build 后会自动生成 .plg。plg 是编译信息文件,编译时的 error 和 warning 信息文件(实际上 是一个 html 文件),一般用处不大.在 Tools-&Options 里面有个选项可以控 制这个文件的生成.8 打开 debug 文件夹,看到里面是空的在该工程下面,我们发现了三个预定义的逻辑文件夹,分别是:&Source Files&、&Header Files&、&Resource Files&。 在每一个文件夹下面,都没有文件;这是因为此前我们选择的是创建一个空的工程。这三个文件夹是 VC 预先定义的,就 编写简单的单一源文件的 C 程序而言,我们只需要使用 Source Files 一个文件夹就够了。 事实上这三个文件夹是按照里面所存放的文件类型来定义的,如下表所示: 预定义文件夹 Source Files Header Files 包含的文件类型c;r;inlResource Frc2;jpe 我们之所以称这三个文件夹为逻辑文件夹,是因为他们只是在工程的配置文件中定义的,在磁盘上并没有物理地存在 这三个文件夹。D、文件――新建――c++ source file,输入文件名 First――点击 确定9 E、先保存一下这个空文件。可以在工程目录下看到 First.cpp 文件Workspace 工作空间 只要了解下面几点就可以了: 1. VC 是 按 照 Workspace 来 管 理 项 目 和 代 码 的 。 一 次 必 须 打 开 一 个 Workspace。 2. 一个 Workspace 中可以包含一个或者多个工程。 3. 一个工程可以包含一个或者多个逻辑文件夹。 4. 一个文件夹里面可以包含零个或者多个文件。 5. 一个工程至少包含一个源代码文件。 6. 当创建新工程的时候, 一个同名的 Workspace 同时被创建; 该 workspace 只包含一个项目,就是新创建的这个项目。10 或者稍稍详细一点说,VC 在管理项目和代码的时候,是按照如下一个树型 的结构来组织的: Workspace?Project 1 (项目 1)o o oHeaer files (一个或者多个头文件) Source files (一个或者多个源代码文件) Other files (一个或者多个其他文件)?Project 2 (项目 2)o o oHeaer files (一个或者多个头文件) Source files (一个或者多个源代码文件) Other files (一个或者多个其他文件)F、 .obj 件了Compile 后 Debug 文件夹下生成了很多文件 程序编译后的二进制文件, 再通过链接器和资源文件链接就成 exe 文.pch 预编译头文件(一般扩展名为.PCH),是把一个工程中较稳定的代码 预先编译好放在一个文件(.PCH)里.这些预先编译好的代码可以是任何的 C/C++ 代码--甚至可以是 inline 函数,只它们在整个工程中是较为稳定的,即在工程开 发过程中不会经常被修改的代码.为什么需要预编译头文件 ?一言以蔽之:提高 编译速度11 .idb The compiler saves state information from the first compile in the project’s .IDB file (the default name is project.IDB or VC60.IDB for files compiled without a project). The compiler uses this state information to speed subsequent compiles. 记录了哪些文件是修改过的, 需要重新编译的。 (对于 VC60 编译的文件是 VC60.IDB) vc60.pdb PDB:Program Debug Database(程序调试数据库)文件保持 着调试和项目状态信息,从而可以对程序的调试配置进行增量链接。 G、 点击 build 后,debug 文件夹中又增加了.exe 可执行文件 .ilk 连接过程中生成的一种中间文件,只供 LINK 工具使用 Test.pdb H、 编译 连接,后就可以运行了。一个办法是在 ide 中运行,第二个办 法是找到 debug 文件中的.exe 文件,双击它就可以运行 2. 编译就是将程序的源代码转换成为机器代码(目标代码)再对目标代码进行连接然后生成.exe 的可执行文件的过程。compile 编译又分为三个子过程 A. B. 预处理过程,就是首先处理预处理命令 编译过程:词法分析、语法分析、生成符号表、进行错误处理(生成error 和 warning 提示) 、生成目标代码,以.obj 扩展名保存在机器中。 3. 连接过程。把编译成功的各个相关的文件关联起来,组成一个程序,生成以.exe 为扩展名的可执行程序。Build12 4.(二) 1. 2. 3. 4. 5. 6.运行 vc6.0 的基本用法 建立控制台工程 建立 source 文件 编辑文件 编译源程序文件 连接目标代码文件 单文件程序和多文件程序七、c++语言的词法及词法规则(一)c++字符集总计 89 个26 个英文字母的大小写共计 52 个
共计 10 个 空格!#%^&*_(下划线) -+=~&&/\| .,:;?‘“()[] {} 共 27 个(二) 1.c++单词及词法规则 标识符是程序员定义的函数名字、类名、变量名等13 A. B. C. D. E.2.数字、字母、下划线组成,以字母或者下划线开头 长度尽量别超过 32 个字符 大小写敏感 使用中遵循望文生义的原则 不要使用系统的保留字 关键字ISO C++98/03 关键字共 63 个,按标准原文排版:asmdoifreturntypedefauto booldouble dynamic_castinline intshort signedtypeid typenamebreak caseelse enumlong mutablesizeof staticunion unsignedcatch charexplicit exportnamespace newstatic_cast structusing virtualclass constextern falseoperator privateswitch templatevoid volatileconst_cast continuefloat forprotected publicthis throwwchar_t whiledefault deletefriend gotoregister reinterpret_c asttrue try这些关键字在我们后期的学习中都会遇到,随着代码越写越多,自然就熟悉, 记住他们了。14 3.运算符 单目运算符 双目运算符 唯一的三目运算符------条件运算符 i&j?i:j 分隔符 空格 逗号 分号 冒号 {} 常量 数字常量 字符常量 字符串常量 注释符单行注释,多行注释 空白符包括空格符,换行符和水平制表符。注意区分空白符和空字符A. B. C.4.A. B. C. D. E.5.A. B. C.6. 7.八、关于 main()函数的补充内容1.一个程序有且只要一个 main 函数,它是入口函数,但不一定是第一个执行的 函数。 2.C++98 中定义了如下两种 main 函数的定义方式: int main()15 int main( int argc,char*argv[]) (参考资料:ISO/IEC-9-01)Programminglanguages― C++3.6Startandtermination)int main()等同于 C99 中的 int main(void); int main( int argc,char*argv[])的用法也和 C99 中定义的一样。同样,main 函数的返回值类 型也必须是 int 。如果 main 函数的末尾没写 return 语句,C++98 规定编译器 要自动在生成的目标文件中加入 return0;。同样,vc6 也不支持这个特性,但 是 g++3.2(Linux 下的 C++编译器)支持。3.关于 void main在 C 和 C++中,不接收任何参数也不返回任何信息的函数原型为“void foo(void);” 。可能正是因为这个,所以很多人都误认为如果不需要程序返回值 时可以把 main 函数定义成 void main(void)。然而这是错误的!main 函数的返 回值应该定义为 int 类型,C 和 C++标准中都是这样规定的。虽然在一些编译器中,void main 可以通过编译(如 vc6) ,但并非所有编译器都支持 void main, 因为标准中从来没有定义过 void main。g++3.2 中如果 main 函数的返回值不是 int 类型,就根本通不过编译。而 gcc3.2 则会发出警告。所以,如果你想你 的程序拥有很好的可移植性,请一定要用 int main。4.返回值的作用16 main 函数的返回值用于说明程序的退出状态。如果返回 0,则代表程序正常退 出,否则代表程序异常退出。下面我们在 winxp 环境下做一个小实验。首先编 译下面的程序: int main(void) { return0; }然后打开附件里的“命令提示符” ,在命令行里运行刚才编译好的可执行文件, 然后输入“echo%ERRORLEVEL%” ,回车,就可以看到程序的返回值为 0。假设刚 才编译好的文件是 a.exe,如果输入“a&&dir” ,则会列出当前目录下的文件夹 和文件。 但是如果改成 “return-1” , 或者别的非 0 值, 重新编译后输入 “a&&dir” , 则 dir 不会执行。因为&&的含义是:如果&&前面的程序正常退出,则继续执行 &&后面的程序,否则不执行。也就是说,利用程序的返回值,我们可以控制要 不要执行下一个程序。 这就是 int main 的好处。 如果你有兴趣, 也可以把 main 函数的返回值类型改成非 int 类型(如 float) ,重新编译后执行“a&&dir” ,看看会出现什么情况,想想为什么会出现那样的情况。顺便提一下,如果输入 a||dir 的话,则表示如果 a 异常退出,则执行 dir。九、补充关于计算机的数字系统计算机的数字系统 计算机采用的是二进制数字系统。17 基本符号:0、1 进位原则:逢二进一 优点: 易于物理实现 二进制数运算简单 机器可靠性高 通用性强 缺点:对人来说可读性差 不同进位计数制间的转换 ――R 进制→十进制 各位数字与它的权相乘,其积相加。 例如: ()2=1*27+1*26+1*25+1*24+1*23+1*22+1*21+1*20+1*2-1+1*2-2 =(255.75)10 (=3*83+5*82+0*81+6*80+2*8-1=( (0.2A)16=2*16-1+10*16-2=(0.――十进制→R 进制 十进制整数转换成 R 进制的整数 “除 R 取余”法,例如: 268 余数 234┄┄┄┄┄┄┄┄┄┄┄┄0 低位18 217┄┄┄┄┄┄┄┄┄┄┄0 28┄┄┄┄┄┄┄┄┄┄┄1 24┄┄┄┄┄┄┄┄┄┄0 22┄┄┄┄┄┄┄┄┄┄0 21┄┄┄┄┄┄┄┄┄0 0┄┄┄┄┄┄┄┄┄1 高位 所以 02 不同进位计数制间的转换――十进制→R 进制 十进制小数转换成 R 进制小数 “乘 R 取整”法,例如: 高位 0..625 0.625×2=1.25 0.25×2=0.5 0.5×2=1.0 所以 0..01012――二、八、十六进制的相互转换19 每位八进制数相当于三位二进制数 每位十六进制数相当于四位二进制数 ()2=(0)2=(132.4)8 ()2=(0)2=(5A.8)16 (F7)16=(=(信息的存储单位 位(bit):度量数据的最小单位,表示一位二进制信息。 字节(byte):由八位二进制数字组成(1byte=8bit)。 K 字节 1K=1024byte M 字节 1M=1024K G 字节 1G=1024M 二进制数的编码表示:原码 &符号──绝对值表示&的编码 例如: X=+0101011[X]原= X=-0101011[X]原= 符号位 缺点: 零的表示不唯一:[+0]原=000...0[-0]原=100...0 进行四则运算时,符号位需单独处理,且运算规则复杂。20 二进制数的编码表示:反码 正数的反码与原码表示相同。 负数的反码与原码有如下关系: 符号位相同(仍用 1 表示),其余各位取反(0 变 1,1 变 0)。例如: X=-1100110[X]原=[X]反= X=+0000000[X]原=[X]反= 反码中零的表示也不唯一 X=-0000000[X]原=[X]反= 反码只是求补码的中间码 二进制数的编码表示:补码 模数: n 位整数(包括一位符号位),则它的模数为 2n。n 位小数,小数点前一位为符号 位,则它的模数为 2。 补数: 一个数减去另一个数,或者说一个数加上一个负数,等于第一个数加上第二个 数的补数。例:8+(-2)=8+10(mod12) 一个二进制负数可用其模数与真值做加法(模减去该数的绝对值)求得其补码。二进制数的编码表示:补码 计算机中的补码表示法 负数的补码由该数反码的末位加 1 求得21 对补码再求补即得到原码 补码运算规则 符号位可作为数值参加运算 减法运算可转换为加法运算:加上一个负数等于加上该数的补码 补码运算的结果仍为补码 运算结果溢出:负数之和得正数,或正数之和得负数小数的表示方法 计算机中通常采用浮点方式表示小数 一个数 N 用浮点形式表示可以写成:N=M×2E E 表示 2 的幂,称为数 N 的阶码。阶码确定了数 N 的小数点的位置,其位数反映 了该浮点数所表示的数的范围。 M 表示数 N 的全部有效数字,称为数 N 的尾数。其位数反映了数据的精度。 非数值信息的表示 西文字符: ASCII 码:用 7 位二进制数表示一个字符,最多可以表示 27=128 个字符 EBCDIC 码:用 8 位二进制数表示一个字符,最多可以表示 28=256 个字符 汉字:应用较为广泛的是&国家标准信息交换用汉字编码&(GB2312-80 标准),简 称国标码。是二字节码,用二个七位二进制数编码表示一个汉字。十、作业课后第五题22 第二章 数据类型和表达式为什么需要类型? 先来看看计算机的基本结构:我们需要在内存中保存我们即将要操作的数据,而内存就像一个空房间,想要 充分的利用,方便的查找,需要划分区域来保存数据,按照要保存的数据的大 小(长度)不同,划分很多大小不等的区域,来提高内存的效率。那么,数据 的大小(长度)就叫做数据的类型,简称数据类型。一、五种基本数据类型1. 存储整数的整型 int 最高位为符号位,用 0 表示正,1 表示负。可加修饰符 singed unsigned long shout unsinged 整数不保存符号,因此有一个多余的位可用,能存储比 singed 数大两 倍的正数 以 8 位二进制数为例
表示 1 想表示-1 的话比较复杂负数的二进制表示方法23 假设有一个 int 类型的数,值为 5,那么,我们知道它在计算机中表示为: 00
转换成二制是 101,不过 int 类型的数占用 4 字节(32 位) ,所以前面填了一堆 0。 现在想知道,-5 在计算机中如何表示?在计算机中,负数以其正值的补码形式表达。什么叫补码呢?这得从原码,反码说起。原码:一个整数,按照绝对值大小转换成的二进制数,称为原码。 比如 00
是 5 的 原码。反码:将二进制数按位取反,所得的新二进制数称为原二进制数的反码。 取反操作指:原为 1,得 0;原为 0,得 1。 (1 变 0; 0 变 1) 比如:将 00
每一位取反,得 11 。 称: 11
的反码。 反码是相互的,所以也可称: 11
互 为反码。补码:反码加 1 称为补码。 也就是说,要得到一个数的补码,先得到反码,然后将反码加上 1,所得数称为补码。 比如:00
的反码是:11 。 那么,补码为: 11
所以,-5 在计算机中表达为:11 。 再举一例,我们来看整数-1 在计算机中如何表示。 假设这也是一个 int 类型,那么: 1) 先取 1 的原码:00 24 2) 得反码: 3) 得补码:11 11 11111可见,-1 在计算机里用二进制表达就是全 1。2. 3.存储字符的字符型 char 可加修饰符 singedunsignedlongshout 存储小数的浮点型单精度 float 双精度 doublelongdouble使用 cout 命令输出 3.1415926#include&iostream.h& voidmain() { double x=3.1415926; cout.precision(15);//vc++默认输出6位有效数字,precision()可以更改 cout&&x&& }关于 float double??? 4. 5. 布尔型 bool 在不同的编译系统中长度有不同,vc++6.0 中 1 字节。 空值 void二、变量区别于常量,变量需要有类型了(一)变量的名字不能使用关键字;见名知意;多个单词之间用下划线隔开,或者单词首字母大 写;变量名一般常用小写字母,常量每个字母都大写(二)变量的类型25 变量的类型有基本类型和构造类型(数组、结构、联合、枚举)两种 变量的存储类(自动类、寄存器类、外部类、静态类;静态类又有内部和外部 之分)与其作用域和寿命相关。在第四章会讲到 一个变量的数据类型决定了该变量在存储时占用的内存大小, (可以使用sizeof(short int(三))测试一下)而且也规定了其合法操作变量的值一个变量有两个有用的值,他所表示的数据值和他存放在内存中的地址值int d=7; cout&&&\n&&&d&& cout&&&d&&endl&&(long)&i&&(四)定义变量变量在使用之前必须定义,在同一程序块内不允许重名。voidmain( int { { int d=5; cout&&&\n&&&d&& // int d=6; } int d=7; cout&&&\n&&&d&& } argc,char*argv[])类型变量名表 定义变量的同时可以赋初值 变量被定义后,他的值可能是被初始化的值或默认值(外部和静态类变量有默 认值)或无意义值(自动类变量未初始化时是无意义值,此时只允许赋值操作)三、常量在程序中不被改变的量(一)整型常量26 1. 2. 3.十进制没有前缀,0~9 组成,不能以 0 开始,没有小数部分 八进制以 0 为前缀,后面跟 0~7 组成,没有小数部分 十六进制以 0x 或 0X 为前缀,后面由 0~9 和 A~F(大小写均可) 组成,没有小数部分 长整型用 l 作后缀,无符号用 u 作后缀(二)浮点型常量由整数部分和小数部分组成。只有十进制表示 有两种表示方法: 1. 2. 小数表示法 0.000032 科学表示法 3.2*10-5 表示为 3.2E-5单精度浮点型后缀为 f,长精度浮点型后缀为 l(三)字符常量用一对单引号括起来,可以用图形符号表示,也可以用八进制或者十六进制的 ASCII 码值来表示 转义字符(四)字符串常量注意字符串中间的续行符 注意字符串是用一个一位数组来存放的,字符串数组默认在最后有一个\0 作为 结束 注意字符常量和字符串常量的三个区别:单引号双引号;占用的内存大小不同; 操作功能不同(五)布尔常量 truefalse27 (六)两种方式定义符号常量 宏定义方式#definePI3.14 关键字方式 constdoublePI=3.141. 2.我们建议使用 const 关键字来定义常量四、数组是数目固定、类型相同的若干个变量的有序集合。每一个变量称为数组的一个 元素。 是一种复合类型,在单一的标识符下把变量结合在一起,一个接着一个。(一) 1. 2. 3.数组的定义 指出数组的类型; 给定数组名; 用[]表示维数;(二) 1. 2. 3.数组的赋值 数组名和下标表示数组的元素 数组元素初始化,使用{{},{}} 数组元素赋值(三)字符数组和存放字符串的数组charc[2]={'a','b'}; charc2[3]={'c','d','\0'};28 把字符串放入数组可以简写 charc[]={&123456&};charc3[3]={&cd&}; C++中增加了字符串库函数,以后会讲到#include&iostream& #include&string& voidmain() { cout&&&Thisisastring:&&&&\n&; std::strings=&c++中的字符串类型&; cout&&s.c_str()&& }(四)数组的访问如果下标超出数组的界限, 就不安全了。 另一个缺陷就是必须在编译期确定数组的大小#include&iostream& voidmain() { int a[3]={1,2,3}; for( int i=0;i&6;i++) { cout&&a[i]&&&at&&&(long)&a[i]&& } } 注意:编译器是这样处理数组的:对于数组 int p[m][n]; 如果要取 p[i][j]的值(i&=0&&i&m&&0&=j&&j&n),编译器是这样寻址的,它的地 址为: p+i*n+j;五、枚举(一)枚举类型枚举符实际上就是有小名的整型数值,默认是以 0 开始(也可以定义以其他整29 型值开始) ,步长为 1。enumPisaSize{BIG,SMALL};(二)枚举变量//枚举 #include&iostream.h& voidmain() { enumPisaSize{BIG,SMALL}; //enumPisaSize{BIG=15,SMALL=20}; enumPisaSizeps=BIG; PisaSizeps2=SMALL; //PisaSizeps2=SuperBIG; PisaSizeps3=(PisaSize)0; cout&&ps&&endl&&ps2&&endl&&ps3&& }(三)枚举变量的值不能直接用整型数值给枚举变量赋值,但是经过强制转换后可以 输出某个枚举变量的值也总是整型数值,这个跟 bool 的输出有点像六、指针第一节课先讲到普通变量的指针 第二节课讲指针和一维数组 第三节课讲二维数组、字符指针(指针部分是 c 语言的特色,也是难点,本节只做简单了解,详细的内容请参 看 c 语言中的指针讲解) 学习指针要注意的地方:30 I. II. III. IV.指针的类型:指针本身的类型都是 unsigned long int 指针指向的类型 指针变量本身占用的内存区 指针指向的内存区2.指针不管什么时候运行一个程序,都是首先把它装入计算机的内存。因此,程序中 的所有元素都驻留在内存中。内存一般被布置成一系列连续的内存空间。 (我们 常把这些位置看作是 8 位, 但实际上每个空间的大小取决于具体的计算机字长。 ) 我们用连续的地址对应这些连续的内存空间,所以每个元素也就对应的存放在 这个地址对应的内存空间。 那么,在 C 和 C++中有一个专门用来存放地址的变量类型,就是指针(pointer) 3. 如何定义指针类型*指针名 int *p 4. I. II. III. 给指针赋值 一般变量的地址 int a=2; int *p=&a; 数组元素的地址 int a[2]={1,2}; int *p=&a[2]; 数组的地址 int a[2]={1,2}; int *p=a;数组名是一个常量指针,书上这样说是不正确的,应该说,数组名多数时候可以看做是一个常量指针,其 值是该数组首元素的地址值。但是碰到运算符 sizeof()的时候,就不能把它看做 指针31 IV.函数的地址 doublesin(doublex);double(*pf)(double);pf=注意,定义指针后,必须先赋值才能引用;可以先给他赋值为 0 5. I. 指针的运算 赋值当把 0 赋值给一个指针时,这个指针叫做空指针 同类型同级别指针之间可以互相赋值 Void 类型指针可以指向各种类型 II. III.int指针可以加上或者减去一个整数值 p+=1;走他的类型的大小的距离。 跳过他的 两个指针相减类型一样的一个元素*p= int A int *lp= int A cout&&(*p-*lp)&&IV.两个指针比较char*s=&&; char*ss=s; cout&&&s&& s=s+8; cout&&*s&& cout&&s-ss&& if(s==(ss+8)){ cout&&&thesame&&& }6.数组元素的指针表示一维数组的指针表示int a[5]={9,8,7,6,5}; cout&&a&& cout&&*a&&//注意 a 是静态指针,不能再被赋值不能 a++等二维数组的指针表示int b[2][3]={1,2,3,4,5,6}; cout&&*(*(b+0)+0)&&32 7.指针数组int intArray[4]={0,1,2,3}; int * p=intA int a[5]={9,8,7,6,5}; int * pp[2]={a,p};//指针数组 cout&&*pp[0]&& cout&&*pp[1]&&8.指向数组的指针我们只介绍指向二维数组的指针。它是一个二级指针,就是指向指针的指针。通常用一个二维数组的行地址(二级指针的地址) 给他赋值int (*ppp)[3];//指向数组的指针,这个称为行指针 int b[2][3]={1,2,3,4,5,6}; ppp=b+1; cout&&*(*(b+0)+0)&& cout&&**ppp&&9.指向字符串的指针(字符指针)Char * s=&&; char*ss=s; cout&&&s&& s=s+8; cout&&*s&& cout&&s-ss&& if(s==(ss+8)){ cout&&&thesame&&& }10.字符指针数组Char * sss[]={&abc&,&def&,&ijkh&}; cout&&sss&& cout&&*sss&&关于数组名是不是指针的问题33 七、引用关于引用,只有一句话, “引用就是变量的小名” ,和小沈阳的小名“小损样” 一样。 引用的本身没有值也没有地址,不占内存。与指针不同,定义引用的同时必须初始化,而指针在使用前初始化即可。八、运算符关于 c++中的运算顺序 1. 算术运算符正负号 加减乘除。在C++中,加减乘除分别使用字符'+'、'-'、'*'、'/'作为运算符号。 加、减、乘的操作没有什么需要特别说明之处。如: int a=1+2-3*4; 得到的结果:a等于-9。当然,乘号使用*表示,这你得记。 除运算除了使用反斜杠'/'表示以外,很重要的一点是别忘了,对于整数类型,或 字符类型的数据进行除运算时,小数部分将被截掉,因为整型类型的数据不能 保存小数部分,如: int a=5/2; 得到结果:a 等于 2,而不是 2.5。 注意:可能大家会以为,之所以 5/2 结果是 2,是因为我们让一个整型变量 a 等于34 它,其实原因并不是因为 a 是 int 类型,请看: floata=5/2; 虽然 a 现在被声明为实型,但执行这句程序,a的值仍然是 2。事实上,精度丢 失是在计算机计算 5/2 时就发生了。所以,准确的写法是:floata=5.0/2; 或者: floata=5/2.0; 或者: floata=5.0/2.0; 也就是说,只有除数或被除数至少需要有一个是明确指定为实型,除运算才能 得到小数部分。这里我们也更明确类似于 5 和 5.0 在计算机中的区别:虽然数值 大小一样,但加了 5.0 被当成实型数对待,而 5 则被当成整型数。 还有一个值得注意的地方就是:在 vc6.0 环境下 5/0=0%操作也是 C++常用的操作符。%并不是进行“百分比”的运算。在 C 和 C++ 里,%进行 int 相除求余数运算,求余数也称“求” ,以下是求模操作的例子: int a=5%2; 结果是,a 等于 1,即:5 除以2,余数为1。 注意,%运算的结果的正负由分子决定35 自加或自减1。 C,C++提供了更为优化的运算操作符:++,--。 设整型变量 a,原值为 10。要实现对其加1,可以写成 ++a,或者:a++; 也就是说,在只自加1的情况下,代码 a++或++a 可以生成最优化的汇编代码。同样,自减1操作也有对应的操作符:--a 或 a--; 设 a 原值为 10,则执行--a 或者 a--后,a的值都为9。现在来谈谈++a 和 a++有什么区别。 在C,C++语言里,++a 和--a 称为前置运算(prefix),而 a++和 a--称为后置运 算(postfix)。 如果仅仅是进行前置工或后置运算,那么结果是相同的,这我们已经在前面谈 过,我们以++为例:设a为10,则无论是++a 或 a++,执行结果都是让a递增 1,成为 11。 但在有其它运算的复杂表达式中,前置++运算过程是:先加1,然后将已加1 的变量参以其它运算。后置++的运算过程是:先用未加1的变量参以其它运算, 然后再将该变量加1。 听起来有些绕,我们举些例子看,还是变量a,原来值为 10: 例子1: int b=++a;//前置++ 运算结果:a的值为 11,b的值也为 11。36 计算过程解析: 先计算++a,结果a值为 11; 然后再计算 b=a;结果b值也为 11。例子2: int b=a++;//后置++ 运算结果:a的值为 11,但b的值为 10。 计算过程解析: 先计算 b=a;因此,b 的值是未加1之前的 a,所以为 10; 然后再计算 a++,a的值为 11。再举一复杂点的表达式: int a=10; int c=5;int b=a+++c; 执行这些代码,b 值为 15倘若换成: int a=10; int c=5; int b=++a+c;37 执行这些代码,b 值为 16; 想一想,为什么?上在举的是++的例子,对于--操作,其计算顺序的规定一样。编译的贪吃特征:所谓贪吃,是指只要能理解成为操作符,就尽量多的读入字 符。 int a=3,b=5,c; c=a++b;//错:编译器理解为 a++b c=a+++b;//ok:编译器 a+++b c=a++++b;//错:编译器理解为 a++++b c=a+++++b;//错:编译器理解为 a+++++b++和--的确能加快运算速度,但它们在前置和后置运算上的微小区别,却很空易 让你的代码变得不清晰。更为不好的是,不同的编译器可能会对比有不同的解 释,造成代码的运行结果也不一样,这是我们应该尽量避免的。所以我们建议 在代码尽量不要依赖于前置和后置运算的区别。 (尽管它会让你的代码看上去很 象“高手”所写) 。 2. 关系运算符所谓的关系运算,在 C,C++语言里,就是比较运算。 算术运算所得的结果是数值,而关系运算所得的结果为逻辑值,也称布尔值。38 即我们以前所学的 bool 类型允许的值: 真或假。 真用 true 表示, 假用 false 表示。 关系操作符有 6 种: 前四种优先级为 6 &(比较左值是否大于右值) &=(比较左值是否大于或等于右值,也称为不小于) &(比较左值是否小于右值) &=(比较左值是否小于或等于右值,也称为不大于) 后两种优先级为 7 ==(比较左右值是否相等) !=(比较左右值是否不相等)注意: 比较是否相等, 使用两个连写的等号表示。 因此==和=是两个不同的概念, 后者指赋值运算。 C,C++的不等于用!=表示,而不是我们更常见的&&,请大家注意。 下面举一些例子。int a=10; int b=9; 则: a==b+1 a==b a&b 运算结果: 运算结果: 运算结果:true39 a&=b b&a a&=b+1 a&=b+1 a!=b;运算结果: 运算结果: 运算结果: 运算结果: 运算结果:关系运算符注意事项: 例: int a = -1, b = 0, c = 1; if ( a&b&c ) cout && “ok1\n” ; if ( a&b && b&c ) cout && “ok2\n” ; 结果为: ok2例应避免对实数作相等或不等的判断如:#include &iostream.h& void main() {float a=3.0,b; a=1.0/a; b=1.0; cout&&(a*3==b ? &same\n& : &not same\n&);}3.逻辑运算符40 逻辑运算有三个操作符: ! && || (非,逻辑求反,NOT) (逻辑与,并且,AND) (逻辑或,或者,OR) 2 级优先 11 级优先 12 级优先下面列出了&&(与)操作的所有可能条件及结果:真&&真=真 真&&假=假 假&&假=假下面列出了||(或)操作的所有可能条件及结果真||真=真 真||假=真 假||假=假以下则为!操作: ! 真 =假 ! 假 =真短路特性:逻辑表达式求解时,并非所有的逻辑运算符都被执行,只是在必须 执行下一个逻辑运算符才能求出表达式的解时,才执行该运算符41 例 a&&b&&c//只在 a 为真时,才判别 b 的值; 只在 a、b 都为真时,才判别 c 的值例 a||b||c//只在 a 为假时,才判别 b 的值; 只在 a、b 都为假时,才判别 c 的值例 a=1;b=2;c=3;d=4;m=1;n=1; (m=a&b)&&(n=c&d) 结果 m=0,n=1&&对应于题目的的“并且”,而||对应“或者” 当我们需要说,只有条件 A 和条件 B 都成立??用 C,C++表达即是:A&&B。 当我们需要说,只要条件 A 或者条件中成立??,这时表达为:A||B。师院美女征友: 凡追我者,请先看以下代码。符合条件者,共聚肯德基啃鸡腿: a=比李嘉诚有钱; b=比我年轻; 见面条件:a&&b; 告示贴了一个月,没啃上鸡腿。心有不甘,遂修改告示如下:师院美女征友: 凡追我者,请先看以下代码。符合条件者,共聚肯德基啃鸡腿: a=比李嘉诚有钱;42 b=比我年轻; 见面条件:a||b; 事情发生了巨大的变化。 现在,第一个应征者,公务员猪悟能,高老庄集团董事长兼总经理,资产雄厚。 第二个应征者,超帅的高数哥。 你感觉怎么样?最后我们来说说“! ” 。感叹号在 C,C++拿来表达“相反”或“非、不”等意思。 它的运行很简单:原来为真,加感叹号后为假,原来为假,加感叹号后为真。4.位操作运算符逻辑位运算 按位求反 按位与 ~ & 都是 1 为 1 使用 0 将某位置 0unsigned int a=1; cout&&(a&2)&&//0按位或|出现1为1使用1将某位置1unsigned int a=1; cout&&(a|2)&&//3按位异或^不同为 1,否则为 0定位翻转(与 0 异或保持原值,与 1 异或取反) 例如:要使
低四位翻转: 0 1 1 1 1 0 1 0 (^) 0 0 0 0 1 1 1 143 0 1 1 1 0 1 0 1unsigned int a=1; cout&&(a^2)&&//3移位运算 左移&& 右移&& 号位为 1 5. 赋值运算符 右补 0 无符号数左边补 0;有符号数补符号和 0,整数符号位为 0,负数符我们已经很熟悉的等号:=,C,C++称为赋值操作。看看例子,是不是很熟悉: int a=10; 再如: b=a; 或: int c=12*2;在C++中,可以使用连等操作: int a,b; a=b=100; 结果是,a和b都为 100。先来看一个计算机编程中常有的语句例子:44 int a=10; a=a+1;上面的代码执行后,结果a的值是 11。可能不是很理解 a=a+1;这种运算。 首先可能会认为, a和 a+1 怎么会相等呢?这可是个严重错误, 要知道, 在 C,C++ 里, '='就是表示赋值操作, 至于表示左右两值 “相等” 的另有符号。 因此, a=a+1, 所完成的工作就是:先计算出 a+1 的值,然后将该值赋给a。 假设我们的存款原为a,现在存入1元,那么新的存款就等于旧存款加上1元 钱,用编程语言表达,就是 a=a+1; 在C,C++中,这样的自加操作可以有另一种表达,并且用这一种表达,计 算机的运算速度比较快。 a=a+1;的另一种运算速度较快的表达方法: a+=1; +=被定义为一种新的操作符(因此+和=要连着,中间不能有空格) 。它实现的操 作就是将其左边的量在自身的基础上加上右边表达式的值。比如: ,假设 a 原来 的值为 10,那么: a+=2; 执行这一句后,a 的值为 12,即 a=10+2;同样的,减,乘,除,求余都有这种操作符:-=、*=、/=、%=等。我们以后学 习到的另外一些运算符,也有同样的这种对应运算。举一些例子:45 假设在分别进行以下操作之前,a 原值都为 10。 a-=2; 执行后,a值为 8;(a=10-2)a*=2; 执行后,a值为 20;(a=10*2)a/=2; 执行后,a 值为 5;(a=10/2)a%=2; 执行后,a 值为 0;(a=10%2)C,C++提供这些操作符,目的仅仅是为了提高相应操作的运算速度。为什 么 a+=2;会比 a=a+2;运算得快呢?从编译的角度上看, 是因为前者可以生成更短 小的汇编代码。 C,C++提供这些别的语言没有的操作符,可以供我们写出优化的代码。 在某些特殊情况下,优化还可以继续。 6. 三目运算符int a=1; double b=2.2; cout&&(a&b?a:b)&&7.逗号运算符int x,y=7;46 float z=4; x=(y=y+7,y/z); cout&&&x= & &&x&&8.sizeof()运算符9.运算中的隐式类型转换类型转换在 C,C++中也属于一种运算。 前面我们举过一个例子: floata=5/2; 还记得 a 的计算结果吗?上式中,a 将得到的值是 2。因为在除式 5/2 中,5 和 2 都是整数,所以计算机按整数类型进行了除运算,结果所有的小数位都被丢失 了。 我们列出了三种可以解决小数位丢失的方法: 方法 1: float a=5.0/2; 方法 2: float a=5/2.0; 方法 3: float a=5.0/2.0;最后一种方法好理解,5.0 和 2.0 都明确指定为实型(double),所以计算结果可以 保存小数位。而像第一种:被除数 5.0 被指定的为实型,但除数 2 仍然为整型, 这两种数据类型的精度不一样,这时,计算机将按哪个类型作为标准呢?C++遇到两种不同数据类型的数值进行运算时,会将某个数做适当的类型转换, 然后再进行转换。转换总是朝表达能力列强的方向进行,并且转换总是逐个运 算符进行的。47 像上面的 a=5/2。计算机先计算 5/2,由于 5,2 一样是整型,所以计算机不作转换, 算出其结果为 2,然后赋值给 a,因此,就算 a 是 float 类型,但仍然只能得到 2 的结果,而不是 2.5。 而 a=5.0/2。计算机在计算 5.0/2 时,发现 5.0 是实型(带小数点),而 2 是整型, 二者不一,所以将 2 先自动转换成 double 数,然后现和 5.0 进行除运算。 这个转换过程,在程序运行时自动进行,称为隐式转换。 隐式(自动)转换尽量使用我们的程序更加合理,但有时它并不能完全符合我 们的要求。比如:int a=1; int c=2; cout&&a/c&&我们只能得到 b=0. 如果我非要得到 0.5 呢。还有一个办法就是强制类型转换int a=1; int c=2; cout&&(float)a/c&&10.强制类型转换运算符强制类型转换。它的语法形式有两种: 形式 1:(类型名)变量或数值 形式 2:类型名(变量或数值)实际例子如: int b=5,c=2;48 floata=(float)b/c; 或者: floata=float(b)/c; 两种写法都可以将变量 b 强制转换为 float 类型。 不过,在要转换的数据类型带有修饰符时,则必须使用第一种型式。比如: (unsigned int )a; 其实,两边都加上括号有时更清晰:(unsigned int )(a); 11. 12. 单目运算符*和& 运算符的优先级、结合性醋坛子,酸味浓 醋-初等,5 种: 坛-单目,9 种 酸-算术,5 个:*/% 味-位移,2 个:&&&& 关系,6 个: +-与和或,插异或条件 赋值 逗号, 结合方向自右向左的只有三类:赋值、单目和三目,其它的都是从左至右结合。49 赋值表达式则规定先对右边的表达式求值,因此使 a=b=c=6;成为可能。九、表达式学习表达式的时候注意两个方面: 表达式的值和类型 表达式中的隐含转换和强制转换 变量、常量、各种运算符等组成表达式,用于表达一个计算过程。下面看课本上的例题: 1、 算术表达式是由算术运算符和位操作运算符组成的表达式。 值:一个数值 类型: 各操作数类型相同时, 表达式的类型就是操作数的类型; 不同时, 表达式的类型是个操作书中各类型最高的操作数的类型。 注意:位操作运算符只能处理整数(浮点数都是近似的二进制表示,所以无法 进行位运算。 ) ,由于操作数都是整数,因此表达式的值也是整数。//例2.10 #include &iostream.h& void main() { a=7*2+-3%5-4/3; b=510+3.2e3-5.6/0.03; cout&&a&&&\t&&&b&& int m(3),n(4); a=m++ - --n;50 cout&&a&&&\t&&&m&&&\t&&&n&& /* cout 默认6为有效数字,所以输出3523.33 */ //例 2.11 #include&iostream.h& void main() { unsigned a(0xab),b(20); cout&&&十六进制的a:&&&hex&&a&& cout&&&十进制的a:&&&dec&&a&&//0xab转化为十进制:10*16的1次幂+11*16的0次幂a&=b;//010100按位与 cout&&&a&=b后a:&&&a&& a^=a;//和自己按位异或 cout&&a&&&\t&&&b&& int x(-3),y(5); int z=(x&&y); cout&&&z=(x&&y)后z: &&&z&& x&&=y; cout&&&x&&=y后x:&&&x&& x=y^~y; y&=~x+1; cout&&x&&&\t&&&y&& }2、 关系表达式 值:1,0 类型:bool//例 2.12 #include &iostream.h& void main() { char x('m'),y('n'); n=x&y; cout&&n&& n=x==y-1; cout&&n&& n=('y'!='Y')+(5&3)+(y-x==1); cout&&n&& }51 /* 1 1 3 */3、 逻辑表达式 值:0,1 类型:bool//例 2.13 #include &iostream.h& void main() { int x,y,z; x=y=z=1; --x&&++y&&z; cout&&x&&'\t'&&y&&'\t'&&z&& ++x&&++y&&++z; cout&&x&&'\t'&&y&&'\t'&&z&& ++x&&y--||++z; cout&&x&&'\t'&&y&&'\t'&&z&& }/* 0 1 1 2 2 1 */1 2 24、 条件表达式 值: 类型:冒号前后类型较高的//例2.14 #include &iostream.h& void main() { int a(3),b(4),c;52 c=a&b?++a:++b; cout&&a&&&,&&&b&&&,&&&c&& c=a-b?a+b:a-3?b:a; cout&&a&&&,&&&b&&&,&&&c&& }/* 3,5,5 3,5,8 */5、 赋值表达式//例 2.15 #include &iostream.h& void main() { int x(1),y(3),z(5); x+=y*=z-=2; cout&&x&&&,&&&y&&&,&&&z&& x*=y/=z-=x; cout&&x&&&,&&&y&&&,&&&z&& x=y=z=2; z=(x*=2)+(y+=4)+2; cout&&z&&} /* 10,9,3 -10,-1,-7 12 */6、 逗号表达式//例 2.16 #include &iostream.h& void main() { int a,b,c; a=1,b=2,c=a+b+3; cout&&a&&','&&b&&','&&c&& c=(a++,a+=b,a+b); cout&&c&& }53 /* 1,2,6 6 */ }7、 隐含转换,不改变原值 发生在双目运算中,当操作数类型不一致时,转换为较高的类型 Short 和 char 自动转换为 int Float 自动转换为 double 例如:short a=32767; short b=32767; short c=a+b; cout&&c&& cout&&a+b&&8、 强制转换,不改变原值 显式强制转换,不安全的窄化转换 隐式强制转换:发生在赋值和函数返回值时十、类型定义#include&iostream.h& void main() { char * a=&ad&; cout&&a&& typedef char * string c=&mmm&; cout&&c&&typedef string StringArray2[2];54 StringArray2 sa2={&cc&,&dd&}; cout&&sa2[0]&& } 复杂类型说明的优先级问题: [] () 最高,* & 其次,数据类型名最低 //例 2.18 #include&iostream.h& void main() { int a(7),* double b(5.6321),* void * pi=&a; pv=&b; cout&&*pi&& pd=(double *) cout&&*pd&& } /* 7 5.6321 */十一、结构1、 结构的定义、结构成员的表示和赋值#include&iostream.h& void main(){ struct student { char * double score[3]; }; student a={18,&Tom&,99.9};//结构变量成员初始化cout&&a.name&& a.name=&Jerry&;//结构变量成员赋值55 student * s=&a; cout&&s-&name&& cout&&(*s).name&&student b[2]; b[0]=a; cout&&b[0].name&& }2、结构的使用//例2.20 #include&iostream.h& #include&string.h& #include&student.h& student stu[3]={{&Fan&,80,82,87},{&wang&,90,85,80},{&Li&,83,78,70}}; student * find(student * s) { char namel[20]; cout&&&Input student's name:&; cin&& for(int i=0;i&3;i++) { if(strcmp(namel,s[i].name)==0)//strcmp是字符串比较函数,string compare ,是string.h 定义好的。比较两个字符串是否相同,相同时返回0 return s+i; } return 0; } void main() { student *p; p=find(stu); cout&&p-&name&&':'&&(p-&score[0]+p-&score[1]+p-&score[2])/3&& }十二、联合联合用 union 关键字定义 联合与结构的不同:56 1、联合变量通常不初始化 2、联合成员共址,而结构成员异址//演示联合的共址 #include&iostream.h& void main() { union{}u; u.i=7; cout&&u.a&& }第三章 预处理和语句讲解顺序: 文件包含――宏定义――条件语句――条件编译――其他语句一、预处理预处理命令就是在程序被正常编译之前执行的命令。所有的预处理命令都是以# 作为标识。每一条预处理命令单独占一行。一般写在程序的开头(也可以根据 需要写在程序的中间和末尾) 1. 文件包含命令# include “文件名” 以&&括起来的文件是指那些有系统提供的并放在指定目录的头文件 以“”括起来的文件是指那些自己定义的放在当前目录或其他目录下的文 件。 头文件,以.h 作为后缀名,是指存放着与标准函数有关的信息,或者存放 符号常量、类型定义、类、其他复杂类型的定义以及与程序环境相关的信息的57 文件。 处理过程:预编译时,用被包含文件的内容取代该预处理命令,再对“包 含”后的文件作一个源文件编译#include “file2.h”file2.hB A file2.h file1.cpp file1.cpp A譬如说,我们定义的 structstudent 一般就放在头文件中。文件包含 命令可以放在程序的中间或结尾: //e.hcout&&&aaa&&& //test.cpp #include&iostream.h&void main() { #include &e.h& }2.条件编译命令作用:用来定义某些编译内容要在满足一定条件下才参与编译,否则将不参与 编译。因此可以使同一个源程序在不同的编译条件下产生不同的目标代码。 条件编译可有效地提高程序的可移植性,并广泛地应用在商业软件中,为一个58 程序提供各种不同的版本。 第一种格式#include&iostream.h& #define eng 3.14 void main() { int x=2; cout&&x&& # cout&&&定义过&&&eng&& #else cout&&&没有定义过&&& #endif }第二种格式 第三种格式 Vc++提供的 defined(标识符)#include&iostream.h& #define eng 3.14 void main() { #if defined( eng ) cout&&&定义过了&&& #elif #endif }关于防止重复包含的文件头卫士59 3.宏定义命令宏定义命令就是给字符串起名字,这个字符串称为替换文本,起好的名字称为 宏名1.简单的宏定义#define eng 3.14取消宏定义: #include&iostream.h& #define eng 3.14 void main() { cout&&eng&& #undef eng #if defined(eng) cout&&&定义过&&& #else cout&&&没有定义货已经取消了&&& #endif } 2. 带参数的宏定义60 #include&iostream.h& #define sum(x,y) x+y void main() { s=sum(3,2); cout&&s&& } 注意:在宏定义的时候,对与参数名相同的字符适当的加上圆括号可以确定计算顺序。 如课本上83页所述。 //例3.5 #include&iostream.h& void main() { int b(5); #define b 2 #define f(x) b*(x) int y(3); cout &&f(y+1)&& #undef b cout &&f(y+1)&& #define b 3 cout &&f(y+1)&& } /* 8 20 12 */61 二、语句1. 表达式语句和空语句表达式加分号结尾就叫表达式语句 空语句就是只有一个分号的语句 2. 复合语句用花括号包围起来的语句 3. 选择语句最基本的执行过程就是顺序结构下面我们来学习简单的分支语句――条件语句 A、条件语句 if else if 语句的两种形态: 对应的语句形式: if (条件表达式) 语句 if (条件表达式) 语句 1 else 语句 262 If 后面的条件需要一个 bool 值,当你使用一个赋值语句作为条件的时候,不能 起到一个条件的作用 If 语句的嵌套 错综复杂时,必须注意两义性: if(x&0) if(x&50) cout&&”x is ok.\n”; else cout&&”x is not ok.\n”; 误解:else 从属于外面的 if if(x&0){ if(x & 50) cout&&”OK\n”; }else63正解:else 从属于紧挨的 if if(x&0){ if(x & 50) cout&&”OK\n”; else cout&&”NOT OK\n”; }cout&&”NOT OK\n”;B、开关语句 switch case//例3.8 #include &iostream.h& void main() { double d1,d2; cout&&&请输入表达式,两个double数的四则运算&&& cin&&d1&&op&&d2; switch(op) { case '+':cout&&d1&&op&&d2&&&=&&&d1+d2&& case '-':cout&&d1&&op&&d2&&&=&&&d1-d2&& case '*':cout&&d1&&op&&d2&&&=&&&d1*d2&& case '/':cout&&d1&&op&&d2&&&=&&&d1/d2&&64
default:cout&&&请安要求重新输入&&& } } //例3.9 #include &iostream.h& void main() { double d1,d2; cout&&&请输入表达式,两个double数的四则运算&&& cin&&d1&&op&&d2; switch(op) { case '+': case '-': case '*': case '/':cout&&d1&&op&&d2&&&=&&&d1/d2&& default:cout&&&请安要求重新输入&&& } } //例3.10 #include &iostream.h& //#define A 0 void main() { int i(1),j(0),m(1),n(2); switch(i++) { case 1: m++; n++; #if defined(A) cout&&m&&','&&n&&//2,3 #endif case 2: switch(++j) {65 case 1: m++; #if defined(A) cout&&m&&','&&n&&//3,3 #endif case 2: n++; #if defined(A) cout&&m&&','&&n&&//3,4 #endif } case 3: m++;n++; #if defined(A) cout&&m&&','&&n&&//4,5 # case 4: m++;n++; } cout&&m&&','&&n&&//4,5 }4.循环语句While(){}0条件退出循环非0语句Do {}while() ;66 语句0条件退出循环 非0For(){} //注意 for(int i=1;i&2;i++)的 i++是什么时候进行计算的,看下面例子#include &iostream.h& void main() { for(int i=1;i&2;i++){ cout&&i&& } cout&&i&& }课堂练习:乘法表//乘法表 #include &iostream.h& void main() { for(int i=1;i&=9;i++) {67 for(int m=1;m&=i;m++) { cout&&m&&&*&&&i&&&=&&&m*i&&'\t'; } cout&& } } //3.15 #include &iostream.h& void main() { int i=1,a=0; for(;i&=1;i++) { cout&&i&& } cout&&a&&&,&&&i&& } //a 0 1 2 3 //i 1 2 3 4 5 6 7 8MSDN sqrtCalculates the square root. double sqrt( double x );Routine sqrtRequired Header Compatibility(兼容性) &math.h& ANSI, Win 95, Win NT//我求素数的方法 //判断一个数是否素数 #include &iostream.h&68 void main() { int i=7; for(int m=2;m&=6;m++) { if(i%m==0) if (m==6) cout&&&i是素数&&& } } //如例题,判断多个数是否素数 #include &iostream.h& #define MIN 50 #define MAX 100 void main() { int i,j; for(i=MIN;i&=MAX;i++)//偶数不可能是素数,所以从51开始直接判断奇数 {for(j=2;j&=i-1;j++) { if(i%j==0) if(j==i-1) cout&&& &&&i; } } cout&& } //3.16 //判断一个数是否素数,只需要判断到他的平方根就可以啦。具体定理可以去问数学老师。 #include &iostream.h& #include &math.h& #define MIN 51 #define MAX 100 void main() { int i,j,k,n(0); for(i=MIN;i&=MAX;i+=2)//偶数不可能是素数,所以从51开始直接判断奇数69 { k=(int)sqrt(double(i));//求i的平方根,取整 for(j=2;j&=k;j++) if(i%j==0) if(j&=k+1) { //if(n%6==0)//控制每行显示六个数 // cout&& // n++; cout&&& &&&i; } } cout&& } //53 59 61 67 71 73 79 83 89 97 //例3.17 #include &iostream.h& void main() { for(int i=1;i&=10;i++) { for(int j=1;j&=11-i;j++) cout&&& &;//俩空格 for(j=1;j&=i;j++) { if(i==10) cout&&i&&& &; //俩空格 else cout&&i&&& &; //三空格 } cout&& } }课后作业: 写一个程序,输入十进制正整数,输出 32 位二进制数#include &iostream.h& void tT2(int a) { int result[32]; for(int n=0;n&32;n++)70 { result[n]=0; }int i=31; while(a&1) { result[i]=a%2; a/=2; i--; } result[i]=a;for(int m=0;m&32;m++) { cout&&result[m]; } cout&&'\n';}5.转向语句A. goto 用来在程序中进行跳转 B. //goto 例题 #include &iostream.h& void main() { int a(1),b(2),c(3),d(4); int i=1; aa: cout&&a&&71 cout&&b&& cout&&c&& cout&&d&&i++; if(i&3) } 注意:尽量减少 goto 语句的使用。 //3.18 #include&iostream.h& void main() { int i,j,num[2][3]; cout&&&请输入数组的 6 个元素&&& for(i=0;i&2;i++) { for(j=0;j&3;j++) { cin&&num[i][j]; } }72 for( i=0;i&2;i++) { for(j=0;j&3;j++) { if(num[i][j]&0) { }} } cout&&&没有您要找的东西&&& found: cout&&&数组 num 的第&&&i+1&&&行,第&&&j+1&&&列,值为 &&&num[i][j]&&&的元素是负数&&& end: ; } C. break 退出开关语句或退出该重循环 #include &iostream.h& #define M 10 void main() {73 int num,sum=0; cout&&&请输入十个正整数,如果您输入了负数,则程序会终止并输出正 整数的和&&& for(int i=0;i&M;i++) { cin&& if(num&0) sum+= } cout&&sum&& } D. continue 结束该次循环,返回到循环条件,判断是否执行下一次循环 //3.20 #include &iostream.h& #define M 10 void main() { int num,sum=0; cout&&&请输入十个正整数,如果您输入了负数,则程序输出正整数的和 &&& for(int i=0;i&M;i++) {74 cin&& if(num&0) sum+= } cout&&sum&& }第四章 函数和作用域函数是对语句进行的抽象,对能够实现一定功能的语句进行模块化。以达到封 装和隐藏实现细节,有利于数据的共享,节省开发时间,增强程序的可靠性。 先看一个简单的例子 //4.1 这是主函数 Test.cpp #include&iostream.h& void main() { /* double x,y; cout&&&Input double x and y&&& cin&&x&&y; double z=x+y; cout &&&sum=&&&z&& */ double x,y;75 cout&&&Input double x and y&&& cin&&x&&y; double sum_double(double ,double);//函数的说明 double sum=sum_double(x,y); cout &&&sum=&&&sum&& } ---------------------------------------------------------------------------------------------//这是函数的定义 sum.cpp #include&iostream.h& double sum_double() { double x,y; cout&&&Input double x and y&&& cin&&x&&y; double z=x+y;} 从上面这个例子可以看出来,当我们把一定的功能抽象成一个函数的时候,那 么这个函数的使用者就不必关心函数的计算过程,只要知道这个函数是做什么 用的就好了。76 一、函数的定义和说明那么,怎么来定义一个函数呢? 类型 函数名 (参数表) {函数体}我们再来看一个简单的例子。昨天我出门很匆忙,当我站在门外,随手关闭了 防盗门,听到“彭”的一声防盗门关上了,心里就猛然一惊。忘了拿钥匙了。 怎么办? 找开锁公司吧。 我就是那个主函数; 开锁公司派来的工人就是被我调用的函数。 #include &iostream.h& void main() {77
void open_door(double ); cin&&x; open_door(x); } -------------------------------------------------------------------------------------------------//开锁工人 Open.cpp #include &iostream.h& void open_door(double x) { if(x&=100) { cout&&&锁已经打开了&&& } else { cout&&&您付的钱不够&&& } } 关于函数的说明: 定义在先,调用在后,则调用前可以不必说明;如果一个函 数定义在后,调用在前,则调用前必须说明78 二、函数的调用函数名 (实参表) 实参是用来在调用函数时给形参初始化的。因此要求函数调用时,实参的个数 和类型与形参的个数和类型是一致的,即数目相等,类型一致。关于 return A. 在有返回值的函数中,必须用 return 返回规定的类型 B. 在没有返回值的函数中,必须使用 void 加以说明,函数体中可以有 return; 语句,也可以没有 1、 函数的传值调用79 传值调用的机制、特点: 实参是常量、变量的值或表达式值 形参是变量 传值调用的实现机制是系统将实参复制一个副本给形参。被调用函数中,形 参是可以改变,但这只影响副本的值,而不影响调用函数的实参值。参数传 递的开销大2、函数的传址调用80 传地址调用的实现机制和特点 使用传地址调用方式时: 调用函数的实参用地址值 被调用函数的形式参数用指针. 调用时,系统将实参的地址值赋给对应的形参指针,使形参指针直接指向实参 变量. 特点:可以通过改变形参指针所指向的变量值来影响实参。这也是函数间传 递信息的一种手段。 例题: #include&iostream.h& void main() { double m(2.1),n(3.3);81 double sum_double(double,double); double sum=sum_double(m,n); cout&&&使用传值的方式 sum=&&&sum&&cout&&&使用传值的方式计算后 m=&&&m&&& n=&&&n&&cout&&cout&&double sum_double(double *,double *); double sum2=sum_double(&m,&n);cout&&&使用传地址的方式 sum=&&&sum2&& cout&&&使用传地址的方式计算后 m=&&&m&&& n=&&&n&& }//这是函数的定义 //这个函数接受两个小数,计算求和,并返回求和结果 //传值 double sum_double(double x,double y) { x+=1; y+=1;82 double z=x+y; } //传地址 double sum_double(double * x,double * y) { *x+=1; *y+=1; double z=*x+*y; } 3、 函数的引用调用前面我们讲过了引用的概念。所谓引用,就是变量的别名 引用主要的用处就是用来作为函数的形参和函数的返回值 使用引用作为函数的形参,调用函数的实参要用变量名,将实参变量赋值给 形参引用,相当于在被调用的函数中使用了实参的别名。 这种调用具有传地址调用中改变实参值和减少开销的特点,但是他又比传地 址调用更方便、更直接。 A. 引用作为形参#include&iostream.h& void main()83 { double m(2.1),n(3.3);double sum_double(double,double); double sum=sum_double(m,n); cout&&&使用传值的方式 sum=&&&sum&&cout&&&使用传值的方式计算后 m=&&&m&&& n=&&&n&&cout&&cout&&double sum_double(double *,double *); double sum2=sum_double(&m,&n); cout&&&使用传地址的方式 sum=&&&sum2&& cout&&&使用传地址的方式计算后 m=&&&m&&& n=&&&n&&cout&&cout&&double sum_double(double &,double &); double sum3=sum_double(&m,&n); cout&&&使用引用的方式 sum=&&&sum3&& cout&&&使用引用的方式计算后 m=&&&m&&& n=&&&n&&84 } //这是函数的定义 //这个函数接受两个小数,计算求和,并返回求和结果 //传值 double sum_double(double x,double y) { x+=1; y+=1; double z=x+y; } //传地址 double sum_double(double * x,double * y) { *x+=1; *y+=1; double z=*x+*y; } //引用 double sum_double(double & x,double & y) {85 x+=1; y+=1; double z=x+y; } B. 引用作为返回值 如果一个函数返回了引用,那么该函数的调用也可以被赋值。int& add(int & m) { m+=4; } ///////////////////////////// #include &iostream.h& #include &math.h& void main() { int k=3; cout&&(add(k)+=1)&& } --------------------------------------------------------------------------------//例 4.6 #include &iostream.h& int & fun(char ,int&,int &); void main( ) { int tn(0),tc(0);86 cout&&&Enter characters:&; cin&& // cout&&ch&&while(ch!='#') { fun(ch,tn,tc)++;//当函数返回引用时,才可以这样写 cin&& } cout && &Number characters: &&&tn&& cout && &Other characters: &&&tc&& } /////////////////////////////////////////////int & fun (char cha ,int& n,int & c) { if(cha&='0'&&cha&='9') } 传值、传地址、传引用的综合练习: 1、写一个 student 结构;包含学号 number 和年龄 age 2、写一个函数 change_age,形参为 student87和 new_age 完成更改年 龄的功能,分别用传值、传地址、传引用实现。 3、在 main 函数中,给 student 赋初值 change_age 函数把年龄更改为 18 并 cout number=001 age=30 ,调用struct student { }; #include &student.h& #include &iostream.h& student change_age(student stu,int new_age) { stu.age=new_ }student & ch_age(student & stu,int new_age) { stu.age=new_ } student * c_age(student * stu,int new_age) { stu-&age=new_ }void main() { student s1={001,30}; cout&&s1.age&&88 // //change_age(s1,20); ch_age(s1,20); c_age(&s1,20); cout&&s1.age&& }三、函数的参数1、 参数的求值顺序由于 c++语言没有规定在函数调用时实参的求值顺序,不同的编译器就会有 不同的结果。 在写函数时,尽量避免二义性的出现。#include &iostream.h& int add_int(int x,int y) { return x+y; } ///////////////////// void main() { int x(4),y(6); // int z=add_int(++x,x+y); int t=++x; int z=add_int(t,x+y); cout&&z&& }2、设置函数参数的默认值在函数说明或者定义的时候可以给一个或多个参数指定默认值,缺省形参值 必须从右向左顺序声明,并且在缺省形参值的右面不能有非缺省形参值的参 数。因为调用时实参取代形参是从左向右的顺序。当调用出现在函数体实现之前时,缺省形参值必须在函数说明中给出; 而当调用出现在函数体实现之后时,缺省形参值需在函数定义时给出。89 ? 例: int add(int x=5,int y=6);//在函数说明 int add(int x=5,int y=6)//在函数定义时 中给出 void main(void) { } int add(int x,int y) { return x+y; } add(); //调用在实现前 给出 { return x+y; }void main(void) { } add(); //调用在实现后//4.8 #include &iostream.h& void fun(int a=1,int b=3,int c=5) { cout&&&a=&&&a&&& b=&&&b&&& } void main() { fun(); fun(7); fun(7,9); fun(7,9,11); cout&&&ok&&& } //4.9 #include &iostream.h& int m(8); int add_int(int x,int y=7,int z=m); void main() { int a(5),b(15),c(20);c=&&&c&&90 int s=add_int(a,b); cout&&s&& } /////////////////////////////// int add_int(int x,int y,int z) { return x+y+z; }3、 A、数组作为函数的参数 形参和实参都用数组调用函数的实参用数组名,被调用函数的形参也用数组名 调用机制:形参和实参共用内存中同一个数组//4.10 #include &iostream.h& int a[8]={1,3,5,7,9,11,13}; void fun(int b[],int n) { for(int i=0;i&n-1;i++) b[7]+=b[i]; } void main() { cout&&a[7]&& int m=8; fun(a,m); cout&&a[7]&& }B、形参和实参都用对应数组的指针//4.11 #include&iostream.h& int a[8]={1,3,5,7,9,11,13};//注意,a[7]=0; void fun(int *pa,int n) { for(int i=0;i&n-1;i++) { *(pa+7)+=*(pa+i); } }91 void main() { cout&&a[7]&& int m=8; fun(a,m); cout&&a[7]&& }C、实参用数组名形参用引用对数组类型使用引用之前,需要使用 typedef 来定义一个数组,然后使用数 组名来定义数组和引用//4.12 #include &iostream.h& typedef int array[8] ; array a={1,3,5,7,9,11,13}; void fun(array &b,int n) { for(int i=0;i&n-1;i++) b[7]+=b[i]; }void main() { int m=8; fun(a,m); cout&&a[7]&& }//4.12 的补充 #include &iostream.h& typedef char array[2] ;92 char a[2]={'1','3'}; void fun(array &b,int n) { for(;n&=0;n--){ cout&&b[n]&& } } void main() { int m=1; fun(a,m); }四、使用内联函数1、 为什么使用内联函数?不精确的说,内联函数就是用空间换时间。 普通的函数在调用的时候,需要执行顺序的转移,像咱们先前所讲,93 保存现场和恢复现场都是需要时间的, 对于一个代码量很少的函数来讲,转来转去就不划算了。 这时我们使用内联函数,在程序编译时,编译器将程序中出现的内联函 数的调用表达式用内联函数的函数体来进行替换。这种做法不会产生转 来转去的问题,但是会增加目标程序的代码量 2、 内联函数的定义只需要在咱们定义普通函数的前面加上 inline 关键字就行了。//4.13 #include&iostream.h& inline int power_int(int x) { return (x)*(x); } void main() { for(int i=1;i&=10;i++) { cout&&i&&&*&&&i&&&=&&&power_int(i)&& } }3、注意事项94 A. 在内联函数中不许出现循环语句和开关语句,否则按照非内联函数处理 B. 内联函数必须出现在他被第一次调用之前,不适用说明的方式。 C. 后面将要讲到的类结构中,所有在类说明内部定义的函数都是内联函数。五、函数的重载我们生活中的重载现象----一词多义 在生活中,我们说刷牙、刷厕所,并不区特别强调刷的方式方法,听的人自 动回领会其中的意图。 但是,当我们使用程序打印 int 和 double 变量时,就要分别给他们命名变 量,这就造成了不方便。 函数重载:出于方便编程的目的,用同一个函数名字来命名的技术称为函数 重载。即函数名相同,形参不同(类型不同或者个数不同) 。编译器在编译源 文件的时候会根据参数表的不同为各个重载函数产生不同的内部标识符。 C++允许功能相近的函数在相同的作用域内以相同函数名声明,从而形成重 载。1、参数类型不同//4.14 #include &iostream.h& int add(int ,int); double add(double,double ); void main() { cout&&add(5,10)&& cout&&add(5.0,10.5)&& }95 int add(int x,int y) { return x+y; } double add(double a,double b) { return a+b; }2、参数个数不同//4.15 #include&iostream.h& int min(int a,int b); int min(int a,int b,int c); int min(int a,int b,int c,int d); void main() { cout&&min(13,5,4,9)&& } int { } int { min(int a,int b) return a&b?a:b; min(int a,int b,int c) int t=min(a,b); return min(t,c); } int { min(int a,int b,int c,int d) int t1=min(a,b); int t2=min(c,d); return min(t1,t2); } 3、参数就进选择 void add_int(double n)//编译器添加内部标识符 add_int@@YAXN@Z {cout&&--n&&} void add_int(int n)//编译器添加内部标识符add_int@@YAXH@Z {cout&&++n&&} void main()96 { add_int(1); }注意: A. 重载函数的形参必须不同: 个数不同或类型不同。 B. 编译将根据实参和形参的类型及个数的最佳匹配来选择调用哪一个函 数。 C. 不要将不同功能的函数声明为重载函数,以免出现调用结果的误解、混 淆。六、函数的嵌套调用和递归调用1、 嵌套调用就是被调用的函数还可以再调用其他函数//4.16 #include &iostream.h& const int k(4); const int n(6); int sum_of_powers(int cishu,int geshu); int powers(int dishu ,int cishu); void main() { cout&&sum_of_powers(k,n)&& }97 int sum_of_powers(int cishu,int geshu) { int sum=0; for(int i=1;i&=i++) { sum+=powers(i,cishu); } } int powers(int dishu ,int cishu)//计算幂 { int product=1; for(int i=1;i&=i++) { product*= } }2、递归调用函数直接或间接调用自己 递归过程的两个阶段: ? 递推:3!=3×2! → 2!=2×1! → 1!=1×0! → 0!=1 未知 ? 回归: 已知3!=3×2!=6 ← 2!=2×1!=2 ← 1!=1×0!=1 ← 0!=1 未知 1 n!= n(n-1) (n&0)98已知 (n=0) 求 2!的图示:main( ) jiecheng(2) cout&&jiecheng(2) result=2*jiecheng(1) returnjiecheng(1) result=1*jiecheng(0) returnjiecheng(0)return 199 100 //4.17 #include &iostream.h& int jiecheng(int m)//递归 { int result=1; if(m==0) else { result=m*jiecheng(m-1); } }int jiecheng2(int m)//非递归 { int result=1; for(int i=1;i&=m;i++) { result*=i; } }void main() { cout&&jiecheng2(8)&& }101 关于 Fibonacci 数列1202 年,意大利数学家斐波那契的《算盘全书》中提到了一个关于兔子繁殖的问题:如果一对兔子每月能生一 对小兔,每对小兔在出生后第三个月又开始生小兔,如果兔子都没有死亡,有一对小兔开始,50 各月后会有多 少对兔子? 如图 时间(n 月) 1 2 3 4 5 6 7 8 9 10 初生兔子(对) 1 0 1 1 2 3 5 8 13 21 成熟兔子(对) 0 1 1 2 3 5 8 13 21 34 兔子总数(对) 1 1 2 3 5 8 13 21 34 55 由此可知,从第一个月开始以后 每个月兔子总数是: 1,1,2,3,5,8,13,21,34,55,89,1 44,233? 如果把上述数列继续写下去,得 到的数列就成为斐波那契数列。 数列中的前两个数是 1,数列中每个数就是前两个数之和。 1, F(n)= 1, n=1 n=2F(n-1)+F(n-2), n&2//4.18 //递归算法: int Fibo( int n) { if(n==1) return 1; else if(n==2) return 1; else return Fibo(n-1)+Fibo(n-2); } //非递归算法: int Fibo2(int n) { int f1=1,f2=1;102 for(int i=1;i&(n+1)/2;i++) { f1=f1+f2; f2=f2+f1; } if(n%2==0) return f2; else return f1; }#include &iostream.h& const int N=8; void main() { long f=Fibo(N); cout&&f&& }七、作用域1、标识符的作用域规则 作用域又称作用范围,在程序中出现的各种标识符,它们的作用范围是不一样 的。 标识符的作用域规则 (1)对于大多数标识符,对它定义和说明是一回事。但是,外部变量、函数和 类等例外 (2)标识符包含了常量名、变量名、函数名、类名、对象名、语句标号等 (3)标识符是在一定范围内定义的 (4)可见是指可以存取或访问操作,不可见是指不可存取或访问操作 2、作用域的种类103 程序级:外部函数和外部变量,在组成 工程 该程序的所有文件中有效。一般使用前 需要说明 文件级:内部函数和外部静态变量 宏 *.cpp 定义 函数级:形参和在函数内定义的自动类 void main() 变量、寄存器变量和内部静态变量和语 { 句标号 int a=1;块级:定义在分程序、if 语句、switch if(a&0) 语句及循环语句中的自动类型变量、寄 存器类型变量和内部静态类变量 { int a=9; cout&&a&& } 3、关于重新定义标识符的规定 在某个作用域内定义的标识符在该域内的子域中可以重新定义该标志符。这时 原定义的标识符在子域内是不可见的,但是他还存在,只不过在子域内被暂时 的隐藏了。过了这段子域后,他又是可见的。//4.19 #include &iostream.h& void main() { int a(5),b(7),c(10); cout&&a&&&,&&&b&&&,&&&c&& { int b(8); float c(8.8); cout&&a&&&,&&&b&&&,&&&c&& a=b;104 { c=b; cout&&a&&&,&&&b&&&,&&&c&& } cout&&a&&&,&&&b&&&,&&&c&& } cout&&a&&&,&&&b&&&,&&&c&& } //4.20 #include &iostream.h& void main() { int x(3); for(;x&0;x--) { int x(5); cout&&x&&&\t&; } cout&&endl&&x&& }4、局部变量和全局变量 局部变量(函数级和块级作用域) 包含自动变量、寄存器变量和内部静态变量及函数参数 ① 自动变量 auto 可以省略 auto函数中的局部变量,如不专门声明为 static 存储类别,都动态地分配存储空间, 数据存储在动态存储区,函数的形参和函数中定义的变量都属于此类。调用时 给它们分配空间,调用结束时,就自动释放这些空间。 例如: int f(int a) {auto int b,c=3;105 ……}② register 变量 如果一些变量使用频繁,则为存取变量的值花不少时间,为提高执行效率, C 语言允许将局部变量的值放在 cpu 中的寄存器中,需要时直接从寄存器取出参 加运算,不必再到内存中存取。 只有局部自动变量和形式参数才能够被定义为寄存器变量,全局变量和局部 静态变量都不能被定义为寄存器变量。所以,如&r&这样的语句 就是错误的,因为全局变量和局部静态变量都被放在静态存储区中,而寄存器 变量被放在寄存器中,一个变量只能选择两种存放方式中的一种。 其次,一个计算机系统中的寄存器数量是有限的,因此不能定义任意多个寄 存器变量。而且对于不同的系统来说,所允许使用的最大寄存器数量也是不同 的。 在 Intel 体系中 CPU 所具有的寄存器个数在 6~16 个之间, 而其他体系的 CPU 所具有的寄存器数量可能更多。不同系统上的寄存器数量可能不同,所以在编 程时所允许使用的寄存器数量也会不同。另外,不同系统对于寄存器变量的处 理方式也可能不同,有的系统只允许将 int、char 和指针型变量定义为寄存器变 量,而有的系统则将寄存器变量当作自动变量来看,并不真正把它们存放在寄 存器中。 目前的编译器基本上可以识别出那些会被频繁使用的变量,对于这些变量编 译器就会把它们存放在寄存器中,而不需要程序员在代码中显式地指定。所以 我们并不轻易的使用寄存器变量。 如 int fac(int n)106 {register int i,f=1; for(i=1;i&=n;i++) f=f*i; } void main() {for(i=1;i&=5;i++) cout&&“i!=“&&fac(i)&& } ③ 内部静态类变量------用 static 声明局部变量 有时候希望函数被调用后变量不消失而保留原值,即其占用的存储单元不 释放,在下一次函数调用时候,该变量已有值,就是上一次函数调用结束时 的值。就该指定该变量为静态局部变量,用关键字 static 进行声明。#include &iostream.h& void add() { ++a; cout&&a&& } void add2() { int a=0; ++a; cout&&a&& } void main() { add(); add(); add2();107 add2(); }----------------------------------------------------------------//静态局部变量 #include &iostream.h& int f(int a); { int b=3; static int c=3; a++; b++; c++; cout&&&a=&&&a&&& b=&&&b&&& c=&&&c&& return a+b+c; }void main() { int a=3; for(int i=0;i&3;i++) cout&&f(a)&& }对静态局部变量的说明: (1)静态局部变量属于静态存储类别,在静态存储区内存分配存储单元。 在整个程序运行期间不释放。 (2)对静态局部变量是在编译时赋初值,即只赋一次,在程序运行时已经有 初始值。 (3)如在定义局部变量时不赋初值的话,对于静态局部变量来说,编译时 自动赋值为 0。 内部静态变量的作用域和和自动变量相同,但生命周期较长,这是一种可见性 和存在性不一致的变量 全局变量(外部变量和外部静态变量)108 是指作用域在程序级和文件级的变量 包括 ① extern 说明外部变量 外部变量是一种在函数外部定义,定义时不加任何存储类说明的变量, 外部变量的作用域是程序级的。编译时将外部变量分配在静态存储区。 外部变量在引用之前需要说明,说明外部变量时应在前面加说明符 extern 表示 该变量是外部变量。 #include &iostream.h& int A=13,B=-8; int max(int x,int y) { z=x&y?x:y;} void main() {extern int A,B; cout&&max(A,B);} 例 #include &iostream.h& #include &math.h& int max1,min1; void max_min(int a,int b,int c) {if (a&b) {max1=b;min1=a;} else {max1=a;min1=b;}109 if(max1&c) max1=c; if (min1&c) min1=c; }void main() { int x,y,z; cout&& &请输入数据&; cin&&x&&y&&z; max_min(x,y,z); cout&&max1&&& &&&min1&& }例:文件 file1.cpp 中的内容为: int A; #include &iostream.h& void main() {int power (int); int b=3,c,d,m; cout&&&输入数据 A 和 m&; cin&&A&&m; c=A*b; cout&&A&&& &&&b&&& &&&c&&110 d=power(m); cout&&d&&& &&& } 文件 file2.cpp 中的内容 extern A; int power (int n) {int i,y=1; for (i=1;i&=n;i++) y*=A; }② 用 static 定义的外部静态变量 是一种在函数外部定义,定义时加 static 说明的变量, 作用域是从定义该变量起到该文件结束,因此外部静态变量是文件级的,外部 静态变量的可见性和存在性不一致。作用域不是整个程序但生命周期是整个程 序。 file1.cpp static int A viod main() {…….. }111 file2.cpp extern int A; fun(int n) {…….. A=A*n; ….. }//4.21 #include &iostream.h& void other(); void main() { int a(3); register int b(5); cout&&&a=&&&a&&&,&&&&b=&&&b&&&,&&&&c=&&&c&& other(); other();0 cout&&&a=&&&a&&&,&&&&b=&&&b&&&,&&&&c=&&&c&& } void other() { int a(5); static int b(12); a+=10; b+=20; cout&&&a=&&&a&&&,&&&&b=&&&b&& }局部变 量变量名 称 内部变 量 内部变变量的存储类 别 自动类变量 寄存器变量关键字 auto可省略 y定义位 置 函数体 函数体作用域 函数级 函数级生存期register n112定义开始到函数结 束 定义开始到函数结 量 形参 内部变 量 外部变 量 外部变 量 无存储类别说 明 静态变量 静态变量 无存储类别说 明 static static extern n n y 函数定 义 函数体 函数外 部 函数外 部 函数级 函数级 文件级 程序级束 定义开始到函数结 束 整个程序 整个程序 整个程序全局变 量5、内部函数和外部函数 内部函数在定义它的文件中可以被调用,而在同一程序的其它文件中不可以被 调用,定义格式如下: static &类型说明& &函数名&(&参数表&) {函数体}//4.23 #include &iostream.h& int i(10); static int reset(),next(int),last(int),other(int); void main() { int i=reset(); for(int j(1);j&=3;j++) { cout&&i&&&,&&&j&&&,&; cout&&next(i)&&&,&; cout&&last(i)&&&,&; cout&&other(i+j)&& } } static int reset() { } static int next(int j) { j=i++; }113 static int last(int j) { static int i(20); j=i--; } static int other(int i) { int j(15); return i=j+=i; }外部函数:是一种作用域在整个程序中的函数,包含组成该程序的所有文件。 Extern 可以省略定义格式如下: [extern] &类型说明& &函数名&(&参数表&) {函数体}//4.24 //f1.cpp #include &iostream.h& int i(1); extern int reset(),next(),last(),other(int); void main() { int i=reset(); for(int j(1);j&=3;j++) { cout&&i&&&,&&&j&&&,&; cout&&next()&&&,&; cout&&last()&&&,&; cout&&other(i+j)&& } } //f2.cpp static int i(10); extern int next() {114 return i+=1; } extern int last() { return i-=1; } extern int other(int i) { static int j(5); return i=j+=1; } 总结:八、c++的系统函数1. 使用系统函数时要包含相应的头文件。例如: Math.h 指数函数 对数函数 绝对值函数 立方根函数 和三角函数 Ctype.h 判断字母 数字 大写字母 小写字母等的函数 String.h 有关字符串的函数 Conio.h 屏幕处理函数115 Graph.h 图形处理函数 调用某个函数时,一定将该函数的功能、参数和函数的返回值搞清楚,否则难 以正确地使用这个函数。调用某个函数时,一定将该函数的功能、参数和函数的返回值搞清楚,否则难 以正确地使用这个函数。 查找系统函数的使用说明 查编译系统的库函数手册 查联机帮助116 117 //4.25 #include &iostream.h& #include &math.h& const double pi(3.); void main() { double i(30*pi/180); double x=sin(i); double y=cos(i); double z=tan(i); cout&&&sin(30)=&&&x&& cout&&&cos(30)=&&&y&& cout&&&tan(30)=&&&z&& }118 2.字符串处理函数在 string.h 头文件中① 字符串长度函数//4.26 #include &iostream.h& #include &string.h& void main() { char s1[]=&abc mnp&; char *s2=&hello!&; char s3[80]; cout&&&Input a word: &; cin&&s3; cout&&&s1:&&&strlen(s1)&& cout&&&s2:&&&strlen(s2)&& cout&&&s3:&&&strlen(s3)&& cout&&strlen(&iostream.h&); }② 字符串复制函数 该函数的功能是用一个字符串去更新另一个字符串,进而实现字符串的复 制。 该函数的函数原形如下:char*strcpy(char*s1, const char*s2); char*strncpy(char*s1, const char*s2, int n); 注意, 不要忘记添加?\0?作为结束符// 4.27 #include &iostream.h& #include &string.h& void main() { char s1[8],s3[8]; char s2[]=&string&; strcpy(s1,s2);119 strncpy(s3,s1,3); s3[3]='\0'; cout&&&s1:&&&s1&& cout&&&s3:&&&s3&& char *s4=strcpy(s3,strcpy(s1,s2)); cout&&&s4:&&&s4&& }③ 字符串连接函数 该函数的功能是将一个字符串添加到另外一个字符串的后面,形成一个包含 两个字符串的新的字符串,该字符串的函数原形如下: char*strcat(char*s1, char*s2); char*strncat(char*s1, char*s2, int n);//4.28 #include &iostream.h& #include &string.h& void main() { char s1[30]=&first&; char s2[20]=&second&; char s3[10]=&third&; char s4[30]; strcpy(s4,s1); strcat(s4,s2); strcat(s4,s3); cout&&&s4:&&&s4&& cout&&strcat(s1,strncat(s2,s3,3))&& }④ 字符串比较函数 该函数的功能是比较两个字符串是否相等,如果该返回值是 0 表示比较的两 个字符串相等。如果返回值大于 0,说明两个字符串不等,第一个大于第二 个,如果返回值小于 0,则说明第一个小于第二个。函数的原形说明如下: int strcmp(const char*s1, const char*s2);120 int strncmp(const char*s1, const char*s2, int n);//4.29 #include &iostream.h& #include &string.h& void main() { int result,n; char s1[80],s2[80]; cout&&&Input string #1: &; cin&&s1; cout&&&Input string #2: &; cin&&s2; cout&&&Input a number: &; cin&&n; result=strncmp(s1,s2,n); if(result==0) cout&&s1&&& is equal to &&&s2&& else if(result&0) cout&&s1&&& is less than &&&s2&& else cout&&s1&&& is greater than &&&s2&& }九、函数模板什么是模板?模板是用来解决代码重用的一种方法 。与重载相比,重载是 为了使用同名函数的不同参数表来区别不同的的函数功能。 模板是对类型进行参数化的工具。分为函数模板和类模板 函数模板是通过对参数类型进行参数化后,获取具有相同形式的函数体。 函数模板是一个通用函数,它可以适用一定范围内的不同类型的对象的操作。 函数模板可以用来创建一个通用功能的函数,以支持多种不同形参,进一 步简化重载函数的函数体设计。 声明方法: template &参数化类型表名& &类型名& &函数名& (&参数表&)121 &参数化类型表名&又称模板参数,多个表项用逗号分开,每个表项称为一个模

我要回帖

更多关于 psw状态寄存器 的文章

 

随机推荐