收藏 分享(赏)

第五章 C程序结构.ppt

上传人:tkhy51908 文档编号:8011220 上传时间:2019-06-04 格式:PPT 页数:75 大小:3.41MB
下载 相关 举报
第五章  C程序结构.ppt_第1页
第1页 / 共75页
第五章  C程序结构.ppt_第2页
第2页 / 共75页
第五章  C程序结构.ppt_第3页
第3页 / 共75页
第五章  C程序结构.ppt_第4页
第4页 / 共75页
第五章  C程序结构.ppt_第5页
第5页 / 共75页
点击查看更多>>
资源描述

1、第五章 C程序结构,一. C程序结构 二. 函数定义与函数声明 三. 函数的调用 四. 函数的嵌套调用与递归调用 五. 变量的作用域和生命期 六. 内部函数与外部函数 七. 如何运行一个多文件的程序 八. 编译预处理,二. C程序结构1. 用C语言设计程序的思路:编写函数,至少要编一个main()函数。2. C语言程序的执行:就是执行相应的main()函数。即从它的main()函数的第一个花括号开始,依次执行后面的语句,直到最后的花括号为止。其它函数只有在执行main()函数的过程中被调用时才能执行。,说明: 一个源程序文件由一个或多个函数组成; C程序的执行从main函数开始,并从main函

2、数结束; 所有函数都是平行的,独立的,但不能嵌套定义函数; 函数间可以互相调用,但不能调用main函数。,3. 函数的概念:在高级语言中的“函数”实际上是“功能”的意思。当 需要完成某一个功能时,就用一个函数(可以是标准库 中的函数或自己设计的函数)。 例如:学生成绩管理系统 菜单函数,4. 函数在使用过程中,包括三步骤: 定义函数:用C语句,或调用其它函数实现它的设计功能。 声明函数:被调用的函数需先声明后调用。但若定义位于调用前面,可省掉声明。为统一或标准化起见,一般将自定义的所有函数都在程序前面(在包含文件语句后)予以声明。 调用函数。,三. 函数定义与函数声明1. 函数定义:就是在程序

3、中设定一个函数模块。一个函数 是由变量声明部分与可执行语句组成的独立实体,用以完 成指定的功能。 函数定义的形式: 有参函数定义的一般形式类型标识符 函数名( 形式参数列表 ) 声明部分语句部分 无参函数定义的一般形式类型标识符 函数名( ) 声明部分语句部分 注:无参函数一般不需带回函数值,可以不写类型标识符,函数定义的内容: 函数类型(即函数数值类型): 通常把函数返回值的类型称为函数的类型。 例如: float max(float x,float y ) float为函数类型; 函数名: 函数名是一个用户定义的标识符,它的命名规则同变量完全一样,函数名应符合C语言对标识符的规定;在同一程

4、序中,不能有同名的函数。 形式参数: 写在函数名后面的一对圆括号内。作用:A. 表示从主调函数中接收哪类型的信息或数据;B. 在函数体中形式参数可以被引用的,可以输入、输出、被赋以新值或者参与运算。 函数体: 函数体是一个子程序结构,由变量定义部分和语句组成。,函数的返回: 函数执行的最后一个操作是返回。float max(float x,float y ) float z;return z; 意义:A. 使流程返回主调函数,宣告函数的一次执行结束B. 将函数值送到调用表达式中。 函数不能嵌套定义,一个函数不能定义在其它函数体内部。 Fun1() fun2(),例:编一函数,打印输出x的n次方

5、的值,其中n是整数。分析:由于x和n都是可变的,所以应该把x和n都作为函 数的参数。由于不需要返回值,因此,函数类型说明 为void型,若取名为power,则求x 的n次方函数可定 义为:,void power(float x,int n) /*函数定义*/ int i;double p=1.0;for (i=1,p=1;i= n;i+)p = p * x;printf(“%f的%d次方=%fn”,x,n,p);,2. 函数声明 一般格式为: 类型标识符 函数名 ( 类型标识符 形参, 类型标识符 形参, ); 注意:可以不写形参名,但不能只写形参名而不写类型,也不能不写函数的类型。以下3种情

