1、事上那些最容易的事情中,拖延事上那些最容易的事情中,拖延时间最不费力!时间最不费力!1高级语言程序设计高级语言程序设计主讲教师:贾彩燕主讲教师:贾彩燕计算机与信息技术学院计算机与信息技术学院计算机科学与技术系计算机科学与技术系2第五章第五章C C程序结构程序结构3主要内容主要内容n数值类型数值类型n函数和标准库函数函数和标准库函数n函数定义和程序的函数分解函数定义和程序的函数分解nC程序结构与变量程序结构与变量n预处理命令预处理命令n定义常量定义常量n字位运算符字位运算符n编程实例编程实例4知识回顾及提升知识回顾及提升n最重要的思想最重要的思想q模块化程序设计思想模块化程序设计思想n函数分解及
2、其思想函数分解及其思想nC程序的组成程序的组成n对象(变量、函数)的存在、声明与使用对象(变量、函数)的存在、声明与使用n变量的生命周期和作用域变量的生命周期和作用域5复杂问题简单问题简单问题1简单问题简单问题2简单问题简单问题n解解1解解2解解n分解整合整合整个问题的解解解解解复杂问题分解与问题解决6解决问题的办法:化整为零,解决问题的办法:化整为零,把复杂程序分解成把复杂程序分解成不同的小模块,分别实现。不同的小模块,分别实现。长程序划分7模块化程序设计思想模块化程序设计思想总体功能总体功能子功能子功能子功能子功能子功能子功能子功能子功能自顶向下自顶向下逐步细化逐步细化重要的软件开发手段软
3、件工程管理理念问题:高级语言提供了什么机制来支持模块化问题:高级语言提供了什么机制来支持模块化程序设计程序设计?8高级语言常见的抽象机制高级语言常见的抽象机制n子程序,子程序,sub-program,sub-routinen过程,过程,proceduren函数,函数,functionn类,类,classn包,包,packagen模块,模块,modulen组件,组件,componentn程序,程序,programC语言提供的语言提供的最基本的代码最基本的代码抽象机制抽象机制9小模块小模块2小模块小模块1函数一般可以传递数据,通过参数传模块间调用返回结果小模块小模块n共处共处应用环境应用环境1应用
4、环境应用环境m大模块大模块1大模块大模块2大模块大模块K打包打包应用于应用于工具箱工具箱xx.caa.c组件,包,模块,程序10main()AvgMultiply(.,1000,);AvgMultiply(,100,);AvgMultiply(,10000,);double AvgMultiply(double array,int n,double y)计算计算n个数的平均值个数的平均值Y;返回结果;返回结果;名字名字从外部获取数据从外部获取数据返回结果返回结果C语言把功能语言把功能独立或相同、独立或相同、相似的片段抽相似的片段抽象成一个函数象成一个函数重复的片段用重复的片段用函数调用代替函数
5、调用代替合称为:合称为:Interface接口,接口,A common boundary between two distinct entities.独立定义独立定义独立实现独立实现独立使用独立使用效效率率/2;一改一改全改全改11函数说明规范:接口说明函数说明规范:接口说明/*函数名称函数名称:写出函数的名称写出函数的名称功能描述功能描述:描述出函数具有的功能描述出函数具有的功能函数参数函数参数:输入输出参数说明,输入输出参数说明,对每个参数都需要作出仔细说明对每个参数都需要作出仔细说明返回值返回值:返回值说明,或者标明无返回值返回值说明,或者标明无返回值模块历史模块历史:谁于某年某月某日创
6、建本模块,创建人谁于某年某月某日创建本模块,创建人email 谁于某年某月某日修改本模块,修改人谁于某年某月某日修改本模块,修改人email 修改原因:可有可无,根据需要添加修改原因:可有可无,根据需要添加*/用处?用处?12C的模块和的模块和C程序结构程序结构n一组函数构成一个函数模块;一组函数构成一个函数模块;n在在C程序里,一个程序里,一个*.c或或*.cpp文件就是由多文件就是由多个函数构成的一个功能模块;个函数构成的一个功能模块;n每个功能模块编译后构成一个独立的目标每个功能模块编译后构成一个独立的目标模块模块*.objn多个目标模块绑定在一起构成一个多个目标模块绑定在一起构成一个*
7、.exe文文件件13a.cb.c*.c一个C程序的组成函数函数函数a.objb.obj*.obj编译MyProg.exe编译编译链接组织成一组织成一个项目个项目项目的中项目的中间结果间结果项目的最项目的最终结果终结果模块模块14模块文件15*.exe文件*.obj文件16变量的作用域与存在期变量的作用域与存在期n变量定义变量定义q确定了变量何处、何时能使用确定了变量何处、何时能使用n何处能使用何处能使用作用域作用域q能够使用变量的范围能够使用变量的范围代码段代码段n何时能使用何时能使用存在期存在期q确定变量建立和销毁时间确定变量建立和销毁时间时间段。时间段。q各种变量的存在期可能不同。各种变量
8、的存在期可能不同。q变量实现的基础是内存单元,存在期就是变量被分变量实现的基础是内存单元,存在期就是变量被分配内存空间到撤消的期间配内存空间到撤消的期间17存储区示意图存储区示意图内存内存静态存储区静态存储区动态存储区动态存储区程序代码程序代码程序占用的存储区程序占用的存储区18存储区用途存储区用途n静态存储区主要用途静态存储区主要用途q保存采用静态分配方式的变量的内容保存采用静态分配方式的变量的内容n外部变量(全局变量)外部变量(全局变量)n静态内部变量静态内部变量q保存程序中的字符串常量保存程序中的字符串常量n动态存储主要用途动态存储主要用途q供自动型内部变量的空间分配使用供自动型内部变量
9、的空间分配使用q供显式动态分配的存储空间分配供显式动态分配的存储空间分配(见后续内容见后续内容)19变量类别及其存在期变量类别及其存在期n内部变量的类别内部变量的类别qauto默认的内部变量类别,可以不用写,存储单元在运行默认的内部变量类别,可以不用写,存储单元在运行过程中动态分配和释放过程中动态分配和释放qstatic静态内部变量,保存在静态存储区,存储单元在程静态内部变量,保存在静态存储区,存储单元在程序启动时分配,程序结束时释放。序启动时分配,程序结束时释放。n外部变量外部变量q在函数之外定义的变量称为外部变量、全局变量。在函数之外定义的变量称为外部变量、全局变量。External Ex
10、ternal variablevariableq全部保存静态存储区,程序启动时分配,程序结束时释放。全部保存静态存储区,程序启动时分配,程序结束时释放。q 在外部变量前加在外部变量前加static只影响对应变量的可见范围,但不影只影响对应变量的可见范围,但不影响变量的生命周期。响变量的生命周期。20函数中的参数函数中的参数n形式参数和实际参数形式参数和实际参数nformal argument形式参数形式参数q定义函数时给出的参数,称为形式参数定义函数时给出的参数,称为形式参数qArguments occurred in function list when defining a functio
11、nnactual argument实际参数实际参数q调用函数时给出的参数,称为实际参数调用函数时给出的参数,称为实际参数qArguments occurred in function list when calling a functionnC函数的参数是值参数。函数的参数是值参数。q函数调用时先计算实参表达式的值函数调用时先计算实参表达式的值q把值复制给对应形参把值复制给对应形参q而后执行函数体。而后执行函数体。q函数内对形参的操作与实参无关。函数内对形参的操作与实参无关。21C语言的函数原型语言的函数原型函数存在信息函数存在信息n函数原型函数原型function prototypen声明声
12、明某一个函数的某一个函数的存在存在q在使用某个函数以前,用函数原型来声明某个函数已经是在使用某个函数以前,用函数原型来声明某个函数已经是一个合法的、有定义的函数,一个合法的、有定义的函数,请声明之后的代码放心使用请声明之后的代码放心使用该函数。该函数。qUse function prototype to declare the existence of a functionn原型说明的形式原型说明的形式q与函数头部类似,与函数头部类似,加分号;加分号;q参数名可省略,可与函数定义用的名字不同;参数名可省略,可与函数定义用的名字不同;q原型的参数名最好用有意义的名字,有利于写注释。原型的参数名最
13、好用有意义的名字,有利于写注释。n提倡把原型说明都放在程序文件最前面提倡把原型说明都放在程序文件最前面22另外一种组织写函数原型办法另外一种组织写函数原型办法n将自己写的所有的函数的函数原型都将自己写的所有的函数的函数原型都写在一起写在一起,组织成一个扩展名为组织成一个扩展名为.h的的header file,即头文,即头文件,如件,如abc.hn然后在然后在.c或或.cpp程序模块的首部用文件包含命程序模块的首部用文件包含命令包含该头文件,如令包含该头文件,如q#include“abc.h”n思考:有什么好处?思考:有什么好处?23主要内容主要内容n数值类型数值类型n函数和标准库函数函数和标准
14、库函数n函数定义和程序的函数分解函数定义和程序的函数分解nC程序结构与变量程序结构与变量n预处理命令预处理命令n定义常量定义常量n字位运算符字位运算符n编程实例编程实例24C语言源程序编译目标模块连接可执行程序函数库C程序加工过程编译之前还有一个源代码预加工的过程5.5 预处理预处理25有预处理命令的C源程序编译目标模块连接可执行程序函数库C程序加工过程包含有编译前的预处理的功能预处理没有预处理命令的C源程序最先做的步骤,预处理程序负责处理源程序里的所有预处理命令,生成不含预处理命令的源程序。预处理命令加在程序中指示预处理程序进行代码处理工作的指令。预处理命令作用:简化编程工作26预处理命令预
15、处理命令nC源程序中以字符源程序中以字符#开始的命令即为预处理命令开始的命令即为预处理命令n常见的预处理命令包括常见的预处理命令包括q#includeq#defineq#undefq#ifq#elseq#elifq#endif27把指定文件内容包含到当前源文件把指定文件内容包含到当前源文件#include 形式形式1#include 文件名文件名形式形式2形式形式1:用于包含系统头文件,预处理程序到指定目录找文件(用于包含系统头文件,预处理程序到指定目录找文件(通常指定几个系统文件目录)。通常指定几个系统文件目录)。形式形式2:用于包含自己的文件。预处理程序先在源文件所在的目用于包含自己的文件
16、。预处理程序先在源文件所在的目录里找,找不到时再到系统指定目录中去找。录里找,找不到时再到系统指定目录中去找。文件包含命令文件包含命令处理过程处理过程:在文件系统中查找指定的文件,如果找到,就用找在文件系统中查找指定的文件,如果找到,就用找到的文件的内容取代该命令行。被包含文件里如有预处理行也到的文件的内容取代该命令行。被包含文件里如有预处理行也会处理。会处理。28stdio.h或或math.h 为为标准头文件(标准头文件(.h 扩展名),它们在系统扩展名),它们在系统子目录里(目录名为子目录里(目录名为 include或或h),),内容包括标准函数原型、内容包括标准函数原型、系统使用的符号常
17、量定义等。系统使用的符号常量定义等。预处理时,文件内容插入到预处理时,文件内容插入到预处理命令行处。预处理命令行处。相当于在源文件相当于在源文件中写这些函数原型,使编译程序能正确完成对标准库函数调用中写这些函数原型,使编译程序能正确完成对标准库函数调用的处理。的处理。#include#include注意:注意:写程序时一定要包含必要的系统头文件写程序时一定要包含必要的系统头文件。29#include“abc.h”double area(double r)return PI*r*r;abc.cpp系统目录中的头文件如果找到,用相应的头文件里的内容替代包含命令。double area(double
18、 r);int func2();void func3();enum YES,NO;#define PI 3.14159继续处理abc.h文件包含处理过程及示例double area(double r);int func2();void func3();enum YES,NO;#define PI 3.14159double area(double r)return PI*r*r;处理后的abc.cpp301 1、一个、一个#include#include命令只能指定一个被包含的文件,若要包含命令只能指定一个被包含的文件,若要包含n n个文件,个文件,应使用应使用n n个个#include#in
19、clude命令;命令;2 2、若文件、若文件1 1包含文件包含文件2 2,而文件,而文件2 2中要用到文件中要用到文件3 3的内容,则可在文件的内容,则可在文件1 1中中用用2 2个个#include#include命令分别包含文件命令分别包含文件2 2和文件和文件3 3,而且文件,而且文件3 3应出现在文应出现在文件件2 2之前,如下表示:之前,如下表示:file1.cfile1.c#include“file3.h”#include“file3.h”#include“file2.h”#include“file2.h”.3 3、文件包含可以嵌套。文件包含可以嵌套。4 4、预编译后的包含文件和源
20、程序文件成为一个文件,所有的、预编译后的包含文件和源程序文件成为一个文件,所有的externextern变变量将成为源程序文件中的全局静态变量。量将成为源程序文件中的全局静态变量。说明:说明:31#include“flie2.h”file1.cfile2.h#include“flie3.h”不包含不包含#include命命令令file3.h#include“flie3.h”#include“flie2.h”file1.c不包含不包含#include命命令令不包含不包含#include命命令令file2.hfile3.h等价等价32#define开始,两种形式:开始,两种形式:简单宏定义简单宏定
21、义,形式:,形式:#define 宏名字宏名字 替代正文替代正文替代正文替代正文可以是任意正文序列,到换行为止。可以是任意正文序列,到换行为止。如最后是如最后是“”,下一行还作为宏定义的继续。,下一行还作为宏定义的继续。作用作用:为:为宏名字宏名字定义替代,由整个定义替代,由整个替代正文替代正文构成构成。预处理程序记录宏名字及其替代。在源程序中遇到预处理程序记录宏名字及其替代。在源程序中遇到宏名字宏名字标识标识符时,就用符时,就用替代正文替代正文替换,替换,这种操作称为宏展开或宏替换这种操作称为宏展开或宏替换。宏定义与宏替换宏定义与宏替换33#define NUM 30#define SLD
22、static long double#define NOSTOP while(1)程序中的:程序中的:SLD x=2.4,y=9.16;替换后变成:替换后变成:static long double x=2.4,y=9.16;预处理程序做正文预处理程序做正文替换替换,替代正文替代正文可以是任何内容。可以是任何内容。后后无无 ;34带参数宏定义带参数宏定义,形式:形式:#define 宏名字宏名字(参数列表参数列表)替代正文替代正文宏名字与括号间不能有空格宏名字与括号间不能有空格,逗号分隔的标识符看作参数。替,逗号分隔的标识符看作参数。替换正文为任意正文序列。换正文为任意正文序列。宏调用的替换分两
23、步展开:先用各实参替代宏定义宏调用的替换分两步展开:先用各实参替代宏定义替代正文替代正文里的里的参数;再将代换的结果代入宏调用位置。参数;再将代换的结果代入宏调用位置。预处理中将被展开为:预处理中将被展开为:z=(x+y)(x*y)?(x+y):(x*y);使用形式与函数调用类似,以类似参数的形式给出宏参数的替代使用形式与函数调用类似,以类似参数的形式给出宏参数的替代段,用逗号分隔,称为段,用逗号分隔,称为宏调用宏调用。#define min(A,B)(A)(B)?(A):(B)z=min(x+y,x*y);35注意注意:宏展开可能引起参数多次计算。如:宏展开可能引起参数多次计算。如:z=mi
24、n(n+,m+);展开后的形式是:展开后的形式是:z=(n+)(m+)?(n+):(m+)替代正文各参数和整段应括起,避免出错替代正文各参数和整段应括起,避免出错。例:。例:#define square(x)x*x在特定环境下可能出问题,例如:在特定环境下可能出问题,例如:z=square(x+y);展开后的形式:展开后的形式:z=x+y*x+y 使用带参宏与调用函数的意义不同。程序加工中在使用带参宏与调用函数的意义不同。程序加工中在“当地当地”展开。程序执行中并没有调用动作,展开。程序执行中并没有调用动作,宏定义宏定义/调用中没有类型问题。一个宏能否使用调用中没有类型问题。一个宏能否使用/使
25、用中发生什使用中发生什么么/能否得到预期效果,完全看展开后的情况。能否得到预期效果,完全看展开后的情况。36n人们有时用宏定义简化程序书写。人们有时用宏定义简化程序书写。n带参宏的展开可避免函数调用开销,但使程序变长。带参宏的展开可避免函数调用开销,但使程序变长。n复杂宏定义展开后出错很难定位。复杂宏定义展开后出错很难定位。n应谨慎使用(尽量少使用)宏应谨慎使用(尽量少使用)宏。n写宏定义的常见错误是在定义行最后写分号。该分号将被代入写宏定义的常见错误是在定义行最后写分号。该分号将被代入程序,有可能引起语法错误。程序,有可能引起语法错误。宏定义从定义处起作用直到文件结束。一个文件里不允许对同一
26、宏定义从定义处起作用直到文件结束。一个文件里不允许对同一宏名字重复定义。宏名字重复定义。#undef取消已有定义:取消已有定义:#undef 宏名字宏名字371.1.宏名一般都用大写字母表示,以区别于变量宏名一般都用大写字母表示,以区别于变量;2.2.宏定义只是替代宏定义只是替代,减少了在程序中书写的工作量减少了在程序中书写的工作量,只是一个简单的代替只是一个简单的代替,不不作语法检查作语法检查;3.3.宏定义不是语句宏定义不是语句,不必再其后加上不必再其后加上“;”;”;4.4.在宏定义中可以进行多层的替代在宏定义中可以进行多层的替代.#definre R3.0#define PI3.141
27、5#define L2*PI*R#define SPI*R*Rmain()printf(“L=%fnS=%fn”,L,S);说明说明38例例#include#define PI 3.1415#define S(r)PI*r*rint main()double a,area;a=3.6;area=S(a);printf(“r=%fnarea=%fn”,a,area);return 0;或或enum PI=3.1415;39例例#include#define M3#define NM+2#define S(N)N*N*Nint main()printf(%dn,S(N);return 0;运行结果
28、为:运行结果为:1740条件编译条件编译一、引入条件编译的原因:一、引入条件编译的原因:只对源程序中满足条件的部分内容进行编译。只对源程序中满足条件的部分内容进行编译。可以减少被编译的语句,从而减少目标程序的长度。可以减少被编译的语句,从而减少目标程序的长度。二、定义形式:二、定义形式:41程序段可以是语句串,也可以是命令行程序段可以是语句串,也可以是命令行方式方式3 3为嵌套定义为嵌套定义方式方式2 2:#if#if 整型表达式整型表达式程序段程序段1 1#else#else程序段程序段2 2#endifendif方式方式1 1:#if#if 整型表达式整型表达式程序段程序段1 1#endi
29、fendif方式方式3 3:#if 整型表达式整型表达式程序段程序段1#elif 整整型表达式型表达式 程序段程序段2#elif 整型表达式整型表达式 程序段程序段3#else程序段程序段n#endif42谓词谓词defined。使用形式:使用形式:defined 标识符标识符或或 defined(标识符标识符)标识符标识符是有宏定义时,是有宏定义时,defined(标识符标识符)得到得到1,否则得,否则得0#ifdef 标识符标识符相当于相当于#if defined(标识符标识符)#ifndef 标识符标识符 相当于相当于#if!defined(标识符标识符)方式方式4 4:#ifdefif
30、def 标识符标识符程序段程序段1 1#else#else程序段程序段2 2#endifendif方式方式5 5:#ifndefifndef 标识符标识符程序段程序段1 1#else#else程序段程序段2 2#endifendif43#define COMPUTER_A 1#ifdef COMPUTER_A#define INTEGER_SIZE 16#else#define INTEGER_SIZE 20#endif#define DEBUG 1#ifdef DEBUG printf(“x=%d,y=%d,z=%dn”,x,y,z);#endif 预处理后只剩下预处理后只剩下#define
31、 INTEGER_SIZE 16参与编译参与编译预处理后预处理后printf参与编译参与编译,若不在希望编译若不在希望编译printf得到得到输出,则删除输出,则删除#define DEBUG 1命令行。命令行。44例例#define LETTER 1int main()char c;int i=0;while(c=getchar()!=n)i+;#ifdef LETTER if(c=a&c=A&c=Z)c=c+32;#endif printf(“%c”,c);return;45主要内容主要内容n数值类型数值类型n函数和标准库函数函数和标准库函数n函数定义和程序的函数分解函数定义和程序的函数分
32、解nC程序结构与变量程序结构与变量n预处理命令预处理命令n定义常量定义常量n字位运算符字位运算符n编程实例编程实例46定义定义“常量常量”有三种方式:有三种方式:n用用enum定义枚举常量,定义枚举常量,n用预处理命令用预处理命令“定义常量定义常量”n用用const定义常值变量,定义常值变量,C程序设计界的一般看法:程序设计界的一般看法:宏定义是简单宏定义是简单正文正文代换,无语法和语义限制。可将标识符代换代换,无语法和语义限制。可将标识符代换为任何东西,容易使源程序意义难以理解。为任何东西,容易使源程序意义难以理解。原则是:能用其他方式的地方原则是:能用其他方式的地方绝绝不应该用不应该用宏宏
33、。因为宏定义没有因为宏定义没有类型的概念。类型的概念。5.6 定义常量定义常量 47const是变量,但不能赋值。是变量,但不能赋值。const可为任何类型的。可为任何类型的。const不能用于不能用于常量表达式常量表达式。如。如不能用作不能用作case标号,不能用于标号,不能用于初始化外部变量或枚举常量。初始化外部变量或枚举常量。许多书籍用宏定义的方式定义常量。如写许多书籍用宏定义的方式定义常量。如写#define len 20#define Pi 3.14159265 建议尽可能用枚举常量和建议尽可能用枚举常量和 constconst。枚举常量值为枚举常量值为int,只能用于定义只能用于定
34、义int常量。可用在需要常量。可用在需要“常常量表达式量表达式”的地方,如作为的地方,如作为case标号,初始化其他枚举常量和标号,初始化其他枚举常量和外部变量等。外部变量等。48n枚举是枚举是int值,如果需要整数类型的常量,应该用枚举定义值,如果需要整数类型的常量,应该用枚举定义n需要需要其他类型的其他类型的“常量常量”可考虑可考虑const:const double Pi=3.14159265;const double E=2.71828;n只有在这两种方式都不合适,而用宏定义又能带来特别的方只有在这两种方式都不合适,而用宏定义又能带来特别的方便时,才应考虑它。便时,才应考虑它。49主要
35、内容主要内容n数值类型数值类型n函数和标准库函数函数和标准库函数n函数定义和程序的函数分解函数定义和程序的函数分解nC程序结构与变量程序结构与变量n预处理命令预处理命令n定义常量定义常量n字位运算符字位运算符n编程实例编程实例50简单程序很少用简单程序很少用位位是是最小数据单位最小数据单位。有些数据用几个位就能表示。有些数据用几个位就能表示。如单词统计程序中如单词统计程序中state可用一位表示。可考虑把多个这类数可用一位表示。可考虑把多个这类数据存入一个变量里。据存入一个变量里。系统程序常需直接操作位数据。硬设备的状态常用二进制串表系统程序常需直接操作位数据。硬设备的状态常用二进制串表示,操
36、作它们常需用二进制位串发命令。示,操作它们常需用二进制位串发命令。C提供了提供了位操作和字位(按位)运算符位操作和字位(按位)运算符,可用于各种,可用于各种整型数据整型数据,把整数看成二进制序列实现位运算。把整数看成二进制序列实现位运算。5.7 字位运算符字位运算符51位运算位运算:从一两个:从一两个 0/1值计算出一个值计算出一个0/1结果。常见:结果。常见:1)位)位否定否定:参数值:参数值1时得时得0,0时得时得1;2)位)位与与:两参数都是:两参数都是1时得时得1,否则,否则0;3)位)位或或:两参数都是:两参数都是0时得时得0,否则,否则1;4)位)位异或异或:恰有一参数为:恰有一参
37、数为1时得时得1,否则,否则0。字位运算符字位运算符基于上面基于上面位运算位运算,用于整型得到整型结果。,用于整型得到整型结果。字位否定字位否定字位与字位与&字位或字位或|字位异或字位异或对对各位求否定;各位求否定;二元二元从两数的各位算出结果的各位。从两数的各位算出结果的各位。52例:设例:设x和和y都都是是16位的整变量,值分别是:位的整变量,值分别是:x:0010,1001,0101,0111y:1001,1100,1111,1010对对x和和y的各种字位运算:的各种字位运算:x1101,0110,1010,1000 x&y 0000,1000,0101,0010 x|y 1011,11
38、01,1111,1111x y 1011,0101,1010,110153掩码的概念掩码的概念n掩码(掩码(mask)q为做位运算而构造的二进制串。为做位运算而构造的二进制串。n例如例如q通过将掩码与运算对象进行位运算,获取运算对象通过将掩码与运算对象进行位运算,获取运算对象的某位的状态,而将其它不关心的位屏蔽掉。的某位的状态,而将其它不关心的位屏蔽掉。q若想在设置运算对象部分位的值同时不影响其它位若想在设置运算对象部分位的值同时不影响其它位的值,也需要用掩码。(类似于交警在道路上画标的值,也需要用掩码。(类似于交警在道路上画标志的时候用的模子)志的时候用的模子)n掩码常用十六进制、八进制形式
39、书写。掩码常用十六进制、八进制形式书写。为什么要叫掩码?为什么要叫掩码?mask54例,设例,设x是是16位整型,写表达式判断位整型,写表达式判断x的第的第5位和第位和第8位是否都为位是否都为0。整数从低位向高位顺序为第。整数从低位向高位顺序为第0到第到第15位:位:15 0位位x1 0 1 1 0 1 1 0 1 0 1 0 1 1 0 1掩码掩码0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0用用掩码掩码与与x做做字位与字位与,第,第5位和第位和第8位的信息留下来,结果中其位的信息留下来,结果中其他位总是他位总是0。上述条件可写为:。上述条件可写为:x&0 x0120=0in
40、t isok(int x)return(x&0 x0120)=0?1:0;可简化:可简化:int isok(int x)return(x&0 x0120)=0;55常用操作使用的掩码和运算(解释,举例)常用操作使用的掩码和运算(解释,举例):1)取出被处理二进制串的某些位:)取出被处理二进制串的某些位:用用&运算运算;掩码:这些位为掩码:这些位为1其他位为其他位为0。2)把某些位置设为)把某些位置设为0其他位不变(其他位不变(“复位复位”/“清清0”):):用用&运运算算;掩码:要改变位为掩码:要改变位为0,其他位为,其他位为1。3)把某些位置设为)把某些位置设为1其他位不变(其他位不变(“置
41、位置位”/“置置1”):):用用|运运算算;掩码:要设置的位为掩码:要设置的位为1,其他位为,其他位为0。4)翻转某些位而其他位不变(翻转):)翻转某些位而其他位不变(翻转):用用 运算;运算;掩码:要翻转位为掩码:要翻转位为1/其他位为其他位为0。这些运算总从两个整数(二进制串)求出结果,不改变原有计这些运算总从两个整数(二进制串)求出结果,不改变原有计算对象。算对象。56另外两个另外两个位运算位运算:左移和右移左移和右移。把数看作位序列,求这个序列左移或右移若干位得到的序列:把数看作位序列,求这个序列左移或右移若干位得到的序列:左移:左移:二元运算符,其左运算对象的是被左二元运算符,其左运
42、算对象的是被左/右移的数据,右运算对象右移的数据,右运算对象指明移位数指明移位数,移空出位置补移空出位置补0。与二元字位运算对应与二元字位运算对应赋值运算符赋值运算符:&=|=修改左边运算对象(掩码放在右边)。修改左边运算对象(掩码放在右边)。例:例:n&=0 xfffe n的的最低位置最低位置0.对应对应运算符运算符是是=。左移可用于将整数值乘左移可用于将整数值乘2的幂,右移可实现除以的幂,右移可实现除以2的幂。的幂。例:例:x (p+1-n)&(0(p+1-n)将将x右移,把所需右移,把所需n位移到右端。位移到右端。掩码:掩码:0的字位否定得到全的字位否定得到全1,左移,左移n位使最低位使
43、最低n位变位变0其余位是其余位是1。求否定得到低。求否定得到低n位为位为1,高位都是,高位都是0的掩码。的掩码。掩码与掩码与x右移结果做右移结果做字位与就取出了所需的字位与就取出了所需的n位。位。p位位 p-n位位 0位位x1 0 1 1 0 1 1 0 1 0 1 0 1 1 0 158 p位位 p-n位位 0位位x1 0 1 1 0 1 1 0 1 0 1 0 1 1 0 1(x (p+1-n)&(0(p+1-n)01 1 1 1 1 1 1 1 1 1 1 1 1 1 1 10n1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 00 0 0 0 0 0 0 0 0 0 1 1
44、1 1 1 1(0(p+1-n)&(0(p+1-n)0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1(0(p+1-n)&(0n)x0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 060主要内容主要内容n数值类型数值类型n函数和标准库函数函数和标准库函数n函数定义和程序的函数分解函数定义和程序的函数分解nC程序结构与变量程序结构与变量n预处理命令预处理命令n定义常量定义常量n字位运算符字位运算符n编程实例编程实例615.8 程序设计实例程序设计实例简单猜数游戏简单猜数游戏:随机生成某范围的数要求用户猜。用户输入猜测:随机生成某范围的数要求用户猜。用户输入猜测后应答:后应
45、答:too big,too small,you win。设计设计:用随机数生成器产生随机数。在程序开始要求范围(:用随机数生成器产生随机数。在程序开始要求范围(0到到32767的整数),后进入游戏循环。用户猜后询问是否继续。的整数),后进入游戏循环。用户猜后询问是否继续。程序主要部分交互输和输出。程序主要部分交互输和输出。从用户得到数的生成范围从用户得到数的生成范围do 生成一个数生成一个数m 交互式地要求用户猜数,直至用户猜对交互式地要求用户猜数,直至用户猜对 while(用户希望继续用户希望继续);结束处理结束处理 基本设计:基本设计:62把取范围和取下一猜数定义为函数:把取范围和取下一猜
46、数定义为函数:int getrange(void);int getnumber(int limit);getrange要求要求2到到32767的值,超范围就要求重输入。的值,超范围就要求重输入。getnumber的猜测值也应在范围内,否则提示重输。的猜测值也应在范围内,否则提示重输。给用户几次重输入机会,超过次数仍不对时返回负值,交给调给用户几次重输入机会,超过次数仍不对时返回负值,交给调用程序段处理。用程序段处理。设计思路设计思路随机数用标准函数随机数用标准函数rand生成。若范围为生成。若范围为0到到m1,可用如下语可用如下语句得到所需的随机数:句得到所需的随机数:unknown=rand
47、()%m;将用户继续判断定义为将用户继续判断定义为0/1值函数,控制大循环:值函数,控制大循环:int next(void);63int main()int m,unknown,guess;if(m=getrange()0)return 1;+m;/*取模的数应比最大的数大一取模的数应比最大的数大一*/do unknown=rand()%m;while(1)if(guess=getnumber(m)unknown)printf(Too big!n);else if(guess unknown)printf(Too small!n);else printf(You win!);break;whi
48、le(next();printf(Game over.n);return 0;64读入猜数上界的函数用常量限定用户出错次数,以免无穷循环读入猜数上界的函数用常量限定用户出错次数,以免无穷循环。检查输入的合法性,合适时返回;有问题时要求用户重输。检查输入的合法性,合适时返回;有问题时要求用户重输。重复次数超过重复次数超过ERRORNUM时返回负值。时返回负值。enum ERRORNUM=5;int getrange(void)int i,n;for(i=0;i ERRORNUM;+i)printf(Choose a range 0,n.Input n:);if(scanf(%d,&n)!=1|n
49、32767)printf(Wrong.A number in 232767.n);while(getchar()!=n);else return n;return-1;65读入猜测数的函数与前一个类似。需要数值范围参数,检查有读入猜测数的函数与前一个类似。需要数值范围参数,检查有所不同,函数结构一样:所不同,函数结构一样:int getnumber(int m)int i,n;for(i=0;i ERRORNUM;+i)printf(Your guess:);if(scanf(%d,&n)!=1|n=m)printf(Wrong!A number in 0%d.n,m-1);while(get
50、char()!=n);else return n;return-1;66int next(void)int c;printf(Next game?(y/n):);while(isspace(c=getchar()/*跳过空白跳过空白*/;if(c=y)return 1;else return 0;把这些函数集成到一起,加上适当头文件就完成了。把这些函数集成到一起,加上适当头文件就完成了。能否进一步优化?能否进一步优化?67加密和解密加密和解密。如要保存或传输文本(或其他文件),不希望别人。如要保存或传输文本(或其他文件),不希望别人了解文件内容。可通过加密了解文件内容。可通过加密改变文件形式改