第一章 程序设计和C语言
1.1.什么是计算机程序 程序:一组计算机能识别和执行的指令。只要让计算机执行这个程序,计算机就会自动地、有条不紊地进行工作 ..
计算机的一切操作都是由程序控制的,离开程序,计算机将一事无成。
1.2什么是计算机语言 计算机语言:人和计算机交流信息的、计算机和人都能识别的语言。 计算机语言发展阶段:机器语言(由0和1组成的指令)
符号语言(用英文字母和数字表示指令) 高级语言(接近于人的自然语言和数学语言)
面向过程的语言(非结构化的语言、结构化语言);面向对象的语言
1.3C语言的发展及其特点 C语言是一种用途广泛、功能强大、使用灵活的过程性编程语言,既可用于编写应用软件,又能用于编写系统软件。因此C语言问世以后得到迅速推广。 C语言主要特点:
语言简洁、紧凑,使用方便、灵活。(只有37个关键字、9种控制语句;程序书写形式自由,源程序短) 运算符丰富。(34种运算符;把括号、赋值、强制类型转换等都作为运算符处理;表达式类型多样化) 数据类型丰富。(包括:整型、浮点型、字符型、数组类型、指针类型、结构体类型、共用体类型;C99又扩充了复数浮点类型、超长整型、布尔类型;指针类型数据,能用来实现各种复杂的数据结构的运算。) 具有结构化的控制语句。(如if…else语句、while语句、do…while语句、switch语句、for语句用函数作为程序的模块单位,便于实现程序的模块化;C语言是完全模块化和结构化的语言) 语法限制不太严格,程序设计自由度大。(对数组下标越界不做检查;对变量的类型使用比较灵活,例如,整型量与字符型数据可以通用;C语言允许程序编写者有较大的自由度,因此放宽了语法检查) 允许直接访问物理地址,能进行位操作,可以直接对硬件进行操作。(C语言具有高级语言的功能和低级语言的许多功能,可用来编写系统软件;这种双重性,使它既是成功的系统描述语言,又是通用的程序设计语言) 用C语言编写的程序可移植性好。(C的编译系统简洁,很容易移植到新系统;在新系统上运行时,可直接编译“标准链接库”中的大部分功能,不需要修改源代码;几乎所有计算机系统都可以使用C语言) 生成目标代码质量高,程序执行效率高。
1.4.1最简单的C语言程序举例 C语言允许用两种注释方式://:单行注释,可单独占一行,可出现在一行中其他内容的右侧。 /*……*/:块式注释,可包含多行。
1.4.2 C语言程序的结构 C语言程序的结构特点:
1、一个程序由一个或多个源程序文件组成(小程序往往只包括一个源程序文件,一个源程序文件中可以包括三个部分:预处理指令、全局声明、函数定义。)
2、函数是C程序的主要组成部分(一个C程序是由一个或多个函数组成的;必须包含一个main函数(只能有一个);每个函数都用来实现一个或几个特定功能;被调用的函数可以是库函数,也可以是自己编制设计的函数。) 3、一个函数包括两个部分(函数首部、函数体(声明部分、执行部分)) 4、程序总是从main函数开始执行
专业 知识分享
完美WORD格式
5、C程序对计算机的操作由C语句完成(C程序书写格式是比较自由的:一行内可以写几个语句;一个语句可以分写在多行上。)
6、数据声明和语句最后必须有分号 7、C语言本身不提供输入输出语句 8、程序应当包含注释,增加可读性
1.6 程序设计的任务 1.问题分析 2.设计算法 3.编写程序 4.对源程序进行编辑、编译和连接 5.运行程序,分析结 6.编写程序文
档
第二章 算法——程序的灵魂
一个程序主要包括以下两方面的信息:
(1) 对数据的描述。在程序中要指定用到哪些数据以及这些数据的类型和数据的组织形式,这就是数据结构。 (2) 对操作的描述。即要求计算机进行操作的步骤,也就是算法。
数据是操作的对象,操作的目的是对数据进行加工处理,以得到期望的结果。
著名计算机科学家沃思(Nikiklaus Wirth)提出一个公式:算法 + 数据结构 = 程序
一个程序除了算法和数据结构这主要要素外,还应当采用结构化程序设计方法进行程序设计,并且用某一种计算机语言表示。
算法、数据结构、程序设计方法和语言工具是一个程序设计人员应具备的知识。
2.1什么是算法 广义地说,为解决一个问题而采取的方法和步骤,就称为“算法”。计算机算法可分为两大类别:数值运算算法(目的是求数值解);非数值运算算法(包括面十分广泛,常见的是用于事务管理领域)
2.3 算法的特性 一个有效算法应该具有以下特点:
(1) 有穷性。一个算法应包含有限的操作步骤,而不能是无限的。
(2) 确定性。算法中的每一个步骤都应当是确定的,而不应当是含糊的、模棱两可的。 (3) 有零个或多个输入。所谓输入是指在执行算法时需要从外界取得必要的信息。 (4) 有一个或多个输出。算法的目的是为了求解,“解” 就是输出。没有输出的算法是没有意义的。
11111(5) 有效性。算法中的每一个步骤都应当能有效地执行,并得到确定的结果。 123499100流程图是表示算法的较好的工具。
2.4.3 三种基本结构和改进的流程图 三种基本结构:(1)顺序结构 (2)选择结构 (3)循环结构 ①当型循环结构 ②直到型循环结构
2.4.5用伪代码表示算法 伪代码是用介于自然语言和计算机语言之间的文字和符号来描述算法。用伪代码写算法并无固定的、严格的语法规则,可以用英文,也可以中英文混用。
2.4.6 用计算机语言表示算法 要完成一项工作,包括设计算法和实现算法两个部分。设计算法的目的是为了实现算法。
例2.19 将例2.17表示的算法(求多项式 的值)用C语言表示。 #include 专业 知识分享 完美WORD格式 double deno = 2.0,sum = 1.0, term; while (deno <= 100) { sign = -sign; term = sign/deno; 5 sum = sum+term; c(f32)9 deno = deno+1; } 5c(f32) printf (\"%f\\n\9 return 0; } 2.5 结构化程序设计方法 采取以下方法保证得到结构化的程序:(1)自顶向下;(2)逐步细化;(3)模块化设计;(4)结构化编码。 第三章 最简单的C程序设计 3.1 顺序程序设计举例 例3.1 有人用温度计测量出用华氏法表示的温度(如 F,今要求把它转换为以摄氏法表示的温度(如 C) 。 解题思路:找到二者间的转换公式 f代表华氏温度,c代表摄氏温度 算法:(N-S图) #include float f,c; 定义f和c为单精度浮点型变量 f=64.0; 指定f的值 c=(5.0/9)*(f-32); 计算c的值 printf(\"f=%f\\nc=%f\\n\输出f和c的值 return 0; } 例3.2 计算存款利息。有1000元,想存一年。有三种方法可选:(1)活期,年利率为r1 (2)一年期定期,年 利率为r2 (3)存两次半年定期,年利率为r3,请分别计算出一年后按三种方法所得到的本息和。 解题思路:确定计算本息和的公式。从数学知识可知:若存款额为p0,则:活期存款一年后本息和为: p1=p0(1+r1);一年期定期存款,一年后本息和为:p2=p0(1+r2);两次半年定期存款,一年 后本息和为:p3=p0(1+r3/2)(1+r3/2) 算法: 专业 知识分享 完美WORD格式 #include {float p0=1000, r1=0.0036,r2=0.0225,r3=0.0198, p1, p2, p3; p1 = p0 * (1 + r1); p2 = p0 * (1 + r2); p3 = p0 * (1 + r3/2) * (1 + r3/2); printf(”%f\\n%f\\n%f\\n”,p1, p2, p3); return 0; } 3.2.1 常量与变量 1.常量:在程序运行过程中,其值不能被改变的量。整型常量:如1000,12345,0,-345;实型常量:十进制小 数形式:如0.34 -56.79 0.0,指数形式:如12.34e3 (代表12.34103);字符常量:如’?’,转义字符:如’\\n’;字符串常量:如”boy”;符号常量:#define PI 3.1416 2.变量:在程序运行期间,变量的值是可以改变的。变量必须先定义,后使用,定义变量时指定该变量的名字和 类型。变量名和变量值是两个不同的概念,变量名实际上是以一个名字代表的一个存储地址。 从变量中取值,实际上是通过变量名找到相应的内存地址,从该存储单元中读取数据。 3.常变量:const int a=3; 4.标识符:一个对象的名字。C语言规定标识符只能由字母、数字和下划线3种字符组成,且第一个字符必须为 字母或下划线 合法的标识符:如sum,average, _total, Class, day, BASIC, li_ling 不合法的标识符:M.D.John,¥123,#33,3D64,a>b 3.2.2 数据类型 所谓类型,就是对数据分配存储单元的安排,包括存储单元的长度(占多少字节)以及数据的存储形式。不同的类型分配不同的长度和存储形式。 C语言允许使用的数据类型: 整型类型:基本整型(int型):占2个或4个字节 短整型(short int):VC++6.0中占2个字节 长整型(long int):VC++6.0中占4个字节 基本类型 双长整型(long long int):C99新增的 字符型 布尔型 浮点类型(单精度浮点型、双精度浮点型、复数浮点型) 枚举类型 空类型 派生类型(指针类型、数组类型、结构体类型、共用体类型、函数类型) 3.2.3 整型数据 整型变量的符号属性:整型变量的值的范围包括负数到正数;可以将变量定义为“无符号”类型; 扩充的整形类型: 有符号基本整型 [signed] int; 无符号基本整型 unsigned int; 专业 知识分享 完美WORD格式 有符号短整型 [signed] short [int]; 无符号短整型 unsigned short [int]; 有符号长整型 [signed] long [int]; 无符号长整型 unsigned long [int] 有符号双长整型 [signed] long long [int]; 无符号双长整型 unsigned long long [int] 3.2.3 字符数据类型 字符是按其代码(整数)形式存储的,C99把字符型数据作为整数类型的一种。 1.字符与字符代码:大多数系统采用ASCII字符集 字母:A ~Z,a ~z 数字:0~9 专门符号:29个:! ” # & ‘ ( ) *等 空格符:空格、水平制表符、换行等 不能显示的字符:空(null)字符(以‘\\0’表示)、警告(以‘\\a’表示)、退格(以‘\\b’表 示)、回车(以‘\\r’表示)等 字符’1’和整数1是不同的概念: 字符’1’只是代表一个形状为’1’的符号,在需要时按原样输出,在内存中以ASCII码形式存储,占1个 字节[0 0 1 1 0 0 0 1]; 整数1是以整数存储方式(二进制补码方式)存储的,占2个或4个字节[0 0 0 0 0 0 0 0 |0 0 0 0 0 0 0 1] 2.字符变量:用类型符char定义字符变量 3.2.5 浮点型数据 浮点型数据是用来表示具有小数点的实数。 float型(单精度浮点型):编译系统为float型变量分配4个字节;数值以规范化的二进制数指数形式存放。 double型(双精度浮点型):编译系统为double型变量分配8个字节;15位有效数字 long double(长双精度)型 3.2.6 怎样确定常量的类型 字符常量:由单撇号括起来的单个字符或转义字符。 整型常量:不带小数点的数值。系统根据数值的大小确定int型还是long型等。 浮点型常量:凡以小数形式或指数形式出现的实数。C编译系统把浮点型常量都按双精度处理;分配8个字节 3.2.7 运算符和表达式 3、算术表达式和运算符的优先级与结合性: 用算术运算符和括号将运算对象(也称操作数)连接起来的、符合C语法规则的式子,称为C算术表达式 运算对象包括常量、变量、函数等 C语言规定了运算符的优先级和结合性 4、不同类型数据间的混合运算: (1)+、-、*、/ 运算的两个数中有一个数为float或double型,结果是double型。系统将float型数据都先 转换为double型,然后进行运算 (2)如果int型与float或double型数据进行运算,先把int型和float型数据转换为double型,然后进行 运算,结果是double型 (3)字符型数据与整型数据进行运算,就是把字符的ASCII代码与整型数据进行运算 专业 知识分享 完美WORD格式 例3.3 给定一个大写字母,要求用小写字母输出。 #include char c1,c2; c1=’A’; c2=c1+32; printf(\"%c\\n\ printf(”%d\\n”,c2); return 0; } 5、强制类型转换运算符 强制类型转换运算符的一般形式为:(类型名)(表达式) (double)a (将a转换成double类型) (int) (x+y) (将x+y的值转换成int型) (float)(5%3)(将5%3的值转换成float型) 有两种类型转换:系统自动进行的类型转换;强制类型转换 3.3.1 C语句的作用与分类 C语句分为以下5类: (1) 控制语句: if、switch、for、while、do…while、continue、break、return、goto等 (2) 函数调用语句 (3)表达式语句 (4)空语句 (5)复合语句 在C程序中,最常用的语句是:赋值语句;输入输出语句。其中最基本的是赋值语句。 例3.4 给出三角形的三边长,求三角形面积。 #include { double a,b,c,s,area; a=3.67; b=5.43; c=6.21; s=(a+b+c)/2; area=sqrt(s*(s-a)*(s-b)*(s-c)); printf(\"a=%f\b=%f\%f\\n\ printf(\"area=%f\\n\ return 0; } 3.4.1 数据的输入输出举例 例3.5 求ax2 + bx + c = 0方程的根。a、b、c由键盘输入,设 b2 -4ac>0 #include 专业 知识分享 完美WORD格式 {double a,b,c,disc,x1,x2,p,q; scanf(\"%lf%lf%lf\ disc=b*b-4*a*c; p=-b/(2.0*a); q=sqrt(disc)/(2.0*a); x1=p+q; x2=p-q; printf(\"x1=%7.2f\\nx2=%7.2f\\n\ return 0; } 3.4.2 有关数据输入输出的概念 几乎每一个C程序都包含输入输出,输入输出是程序中最基本的操作之一。 (1) 所谓输入输出是以计算机主机为主体而言的: 从计算机向输出设备(如显示器、打印机等)输出数据称为输出 从输入设备(如键盘、磁盘、光盘、扫描仪等)向计算机输入数据称为输入 (2) C语言本身不提供输入输出语句,输入和输出操作是由C标准函数库中的函数来实现的。printf和scanf不 是C语言的关键字,而只是库函数的名字 (3) 在使用输入输出函数时,要在程序文件的开头用预编译指令#include 3.4.3 用printf函数输出数据 在C程序中用来实现输出和输入的,主要是printf函数和scanf函数。这两个函数是格式输入输出函数,用这两个函数时,必须指定格式。 1.printf函数的一般格式,printf(格式控制,输出表列)例如:printf(”i=%d,c=%c\\n”,i,c); 2.常用格式字符:d格式符:用来输出一个有符号的十进制整数。可以在格式声明中指定输出数据的域宽 printf(”%5d%5d\\n”,12,-345);%d输出int型数据;%ld输出long型数据。 c格式符。用来输出一个字符,char ch=’a’;printf(”%c”,ch);或printf(”%5c”,ch) s格式符。用来输出一个字符串,printf(”%s”,”CHINA”); f格式符。用来输出实数,以小数形式输出。 ①不指定数据宽度和小数位数,用%f; ②指定数据宽度和小数位数。用%m.nf; ③输出的数据向左对齐,用%-m.nf e格式符。指定以指数形式输出实数。%e,VC++给出小数位数为6位,指数部分占5列,小数 点前必须有而且只有1位非零数字。printf(”%e”,123.456);输出:1.234560 e+002。%m.ne,printf(”%13.2e”,123.456);输出: 1.23e+002 (前面有4个空格) 3.4.4 用scanf函数输入数据 1. scanf 函数的一般形式:scanf(格式控制,地址表列) 2. scanf函数中的格式声明:与printf函数中的格式声明相似;以%开始,以一个格式字符结束,中间可以插入附加的字符,scanf(\"a=%f,b=%f,c=%f\; 3. 使用scanf函数时应注意的问题 3.4.5 字符数据的输入输出 1.用putchar函数输出一个字符,从计算机向显示器输出一个字符,putchar函数的一般形式为:putchar(c) 专业 知识分享 完美WORD格式 例3.8 先后输出BOY三个字符。 #include char a='B',b='O',c='Y'; putchar(a); putchar(b); putchar(c); putchar ('\\n'); return 0; } 2.用getchar函数输入一个字符,向计算机输入一个字符,getchar函数的一般形式为:getchar( ) 例3.9 从键盘输入BOY三个字符,然后把它们输出到屏幕。 #include int main ( ) { char a,b,c; a=getchar(); b=getchar(); c=getchar(); putchar(a); putchar(b); putchar(c); putchar('\\n'); return 0; } 第四章 选择结构程序设计 4.1 选择结构和条件判断 C语言有两种选择语句:(1)if语句,实现两个分支的选择结构;(2)switch语句,实现多分支的选择结构 2 例4.1 在例3.5的基础上对程序进行改进。题目要求是求 ax+ bx + c = 0方程的根。 22 由键盘输入a,b,c。假设a,b,c的值任意,并不保证 b - 4ac ≥ 0。需要在程序中进行判别,如果b - 4ac ≥ 0,就计算并输出方程的两个实根,否则就输出“方程无实根”的信息。 #include double a,b,c,disc,x1,x2,p,q; scanf(\"%lf%lf%lf\ disc=b*b-4*a*c; 专业 知识分享 完美WORD格式 if (disc<0) printf(“has not real roots\\n”); else { p=-b/(2.0*a); q=sqrt(disc)/(2.0*a); x1=p+q; x2=p-q; printf(“real roots:\\nx1=%7.2f\\nx2=%7.2f\\n”,x1,x2); } return 0; } 4.2.1 用if语句处理选择结构举例 例4.2 输入两个实数,按代数值由小到大的顺序输出这两个数。 #include scanf(\"%f,%f\ if(a>b) { t=a; a=b; b=t; } printf(\"%5.2f,%5.2f\\n\ return 0; } 例4.3 输入3个数a,b,c,要求按由小到大的顺序输出。 #include { float a,b,c,t; scanf(\"%f,%f,%f\ if(a>b) { t=a; a=b; b=t; } if(a>c) { t=a; a=c; c=t; } if(b>c) { t=b; b=c; c=t; } printf(\"%5.2f,%5.2f,%5.2f\\n\ return 0; 专业 知识分享 完美WORD格式 } 4.2.2 if语句的一般形式 if (表达式) 语句1 [ else 语句2 ] 最常用的3种if语句形式: 1. if (表达式) 语句1 (没有else子句) 2. if (表达式) 语句1 else 语句2 (有else子句) 3. if(表达式1) 语句1 else if(表达式2) 语句2 else if(表达式3) 语句3 ┆ else if(表达式m) 语句m else 语句m+1 (在else部分又嵌套了多层的if语句) 说明:(1)整个if语句可写在多行上,也可写在一行上,但都是一个整体,属于同一个语句; (2)“语句1”…“语句m”是if中的内嵌语句,内嵌语句也可以是一个if语句; (3)“语句1”…“语句m”可以是简单的语句,也可以是复合语句。 4.3.1 关系运算符及其优先次序 关系运算符:用来对两个数值进行比较的比较运算符 C语言提供6种关系运算符:①<(小于) ②<=(小于或等于) ③>大于) ④>=大于或等于)【优先级相同(高)】 ⑤ == (等于) ⑥ != (不等于)【优先级相同(低)】 关系、算术、赋值运算符的优先级:算数运算符 > 关系运算符 > 赋值运算符 4.3.2 关系表达式 关系表达式:用关系运算符将两个数值或数值表达式连接起来的式子;关系表达式的值是一个逻辑值,即“真” 或“假”;在C的逻辑运算中,以“1”代表“真”,以“0”代表“假” 4.4.1 逻辑运算符及其优先次序 3种逻辑运算符:&&(逻辑与) ||(逻辑或) !(逻辑非) &&和||是双目(元)运算符 !是一目(元)运算符 逻辑表达式(用逻辑运算符将关系表达式或其他逻辑量连接起来的式子) 逻辑运算的真值表 专业 知识分享 完美WORD格式 逻辑运算符的优先次序:! → && → || (!为三者中最高) 与其他运算符的优先次序:赋值运算符 < &&和|| < 关系运算符 < 算数运算符 < ! 4.4.2 逻辑表达式 逻辑表达式的值应该是逻辑量“真”或“假” 编译系统在表示逻辑运算结果时,以数值1代表“真”,以0代表“假” 但在判断一个量是否为“真”时,以0代表“假”,以非0代表“真” 注意:将一个非零的数值认作为“真” 修改后的逻辑运算真值表 4.4.3 逻辑型变量 这是C99所增加的一种数据类型,可以将关系运算和逻辑运算的结果存到一个逻辑型变量中,以便于分析和运算 4.5 条件运算符和条件表达式 有一种if语句,当被判别的表达式的值为“真”或“假” 时,都执行一个赋值语句且向同一个变量赋值 如:if (a>b) max=a; else max=b; 条件运算符的执行顺序:①求解表达式1;②若为非0(真)则求解表达式2,此时表达式2的值就作为整个条件 表达式的值;③若表达式1的值为0(假),则求解表达式3,表达式3的值就是整个条件表达式的值 条件运算符优先于赋值运算符;条件运算符的结合方向为“自右至左”。 例4.4 输入一个字符,判别它是否大写字母,如果是,将它转换成小写字母;如果不是,不转换。然后输出最后得到的字符。#include char ch; scanf(\"%c\ ch=(ch>='A' && ch<='Z‘)?(ch+32):ch; printf(\"%c\\n\ return 0; } 4.6 选择结构的嵌套 在if语句中又包含一个或多个if语句称为if语句的嵌套。一般形式: if( ) else总是与它上面最 if() 专业 知识分享 完美WORD格式 if( ) 语句1 近的未配对的if配对 { else 语句2 if()语句1 内嵌if else 内嵌if } if( ) 语句3 else语句2 {}限定了内嵌if范围 else 语句4 -1 (x < 0) 例4.5有一函数: y = 0 (x = 0)编一程序,输入一个x值,要求输出相应的y值。 1 (x > 0) 解题思路:方法1 (1) 先后用3个独立的if语句处理: 输入x scanf(\"%d\; 若 x < 0, 则y =-1 if(x<0) y = -1; 若 x = 0, 则y = 0 if(x==0) y = 0; 若 x > 0, 则y = 1 if(x>0) y = 1; 输出x和y printf(\"x=%d,y=%d\\n\; 方法2 (2) 用一个嵌套的if语句处理: 输入x scanf(\"%d\; 若x < 0, 则y = -1 if(x<0) y=-1; 否则 else 若 x = 0, 则y = 0 if(x==0) y=0; 否则 y = 1 else y=1; 输出x和y printf(\"x=%d,y=%d\\n\; 4.7 用switch语句实现多分支选择结构 例4.6 、例4.7 switch语句的作用是根据表达式的值,使流程跳转到不同的语句.switch语句的一般形式 4.8 选择结构程序综合举例 例4.8 写一程序,判断某一年是否闰年。 #include printf(\"enter year:\"); scanf(\"%d\ if (year%4==0) if(year%100==0) if(year%400==0) leap=1; else leap=0; else leap=1; else leap=0; if (leap) printf(\"%d is \ else printf(\"%d is not \ printf(\"a leap year.\\n\"); return 0; } 2 例4.9 求ax + bx + c = 0方程的解。 专业 知识分享 完美WORD格式 #include double a,b,c,disc,x1,x2,realpart,imagpart; scanf(\"%lf,%lf,%lf\ printf(\"The equation \"); if(fabs(a)<=1e-6) printf(\"is not a quadratic\\n\"); else {disc=b*b-4*a*c; if(fabs(disc)<=1e-6) printf(\"has two equal roots:%8.4f\\n\ else if(disc>1e-6) {x1=(-b+sqrt(disc))/(2*a); x2=(-b-sqrt(disc))/(2*a); printf(\"has distinct real roots:%8.4fand %8.4f\\n\ } else { realpart=-b/(2*a); imagpart=sqrt(-disc)/(2*a); printf(\" has complex roots:\\n\"); printf(\"%8.4f+%8.4fi\\n“,realpart,imagpart); printf(\"%8.4f-%8.4fi\\n\ } } return 0; } 例4.10 运输公司对用户计算运输费用。路程(s km)越远,每吨·千米运费越低。 标准如下: #include 500≤s < 1000 5%折扣 int c,s; 1000≤s < 2000 8%折扣 float p,w,d,f; 2000≤s < 3000 10%折扣 printf(\"please enter price,weight,discount:\"); 3000≤s 15%折扣 scanf(\"%f,%f,%d\ if(s>=3000) c=12; else c=s/250; f = p * w * s * (1 - d / 100); printf(“freight=%10.2f\\n”,f); return 0; } 第五章 循环结构程序设计 专业 知识分享 完美WORD格式 大多数的应用程序都会包含循环结构。循环结构和顺序结构、选择结构是结构化程序设计的三种基本结构,它们是各种复杂程序的基本构造单元。 5.2 用while语句实现循环 while语句的一般形式如下:while ( 表达式 ) 语句 循环体 “真”时执行循环体语句 “假”时不执行 while循环的特点是:先判断条件表达式,后执行循环体语句。 例5.1求1+2+3+…+100,即 100nn1 #include int i=1,sum=0; while (i<=100) { sum=sum+i; i++; } printf(\"sum=%d\\n\ return 0; } 5.3用do——while语句实现循环 do---while语句的特点:先无条件地执行循环体,然后判断循环条件是否成立。一般形式为: do 语句 while (表达式); 例5.2 用do…while语句求: 1+2+3+…+100 #include 专业 知识分享 完美WORD格式 do { sum=sum+i; i++; }while(i<=100); printf(\"sum=%d\\n\ return 0; } 例5.3 while和do---while循环的比较。 int i,sum=0; 当while后面 printf(“i=?”); 的表达式的 printf( scanf(“%d”,&i); 第一次的值 scanf( while(i<=10) 为“真”时, { 两种循环得到 { sum=sum+i; 的结果相同; sum=sum+i; i++; 否则不相同。 i++; } }while(i<=10); 专业 知识分享 “i=?”); “%d”,&i); int i,sum=0; do 完美WORD格式 printf(“sum=%d\\n\“sum=%d\\n\ 5.4用for语句实现循环 for语句不仅可以用于循环次数已经确定的情况,还可以用于循环次数不确定而只给出循环结束条件的情况。 for语句完全可以代替while语句。for语句的一般形式为:for(表达式1;表达式2;表达式3) 语句 设置初始条件,只执 循环条件表达式,用来判定是否 作为循环的调整器,例如 行一次。可以为零个、 继续循环。在每次执行循环体前 使循环变量增值,它是在 一个或多个变量设置 先执行此表达式,决定是否继续 执行完循环体后才进行的。 初值执行。 执行循环。 for语句的执行过程: (1) 先求解表达式1 (2) 求解表达式2,若其值为真,执行循环体,然后执行下面第(3)步。若为假,则结束循环,转到第(5)步 (3) 求解表达式3 (4) 转回上面步骤(2)继续执行 (5) 循环结束,执行for语句下面的一个语句 5.5 循环的嵌套 一个循环体内又包含另一个完整的循环结构,称为循环的嵌套。内嵌的循环中还可以嵌套循环,这就是多层循环。 3种循环(while循环、do…while循环和for循环)可以互相嵌套。 5.7 用break语句提前终止循环 break语句可以用来从循环体内跳出循环体,即提前结束循环,接着执行循环下面的语句 例5.4 在全系1000学生中,征集慈善募捐,当总数达到10万元时就结束,统计此时捐款的人数,以及平均每人捐款的数目。 #include { float amount,aver,total; int i; for (i=1,total=0;i<=1000;i++) { printf(\"please enter amount:\"); scanf(\"%f\ total= total+amount; if (total>=SUM) break; 专业 知识分享 完美WORD格式 } aver=total / i ; printf(“num=%d\\naver=%10.2f\\n”,i,aver); return 0; } 5.7.2 用continue语句提前结束本次循环 有时不希望终止整个循环的操作,而只希望提前结束本次循环,而接着执行下次循环。这时可以用continue语句。 例5.5 要求输出100~200之间的不能被3整除的数。 for(n=100;n<=200;n++) { if (n%3==0) continue; printf(\"%d \ } 5.7.3 break语句和continue语句的区别 continue语句只结束本次循环,而不是终止整个循环的执行 break语句结束整个循环过程,不再判断执行循环的条件是否成立 例5.6 输出以下4*5的矩阵。 1 2 3 4 5 2 4 6 8 10 3 6 9 12 15 4 8 12 16 20 #include int main() { int i,j,n=0; for (i=1;i<=4;i++) 控制输出4行 for (j=1;j<=5;j++,n++) 控制每行中输出5个数据 { if (n%5==0) printf (“\\n”); 专业 知识分享 完美WORD格式 printf (\"%d\\ } printf(\"\\n\"); return 0; } 5.8 循环程序举例 例5.7用 /4 ≈ 1-1/3 +1/5-1/7+`````` 公式求 的近似值,直到发现某一项的绝对值小于10为止(该项不累计加)。 -6 #include { int sign=1; double pi=0,n=1,term=1; while(fabs(term)>=1e-6) { pi=pi+term; n=n+2; sign=-sign; term=sign/n; } pi=pi*4; printf(\"pi=%10.8f\\n\ return 0; } 专业 知识分享 完美WORD格式 例5.8 求费波那西(Fibonacci)数列的前40个数。这个数列有如下特点:第1、2两个数为1、1。从第3个数开始,该数是其前面两个数之和。即: F1 =1 (n=1) F2 =1 (n=2) Fn =Fn-1 + Fn-2 (n≥3) 这是一个有趣的古典数学问题:有一对兔子,从出生后第3个月起每个月都生一对兔子。小兔子长到第3个月后每个月又生一对兔子。假设所有兔子都不死,问每个月的兔子总数为多少? #include { int f1=1,f2=1,f3; int i; { int f1=1,f2=1; int i; printf(\"%12d\\n%12d\\n\ for(i=1; i<=38; i++) { printf(\"%12d %12d \ { f3=f1+f2; if(i%2==0) printf(\"\\n\"); printf(\"%12d\\n\ f1=f2; f2=f2+f1; f2=f3; } } return 0; return 0; } } 例5.9输入一个大于3的整数n,判定它是否素数(prime,又称质数)。 #include printf(“n=?\"); scanf(\"%d\ for (i=2;i<=n-1;i++) 专业 知识分享 完美WORD格式 if(n%i==0) break; if(i for(n=101;n<=200;n=n+2) { k=sqrt(n); for (i=2;i<=k;i++) if (n%i==0) break; if (i>=k+1) } …… 例5.11 译密码。为使电文保密,往往按一定规律将其转换成密码,收报人再按约定的规律将其译回原文。 解题思路:问题的关键有两个: (1) 决定哪些字符不需要改变,哪些字符需要改变,如果需要改变,应改为哪个字符 处理的方法是:输入一个字符给字符变量c,先判定它是否字母(包括大小写),若不是字母,不改变c的值;若是字母,则还要检查它是否’W’到’Z’的范围内(包括大小写字母)。如不在此范围内,则使变量c的值改变为其后第4个字母。如果在’W’到’Z’的范围内,则应将它转换为A~D(或a~d)之一的字母。 专业 知识分享 { printf(\"%d \ m=m+1; } if(m%10==0) printf(“\\n”); 完美WORD格式 (2) 怎样使c改变为所指定的字母?办法是改变它的ASCII值 例如字符变量c的原值是大写字母’A’,想使c的值改变为’E’,只需执行“c=c+4”即可,因为’A’的ASCII值为65,而’E’ 的ASCII值为69,二者相差4 char c; c=getchar(); while(c!=‘\\n’) { if((c>=‘a’ && c<=‘z’) || (c>=‘A’ && c<=‘Z’)) { if(c>='W' && c<='Z' || c>='w' && c<='z') c=c-22; else c=c+4; } printf(\"%c\ c=getchar(); } char c; while((c=getchar())!=‘\\n’) { if((c>=‘A’ && c<=‘Z’) || (c>=‘a’ && c<=‘z’)) { c=c+4; if(c>=‘Z’ && c<=‘Z’+4 || c>‘z’) c=c-26; } printf(\"%c\} 第六章利用数组处理批量数据 数组是一组有序数据的集合。数组中各数据的排列是有一定规律的,下标代表数据在数组中的序号。用一个数组名和下标惟一确定数组中的元素。数组中的每一个元素都属于同一个数据类型 6.1.1怎样定义一维数组 一维数组是数组中最简单的。它的元素只需要用数组名加一个下标,就能惟一确定。要使用数组,必须在程序中先定义数组 定义一维数组的一般形式为:类型符 数组名[常量表达式]; 数组名的命名规则和变量名相同,如 int a[10]; 6.1.2怎样引用一维数组元素 在定义数组并对其中各元素赋值后,就可以引用数组中的元素。注意:只能引用数组元素而不能一次整体调用整个数组全部元素的值。 引用数组元素的表示形式为:数组名[下标],如a[0]=a[5]+a[7]-a[2*3] 合法 例6.1:对10个数组元素依次赋值为0,1,2,3,4,5,6,7,8,9,要求按逆序输出。 解题思路:定义一个长度为10的数组,数组定义为整型。要赋的值是从0到9,可 以用循环来赋值。 用循环按下标从大到小输出这10个元素 #include int main() 专业 知识分享 完美WORD格式 { int i,a[10]; for (i=0; i<=9;i++) a[i]=i; for(i=9;i>=0; i--) printf(\"%d \ printf(\"\\n\"); return 0; } 6.1.3一维数组的初始化 6.1.4一维数组程序举例 例6.2:用数组处理求Fibonacci数列问题 解题思路:例5.8中用简单变量处理的,缺点不能在内存中保存这些数。假如想直接输出数列中第25个 数,是很困难的。如果用数组处理,每一个数组元素代表数列中的一个数,依次求出各数并存放在相应的数组元素中。 #include { int i; int f[20]={1,1}; for(i=2;i<20;i++) f[i]=f[i-2]+f[i-1]; for(i=0;i<20;i++) { if(i%5==0) printf(“\\n”); printf(“%12d”,f[i]); } printf(\"\\n\"); 专业 知识分享 完美WORD格式 return 0; } 例6.3:有10个地区的面积,要求对它们按由小到大的顺序排列。 解题思路:排序的规律有两种:一种是“升序”,从小到大;另一种是“降序”,从大到小。把题目抽象 为:“对n个数按升序排序”。采用起泡法排序。 int a[10]; int i,j,t; printf(\"input 10 numbers :\\n\"); for (i=0;i<10;i++) scanf(\"%d\ printf(\"\\n\"); for(j=0;j<9;j++) for(i=0;i<9-j;i++) if (a[i]>a[i+1]) {t=a[i];a[i]=a[i+1];a[i+1]=t;} 123a45614b2536 printf(\"the sorted numbers :\\n\"); for(i=0;i<10;i++) printf(\"%d \ printf(\"\\n\"); 6.2.1怎样定义二维数组 二维数组定义的一般形式为:类型符 数组名[常量表达式][常量表达式];如:float a[3][4],b[5][10];;二维 数组可被看作是一种特殊的一维数组:它的元素又是一个一维数组。例如,把a看作是一个一维数组,它有3个元素:a[0]、a[1]、a[2],每个元素又是一个包含4个元素的一维数组 6.2.2怎样引用二维数组的元素 二维数组元素的表示形式为:数组名[下标][下标] 6.2.4二维数组程序举例 例6.4 ;将一个二维数组行和列的元素互换,存到另一个二维数组中。 解题思路:可以定义两个数组:数组a为2行3列,存放指定的6个数,数组b为3行2列,开始时未 赋值;将a数组中的元素a[i][j]存放到b数组中的b[j][i]元素中,用嵌套的for循环完成。 #include 专业 知识分享 完美WORD格式 { int a[2][3]={{1,2,3},{4,5,6}}; int b[3][2],i,j; printf(\"array a:\\n\"); for (i=0;i<=1;i++) { for (j=0;j<=2;j++) { printf(\"%5d\ b[j][i]=a[i][j]; } printf(\"\\n\"); } printf(\"array b:\\n\"); for (i=0;i<=2;i++) { for(j=0;j<=1;j++) printf(\"%5d\ printf(\"\\n\"); } return 0; } 例6.5:有一个3×4的矩阵,要求编程序求出其中值最大的那个元素的值,以及其所在的行号和列号。 解题思路:采用“打擂台算法”;先找出任一人站在台上,第2人上去与之比武,胜者留在台上;第3人 与台上的人比武,胜者留台上,败者下台;以后每一个人都是与当时留在台上的人比武,直到所有人都上台比为止,最后留在台上的是冠军。 先把a[0][0]的值赋给变量max;max用来存放当前已知的最大值;a[0][1]与max比较,如果 a[0][1]>max,则表示a[0][1]是已经比过的数据中值最大的,把它的值赋给max,取代了max的原值;以后依此处理,最后max就是最大的值。 …… int i,j,row=0,colum=0,max; int a[3][4]={{1,2,3,4},{9,8,7,6},{-10,10,-5,2}}; max=a[0][0]; for (i=0;i<=2;i++) for (j=0;j<=3;j++) if (a[i][j]>max) { max=a[i][j]; row=i; colum=j; } printf(\"max=%d\\nrow=%d\\ncolum=%d\\n\ …… 6.3.1怎样定义字符数组 用来存放字符数据的数组是字符数组。字符数组中的一个元素存放一个字符。定义字符数组的方法与定义数值型数组的方法类似。 例6.6 输出一个已知的字符串。 解题思路:定义一个字符数组,并用“初始化列表”对其赋以初值;用循环逐个输出此字符数组中的字符 #include { char c[15]={'I',' ','a','m',' ','a',' ','s','t','u','d','e','n','t','.'}; 专业 知识分享 完美WORD格式 int i; for(i=0;i<15;i++) printf(\"%c\ printf(\"\\n\"); return 0; } 例6.7:输出一个菱形图。 解题思路:定义一个字符型的二维数组,用“初始化列表”进行初始化;用嵌套的for循环输出字符数组中的所有元素。 #include for (i=0;i<5;i++) {for (j=0;j<5;j++) printf(\"%c\ printf(\"\\n\"); } return 0; 6.3.4字符串和字符串结束标志 在C语言中,是将字符串作为字符数组来处理的;关心的是字符串的有效长度而不是字符数组的长度;为了测定字符串的实际长度,C语言规定了字符串结束标志’\\0’。(’\\0’代表ASCII码为0的字符,从ASCII码表可以查到,ASCII码为0的字符不是一个可以显示的字符,而是一个“空操作符”,即它什么也不做;用它作为字符串结束标志不会产生附加的操作或增加有效字符,只起一个供辨别的标志。) 6.3.5字符数组的输入输出 字符数组的输入输出可以有两种方法:逐个字符输入输出(%c);整个字符串一次输入输出(%s)。 输出的字符中不包括结束符’\\0’;用%s输出字符串时,printf函数中的输出项是字符数组名,不是数组元素名。 如果一个字符数组中包含多个’\\0’,则遇第一个’\\0’时输出就结束。可以用scanf函数输入一个字符串。scanf函数中的输入项c是已定义的字符数组名,输入的字符串应短于已定义的字符数组的长度。 6.3.6善于使用字符串处理函数 在C函数库中提供了一些用来专门处理字符串的函数,使用方便 1.puts函数----输出字符串的函数,其一般形式为:puts (字符数组),作用是将一个字符串输出到终端。 2. gets函数----输入字符串的函数,其一般形式为:gets(字符数组),作用是输入一个字符串到字符数组 3. strcat函数----字符串连接函数,其一般形式为:strcat(字符数组1,字符数组2),其作用是把两个字符串连接起来,把字符串2接到字符串1的后面,结果放在字符数组1中。 使用字符串函数时,在程序开头用#include 可以用strncpy函数将字符串2中前面n个字符复制到字符数组1中去; strncpy(str1,str2,2):作用是将str2中最前面2个字符复制到str1中,取代str1中原有的最前面2个 专业 知识分享 完美WORD格式 字符;复制的字符个数n不应多于str1中原有的字符。 5. strcmp函数----字符串比较函数,其一般形式为:strcmp(字符串1,字符串2),作用是比较字符串1和字符 串2。 6. strlen函数----测字符串长度的函数,其一般形式为:strlen (字符数组),它是测试字符串长度的函数,函 数的值为字符串中的实际长度。 7. strlwr函数----转换为小写的函数,其一般形式为:strlwr (字符串),函数的作用是将字符串中大写字母换 成小写字母。 8. strupr函数----转换为大写的函数,其一般形式为:strupr (字符串),函数的作用是将字符串中小写字母换 成大写字母。 6.3.7字符数组应用举例 例6.8 输入一行字符,统计其中有多少个单词,单词之间用空格分隔开。 …… char string[81],c; int i,num=0,word=0; gets(string); for (i=0;(c=string[i])!=‘\\0’;i++) if(c==‘ ’) word=0; else if(word==0) { word=1; num++; } printf(“%d words\\n”,num); …… 例6.9 有3个字符串,要求找出其中最大者。 #include #include {char str[3][10]; char string[10]; int i; for (i=0;i<3;i++) gets (str[i]); if (strcmp(str[0],str[1])>0) strcpy(string,str[0]); else strcpy(string,str[1]); if (strcmp(str[2],string)>0) strcpy(string,str[2]); printf(\"\\nthe largest:\\n%s\\n\ return 0; } 第七章 用函数实现模块化程序设计 7.1 为什么要用函数 专业 知识分享 完美WORD格式 问题: 如果程序的功能比较多,规模比较大,把所有代码都写在main函数中,就会使主函数变得庞杂、头绪不清,阅读和维护变得困难。 有时程序中要多次实现某一功能,就需要多次重复编写实现此功能的程序代码,这使程序冗长,不精炼 解决的方法:用模块化程序设计的思路 采用“组装”的办法简化程序设计的过程;事先编好一批实现各种不同功能的函数;把它们保存在函数库中,需要时直接用。函数就是功能;每一个函数用来实现一个特定的功能;函数的名字应反映其代表的功能。 在设计一个较大的程序时,往往把它分为若干个程序模块,每一个模块包括一个或多个函数,每个函数实现一个特定的功能。C程序可由一个主函数和若干个其他函数构成;主函数调用其他函数,其他函数也可以互相调用;同一个函数可以被一个或多个函数调用任意多次。 可以使用库函数;可以使用自己编写的函数;在程序设计中要善于利用函数,可以减少重复编写程序段的工作量,同时可以方便地实现模块化的程序设计。 例7.1 输出以下的结果,用函数调用实现。 ****************** How do you do! ****************** 解题思路:在输出的文字上下分别有一行“*”号,显然不必重复写这段代码,用一个函数print_star来 实现输出一行“*”号的功能。再写一个print_message函数来输出中间一行文字信息,用主函数分别调用这两个函数。 #include { void print_star(); 声明函数 void print_message(); print_star(); print_message(); print_star(); return 0; } void print_star() 输出16个* 定义函数 { printf(“******************\\n”); } void print_message() 输出一行文字 { printf(“ How do you do!\\n”); } 专业 知识分享 完美WORD格式 说明: (1) 一个C程序由一个或多个程序模块组成,每一个程序模块作为一个源程序文件。对较大的程序, 一般不希望把所有内容全放在一个文件中,而是将它们分别放在若干个源文件中,由若干个源程序文件组成一个C程序。这样便于分别编写、分别编译,提高调试效率。一个源程序文件可以为多个C程序共用。 (2) 一个源程序文件由一个或多个函数以及其他有关内容(如预处理指令、数据声明与定义等)组 成。一个源程序文件是一个编译单位,在程序编译时是以源程序文件为单位进行编译的,而不是以函数为单位进行编译的。 (3) C程序的执行是从main函数开始的,如果在main函数中调用其他函数,在调用后流程返回到main函数,在main函数中结束整个程序的运行。 (4) 所有函数都是平行的,即在定义函数时是分别进行的,是互相独立的。一个函数并不从属于另 一个函数,即函数不能嵌套定义。函数间可以互相调用,但不能调用main函数。main函数是被操作系统调用的。 (5) 从用户使用的角度看,函数有两种。 库函数,它是由系统提供的,用户不必自己定义而直接使用它们。应该说明,不同的C语言编译 系统提供的库函数的数量和功能会有一些不同,当然许多基本的函数是共同的。 用户自己定义的函数。它是用以解决用户专门需要的函数。 (6) 从函数的形式看,函数分两类。 ①无参函数。无参函数一般用来执行指定的一组操作。无参函数可以带回或不带回函数值,但一 般以不带回函数值的居多。 ②有参函数。在调用函数时,主调函数在调用被调用函数时,通过参数向被调用函数传递数据, 一般情况下,执行被调用函数时会得到一个函数值,供主调函数使用。 7.2.1 为什么要定义函数 C语言要求,在程序中用到的所有函数,必须“先定义,后使用” 指定函数名字、函数返回值类型、函数实现的功能以及参数的个数与类型,将这些信息通知编译系统。 指定函数的名字,以便以后按名调用 指定函数类型,即函数返回值的类型 指定函数参数的名字和类型,以便在调用函数时向它们传递数据 指定函数的功能。这是最重要的,这是在函数体中解决的 对于库函数,程序设计者只需用#include指令把有关的头文件包含到本文件模块中即可。 程序设计者需要在程序中自己定义想用的而库函数并没有提供的函数。 7.2.2 定义函数的方法 1.定义无参函数,定义无参函数的一般形式为: 类型名 函数名() 类型名 函数名(void) { { 函数体 函数体 } } 包括声明部分和语句部分 2.定义有参函数,定义有参函数的一般形式为: 类型名 函数名(形式参数表列) { 专业 知识分享 完美WORD格式 函数体 } 3. 定义空函数,定义空函数的一般形式为: 类型名 函数名( ) { } 用空函数占一个位置,以后逐步扩充。好处:程序结构清楚,可读性好,扩充新功能方便,对程序结构影响不大。 7.3.1函数调用的形式 函数调用的一般形式为:函数名(实参表列) 如调用无参函数,则“实参表列”可以没有,但括号不能省略;如实参表列含多个实参,则各参数间用逗号隔开。 按函数调用在程序中出现的形式和位置来分,可以有以下3种函数调用方式: 第四章 函数调用语句:把函数调用单独作为一个语句,如printf_star();这时不要求函数带回值,只要求函数完成一定的操作。 第五章 函数表达式:函数调用出现在另一个表达式中,如c=max(a,b);这时要求函数带回一个确定的值以参加表达式的运算。 第六章 函数参数:函数调用作为另一函数调用时的实参,如m=max(a,max(b,c));其中max(b,c)是一次函数调用,它的值作为max另一次调用的实参。 7.3.2 函数调用时的数据传递 1.形式参数和实际参数 在调用有参函数时,主调函数和被调用函数之间有数据传递关系 定义函数时函数名后面的变量名称为“形式参数”(简称“形参”) 主调函数中调用一个函数时,函数名后面参数称为“实际参数”(简称“实参”),实际参数可以是常量、变量或表达式 2. 实参和形参间的数据传递 在调用函数过程中,系统会把实参的值传递给被调用函数的形参;或者说,形参从实参得到一个值,该值在函数调用期间有效,可以参加被调函数中的运算 例7.2 输入两个整数,要求输出其中值较大者。要求用函数来找到大数。 解题思路:(1)函数名应是见名知意,今定名为max (2)由于给定的两个数是整数,返回主调函数的值(即较大数)应该是整型 (3)max函数应当有两个参数,以便从主函数接收两个整数,因此参数的类型应当是整型 先编写max函数: int max(int x,int y) { int z; z=x>y?x:y; 专业 知识分享 完美WORD格式 return(z); } 在max函数上面,再编写主函数 #include { int max(int x,int y); int a,b,c; int max(int x, int y) (max函数) printf(“two integer numbers: \"); { scanf(“%d,%d”,&a,&b); int z; c=max( a,b );实参可以是常量、变量或表达式 z=x>y?x:y; printf(“max is %d\\n”,c); return(z); } } 7.3.3 函数调用的过程 在定义函数中指定的形参,在未出现函数调用时,它们并不占内存中的存储单元。在发生函数调用时,函数max的形参被临时分配内存单元。 调用结束,形参单元被释放;实参单元仍保留并维持原值,没有改变。如果在执行一个被调用函数时,形参的值发生改变,不会改变主调函数的实参的值。 7.3.4. 函数的返回值 通常,希望通过函数调用使主调函数能得到一个确定的值,这就是函数值(函数的返回值) 2.函数的返回值是通过函数中的return语句获得的。一个函数中可以有一个以上的return语句,执行到哪一个 return语句,哪一个就起作用;return语句后面的括号可以不要。 3.函数值的类型。应当在定义函数时指定函数值的类型。 4.在定义函数时指定的函数类型一般应该和return语句中的表达式类型一致。如果函数值的类型和return语句 中表达式的值不一致,则以函数类型为准。 例7.3将例7.2稍作改动,将在max函数中定义的变量z改为float型。函数返回值的类型与指定的函数类型不同,分析其处理方法。 解题思路:如果函数返回值的类型与指定的函数类型不同,按照赋值规则处理。 #include 专业 知识分享 完美WORD格式 int main() { int max(float x,float y); float a,b; int c; scanf(\"%f,%f,\ c=max(a,b); printf(\"max is %d\\n\ return 0; } int max(float x,float y) { float z; z=x>y?x:y; return( z ) ; } 7.4对被调用函数的声明和函数原型 在一个函数中调用另一个函数需要具备如下条件: (1) 被调用函数必须是已经定义的函数(是库函数或用户自己定义的函数) (2) 如果使用库函数,应该在本文件开头加相应的#include指令 (3) 如果使用自己定义的函数,而该函数的位置在调用它的函数后面,应该声明 例7.4 输入两个实数,用一个函数求出它们之和。 解题思路:用add函数实现。首先要定义add函数,它为float型,它应有两个参数,也应为float型。 特别要注意的是:要对add函数进行声明。 #include { float add(float x, float y); float a,b,c; printf(\"Please enter a and b:\"); scanf(\"%f,%f\ c=add(a,b); printf(\"sum is %f\\n\ return 0; 专业 知识分享 完美WORD格式 } float add(float x,float y) { float z; z=x+y; return(z); } 函数原型的一般形式有两种: 如 float add(float x, float y); float add(float, float); 原型说明可以放在文件的开头,这时所有函数都可以使用此函数 7.5 函数的嵌套调用 C语言的函数定义是互相平行、独立的,即函数不能嵌套定义,但可以嵌套调用函数,即调用一个函数的过程中,又可以调用另一个函数。 main函数 a函数 b函数 ① ② ③ ④ 调用a函数 调用b函数 ⑤ ⑨ ⑦ ⑧ ⑥ 结束 例7.5 输入4个整数,找出其中最大的数。用函数的嵌套调用来处理。 解题思路:main中调用max4函数,找4个数中最大者 max4中再调用max2,找两个数中的大者 max4中多次调用max2,可找4个数中的大者,然后把它作为函数值返回main函数 main函数中输出结果 主函数 #include { int max4(int a,int b,int c,int d); int a,b,c,d,max; printf(“4 interger numbers:\"); scanf(\"%d%d%d%d\ max=max4(a,b,c,d); printf(\"max=%d \\n\ return 0; } max4函数 max2函数 int max4(int a,int b,int c,int d) int max2(int a,int b) { int max2(int a,int b); { if(a>=b) int m; return a; m=max2(a,b); else 专业 知识分享 完美WORD格式 m=max2(m,c); return b; m=max2(m,d); } return(m); } int max2(int a,int b) (n0,1)n!1{ return(a>b?a:b); } 7.6 函数的递归调用 n!n•(n1)(n1)在调用一个函数的过程中又出现直接或间接地调用该函数本身,称为函数的递归调用。 C语言的特点之一就在于允许函数的递归调用。 例7.6 有5个学生坐在一起。问第5个学生多少岁?他说比第4个学生大2岁;问第4个学生岁数,他说比第3个学生大2岁;问第3个学生,又说比第2个学生大2岁;问第2个学生,说比第1个学生大2岁;最后问第1个学生,他说是10岁。请问第5个学生多大? #include { int age(int n); printf(\"NO.5,age:%d\\n\ return 0; } int age(int n) { int c; if(n==1) c=10; else c=age(n-1)+2; return(c); } 例7.7 用递归方法求n!。 解题思路:求n!可以用递推方法:即从1开始,乘2,再乘3……一直乘到n。 递推法的特点是从一个已知的事实(如1!=1)出发,按一定规律推出下一个事实(如2!=1!*2), 再从这个新的已知的事实出发,再向下推出一个新的事实(3!=3*2!)。n!=n*(n-1)!。 求n!也可以用递归方法,即5!等于4!×5,而4!=3!×4…,1!=1 可用下面的递归公式表示: #include {int fac(int n); int f; int n; int y; if(n<0) printf(\"input an integer number:\"); printf(\"n<0,data error!\"); scanf(\"%d\ y=fac(n); f=1; printf(\"%d!=%d\\n\ 专业 知识分享 完美WORD格式 return 0; return(f); } } 例7.8 Hanoi(汉诺)塔问题。古代有一个梵塔,塔内有3个座A、B、C,开始时A座上有64个盘子,盘子大小不等,大的在下,小的在上。有一个老和尚想把这64个盘子从A座移到C座,但规定每次只允许移动一个盘,且在移动过程中在3个座上都始终保持大盘在下,小盘在上。在移动过程中可以利用B座。要求编程序输出移动一盘子的步骤。 #include { void hanoi(int n,char one,char two,char three); int m; printf(“the number of diskes:\"); scanf(\"%d\ printf(\"move %d diskes:\\n\ hanoi(m,'A','B','C'); } void hanoi(int n,char one,char two,char three) { void move(char x,char y); if(n==1) move(one,three); else { hanoi(n-1,one,three,two); move(one,three); hanoi(n-1,two,one,three); } } void move(char x,char y) { printf(\"%c-->%c\\n\ } 7.7.1数组元素作函数实参 例7.9 输入10个数,要求输出其中值最大的元素和该数是第几个数。 #include { int max(int x,int y); int max(int x,int y) int a[10],m,n,i; { return(x>y?x:y); } printf(“10 integer numbers:\\n\"); for(i=0;i<10;i++) scanf(\"%d\ printf(\"\\n\"); for(i=1,m=a[0],n=0;i<10;i++) { if (max(m,a[i])>m) { m=max(m,a[i]); n=i; 专业 知识分享 完美WORD格式 } } printf(“largest number is %d\\n\ printf(“%dth number.\\n“,n+1); } 7.7.2数组名作函数参数 除了可以用数组元素作为函数参数外,还可以用数组名作函数参数(包括实参和形参)。用数组元素作实参时,向形参变量传递的是数组元素的值;用数组名作函数实参时,向形参传递的是数组首元素的地址。 例7.10 有一个一维数组score,内放10个学生成绩,求平均成绩。 #include { float average(float array[10]); float score[10],aver; int i; printf(\"input 10 scores:\\n\"); for(i=0;i<10;i++) scanf(\"%f\ printf(\"\\n\"); aver=average(score); printf(\"%5.2f\\n\ return 0; } float average(float array[10]) { int i; float aver,sum=array[0]; for(i=1;i<10;i++) sum=sum+array[i]; aver=sum/10; return(aver); } 例7.11 有两个班级,分别有35名和30名学生,调用一个average函数,分别求这两个班的学生的平均成绩。 #include { float average(float array[ ],int n); float score1[5]={98.5,97,91.5,60,55}; float score2[10]={67.5,89.5,99,69.5, 77,89.5,76.5,54,60,99.5}; printf(“%6.2f\\n”,average(score1,5)); printf(“%6.2f\\n”,average(score2,10)); return 0; } 调用形式为average(score1,5)时 调用形式为average(score2,10)时 float average(float array[ ],int n) float average(float array[ ],int n) 专业 知识分享 完美WORD格式 { int i; { int i; float aver,sum=array[0]; float aver,sum=array[0]; for(i=1;i { void sort(int array[],int n); int a[10],i; printf(\"enter array:\\n\"); for(i=0;i<10;i++) scanf(\"%d\ sort(a,10); printf(\"The sorted array:\\n\"); for(i=0;i<10;i++) printf(\"%d \ printf(\"\\n\"); return 0; } void sort(int array[],int n) { int i,j,k,t; for(i=0;i 7.7.3多维数组名作函数参数 例7.13 有一个3×4的矩阵,求所有元素中的最大值。 #include 7.8.1 局部变量 专业 知识分享 完美WORD格式 定义变量可能有三种情况:在函数的开头定义;在函数内的复合语句内定义;在函数的外部定义。 在一个函数内部定义的变量只在本函数范围内有效;在复合语句内定义的变量只在本复合语句范围内有效;在函数内部或复合语句内部定义的变量称为“局部变量”。 7.8.2全局变量 在函数内定义的变量是局部变量,而在函数之外定义的变量称为外部变量,外部变量是全局变量(也称全程变量)。 全局变量可以为本文件中其他函数所共用,有效范围为从定义变量的位置开始到本源文件结束。 例7.14 有一个一维数组,内放10个学生成绩,写一个函数,当主函数调用此函数后,能求出平均分、最高分和最低分。 #include float Max=0,Min=0; int main() { float average(float array[ ],int n); float ave,score[10]; int i; printf(\"Please enter 10 scores:\\n\"); for(i=0;i<10;i++) scanf(\"%f\ ave=average(score,10); printf(\"max=%6.2f\\nmin=%6.2f\\n average=%6.2f\\n\ return 0; } float average(float array[ ],int n) { int i; float aver,sum=array[0]; Max=Min=array[0]; for(i=1;i else if(array[i] 例7.15 若外部变量与局部变量同名,分析结果。 #include { int max(int a,int b); int a=8; printf(“max=%d\\n”,max(a,b)); return 0; } int max(int a,int b) { int c; 专业 知识分享 完美WORD格式 c=a>b?a:b; return(c); } 7.9.1动态存储方式与静态存储方式 从变量的作用域的角度来观察,变量可以分为全局变量和局部变量。 从变量值存在的时间(即生存期)观察,变量的存储有两种不同的方式:静态存储方式和动态存储方式 静态存储方式是指在程序运行期间由系统分配固定的存储空间的方式。 动态存储方式是在程序运行期间根据需要进行动态的分配存储空间的方式。 用户区 程序区 全局变量全部存放在静态存储区中 程序开始执行时给全局变量分配存储区,程序执行完毕就释放。 静态存储区 在程序执行过程中占据固定的存储单元 将数据存放在此区 动态存储区 ①函数形式参数②函数中定义的没有用关键字static声明的变量 ③函数调用时的现场保护和返回地址等存放在动态存储区 函数调用开始时分配,函数结束时释放。在程序执行过程中,这种分配和释放是动态的 每一个变量和函数都有两个属性:数据类型和数据的存储类别 数据类型,如整型、浮点型等; 存储类别指的是数据在内存中存储的方式(如静态存储和动态存储) 存储类别包括:自动的、静态的、寄存器的、外部的;根据变量的存储类别,可以知道变量的作用域和生存期。 7.9.2 局部变量的存储类别 1.自动变量(auto变量) 局部变量,如果不专门声明存储类别,都是动态地分配存储空间的。调用函数时,系统会给局部变量分配存储空间,调用结束时就自动释放空间。因此这类局部变量称为自动变量。自动变量用关键字auto作存储类别的声明。 int f(int a) { auto int b,c=3; ┇ } 2.静态局部变量(static局部变量) 希望函数中的局部变量在函数调用结束后不消失而继续保留原值,即其占用的存储单元不释放,在下一次再调用该函数时,该变量已有值(就是上一次函数调用结束时的值),这时就应该指定该局部变量为“静态局部变量”,用关键字static进行声明。 例7.16 考察静态局部变量的值。 #include 完美WORD格式 int a=2,i; b=b+1; for(i=0;i<3;i++) c=c+1; printf(“%d\\n”,f(a)); return(a+b+c); return 0; } } 例7.17 输出1到5的阶乘值。 #include { int fac(int n); int i; for(i=1;i<=5;i++) printf(“%d!=%d\\n”,i,fac(i)); return 0; } int fac(int n) { static int f=1; f=f*n; return(f); } 3. 寄存器变量(register变量) 一般情况下,变量(包括静态存储方式和动态存储方式)的值是存放在内存中的。 寄存器变量允许将局部变量的值放在CPU中的寄存器中。 现在的计算机能够识别使用频繁的变量,从而自动地将这些变量放在寄存器中,而不需要程序设计者指定。 7.9.3 全局变量的存储类别 全局变量都是存放在静态存储区中的。因此它们的生存期是固定的,存在于程序的整个运行过程。 一般来说,外部变量是在函数的外部定义的全局变量,它的作用域是从变量的定义处开始,到本程序文件的末尾。在此作用域内,全局变量可以为程序中各个函数所引用。 1. 在一个文件内扩展外部变量的作用域 外部变量有效的作用范围只限于定义处到本文件结束。 如果用关键字extern对某变量作“外部变量声明”,则可以从“声明”处起,合法地使用该外部变量。 例7.18 调用函数,求3个整数中的大者。 #include { int max( ); extern int A,B,C; scanf(“%d %d %d”,&A,&B,&C); printf(\"max is %d\\n\ return 0; } 专业 知识分享 完美WORD格式 int A ,B ,C; int max( ) { int m; m=A>B?A:B; if (C>m) m=C; return(m); } 2. 将外部变量的作用域扩展到其他文件 如果一个程序包含两个文件,在两个文件中都要用到同一个外部变量Num,不能分别在两个文件中各自定义一个外部变量Num 应在任一个文件中定义外部变量Num,而在另一文件中用extern对Num作“外部变量声明” 在编译和连接时,系统会由此知道Num有“外部链接”,可以从别处找到已定义的外部变量Num,并将在另一文件中定义的外部变量num的作用域扩展到本文件 例7.19 给定b的值,输入a和m,求a*b和am的值。 文件file1.c: #include int main() { int power(int); int b=3,c,d,m; scanf(\"%d,%d\ c=A*b; printf(\"%d*%d=%d\\n\ d=power(m); printf(\"%d**%d=%d\\n\ return 0; } 文件file2.c: extern A; int power(int n) { int i,y=1; for(i=1;i<=n;i++) y*=A; return(y); } 3.将外部变量的作用域限制在本文件中 有时在程序设计中希望某些外部变量只限于被本文件引用。这时可以在定义外部变量时加一个static声明。 file1.c file2.c static int A; extern A; int main ( ) 只能用于 void fun (int n) 本文件仍 { 本文件 { …… 然不能用 …… A=A*n; } …… } 专业 知识分享 完美WORD格式 说明: 不要误认为对外部变量加static声明后才采取静态存储方式,而不加static的是采取动态存储。 声明局部变量的存储类型和声明全局变量的存储类型的含义是不同的:对于局部变量来说,声明存储类型的作用是指定变量存储的区域以及由此产生的生存期的问题,而对于全局变量来说,声明存储类型的作用是变量作用域的扩展问题。 用static 声明一个变量的作用是: (1) 对局部变量用static声明,把它分配在静态存储区,该变量在整个程序执行期间不释放,其所分配的空间始终存在。 (2) 对全局变量用static声明,则该变量的作用域只限于本文件模块(即被声明的文件中)。 7.9.4 存储类别小结 对一个数据的定义,需要指定两种属性:数据类型和存储类别,分别使用两个关键字,例如: static int a; 静态局部整型变量或静态外部整型变量 auto char c; 自动变量,在函数内定义 register int d; 寄存器变量,在函数内定义 可以用extern声明已定义的外部变量,例如: extern b; 将已定义的外部变量b的作用域扩展至此 (1)从作用域角度分,有局部变量和全局变量。它们采用的存储类别如下: 自动变量 局部变量 静态局部变量 按作用域角度分 寄存器变量 全局变量 静态外部变量 外部变量 第二章 从变量存在的时间区分,有动态存储和静态存储两种类型。静态存储是程序整个运行时间都存在,而动态存储则是在调用函数时临时分配单元。 自动变量 动态存储 寄存器变量 形式参数 按生存期分 静态局部变量 静态存储 静态外部变量 外部变量 第三章 从变量值存放的位置来区分,可分为: (4) 关于作用域和生存期的概念 对一个变量的属性可以从两个方面分析: 作用域:如果一个变量在某个文件或函数范围内是有效的,就称该范围为该变量的作用域 生存期:如果一个变量值在某一时刻是存在的,则认为这一时刻属于该变量的生存期 作用域是从空间的角度,生存期是从时间的角度 二者有联系但不是同一回事 (5) static对局部变量和全局变量的作用不同 局部变量使变量由动态存储方式改变为静态存储方式;全局变量使变量局部化(局部于本文件),但仍为静态存储方式。从作用域角度看,凡有static声明的,其作用域都是局限的,或者是局限于本函数内(静态局部变量), 专业 知识分享 完美WORD格式 或者局限于本文件内(静态外部变量)。 7.10 关于变量的声明和定义 一般为了叙述方便,把建立存储空间的变量声明称定义,而把不需要建立存储空间的声明称为声明 函数中出现的对变量的声明(除了用extern声明的以外)都是定义,函数中对其他函数的声明不是函数的定义。 7.11.1 内部函数 如果一个函数只能被本文件中其他函数所调用,它称为内部函数。在定义内部函数时,在函数名和函数类型的前面加static,即:static 类型名 函数名(形参表) 内部函数又称静态函数,因为它是用static声明的。通常把只能由本文件使用的函数和外部变量放在文件的开头,前面都冠以static使之局部化,其他文件不能引用。提高了程序的可靠性。 7.11.2 外部函数 如果在定义函数时,在函数首部的最左端加关键字extern,则此函数是外部函数,可供其他文件调用。如函数首部可以为extern int fun (int a, int b) 如果在定义函数时省略extern,则默认为外部函数。 例7.20 有一个字符串,内有若干个字符,今输入一个字符,要求程序将字符串中该字符删去。用外部函数实现。 #include { extern void enter_string(char str[]); extern void delete_string(char str[],char ch); extern void print_string(char str[]); char c,str[80]; enter_string(str); scanf(“%c”,&c); delete_string(str,c); print_string(str); return 0; } void enter_string(char str[80]) { gets(str); } file2(文件2) void delete_string(char str[],char ch) { int i,j; for(i=j=0;str[i]!='\\0';i++) if(str[i]!=ch) str[j++]=str[i]; str[j]='\\0'; file3(文件3) } void print_string(char str[]) { printf(\"%s\\n\(文件4) 专业 知识分享 因篇幅问题不能全部显示,请点此查看更多更全内容