6、况可以省略对被调函数的声明: 被调函数的定义在主调函数之前,编译系统已知道了函数的类型,可根据函数首部对函数的调用进行检查。 若被调函数的返回类型是int型或char型,因为整型是系统默认的类型。 在所有函数定义之前,在函数的外部已做了对函数的声明,则主调函数内可以不必再次声明。,Eg. double func ( double a, int b , float c );,四.函数的调用1. 函数参数的值传递参数是函数调用时进行信息交换的载体;即实参是调用函数中的变量,形参是被调函数中的变量;调用过程中实现实参与形参的结合。特点: 形参与实参各占一个独立的存储空间; 形参的存储空间是函数被调用

7、时才分配的; 函数返回时,临时存储区也被撤销。,总结:函数中对形参变量的操作不会影响到调用函数中的实参变量,即形参值不能传回给实参。,传值方式: 函数只有一个入口-实参传值给形参。一个出口-函数返回值。,main() x y 实参_swap() a b 形参temp,例: 用函数传值来交换两个变量的值,main() int x=3,y=4;swap (x , y) ; ,3,4,4,3,3,4,3,swap ( int a , int b ) int temp;Temp=a; a=b; b=temp; ,2.函数调用的方式,无返回值函数的调用只要把函数作为一条语句处理,无返回值函数的调用格式为

8、:( );这时不需要函数返回值,只要求函数完成一定的功能。,例:编写求任意数之幂的程序。分析: 在前面已给出了求x的n次方的函数power(),所以只要在主函数中,输入x和n的值,并作为power()的参数,加上调用power(x,n) 语句即可,完整的程序清单如下:,#include “stdio.h“ void power ( float x , int n ) ; /*函数说明*/ main() float x; int n;printf (“输入x=? n=? n“);scanf (“%f%d“,编写求任意数之幂的程序,有返回值函数的调用把函数返回值赋给调用函数中的某个变量,一般形式为

9、:= ( );,例:编程求s=s1+s2+s10的值, 其中:Sn = 1+1/2+1/3+1/4+1/5+1/n( n =1,2,3,.,10 ) 分析: 需要先编写自定义函数sum(),用以求1+1/2+1/3+1/4+1/5+1/n的值。 在主函数中,分别用1,2,.,10作为参数,调用函数sum(1),sum(2),.,sum(10),并把函数值累加到变量S即可。,编程求s=s1+s2+s10的值. Sn = 1+1/2+1/3+1/4+1/5+1/n ( n =1,2,3,.,10 )#include double sum( int n) int i;double s=0.0; fo

10、r(i=1;i=n;i+)s=1.0/(double)i ;return s; ,main() int i;double y=0.0;for(i=1;i=10;i+)y=y+sum(i);printf(“sum=%fn“,y); ,相传古代印度国王舍罕要褒奖他的聪明能干的宰相达依尔(国际象棋发明者),问他需要什么,达依尔回答说:“国王只要在国际象棋的棋盘上第一个格子放一粒麦子,第二个格子放上二粒,第三个格子放四粒,以此类推,每一格加一倍,一直放到64格,我就感恩不尽了”。国王答应了,结果全印度的粮食用完还不够。国王很纳闷,怎么也算不清这笔账。现在我们用C编程来算一下(1立方米数小麦大约1.42

11、108 粒)。改写:函数调用,main() int i;double sum,j;double a1,a2;a1=1;sum=1;for(i=1;i64;i+) a2=2*a1;a1=a2; sum=sum+a2;j=1.42e8;sum=sum/j;printf(“%fn“,sum); ,double sum( int k ) double n,a1,a2;a1=1;n=1;for(k=1;ki;k+) a2=2*a1;a1=a2;n=n+a2;return n; main() int i;double V,j;i=64;j=1.42e8;V=sum( i )/j;printf(“%fn“,

12、V); ,u=f1(i,t); , c=f2(b-1,b+1); ,返回f2函数值,五.函数的嵌套调用与递归调用,1、函数的嵌套调用:在执行被调用函数时,被调用函数又调用了其它函数。嵌套调用为结构化程序设计提供了基本的支持。,main()函数 f1函数 f2函数,int max3(int x,int y,int z) int w1,w2;w1=max2(x,y);w2=max2(w1,z);return w2; int max2(int u,int v) return uv ? u:v; main() int a,b,c,max;max=max3(a,b,c)printf(“max is %d

13、”,max); ,例:求三个数中的最大数。,算法分析:(1)取出红球的可能性是 ,;白球的可能性是 ,; 黑球的可能性是 ,;,(2)如果红白球之和小于个,则凑不满个,故每次红白球之和至少应为 个;,(3)设红球分别取,个(即对红球的可能取法循环),白球可能的取法也是,但同时必须满足红白球之和不少于,黑球的个数为红白;,(4)每找到一种组合,都将它们的组合形式打印出来。,例:设口袋中放着12个球,其中3个是红的,个是白的,6个是黑的,每次从中取个球,问有多少种取法。,伪代码:所有变量均说明为整型变量sum=0 (计数变量初始化)begin loop (red=0 to 3) (对红球的可能取法

14、循环)begin loop (white=0 to 3) (对白球可能的取法循环)if red+white2 ( 红球+白球2) 则本次取不到8个球,不计数elsesum=sum+1 (计数)end ifend loop (循环结束)end loop (循环结束)print “sum=“;sum (打印结果)结束程序,int pri(int,int); main() int r,w,sum=0,i=1; for(r=0;r=2)sum=sum+1;printf(“No %2d “,i);pri(r,w);i+; printf(“nsum=%dn“,sum); ,pri(int r,int w)

