c语言程序设计11第十一讲(第五章下).ppt_第1页
c语言程序设计11第十一讲(第五章下).ppt_第2页
c语言程序设计11第十一讲(第五章下).ppt_第3页
c语言程序设计11第十一讲(第五章下).ppt_第4页
c语言程序设计11第十一讲(第五章下).ppt_第5页
已阅读5页,还剩67页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

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

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论