15、int b,i;b=8-r-w;for(i=1;i=r;i+)printf(“红“); for(i=1;i=w;i+)printf(“白“);for(i=1;i=b;i+)printf(“黑“);putchar(n); ,2、函数的递归调用 递归就是某一事物直接或间接地由自己组成。 递归函数执行时,首先,由于反复调用其自身而逐层深入;当满足递归终止条件时则结束递归调用,逐层返回,直到返回最上一层而结束整个递归调用。 分类:直接递归调用;间接递归调用。,直接调用,fun(a,b) .fun(x,y); ,间接调用,fun1(a,b) .fun2(x,y); ,fun2(t,b) .fun1(x,

16、y); ,无论是直接还是间接递归,两者都是无终止的调用自身。要避免这种情况的发生,使用递归解决的问题应满足两个基本条件:,(1)问题的转化。有些问题不能直接求解或难以求解,但它可以转化为一个新问题,这个新问题相对原问题简单或更接近解决方法。这个新问题的解决与原问题一样,可以转化为下一个新问题,。,(2)转化的终止条件。原问题到新问题的转化是有条件的、次数是有限的,不能无限次数地转化下去。这个终止条件也称为边界条件,相当于递推关系中的初始条件。,例:编写程序,利用递归调用方式,计算n!。,n! 的边界条件为n=1。递归调用公式可表示为:,计算n!可以用下式定义:,n!= n(n-1)(n-2)2

17、1= n(n-1)!,即mn问题可以理解为:直接计算n!没有相应的运算符,但可以将n!转化为(n-1)!n的形式,即将n!转化为一个乘法问题,但乘法中的(n-1)!与n!是同一类问题,需要继续进行转化,直到问题趋于边界条件1!=1。,5*fact(4),4*fact(3),3*fact(2),2*fact(1),1,fact(5),main(),#include int fact(int); main()int i,n;scanf(“%d“, ,int fact(n)int f;if(n=1)f=1;elsef=fact(n-1)*n;return f; ,fact(5),fact(4),fa

18、ct(3),fact(2),fact(1),120,120,24,6,2,为计算过程计时 统计程序/程序片段的计算时间有助于理解程序性质。许多语言或系统都提供了内部计时功能。,有关函数在time.h,统计程序时间时程序头部应写:#include 在程序里计时,通常写表达式:clock()/CLOCKS_PER_SEC 得到从程序开始到表达式求值时所经历的秒数。 注意:有些老的C系统(如Turbe-C)用 CLK_TCK。,确定计算fib(45)所需要的时间的程序: #include #include long fib (int n) return n=1 ? 1 : fib(n-1)+fib(

19、n-2); int main () /* 自己做其他试验 */double x;x = clock() / CLK_TCK;fib(45);x = clock() / CLK_TCK - x;printf(“Timing fib(45): %f.n“, x);return 0; ,例,汉诺(Hanoi)塔游戏。,汉诺塔(Tower of Hanoi)游戏据说来源于布拉玛神庙。游戏的装置如图(图上以3个金片例),底座上有三根金的针,第一根针上放着从大到小64个金片。游戏的目标是把所有金片从第一根针移到第三根针上,第二根针作为中间过渡。每次只能移动一个金片,并且大的金片不能压在小的金片上面。该游戏

20、的结束就标志着“世界末日”的到来。,分析:,游戏中金片移动是一个很繁琐的过程。通过计算,对于64个金片至少需要移动 264 1 = 1.81019 次 。,不妨用A表示被移动金片所在的针(源),C表示目的针,B表示过渡针。对于把n(n1)个金片从第一根针A上移到第三根针C的问题可以分解成如下步骤:,将n-1个金片从A经过C移动到B。,将第n个金片移动到C。,再将n-1个金片从B经过A移动到C。,这样就把移动n个金片的问题转化为移动n-1个金片的问题,即移动n个金片的问题可用移动n-1个金片的问题递归描述,以此类推,可转化为移动一个金片的问题。显然,一个金片就可以直接移动。,hanoi(n-1,

21、A, C, B)move(one,C)hanoi(n-1,B,A,C),A (B) C 1: A (C) B2: 第n C3: B (A) C,void move(char x,char y) printf(“%c%cn“,x,y); void hanoi (int n,char one,char two,char three) if(n= =1)move(one,three);elsehanoi(n-1,one,three,two);move(one,three);hanoi(n-1,two,one,three); ,main() int m; printf(“input the numbe

22、r of diskes:“); scanf(“%d“, ,六.变量的作用域和生命期,(一)问题引入 项目:三人合作开发一个简单的数据库系统,项目负责人编写主函数main(),并负责统一连编调试,另两人各自完成记录添加和查询模块,三人所编的程序模块分别取名prog.c、prog1.c 和prog2.c。并作如下约定: 约定表示记录总数用ip变量,存储数据记录用二维数组char score406; 规定记录添加和查询的函数取名为add()和inqury(),其中参数为一维数组,因此,添加和查询操作均对形参数组进行。 问题 对于变量,如何实现不同模块间的共享和隐藏。用C语言表述为变量的存储属性和生命

23、期; 如何实现在不同程序文件中函数的调用,即内部函数和外部函数。,/*prog.c */ #include “stdio.h” int ip; main() char score; add(score); inqury(score); ,/*prog1.c*/ int ip; void add(char s) ,/*prog2.c*/ int ip; void inqury(char s) ,(二)变量的存储属性,C语言程序占用的存储空间通常分为三部分: 程序区: 存放可执行的程序机器指令; 静态存储区: 存放需要占用固定存储单元的变量; 动态存储区: 存放不需要占用固定存储单元的变量。,变量

24、定义包含三方面的内容: 变量的数据类型,如:int,char和float等; 变量的作用域,即变量能够起作用的程序范围; 变量的存储类型,即变量的存储方法,将影响变量值生存期;变量定义的完整形式应为:存储类别 数据类型 变量名 = 初始化表达式, ;,(三)局部变量及存储类型,在函数内定义的变量称局部变量即内部变量,它只在本函数范围内有效,即局部变量的作用域仅仅局限于定义它的函数内。因此,在本函数内不能使用其它函数内定义的变量,不同函数内可以有同名的局部变量。,例如: int f1(int a) /*函数f1*/ int b,c; /*a,b,c作用域:仅限于函数f1()中*/int f2(i

25、nt x) /*函数f2*/ int y,z; /*x,y,z作用域:仅限于函数f2()中*/main() int m,n; /*m,n作用域:仅限于函数main()中*/,1静态类变量如果希望在函数调用结束后仍然保持函数中定义的局部变量的值,则可以将该局部变量定义为静态局部变量。其方法是在前面加上static 关键字,如:static int a; 存储特点: 静态变量在静态存储区中分配存储单元。因此,在所在函数调用结束后,它的值并不消失。换句话说,在程序执行期间,静态局部变量始终存在,但其它函数是不能引用它们的。 定义但不初始化,则自动赋以“(整型和实型)或0(字符型);且每次调用它们所在

26、的函数时,不再重新赋初值,只是保留上次调用结束时的值。,局部变量分为三种存储类型: 静态类(static)、自动类(auto)和寄存器(register)。,例:静态类变量举例 #include “stdio.h” void test() static int value=0;printf(“value=%dn”,value);value+; main() int i;for(i=0;i3;i+)test(); ,程序运行结果:value=0value=1value=2,2. 自动类变量(auto) 在函数内定义的变量,如不指定存储类型,就是自动类存储变量。准确地讲,应在变量前加上auto关键

27、字,如:auto int a; 存储特点: 自动变量属于动态存储方式。在函数中定义的自动变量,只在该函数内有效;函数被调用时分配存储空间,调用结束释放。在复合语句中定义的自动变量,只在该复合语句中有效。 定义而不初始化,则其值是不确定的。如果初始化,则赋初值操作是在调用时进行的,且每次调用都要重新赋一次初值。 由于自动变量的作用域和生存期,都局限于定义它的个体内(函数或复合语句),因此不同的个体中允许使用同名的变量而不会混淆。即使在函数内定义的自动变量,也可与该函数内部的复合语句中定义的自动变量同名。,例:观察下程序中自动类变量的值的变化。 #include “stdio.h” void te

28、st() int value=0;printf(“value=%dn”,value);value+; main() int i;for(i=0;i3;i+)test(); ,程序运行结果: value=0 value=0 value=0,例:自动变量与静态局部变量的存储特性。void auto_static(void) int v_auto=0; /*自动变量:每次调用都重新初始化*/static int v_static=0; /*静态局部变量:只初始化1次*/printf(“v_auto=%d, v_static=%dn”, v_auto, v_static);+v_auto;+v_sta

29、tic; main() int i;for(i=0; i5; i+)auto_static(); ,3寄存器变量通常,变量的值都是存储在内存中的。为提高执行效率,将局部变量的值存放到寄存器中,称寄存器变量。register 数据类型 变量表;存储特点: 只有局部变量才能定义成寄存器变量,全局变量不行,即只能出现在函数内部,必须有关键词register。 对寄存器变量的实际处理,随系统而异。例如,微机上的TC将寄存器变量实际当作自动变量处理。 允许使用的寄存器数目是有限的,不能定义任意多个寄存器变量。 当一变量被说明为register变量时,其值存放在寄存器中,这样对寄存器变量的存取速度就很快,

30、因此寄存器变量通常用来存放循环变量,用来提高程序执行速度 。,例:寄存器变量实例。 #include long factor (int n ) register int i;long r;for (i=1,r=1;i=n;i+)r*=i;return r; main() int k;for (k=1;k=5;k+)printf(“%dn“,factor(k); ,关于局部变量的作用域还要说明以下几点: 主函数main()中定义的内部变量,也只能在主函数中使用,其它函数不能使用。同时,主函数中也不能使用其它函数中定义的内部变量。 形参变量也是内部变量,属于被调用函数;实参变量,则是调用函数的内部

31、变量。 允许在不同的函数中使用相同的变量名,它们代表不同的对象,分配不同的单元,互不干扰,也不会发生混淆。,(四)全局变量及其存储类型,在函数外定义的变量称为全局变量,也称外部变量。全局变量的作用域是从定义的位置开始到本源文件的结束,即位于全局变量的定义后面的所有函数都可以使用此变量。如:,int x, y; main() int z; void func() ,全局变量z 的作用范围,全局变量x,y 的作用范围,1静态全局变量如果希望在一个文件中定义的全局变量的作用域仅局限于此文件中,而不被其它文件所访问,则应在全局变量名前使用static关键字,即定义为静态全局变量。如:static in

32、t a;静态全局变量的使用主要用于在多人合作完成一个较大程序时,为避免同名的全局变量造成程序混乱,最好在全局变量前冠上static关键字。全局变量都是存储在静态存储区中,因此是静态存储的,并非在变量名前使用static关键字才是静态存储的。静态全局变量与全局变量的区别仅仅是作用域的不同。引入全局变量的目的,主要是为了在函数与函数之间,文件与文件之间进行通信。,全局变量分为:静态的(static)和非静态的(外部的extern) 。,prog2.c extern int ip; void inqury(char s6) ,prog.cint ip; main() add(score);inqur

33、y(score) ; ,prog1.c extern int ip; void add(int se 6) ,2. 外部变量(非静态全局变量)未说明为static的全局变量称为外部变量。在组成一个程序所有文件中(多个源程序文件)都可以使用外部变量。,文件prog1.c,prog2.c都可以引用文件prog.c中定义的外部变量ip,只要在prog1.c或prog2.c文件中用extern 关键字把此变量说明为外部的变量extern int ip。这种说明,一般应在文件的开头且位于所有函数外面。,对于全局变量还有以下几点说明: 全局变量可加强函数模块之间的数据联系,使这些函数依赖这些全局变量,使得

34、这些函数的独立性降低。从模块化程序设计的观点来看这是不利的,因此不是非用不可时,不要使用全局变量。 在同一源文件中,允许全局变量和局部变量同名。在局部变量的作用域内,全局变量将被屏蔽而不起作用。 全局变量的作用域是从定义点到本文件结束。如果定义点之前的函数需要引用这些全局变量时,需要在函数内对被引用的全局变量进行说明。全局变量说明的一般形式为:extern 数据类型 外部变量,外部变量2; 注意:全局变量的定义和全局变量的说明是两回事。全局变量的定义,必须在所有的函数之外,且只能定义一次。而全局变量的说明,出现在要使用该全局变量的函数内,而且可以出现多次。,#include Static in

35、t sum; void plusone( ) sum+; void plustwo( ) int sum;sum+=2; main( ) sum=5;plusone();plustwo();printf (“The sum is %dn“, sum); ,例:全局变量用于同一文件的函数之间的数据交换。,例:将外部变量的作用域扩充到其它文件。,file1.c int x, y; char ch; main( ) x=2; y=24; f1() ;printf(“%cn”,ch); ,file2.c extern int x,y; extern char ch;f1() printf(“%d,%d

36、n”,x,y); ch=a; ,注意:在file2.c文件中不能再定义“自己的外部变量” x,y,ch,否则就会犯“重复定义”的错误,七、内部函数与外部函数,C中所有的函数根据是否允许在多个文件中使用,而将它们分为内部函数和外部函数,分别用static和extern关键字来定义或声明。 内部函数内部函数又被称为静态函数,它只能在定义它的文件中被调用,而不能被其它文件中的函数调用。为了定义内部函数,需要在函数定义的前面使用static关键字:static 类型标识符 函数名(形参表)如:static float fun(float a, float b),外部函数外部函数可以被其它文件中的函数所

37、调用。有时为了明确这种性质,可以在函数定义和调用的文件中使用extern关键字:extern 类型标识符 函数名(参数表)如:extern float fun(float a, float b)在其他文件中如果有函数要调用fun(),则应在调用前用extern作外部函数说明:extern float fun(float a, float b);注意:C语言规定,在定义函数时省略extern,则隐含为外部函数。,外部函数举例,在程序prog.c中调用的函数add和inqury,是定义在prog1.c和prog2.c中,必须在程序prog.c中说明为外部函数extern void add()和ex

38、tern void inqury()。,prog2.c extern int ip; void inqury(char s6) ,prog.c extern void add(); extern void inqury(); int ip; main() add(score);inqury(score) ; ,prog1.c extern int ip; void add(int se 6) ,八、如何运行一个多文件的程序,在VC+集成环境中多文件的程序的编译连接问题。操作步骤如下: 1创建工程文件:设工程文件名为myprog,,2添加C文件3编译连接选择Complie Make EXE fi

39、le ,回车执行编译、连接。或按功能键F9,进行编译、连接,系统将3个文件翻译成目标文件,并把它们连接一个可执行文件myprog.exe。,程序设计实例,简单猜数游戏:随机生成某范围的数要求用户猜。用户输入猜测后应答:too big,too small,you win。,设计:用随机数生成器产生随机数。为更灵活,在程序开始要求范围(0到32767的整数),后进入游戏循环。用户猜后询问是否继续。 程序主要部分交互输和输出。,从用户得到数的生成范围 do 生成一个数m交互式地要求用户猜数,直至用户猜对 while(用户希望继续); 结束处理,基本设计:,随机数用标准函数rand生成。若范围为0到m

40、1,可用如下语句得到所需的随机数:unknown = rand() % m; 将用户继续判断定义为0/1值函数,控制大循环: int next(void); 把取范围和取下一猜数定义为函数: int getrange(void); int getnumber(int limit); getrange要求2到32767的值,超范围就要求重输入。 getnumber的猜测值也应在范围内,否则提示重输。 给用户几次重输入机会,超过次数仍不对时返回负值,交给调用程序段处理。,int main() int m, unknown, guess;if (m = getrange() unknown) pri

41、ntf(“Too big!n“);else if (guess unknown) printf(“Too small!n“);else printf(“You win!“);break; while (next();printf(“Game over.n“);return 0; ,读入猜数上界的函数用常量限定用户出错次数,以免无穷循环。检查输入的合法性,合适时返回;有问题时要求用户重输。重复次数超过ERRORNUM时返回负值。,enum ERRORNUM = 5 ; int getrange(void) int i, n;for (i = 0; i 32767) printf(“Wrong.

42、A number in 232767.n“);while (getchar() != n) ;else return n;return -1; ,读入猜测数的函数与前一个类似。需要数值范围参数,检查有所不同,函数结构一样:,int getnumber(int m) int i, n;for (i = 0; i =m) printf(“Wrong! A number in 0%d.n“, m-1);while (getchar() != n);else return n;return -1; ,可以统一这两个定义。其中的提示串不同,下章考虑。,next很简单: int next(void) in

43、t c;printf(“Next game? (y/n): “);while (isspace(c = getchar() /*跳过空白*/;if (c = y) return 1;else return 0; ,把这些东西集成到一起,加上适当头文件就完成了。,改造:加入某些统计,输出统计数据。评价、策略等。,加密和解密。如要保存或传输文本(或其他文件),不希望别人了解文件内容。可通过加密改变文件形式。为看到文件真实内容需要恢复文件原貌,即解密。,加密/解密互逆,历史悠久,可利用任何辅助信息/手段。 用计算机做加密/解密,需要定义一套改变文件内容编码的系统方案,要求这一修改是可逆的,以便解密。

44、,下面介绍的是极其简单的变换。人们提出了许多更加安全更技术性的变换方法,以满足各种需要。,简单的文本加密程序的工作就是读入一个个字符,通过一个函数把变换修改过的字符写出去。,一个简单的加密程序: #include int code(int c) return c + 13; int main() int c;while (c = getchar() != EOF)putchar(code(c);return 0; ,相应解密函数: int code(int c) return c - 13; 需要另外写一个类似程序,其中调用这个函数。,(一)编译预处理:是在编译前对源程序进行的一些预加工。命令

45、形式:以#开头,末尾不加分号。两个命令:#define 和 #include(二)宏替换定义:用预处理命令#define指定的预处理。1、不带参数的宏定义(字符串宏替换)形式:#define 宏名 宏体(字符串),八.编译预处理,注意:#define是宏定义命令。,例如: #define PI 3.14159265 main( ) float l,s,r,v; printf(“intut radius :”); l=2.0*PI*r*r; s=PI*r*r; v=4.0/3*PI*r*r*r; scanf(“%f”, ,注意: 宏名一般习惯用大写字母,可用小写字母; 使用宏名代替一个字符串;

46、宏定义不是C语句;不必在行末加分号; #define命令写在文件开头,函数之前,作为文件的一部分,在此文件范围内有效; 可用#undef命令终止宏定义的作用域; 在进行宏定义时,可引用已定义的宏名,可以层层转换; 对程序中用双引号括起来的字符,即使与宏名相同,也不进行转换。,2、带参的宏替换一般形式为: #define 宏名(参数表)字符串,例如: #define PI 3.1415926 #define S(r) PI*r*r Main() float a,area; A=3.6; Area=S(a); printf(“r=%fnarea=%fn”,a,area);,注意: 对带参数的宏的展

47、开只是将语句中的宏名后面括号内的实参字符串代替#define命令行中的形参。如有以下语句:area=S(a+b) 这时把实参a+b代替PI*r*r中的形参r, area=PI*a+b*a+b而我们的目的是应得到:area=PI*(a+b)*(a+b)正确的书写是:#define S(r) PI*(r)*(r) 宏名与带参数的括号之间不应加空格,否则将空格以后的字符都作为替代字符串的一部分。 如: #define S(r) PI*r*rarea=S (a)area= (a),(r) PI*r*r,宏定义与函数的不同: 调用函数时,先求出实参表达式的值,然后代入形参。 对函数中的形参和实参定义的类型要一致。#define CHAR1 CHNA (字符)#define a 3.6 (数值) 调用函数只可得到一个返回值,而用宏可以设法得到几个结果。例如 :#define square(n) (n)*(n)main() int I=1;While(I=10)Printf(“%dn”,square(I+); ,

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报