
中职C程序设计与训练课件完整版全套ppt电子课件.ppt
309页C C程序设计与训练程序设计与训练程序设计与训练程序设计与训练第二版目目 录录第1章 C语言概述第2章 数据类型、运算符与表达式第3章 顺序结构程序设计第4章 选择结构程序设计第5章 循环结构程序设计第6章 数 组第7章 函 数第8章 文 件第9章 自定义数据类型第第1章章 C语言概述C语言概述本章主要介绍C语言程序的结构和书写规则,以及VC6.0 V2.0的基本操作1.1 程序设计语言程序设计语言 1.2 算算法的概念法的概念1.3 C语言概C语言概述述1.3 C语言的语句和关键字语言的语句和关键字1.4 C程序的设计步骤与运行环境程序的设计步骤与运行环境 [Return] 第第2章章 数据类型与表达式数据类型与表达式2.1 C语言基本字符集和词汇语言基本字符集和词汇2.2 C语言数据类型语言数据类型2.3 常量常量2.4 变量变量2.5 运算符和表达式运算符和表达式*2.6 指针类型指针类型*2.7 位运算符位运算符*2.8 类型转换类型转换[Return]2.1 C语言基本字符集和词汇语言基本字符集和词汇2.1.1 C语言基本字符集语言基本字符集C语言基本字符集是ASCII码的子集,包括以下几类:(1) 英文字母:26个小写英文字母a~z和26个大写英文字母A~Z共52个字符; (2) 数字:分别为0~9共10个字符。
3) 空白符:包括空格符、制表符、回车符等空白符只在字符常量和字符串常量中起作用在其他地方出现时,只起间隔作用,编译程序对它们忽略不计因此在程序中使用空白符与否,对程序的编译不发生影响,但在程序中适当的地方使用空白符将增加程序的清晰性和可读性4) 特殊字符:包括29个特殊字符2.1 C语言基本字符集和词汇语言基本字符集和词汇2.1.2 词汇词汇C语言的词汇包括关键字、标识符、运算符和分隔符等1. 关键字关键字关键字又称为保留字,是C语言预先声明的具有特定意义的单词用户不能将这些关键字用作自定义的标识符C语言常用关键字可分为以下几类数据类型关键字,包括char、double、float、int、long、short、unsigned、union、void、enum、 signed、struct等;控制语句关键字,包括do、break、case、continue、for、goto、return、else、default、if、while、switch、extern等;存储类型关键字,包括auto、register、static;其他关键字,有const、sizeof、typedef、volatile、inline。
2.1 C语言基本字符集和词汇语言基本字符集和词汇2. 标识符标识符标识符是编程人员声明的单词,用来表示各种程序对象(如变量、类型、函数、文件等)的名字在C语言中标识符的构成规则如下:(1) 以字母或下划线“_”开头,后接字母、数字、下划线组成的字符序列2) 大小写字母含义不同例如,Name 和 name 是两个不同的标识符习惯上,一般用小写字母表示变量名,所有字母大写表示符号常量名,虽然这不是必须的,但它可以增加程序的可读性3) 标准C不限制标识符的长度,可由1个字符构成,也可由若干个字符构成,但其最大长度受各种版本的C语言编译系统限制我们在编写程序时可不考虑这一限制,因一般的编译系统都支持长标识符 2.1 C语言基本字符集和词汇语言基本字符集和词汇2. 标识符标识符依照上述规则,下列标识符是合法的sum, area, Number_of_moves, number_of_moves, j3_1, count1下列标识符是不合法的3xy (以数字开头) x2+y3 (出现非法字符“+”)@Mn3 (出现非法字符“@”) max–b2 (出现非法字符“–”)$xz_1238 (出现非法字符“$”)M.J.ttY (出现非法字符“. ”) 2.1 C语言基本字符集和词汇语言基本字符集和词汇2. 标识符标识符标识符命名时需要注意:(1) 标识符命名时做到“见名知义”,如PI、name、count、max等,以便于阅读和理解。
2) 尽量避免使用会引起混淆的字符如字母“O”和数字“0”,字母“I”、“l”和数字“1”,字母“z”和数字“2”等都易混淆3) 不能把关键字用作标识符4) 在C语言中,还有一类具有特定含义的标识符,它们主要用作C语言的预处理命令,因此,人们习惯上也把它们看成关键字,不作一般标识符使用,它们是:define、include、undef、ifdef、ifndef、endif5) C语言提供了大量的标准库函数,每一个函数都对应一个函数名,例如库函数sin、printf、scanf等不应将这些函数名定义为一般标识符来使用 2.1 C语言基本字符集和词汇语言基本字符集和词汇3. 运算符运算符运算符是用来表示某种运算的符号,多数运算符由一个字符组成,也有的由多个字符组成C语言中有44个运算符,分为15种优先级和两种结合性,详见附录B4. 分隔符分隔符分隔符是用于分隔单词或程序正文,一般不表示任何实际的操作,仅用于构造程序C语言中常用的分隔符是空格、制表符、逗号和换行符等 [Return]2.2 C语言数据类型语言数据类型在C语言中,凡是数据都必须有类型,必须在使用前进行类型说明。
[Return]2.3 常量常量 在程序运行过程中,其值不能被改变的量称为常量 常量的分类 (1)整型常量(2)实型常量(3)字符常量4)符号常量2.3.1 整型常量整型常量C语言中的常量有三类:数、字符和字符串由于它们本身已经隐含了数据类型,所以使用时不必事先进行类型说明就可以直接使用整型常量简称整数,C语言中整型常量可以用三种数制来表示:(1) 十进制整数:以日常所用的十进制整数形式给出,数码取值为0~9如154、-65、5232) 八进制整数:以数字0开头的数是八进制数,数码取值为0~7如十进制数39,用八进制表示为0473) 十六进制整数:以0x(数字0和字母x)或0X开头的数是十六进制数,其数码取值为0~9、A~F或a~f如0x1A23、0X2b2.3.2 实型常量通常,在计算机科学中,把带小数的数称为实数C语言中的实数有float(单精度)实数和double(双精度)实数,它们在计算机内存中是以浮点数形式存放的,故又称为浮点数实型常量只能用十进制形式表示,不能用八进制和十六进制形式表示实型常量有两种表示方法:(1) 十进制数形式:由数码0~9、小数点及正负号组成,如3.1415926,-0.12 等都是合法的实数。
2) 指数形式:由十进制数a,加阶码标识“e”或“E”以及阶码n组成一般形式为:a E n或a e n其中,a为实数,n为阶码,“e”或“E”两边必须有数字2.3.3 字符型常量字符型常量字符型常量是用一对单引号括起来的单个字符构成,例如,'a','b','1'等都是有效的字符型常量在C语言中,字符是用其对应的ASCII码值来表示,一个字符占一个字节例如,字符常量'0'、'A'、'a'的ASCII码值分别是48、65、97,它们对应的存储单元的内容分别为48、65、97C语言还使用一种特殊形式的字符型常量,这就是以反斜杠'\'开头,后跟一个或几个字符,它们不再具有字符原有的意义,而具有特定含义,故将其称为“转义”字符转义字符常用来表示那些用一般方式无法表示的控制字符例如,用'\n'表示换行字符,它的ASCII码值为10常见的转义字符如表2-2所示在字符常量中要使用单引号和反斜杠时,必须用转义字符表示,即在这些字符前加上反斜杠,例如'\\'、'\''2.3.4 字符串常量字符串常量C语言中,除了允许使用字符常量以外,还允许使用字符串常量在编写程序时使用一对双引号括起来的字符串序列就是字符串常量,注意,这里的双引号仅起定界符的作用,并不是字符串中的字符。
以下均是字符串常量:"I am a student."、"CHINA"、"a"、"123.4"等字符串常量在内存中存储时,除了一个字符占用一个字节外,还会自动在其尾部增加一个转义字符'\0',用这个特殊的字符作为字符串结束的标识或者说,若干个字符后有了结束标识'\0',才称为C语言的字符串例如,字符串"computer"包含8个字符,但其在内存中占用9个字节,最后一个字节就是存放字符串结束标识符'\0'用它来表示本字符串到此为止,之后的内容不属于本字符串computer\0图2-2 字符串常量在内存中的表示2.3.5 符号常量符号常量以上几种常量一般从字面上即可判别,所以又统称为字面常量或直接常量在C语言中还可以用一个标识符来代表一个常量,称之为符号常量符号常量在使用之前必须先定义在C语言中,使用宏定义命令#define定义符号常量其一般形式为:#define 标识符 常量表达式#define PI 3.14[Return]2.4 变量变量所谓变量是指在程序运行过程中其值可以发生变化的一种数据对象每一个变量都用一个标识符来表示,该标识符称为变量名每个变量都属于某个确定的数据类型,在内存中占据一定的存储单元,在该存储单元中存放变量的值,因此,变量具有如下属性:(1) 地址(2) 变量名(3) 变量值(4) 类型2.4 变量变量 在C语言中,变量一定要先定义后使用。
定义变量的一般形式如下类型类型 变量名表变量名表;这里,类型必须是C语言的有效数据类型变量名表是一个或多个标识符,中间用逗号隔开,最后用分号表示变量定义结束以下是定义变量的例子:int i, j, num; // 说明i、j、num为整型变量 float a, b, sum; // 说明a、b、sum为实型变量char c, ch; // 说明c、ch为字符型变量2.4.1 整型变量整型变量1.整型变量在内存中的存放形式数据在内存中是以二进制形式存放的例如,定义了一个整型变量i:int i;将十进制数9赋值给变量i:i=9;2. 整型变量的分类整型变量的分类整型变量的基本类型符为int,可以根据数值的范围将变量定义为基本整型、短整型或长整型在int 之前可以根据需要加上修饰符:short(短型)或long(长型)对这三种类型都可以加上修饰符unsigned以指定其为“无符号数”如果加上修饰符signed,则表示“有符号数”默认为有符号数(signed)有符号基本整型[signed] int有符号短整型[signed] short [int]有符号长整型[signed] long [int]无符号基本整型unsigned int无符号短整型unsigned short [int]无符号长整型unsigned long [int]3. 整型变量的定义与使用整型变量的定义与使用C语言规定在程序中要用到的变量必须先定义后使用。
例2-3】 整型变量的定义与使用include
ANSI C并未规定每一种数据类型的长度、精度和数值范围表2-4列出了TC 3.0和VC++ 6.0定义的实数类型和取值范围2.4.2 实型变量实型变量对每一个实型变量应在使用之前加以定义和初始化如:float x,y;float m=12.8;double min;long double t;2.4.3 字符型变量字符型变量字符型变量用来存放字符常量,一个字符变量只能存放一个字符表2-5列出了TC3.0和VC++6.0定义的字符类型和取值范围字符变量定义形式如下:字符变量定义形式如下:char c1,c2;定义c1、c2为字符型变量,在内存中各占一个字节,可以分别存放一个字符下面是对c1、c2赋值:c1='a';c2='b';也可以在定义字符变量的同时为其赋值,如:char c1='a',c2='b';[Return]2.5 运算符和表达式运算符和表达式2.5.1 C语言运算符与表达式简介语言运算符与表达式简介 1.运算符.运算符在程序中对变量或常量进行处理的符号称之为运算符2.表达式.表达式表达式是用运算符和括号把操作数连接起来所形成的式子操作数可以是常量、变量和函数。
每个表达式不管多么复杂,都能依据运算符的优先级、结合性以及数据类型转换规则计算出唯一的值该值的类型就是表达式的类型C语言表达式依据其的可分为:算术表达式、赋值表达式、关系表达式、逻辑表达式、条件表达式和逗号表达式等其中关系表达式、逻辑表达式将在第4章介绍2.5 运算符和表达式运算符和表达式2.5.2 算术运算符和算术表达式算术运算符和算术表达式 1.算术运算符.算术运算符2.5 运算符和表达式运算符和表达式2.5.2 算术运算符和算术表达式算术运算符和算术表达式 2.算术表达式和运算符的优先级与结合性.算术表达式和运算符的优先级与结合性2.5 运算符和表达式运算符和表达式2.5.2 算术运算符和算术表达式算术运算符和算术表达式 3.自增、自减运算符.自增、自减运算符2.5 运算符和表达式运算符和表达式2.5.2 算术运算符和算术表达式算术运算符和算术表达式4..sizeof运算符运算符sizeof运算符可操作的数据对象可以是表达式,也可以是类型名,其形式如下:sizeof(数据类型标识)sizeof 表达式2.5 运算符和表达式运算符和表达式2.5.3 赋值运算符和赋值表达式赋值运算符和赋值表达式1.赋值运算符.赋值运算符赋值运算符(=) 的作用是将其右边表达式的值赋给左边的变量。
赋值号左边一定是变量,右边是表达式如:a=3; r=x%y;2.5 运算符和表达式运算符和表达式2.5.3 赋值运算符和赋值表达式赋值运算符和赋值表达式2.复合赋值运算符.复合赋值运算符在C语言中,可以在赋值运算符之前加上其他运算符,构成复合赋值运算符复合赋值运算符共有10种,分别是:+= -= *= /= %= <<= >>= &= ^= |=前5个运算符是由算术运算符和赋值运算符结合在一起构成的复合赋值运算符;后5个运算符是由位运算符和赋值运算符结合在一起构成复合赋值运算符1) x+=3; 等价于x=x+3;(2) y*=y+z;等价于y=y*(y+z);(3) x%=3; 等价于 x=x%3;(4) i<<=3;等价于i=i<<3;2.5 运算符和表达式运算符和表达式2.5.3 赋值运算符和赋值表达式赋值运算符和赋值表达式3.赋值表达式.赋值表达式由赋值运算符将一个变量和一个表达式连接起来的式子称为赋值表达式,其一般形式为: 变量 = 表达式赋值表达式的作用是将赋值运算符右边的表达式的值赋给左边的变量C语言规定,赋值运算是右结合性,即从右至左进行运算,因此表达式x=(y=8)中的括号可以省略,写成:x=y=8 。
2.5 运算符和表达式运算符和表达式2.5.4 逗号运算符和逗号表达式逗号运算符和逗号表达式逗号运算符“,”是C语言中一个比较特殊的运算符,它的作用是将若干个表达式连接起来其基本信息如表2-10所示逗号表达式的一般形式为:表达式表达式1,表达式,表达式2,表达式,表达式3,,…,表达式,表达式n例如:a=3, b=5, c=a*b它是由三个独立的表达式结合而成的整个逗号表达式的值是15,a的值是3,b的值是5,c的值是152.5 运算符和表达式运算符和表达式2.5.5 条件运算符和条件表达式条件运算符和条件表达式条件运算符“?:”是C语言中唯一的三目运算符,即有三个操作数参与运算其基本信息如表2-11所示由条件运算符组成条件表达式的一般形式为: 表达式1 ? 表达式2 :表达式3其求值规则为:如果表达式1的值为真,则以表达式2 的值作为条件表达式的值,否则以表达式3的值作为条件表达式的值条件表达式通常用于赋值语句之中,例如一个条件表达式如下:max=(a>b)?a:b;[Return]2.6 指针类型指针类型2.6.1 字符常量字符常量指针是C语言中一个非常重要的概念,也是C语言的一个重要特色。
指针是一种很特殊的数据类型,其实它既不是简单类型也不是构造类型利用指针变量可以表示各种数据结构;可以方便地使用数组和字符串;并能象汇编语言一样处理内存地址,使得程序员能编写出精练而高效的程序指针的这些特点和用途对于设计系统软件和应用程序是非常必要的正确地使用指针,可以编写出简洁、紧凑、高效的程序[Return]2.7 位运算符位运算符在很多应用中,常常要求在二进制位(bit)一级进行运算位运算是指对操作数的各二进制位进行运算,C语言提供了六种位运算符,它们是: (1) &:按位与;(2) |:按位或;(3) ^:按位异或;(4) ~:按位非;(5) <<:左移;(6) >>:右移[Return]2.8 类型转换 2.8.1 自动类型转换自动类型转换 1. 赋值运算中的类型转换赋值运算中的类型转换 2. 混合运算中的类型转换混合运算中的类型转换 2.8.2 强制类型转换强制类型转换【例2-12】 强制类型转换示例include
的值解:(1) 求a%3,其值为1,表达式变为 x+1*(int)(x+y)%2/4;(2) 求(x+y),其值为7.1,表达式变为 x+1*(int)(7.1)%2/4;(3) 求(int)(7.1),其值为7,表达式变为 x+1*7%2/4;(4) 求1*7,其值为7,表达式变为 x+7%2/4;(5) 求7%2,其值为1,表达式变为 x+1/4;(6) 求1/4,其值为0,表达式变为 x;(7) x值为3.2,因此,表达式x+a%3*(int)(x+y)%2/4的值为3.2;(8) z=x+ a%3*(int)(x+ y)%2/4,z的 类 型 为 int, 自 动 将 x+ a%3*(int)(x+y)%2/4的类型转换为整型,因此,变量z的值是3[Return]第第3章章 基本语句与顺序结构程序设计基本语句与顺序结构程序设计3.1 语句语句3.2 数据输入与输出数据输入与输出3.3 顺序结构程序设计顺序结构程序设计3.4 顺序结构程序设计举例顺序结构程序设计举例[Return]3.1 语句语句语句是构成高级语言源程序的基本单位C语言中的语句是以分号结束的一段字符构成,例如:printf(“Good morning!\n”);C语言中语句分为简单语句和结构语句,如图3-1所示。
1. 简单语句简单语句(1) 空语句只有一个分号的语句就是空语句,它什么也不做写法如下:;(2) 表达式语句在任何一个表达式后面加上一个分号就构成一条表达式语句,它是C语言程序中最常用的语句例如: a=3+x; (赋值表达式语句)++i;(算术表达式语句)(3) return 语句 return 语句用于函数的返回 (4) break语句break语句用于退出循环结构或switch结构5) continue语句continue语句用于循环结构中,其作用是结束本次循环6)goto语句尽管在编写程序时不提倡使用goto语句7) 函数调用语句由函数调用加一个分号构成一条语句2. 结构语句结构语句(1) 复合语句复合语句是用符号“{”和“}”把若干有序的语句组合在一起而构成的例如:{int t;t=a; a=b; b=t;} 在逻辑上将复合语句看成是一条语句要注意的是,在复合语句括号“}”外不需要再加分号2) 选择结构与循环结构语句----程序的流程控制语句[Return]3.2 数据数据输入与输出输入与输出3.2.1 数据输入输出的概念数据输入输出的概念 在计算机中,输入输出(I/O)是以计算机主机为主体而言的。
若从主机向输出设备(如:显示器、打印机等)输出数据,称为“输出(Output)”而从输入设备(如键盘、鼠标等)向计算机传输数据,则称为“输入(Input)” C语言中没有定义任何处理输入输出的关键字,程序的输入输出都是使用系统库函数完成C语言的输入输出系统包括了许多函数,这些函数的有关信息在文件stdio.h(标准输入输出库,文件名后缀中的“h”是header的缩写)中说明在使用系统库函数时,要在程序文件的开头用预处理命令“#include”把有关文件包含在本程序中形式如下:#include "头文件头文件" 或或 #include <头文件头文件> 区别:用尖括号形式时,编译系统在存放C库函数头文件的目录中寻找要包含的文件,这称为标准方式用双引号形式时,系统在用户当前目录中寻找要包含的文件,若找不到,再按标准方式查找(即再按尖括号的方式查找)3.2.2 字符数据的输入输出函数字符数据的输入输出函数单个字符的输入──getchar()函数[例] 说明getchar()函数的格式和作用/*功能:说明getchar()函数的格式和作用/#include "stdio.h"/*文件包含*/main(){ char ch; printf("Please input two character: "); ch=getchar();/*输入1个字符并赋给ch */ putchar(ch);putchar('\n'); putchar(getchar()); /*输入一个字符并输出*/ putchar('\n');} 程序运行情况如下: Please input two characters: ab↙ a b 1.getchar()函数的格式:getchar(); 2.getchar()函数的作用:从系统隐含的输入设备(如键盘)输入一个字符。
另外,从功能角度来看,scanf()函数可以完全代替getchar()函数 (1)getchar()函数只能用于单个字符的输入,一次输入一个字符 (2)程序中要使用getchar()函数,必须在程序(或文件)的开头加上编译预处理命令: #include "stdio.h“3.2.2 字符数据的输入输出函数字符数据的输入输出函数单个字符的输出──putchar()函数[例1] putchar() 函数的格式和使用方法/*功能:说明putchar()函数的格式和使用方法/#include "stdio.h"/*编译预处理命令:文件包含*/main() {char ch1='N', ch2='E', ch3='W'; putchar(ch1); putchar(ch2); putchar(ch3); /*输出*/ putchar('\n'); putchar(ch1); putchar('\n');/*输出ch1的值,并换行*/ putchar('E'); putchar('\n');/*输出字符'E',并换行*/ putchar(ch3); putchar('\n'); } 程序运行结果如下: NEW N E W 1.putchar()函数的格式: putchar(ch); 其中ch可以是一个字符变量或常量,也可以是一个转义字符。
2.putchar()函数的作用:向终端输出一个字符 (1)putchar()函数只能用于单个字符的输出,且一次只能输出一个字符另外,从功能角度来看,printf()函数可以完全代替putchar()函数 (2)在程序中使用putchar()函数,务必牢记:在程序(或文件)的开头加上编译预处理命令(也称包含命令),即: #include "stdio.h" 表示要使用的函数,包含在标准输入输出(stdio)头文件(.h)中3.2.3 格式化输入与输出函数格式化输入与输出函数 printf( )和scanf( )是最常用的输入输出函数,它们可以在程序设计者的控制下以各种格式分别实现数据的输出和输入操作 1. printf( ) 函数函数[例2] 已知圆半径radius=1.5,求圆周长和圆面积main() {float radius,length,area,pi=3.1415926; radius=1.5; length=2*pi*radius;/*求圆周长*/ area=pi*radius*radius; /*求圆面积*/ printf(“radius=%f\n”,radius);/*输出圆半径*/ printf(“length=%7.2f,area=%7.2f\n”,length,area); /*输出圆周长、面积*/ } 程序运行结果如下: radius=1.500000 length= 9.42,area= 7.07 printf()函数的一般格式如下:printf("格式字符串格式字符串" [,输出项表,输出项表]);; 1.格式字符串。
格式字符串”也称“转换控制字符串”,可以包含三种字符: (1)格式指示符格式指示符的一般形式如下:%[标志标志][宽度宽度][.精度精度][F|N|h|L][类型类型] 常用的标志字符如表3-1所示,常用的宽度指示符如表3-2所示,常用的精度指示符如表3-3所示,长度修饰符如表3-4所示,类型转换字符如表3-5所示 (2)转义字符 例如,[例例1]中printf()函数中的'\n'就是转义字符,输出时产生一个“换行”操作 (3)普通字符──除格式指示符和转义字符之外的其它字符格式字符串中的普通字符,原样输出 例 如 , [例例 2]中 “printf("radius=%f\n", radius);”语 句 中 的“radius=”,“printf("length=%7.2f,area=%7.2f\n", length,area);”语句中的“length=”、“area=”等都是普通字符 2.输出项表 输出项表是可选的如果要输出的数据不止1个,相邻2个之间用逗号分开下面的printf()函数都是合法的: (1)printf("I am a student.\n"); (2)printf("%d",3+2); (3)printf("a=%f b=%5d\n", a, a+3);必必须须强强调调:“格式字符串”中的格式指示符,必须与“输出项表”中、输出项的数据类型一致,否则会引起输出错误。
格式指示符格式指示符 输出不同类型的数据,要使用不同的类型转换字符 1) 类型转换字符类型转换字符d──以带符号的十进制整数形式输出以带符号的十进制整数形式输出 [例例3] 类型转换字符d的使用main() {int num1=123; long num2=123456; /*用3种不同格式,输出int型数据num1的值*/ printf("num1=%d,num1=%5d,num1=%-5d,num1=%2d\n",num1,num1,num1,num1); /*用3种不同格式,输出long型数据num2的值*/ printf("num2=%ld,num2=%8ld,num2=%5ld\n",num2,num2,num2); printf("num1=%ld\n",num1); } [程序演示程序演示]程序运行结果如下:num1=123,num1=□□123,num1=123□□,num1=123num2=123456,num2=□□123456,num2=123456num1=16908411对于整数,还可用八进制、无符号形式(%o(小写字母o))和十六进制、无符号形式(%x)输出。
对于unsigned型数据,也可用%u格式符,以十进制、无符号形式输出所谓无符号形式是指,不论正数还是负数,系统一律当作无符号整数来输出例如,printf("%d,%o,%x\n",-1,-1,-1); 2) 类类型型转转换换字字符符f──以以小小数数形形式式、、按按系系统统默默认认的的宽宽度度,,输输出出单单精精度度和双精度实数和双精度实数[例例4] 类型转换字符f的使用main( ){ float f=123.456; double d1,d2; d1=1111111111111.111111111; d2=2222222222222.222222222; printf("%f,%12f,%12.2f,%-12.2f,%.2f\n",f,f,f,f,f); printf("d1+d2=%f\n",d1+d2);} [程序演示程序演示] 程序运行结果如下: 123.456001,□□123.456001,□□□□□□123.46,123.46□□□□□□,123.46 d1+d2=3333333333333.333010 本 例 程 序 的 输 出 结 果 中 , 数 据 123.456001和3333333333333.333010中的001和010都是无意义的,因为它们超出了有效数字的范围。
对于实数,也可使用格式符%e,以标准指数形式输出:尾数中的整数部分大于等于1、小于10,小数点占一位,尾数中的小数部分占5位;指数部分占4位(如e-03),其中e占一位,指数符号占一位,指数占2位,共计11位 也可使用格式符%g,让系统根据数值的大小,自动选择%f或%e格式、且不输出无意义的零3) 类型转换字符类型转换字符c──输出一个字符(只占一列宽度)输出一个字符(只占一列宽度)[例例5] 类型转换字符c的使用 main() { char c='A'; int i=65; printf("c=%c,%5c,%d\n",c,c,c); printf("i=%d,%c",i,i); }程序运行结果如下: c=A,□□□□A,65 i=65,A[程序演示程序演示] 需需要要强强调调的是:在C语言中,整数可以用字符形式输出,字符数据也可以用整数形式输出将整数用字符形式输出时,系统首先求该数与256的余数,然后将余数作为ASCII码,转换成相应的字符输出4) 类型转换字符类型转换字符s──输出一个字符串。
输出一个字符串[例例6] 类型转换字符s的使用 main() { printf("%s,%5s,%-10s","Internet","Internet","Internet"); printf("%10.5s,%-10.5s,%4.5s\n","Internet","Internet","Internet"); } [程序演示程序演示]程序运行结果如下:Internet,Internet,Internet□□,□□□□□Inter,Inter□□□□□,Inter注意注意:系统输出字符和字符串时,不输出单引号和双引号使用说明使用说明 (1)printf()可以输出常量、变量和表达式的值但格式控制中的格式说明符,必须按从左到右的顺序,与输出项表中的每个数据一一对应,否则出错 例如,printf("str=%s, f=%d, i=%f\n", "Internet", 1.0 / 2.0, 3 + 5, "CHINA");是错误的 (2)格式字符x、e、g可以用小写字母,也可以用大写字母使用大写字母时,输出数据中包含的字母也大写除了x、e、g格式字符外,其它格式字符必须用小写字母。
例如,%f不能写成%F (3)格式字符紧跟在“%”后面就作为格式字符,否则将作为普通字符使用(原样输出) 例如,“printf(”c=%c, f=%f\n“, c, f);”中的第一个c和f,都是普通字符2. scanf( )函数函数scanf()函数是用来从外部输入设备向计算机主机输入数据的 scanf()函数的一般格式函数的一般格式 [例例7] 已知圆柱体的底半径radius=1.5,高high=2.0,求其体积main() { float radius=1.5, high=2.0, pi=3.14159, vol; vol=pi*radius*radius*high; /*求体积*/ printf(“vol=%7.2f\n”,vol);/*输出求出的体积*/ } [程序演示程序演示][例例8] 已知圆柱体的底半径为radius,高为high,求其体积/*功能:说明函数scanf()的格式及作用/main() {float radius,high,vol,pi=3.1415926; printf("Please input radius & high: "); scanf("%f%f",&radius,&high);/*从键盘输入两个实数赋给变量r,h*/ vol=pi*radius*radius*high; printf("radius=%7.2f, high=%7.2f, vol=%7.2f\n",radius,high,vol); } [程序演示程序演示]程序运行结果如下: Please input radius & high: 1.5□2.0↙ radius=□□□1.50,high=□□□2.00,vol=□□14.14 在程序中给计算机提供数据,可以用赋值语句,也可以用输入函数。
在C语言中,可使用scanf()函数,通过键盘输入,给计算机同时提供多个、任意的数据scanf()函数的一般格式scanf("格式字符串格式字符串", 输入项首地址表输入项首地址表);(1)格式字符串格式字符串可以包含3种类型的字符:格式指示符、空白字符(空格、Tab键和回车键)和非空白字符(又称普通字符)格式指示符与printf()函数的相似,空白字符作为相邻2个输入数据的缺省分隔符,非空白字符在输入有效数据时,必须原样一起输入(2)输入项首地址表──由若干个输入项首地址组成,相邻2个输入项首地址之间,用逗号分开输入项首地址表中的地址,可以是变量的首地址,也可以是字符数组名或指针变量变量首地址的表示方法: &变量名变量名其中“&”是地址运算符例如,[案案例例3.7]中的“&radius”是指变量radius在内存中的首地址 2.scanf()函数的功能:从键盘上接收格式化输入运行[案案例例8]的程序时,从键盘上输入2个实数,分别存入&radius、&high起始的存储单元中,即输入两个实数分别赋给radius和high 格式指示符格式指示符 格式指示符的一般形式为: % [*] [宽宽度度] [F|N] [h|l] 类型字符类型字符 1)类型字符)类型字符 类型字符如表3-6所示。
例如,在[例例8]的scanf()函数语句中,格式字符串“%f%f” 2)宽度)宽度n 指定该项输入数据所占列数为n 换句话说,读取输入数据中相应的n位,但按需要的位数赋给相应的变量,多余部分被舍弃 例如,scanf("%3c%3c",&ch1,&ch2); printf("ch1=%c,ch2=%c\n",ch1,ch2); 假设输入“abcdefg”,则系统将读取的“abc”中的“a”赋给变量ch1;将读取的“def”中的“d”赋给变量ch2,所以printf()函数的输出结果为:ch1=a,ch2=d 3)赋值抑制字符)赋值抑制字符* 表示本输入项对应的数据读入后,不赋给相应的变量(该变量由下一个格式指示符输入) 例如,scanf("%2d%*2d%3d",&num1,&num2); printf("num1=%d,num2=%d\n",num1,num2); 假设输入“123456789”,则系统将读取“12”并赋值给num1;读取“34”、但舍弃掉(“*”的作用);读取“567”并赋值给num2。
所以,printf()函数的输出结果为:num1=12,num2=567 4)类型修饰符)类型修饰符──F、、N、、h、、l 其含义与printf()中的一样,分别为远指针、近指针、短整型和长整型 数据输入操作数据输入操作 1)如果相邻2个格式指示符之间,不指定数据分隔符(如逗号、冒号等),则相应的2个输入数据之间,至少用一个空格分开,或者用Tab键分开,或者输入1个数据后,按回车,然后再输入下1个数据 例如,scanf("%d%d",&num1,&num2); 假设给num1输入12,给num2输入36,则正确的输入操作为:12□36↙ 或者:12↙ 36↙ 注注:使用“↙”符号表示按回车键操作,在输入数据操作中的作用是,通知系统输入操作结束 2)“格式字符串”中出现的普通字符(包括转义字符形式的字符),务必原样输入 例如,scanf("%d,%d",&num1,&num2); 假设给num1输入12,给num2输入36,正确的输入操作为:12,36↙ 另外,scanf()函数中、格式字符串内的转义字符(如\n),系统并不把它当转义字符来解释,从而产生一个控制操作,而是将其视为普通字符,所以也要原样输入。
例如:scanf("num1=%d,num2=%d\n",&num1,&num2); 假设给num1输入12,给num2输入36,正确的输入操作为: num1=12,num2=36\n↙ 提提高高人人机机交交互互性性建建议议:为改善人机交互性,同时简化输入操作,在设计输入操作时,一般先用printf()函数输出一个提示信息,再用scanf()函数进行数据输入 例如,将scanf("num1=%d,num2=%d\n",&num1,&num2);改为: printf("num1="); scanf("%d",&num1); printf("num2="); scanf("%d",&num2); 3)输入数据时,遇到以下情况,系统认为该数据结束: (1)遇到空格,或者回车键,或者Tab键 (2)遇到输入域宽度结束例如“%3d”,只取3列 (3)遇到非法输入例如,在输入数值数据时,遇到字母等非数值符号(数值符号仅由数字字符0-9、小数点和正负号构成) 4)使用格式说明符“%c”输入单个字符时,空格和转 义字符均作为有效字符被输入。
例如,scanf("%c%c%c",&ch1,&ch2,&ch3); printf("ch1=%c,ch2=%c,ch3=%c\n",ch1,ch2,ch3); 假设输入:A□B□C↙,则系统将字母'A'赋值给ch1,空格'□'赋值给ch2,字母'B'赋值给ch3 [Return]3.3 顺序结构程序设计顺序结构程序设计在顺序结构程序中,各语句(或命令)是按照位置的先后次序,顺序执行的,且每个语句都会被执行到[例例1] 输入任意三个整数,求它们的和及平均值 /*功能:设计一个顺序结构程序,求三个整数的和及平均值/ main(){ int num1,num2,num3,sum; float aver; printf("Please input three numbers:"); scanf("%d,%d,%d",&num1,&num2,&num3);/*输入三个整数*/ sum=num1+num2+num3; /*求累计和*/ aver=sum/3.0; /*求平均值*/ printf("num1=%d,num2=%d,num3=%d\n",num1,num2,num3); printf("sum=%d,aver=%7.2f\n",sum,aver);}思考题思考题:能否将“aver=sum/3.0;”中“3.0”改为“3”?[例例2] 求方程ax2+bx+c=0的实数根。
a,b,c由键盘输入,a≠0且b2-4ac>0/*功能:设计一个顺序结构程序,求方程的根/#include "math.h"/*为使用求平方根函数sqrt(),包含math.h头文件 */main(){ float a,b,c,disc,x1,x2; printf("Input a, b, c: "); scanf("%f,%f,%f",&a,&b,&c);/*输入方程的三个系数的值*/ disc=b*b-4*a*c;/*求判别式的值赋给disc*/ x1=(-b+sqrt(disc))/(2*a); x2=(-b-sqrt(disc))/(2*a); printf("\nx1=%6.2f\nx2=%6.2f\n",x1,x2);} [程序演示程序演示] [例例3] 从键盘输入一个小写字母,要求用大小写字母形式输出该字母及对应的ASCII码值 #include "stdio.h"main(){ char c1,c2; printf("Input a lowercase letter: "); c1=getchar(); putchar(c1);printf(",%d\n",c1); c2=c1-32;/*将大写字母转换成对应的小写字母*/ printf("%c,%d\n",c2,c2);} [程序演示程序演示]程序运行情况如下: Input a lowercase letter: a↙ a,97 A,65 在顺序结构程序中,一般包括以下几个部分: 1.程序开头的编译预处理命令。
在程序中要使用标准函数(又称库函数),除printf()和scanf()外,其它的都必须使用编译预处理命令,将相应的头文件包含进来 2.顺序结构程序的函数体中,是完成具体功能的各个语句和运算,主要包括: (1)变量类型的说明 (2)提供数据语句 (3)运算部分 (4)输出部分[Return]3.4 顺序结构程序应用举例顺序结构程序应用举例【例【例1】】 写出下面程序的输出结果#include
include
include
在C语言中表示条件,一般用关系表达式或逻辑表达式,实现选择结构用if语句或switch语句4.1 问题的提出问题的提出4.2 关系运算和逻辑运算关系运算和逻辑运算4.3 if语句语句4.4 switch语句语句4.5 选择结构程序设计应用举例选择结构程序设计应用举例良好的源程序书写风格良好的源程序书写风格──注释注释[Return]4.1 问题的提出问题的提出用顺序结构能编写一些简单的程序,以进行简单的运算但是,人们对计算机运算的要求并不是仅限于一些简单的运算,经常遇到要求程序进行逻辑判断,即让程序判断是否满足给定条件,并按判断结果进行不同的处理例如:(1) 从键盘输入一个数,如果它是正数,则输出,否则不输出2) 输入一个代表年份的四位数,判断其是否是闰年3) 输入一个考试成绩,判断它的等级(优、良、中、及格或不及格)以上这些问题都需要程序按给定的条件进行判断,并按判断后的不同情况进行不同的处理,这类程序设计就属于选择结构,选择结构也称分支结构[Return]4.2 关系运算与关系运算与逻辑运算逻辑运算4.2.1 关系运算关系运算 所谓“关系运算”实际上就是“比较运算”,即将两个数据进行比较,判定两个数据是否符合给定的关系。
例如,“a > b”中的“>”表示一个大于关系运算如果a的值是5,b的值是3,则大于关系运算“>”的结果为“真”,即条件成立;如果a的值是2,b的值是3,则大于关系运算“>”的结果为“假”,即条件不成立 关系运算符及其优先次序关系运算符及其优先次序1.关系运算符C语言提供6种关系运算符:<(小于小于), <=(小于或等于小于或等于), >(大于大于), >=(大于或等于大于或等于), ==(等于等于), !=(不等于不等于)注意注意:在C语言中,“等于”关系运算符是双等号“= =”,而不是单等号“= ”(赋值运算符) 2.优先级 (1)在关系运算符中,前4个优先级相同,后2个也相同,且前4个高于后2个 (2)与其它种类运算符的优先级关系 关系运算符的优先级,低于算术运算符,但高于赋值运算符 关系表达式关系表达式 1.关系表达式的概念 所谓关系表达式是指,用关系运算符将两个表达式连接起来,进行关系运算的式子 例如,下面的关系表达式都是合法的: a>b,a+b>c-d,(a=3)<=(b=5),'a'>='b',(a>b)= =(b>c) 2.关系表达式的值——逻辑值(非“真”即“假”)。
由于C语言没有逻辑型数据,所以用整数“1”表示“逻辑真”,用整数“0”表示“逻辑假” 例如,假设num1=3,num2=4,num3=5,则: (1)num1>num2的值=0 (2)(num1>num2)!=num3的值=1 (3)num1
2) || :当且仅当两个运算量的值都为“假”时,运算结果为“假”,否则为“真” 3) ! :当运算量的值为“真”时,运算结果为“假”;当运算量的值为“假”时,运算结果为“真”例如,假定x=5,则(x>=0) && (x<10)的值为“真”,(x<-1) || (x>5)的值为“假” 2.逻辑运算符的运算优先级 (1)逻辑非的优先级最高,逻辑与次之,逻辑或最低,即:!(非) → &&(与) → ||(或) (2)与其它种类运算符的优先关系 !→ 算术运算 → 关系运算 → &&→ || → 赋值运算 逻辑表达式逻辑表达式 1.逻辑表达式的概念 所谓逻辑表达式是指,用逻辑运算符将1个或多个表达式连接起来,进行逻辑运算的式子在C语言中,用逻辑表达式表示多个条件的组合 例如,(year%4==0)&&(year%100!=0)||(year%400==0)就是一个判断一个年份是否是闰年的逻辑表达式 逻辑表达式的值也是一个逻辑值(非“真”即“假”) 2.逻辑量的真假判定──0和非0 C语言用整数“1”表示“逻辑真”、用“0”表示“逻辑假”。
但在判断一个数据的“真”或“假”时,却以0和非0为根据:如果为0,则判定为“逻辑假”;如果为非0,则判定为“逻辑真” 例如,假设num=12,则: !num的值=0 ,num>=1 && num<=31的值=1 ,num || num>31的值=1 3.说明 (1)逻辑运算符两侧的操作数,除可以是0和非0的整数外,也可以是其它任何类型的数据,如实型、字符型等 (2)在计算逻辑表达式时,只有在必须执行下一个表达式才能求解时,才求解该表达式(即并不是所有的表达式都被求解)换句话说: 1)对于逻辑与运算,如果第一个操作数被判定为“假”,系统不再判定或求解第二操作数 2)对于逻辑或运算,如果第一个操作数被判定为“真”,系统不再判定或求解第二操作数 例如,假设n1、n2、n3、n4、x、y的值分别为1、2、3、4、1、1,则求解表达式“(x=n1>n2)&&(y=n3>n4)”后,x的值变为0,而y的值不变,仍等于1! [Return]4.3 if语句语句4.3.1 if语句语句[例例1] 输入任意三个整数num1、num2、num3,求三个数中的最大值。
/*功能:说明if 语句的格式/ main(){ int num1,num2,num3,max; printf("Please input three numbers:"); scanf("%d,%d,%d",&num1,&num2,&num3); if (num1>num2) max=num1; else max=num2; if (num3>max) max=num3; printf("The three numbers are:%d,%d,%d\n",num1,num2,num3); printf("max=%d\n",max);}[程序演示程序演示]程序运行情况如下: Please input three numbers:11,22,18↙The three numbers are:11,22,18max=22本例中的第1个if语句,可优化为如下不带else子句的形式:max=num1;if(num2>max) max=num2;这种优化形式的基本思想是:首先取一个数预置为max(最大值),然后再用max依次与其余的数逐个比较,如果发现有比max大的,就用它给max重新赋值,比较完所有的数后,max中的数就是最大值。
这种方法,对从3个或3个以上的数中找最大值的处理,非常有效请读者仔细体会 [例例2]输入任意三个数num1、num2、num3,按从小到大的顺序排序输出 main(){int num1,num2,num3,temp;printf("Please input three numbers:");scanf("%d,%d,%d",&num1,&num2,&num3);if (num1>num2) {temp=num1;num1=num2;num2=temp;}if (num2>num3) {temp=num2;num2=num3;num3=temp;}if (num1>num2) {temp=num1;num1=num2;num2=temp;} printf("Three numbers after sorted: %d,%d,%d\n",num1,num2,num3);} [程序演示程序演示] 程序运行情况如下:Please input three numbers:11,22,18↙Three numbers after sorted: 11,18,22 1.if语句的一般格式 if(表达式表达式) {语句组语句组1;} [else {语句组语句组2;} ](1)if语句中的“表达式”必须用“(”和“)”括起来。
2)else子句(可选)是if语句的一部分,必须与if配对使用,不能单独使用3)当if和else下面的语句组,仅由一条语句构成时,也可不使用复合语句形式(即去掉花括号) 2.if语句的执行过程(1)缺省else子句时 当“表达式”的值不等于0(即判定为“逻辑真”)时,则执行语句组1,否则直接转向执行下一条(2)指定else子句时当“表达式”的值不等于0(即判定为“逻辑真”)时,则执行语句组1,然后转向下一条语句;否则,执行语句组2 3.if语句的嵌套与嵌套匹配原则 if语句允许嵌套所谓if语句的嵌套是指,在“语句组1”或(和)“语句组2”中,又包含有if语句的情况 if语句嵌套时,else子句与if的匹匹配配原原则则:与在它上面、距它最近、且尚未匹配的if配对为明确匹配关系,避免匹配错误,强强烈烈建建议议:将内嵌的if语句,一律用花括号括起来[例例3] 写一程序,从键盘上输入1年份year(4位十进制数),判断其是否闰年闰年的条件是:能被4整除、但不能被100整除,或者能被400整除算法设计要点算法设计要点:(1)如果X能被Y整除,则余数为0,即如果X%Y的值等于0,则表示X能被Y整除!(2)首先将是否闰年的标志leap预置为0(非闰年),这样仅当year为闰年时将leap置为1即可。
这种处理两种状态值的方法,对优化算法和提高程序可读性非常有效,请读者仔细体会参考程序如下:/*功能:说明if语句的嵌套格式和用法/main(){ int year,leap=0;/* leap=0:预置为非闰年*/ printf("Please input the year:"); scanf("%d",&year); if (year % 4==0) {if (year % 100 != 0) leap=1;} else {if (year%400==0) leap=1; } if (leap) printf("%d is a leap year.\n",year); else printf("%d is not a leap year.\n",year);} [程序演示程序演示]利用逻辑运算能描述复杂条件的特点,可将上述程序优化如下:main(){ int year; printf("Please input the year:"); scanf("%d",&year); if ((year%4==0 && year%100!=0)||(year%400==0)) printf("%d is a leap year.\n",year); else printf("%d is not a leap year.\n",year);} 4.说明 (1)if后面的“表达式”,除常见的关系表达式或逻辑表达式外,也允许是其它类型的数据,如整型、实型、字符型等。
(2)if语句允许嵌套,但嵌套的层数不宜太多在实际编程时,应适当控制嵌套层数(2~3层) (3)“语句组1”和“语句组2”,可以只包含一个简单语句,也可以是复合语句务务必必牢牢记记:不管是简单语句,还是复合语句中的各个语句,每个语句后面的分号必不可少! 例如,[例例1]中的: if (num1>num2) max=num1; else max=num2;语句: if行后面的赋值语句“max=num1;”分号不能省略但不要误认为if和else是2个独立的语句,它们都属于if语句中的一部分,else是if语句的子句 条件运算符条件运算符 1.一般格式: 表达式1?表达式2:表达式3 条件表达式中的“表达式1”、“表达式2”、“表达式3”的类型,可以各不相同 2.运算规则 如果“表达式1”的值为非0(即逻辑真), 则运算结果等于“表达式2”的值;否则,运算结果等于“表达式3”的值如图4-2所示 3.运算符的优先级与结合性 条件运算符的优先级,高于赋值运算符,但低于关系运算符和算术运算符。
其结合性为“从右到左”(即右结合性) [例例4] 从键盘上输入一个字符,如果它是大写字母,则把它转换成小写字母输出;否则,直接输出 main(){ char ch; printf("Input a character: "); scanf("%c",&ch); ch=(ch>='A' && ch<='Z') ? (ch+32) : ch; printf("ch=%c\n",ch);} [程序演示程序演示] [Return]4.4 switch语句语句C语言提供了switch语句直接处理多分支选择[例例5] 从键盘上输入一个百分制成绩score,按下列原则输出其等级:score≥90,等级为A;80≤score<90,等级为B;70≤score<80,等级为C;60≤score<70,等级为D;score<60,等级为Emain(){int score, grade; printf(“Input a score(0~100): ”); scanf(“%d”, &score); grade = score/10; /*将成绩整除10,转化成switch语句中的case标号*/ switch (grade){case 10: case 9: printf(“grade=A\n”); break; case 8: printf("grade=B\n"); break; case 7: printf("grade=C\n"); break; case 6: printf("grade=D\n"); break; case 5: case 4: case 3: case 2: case 1: case 0: printf(“grade=E\n”); break; default: printf(“The score is out of range!\n”);}}[程序演示程序演示]程序运行情况如下:Input a score(0~100): 85↙grade=B1.switch语句的一般形式switch(表达式) { case 常量表达式1:语句组;break; case 常量表达式2:语句组;break; ...... case 常量表达式n:语句组;break; [default:语句组;[break; ]] } 2.执行过程 (1)当switch后面“表达式”的值,与某个case后面的“常量表达式”的值相同时,就执行该case后面的语句(组);当执行到break语句时,跳出switch语句,转向执行switch语句的下一条。
(2)如果没有任何一个case后面的“常量表达式”的值,与“表达式”的值匹配,则执行default 后面的语句(组)然后,再执行switch语句的下一条 3.说明(1)switch后面的“表达式”,可以是int、char和枚举型中的一种2)每个case后面“常量表达式”的值,必须各不相同,否则会出现相互矛盾的现象(即对表达式的同一值,有两种或两种以上的执行方案)3)case后后面面的的常常量量表表达达式式仅仅起起语语句句标标号号作作用用,,并并不不进进行行条条件件判判断断系统一旦找到入口标号,就从此标号开始执行,不再进行标号判断,所以必须加上break语句,以便结束switch语句思思考考题题:如果去掉[例例5]程序中的所有break语句,且输入的成绩为75,输出会如何?(4)各case及default子句的先后次序,不影响程序执行结果5)多个case子句,可共用同一语句(组)例如,在[例例5]中的“case 10: ”和“case 9: ”共用语句“printf("grade=A\n"); break;”,“case 5: ”~“case 0: ”共用语句“printf("grade=E\n"); break;”。
6)用switch语句实现的多分支结构程序,完全可以用if语句或if语句的嵌套来实现[Return]4.5 选择结构程序设计应用举例选择结构程序设计应用举例[例例6] 求一元二次方程ax2+bx+c=0的解(a≠0)/*案例代码文件名:AL4_6.C//*功能:求一元二次方程的解/#include "math.h"main(){ float a,b,c,disc,x1,x2,p,q; scanf(“%f,%f,%f”, &a, &b, &c); disc=b*b-4*a*c; if (fabs(disc)<=1e-6)/*fabs():求绝对值库函数*/ printf(“x1=x2=%7.2f\n”, -b/(2*a));/*输出两个相等的实根*/ else { if (disc>1e-6) {x1=(-b+sqrt(disc))/(2*a);/*求出两个不相等的实根*/ x2=(-b-sqrt(disc))/(2*a); printf("x1=%7.2f,x2=%7.2f\n", x1, x2); } else {p=-b/(2*a);/*求出两个共轭复根*/ q=sqrt(fabs(disc))/(2*a); printf(“x1=%7.2f + %7.2f i\n“, p, q);/*输出两个共轭复根*/ printf(”x2=%7.2f - %7.2f i\n“, p, q); } }}[程序演示程序演示] 说明说明:由于实数在计算机中存储时,经常会有一些微小误差,所以本案例判断disc是否为0的方法是:判断disc的绝对值是否小于一个很小的数(例如10-6)。
思考题思考题:如果将系数a、b、c定义成整数,能否直接判断disc是否等于0? [例例7] 已知某公司员工的保底薪水为500,某月所接工程的利润profit(整数)与利润提成的关系如下(计量单位:元): profit≤1000没有提成;1000<profit≤2000提成10%;2000<profit≤5000提成15%;5000<profit≤10000提成20%;10000<profit提成25% 算法设计要点:算法设计要点: 为使用switch语句,必须将利润profit与提成的关系,转换成某些整数与提成的关系分析本题可知,提成的变化点都是1000的整数倍(1000、2000、5000、……),如果将利润profit整除1000,则当: profit≤1000对应0、11000<profit≤2000对应1、22000<profit≤5000对应2、3、4、55000<profit≤10000对应5、6、7、8、9、1010000<profit对应10、11、12、…… 为解决相邻两个区间的重叠问题,最简单的方法就是:利润profit先减1(最小增量),然后再整除1000即可: profit≤1000对应0 1000<profit≤2000对应1 2000<profit≤5000对应2、3、4 5000<profit≤10000对应5、6、7、8、9 10000<profit对应10、11、12、……main() {long profit; int grade; float salary=500; printf("Input profit: "); scanf("%ld", &profit); grade= (profit – 1) / 1000;/*将利润-1、再整除1000,转化成 switch语句中的case标号*/switch(grade){ case 0: break;/*profit≤1000 */ case 1: salary += profit*0.1; break;/*1000<profit≤2000 */ case 2: case 3: case 4: salary += profit*0.15; break;/*2000<profit≤5000 */ case 5: case 6: case 7: case 8: case 9: salary += profit*0.2; break;/*5000<profit≤10000 */ default: salary += profit*0.25;/*10000<profit */}printf("salary=%.2f\n", salary);} [程序演示程序演示]【例8】输入一个小于1000的正整数,要求:(1)求出它是几位数;(2)分别输出该数的每一位数字;(3)按逆序输出该数(例如原数为123,输出为321)。
include
在C语言源程序中,注释可分为三种情况:(1)在函数体内对语句的注释;(2)在函数之前对函数的注释;(3)在源程序文件开始处,对整个程序的总体说明函数体内的语句,是由顺序结构、选择结构和循环结构等三种基本结构构成的在什么地方加以注释的原则是:如果不加注释,理解起来就会有困难,或者虽无困难、但浪费时间 (1)顺序结构在每个顺序程序段(由若干条语句构成)之前,用注释说明其功能除很复杂的处理外,一般没有必要每条语句都加以注释 (2)选择结构 在C语言中,选择结构是由if语句和switch语句来实现的一般地说,要在前面说明其作用,在每个分支条件语句行的后面,说明该分支的含义,如下所示: 1)if语句 /*……(说明功能)*/ if(条件表达式)/*条件成立时的含义*/ {……} else/*入口条件含义*/ {……} 2)switch语句 /*……(说明功能) */ switch(表达式) { case 常量表达式1: /*该入口值的含义*/ 语句组; …… case 常量表达式n: /*该入口值的含义*/ 语句组; default: /*该入口值的含义*/ 语句组; } 如果条件成立时(或入口值)的含义,已经很明确了,也可不再加以注释。
[Return]第第5章章 循环结构程序设计循环结构程序设计5.1 while循环语句循环语句5.2 do … while循环语句循环语句5.3 for循环语句循环语句5.4 循环结构的嵌套循环结构的嵌套5.5 转移语句转移语句5.6 循环结构程序设计应用举例循环结构程序设计应用举例良好的源程序书写习惯良好的源程序书写习惯──注释注释(续)(续)[Return]5.1 while循环语句循环语句求1~100的累计和根据已有的知识,可以用“1+2+……+100”来求解,但显然很繁琐现在换个思路来考虑:首先设置一个累计器sum,其初值为0,利用sum += n来计算(n依次取1、2、……、100),只要解决以下3个问题即可: (1)将n的初值置为1; (2)每执行1次“sum += n”后,n增1; (3)当n增到101时,停止计算此时,sum的值就是1~100的累计和 根据已有的知识,单独实现每一步都不难但是,由于需要经常使用这种重复计算结构(称为循环结构),C语言提供了3条循环语句来实现,以简化、并规范循环结构程序设计。
在C语言中,可用以下语句实现循环:(1)用for语句2)用do-while语句3)用while语句(4)用goto语句和if语句构成循环使用goto语句实现求解1~100累计和的程序可以如下:main(){ int n=1, sum=0; loop: sum += n; n++; if (n<=100) goto loop; printf(“sum=%d\n”, sum);}其中“loop:”为语句标号(格式:标号: 语句行),其命名遵循标识符命名规则goto语句格式:goto 标号,功能为:使系统转向标号所在的语句行执行 注意注意:结构化程序设计方法,主张限制使用goto语句因为滥用goto语句,将会导致程序结构无规律、可读性差 另外,从功能上说,for语句可完全代替当型循环语句while,所以该语句也不是必需的while语句语句(1)一般格式 while (表达式) 循环体(2)执行过程执行过程如图所示1)求解“循环继续条件”表达式如果其值为非0,转2);否则转3)2)执行循环体语句组,然后转1)3)执行while语句的下一条。
【例【例1】】 用用while语句求语句求n的阶乘include
[例3] 求1~100的累计和/*程序功能:求1~100的累计和*/main() { int i,sum=0; /*将累加器sum初始化为0*/ for(i=1; i<=100; i++) sum += i; /*实现累加*/ printf("sum=%d\n",sum); }[程序演示]程序运行情况如下:sum=5050[例例4] 求n的阶乘n!(n!=1*2*……*n)/*程序功能:求n!*/main() { int i, n; long fact=1; /*将累乘器fact初始化为1*/ printf(“Input n: ”); scanf(“%d”, &n); for(i=1; i<=n; i++) fact *= i;/*实现累乘*/ printf("%d ! = %ld\n", n, fact); }[程序演示程序演示]程序运行情况如下:Input n: 5↙5 ! = 1201.for语句的一般格式 for (表达式1;表达式2;表达式3)循环体2.for语句的执行过程(1)求解“表达式1”。
2)求解“表达式2”如果其值非0,执行(3);否则,转至(4)3)执行循环体,并求解“表达式3”,然后转向(2)4)执行for语句的下一条语句3.说明(1)“表达式1”、“表达式2”和“表达式3”部分均可缺省,甚至全部缺省,但其间的分号不能省略(2)当循环体仅由一条语句构成时,可以不使用复合语句形式,如上例所示3)“表达式1”,既可以是给循环变量赋初值的赋值表达式,也可以是与此无关的其它表达式(如逗号表达式)例如,for(sum=0;i<=100;i++) sum += i; for(sum=0,i=1;i<=100;i++) sum += i;(4)“表达式2”部分是一个逻辑量,除一般的关系(或逻辑)表达式外,也允许是数值(或字符)表达式[Return]5.4 循环结构的嵌套循环结构的嵌套(1)循环语句的循环体内,又包含另一个完整的循环结构,称为循环的嵌套2)for语句和while语句允许嵌套,do-while语句也不例外合法的循环嵌套结构: 合法的循环嵌套结构:而下面形式的循环嵌套是不允许的,因为在这个嵌套结构中出现了交叉【例5】输出下列图案include
分析:由于xyz和yzz分别代表一个三位数,所以x的取值范围是1-4,y的取值范围是1-4,z的取值为1和6下列用三种循环语句构成的三重循环嵌套实现,程序如下:#include
3.break和continue语句对循环控制的影响如图5-4所示4.说明(1)break能用于循环语句和switch语句中,continue只能用于循环语句中2)循环嵌套时,break和continue只影响包含它们的最内层循环,与外层循环无关goto语句语句goto语句也称无条件转移语句,其一般格式如下:goto 语句标号;其中语句标号是按标识符命名规定命名的符号,放在某一语句行的前面,标号后加冒号“:”语句标号起标识语句的作用,与goto 语句配合使用例如:label: i++;loop: while(x<7) …; // 其中的label,loop均为语句标号C语言不限制程序中使用标号的次数,但各标号不得重名goto语句的语义是改变程序流向,转去执行语句标号所标识的语句goto语句只能在所在的函数体内转移,即goto语句与语句标号必须在同一个函数内goto语句通常与if语句配合使用,可用来实现条件转移,构成循环,跳出循环体等功能但按照结构化程序设计原则,应该限制使用goto语句最常见的用法是用来退出多重循环,而前面介绍的break语句只能退出它所在的那层循环但要注意,使用goto语句只能从内层循环跳转到外层循环,而不能从外层循环跳转到内层循环。
[Return]5.6 循环结构程序设计应用举例循环结构程序设计应用举例【例1】编程统计由4个数字1、2、3和4可以组成多少个互不相同且各位数字无重复的3位数?分析:可填在百位、十位、个位的数字是1、2、3、4中任意一个数字用一个三重循环分别计算出百位、十位、个位数字,并判断是否满足条件,若满足则计数并显示程序如下:#include "stdio.h"void main(){int bw,gw,sw, jsj=0;for (bw=1; bw<5; bw++) for (sw=1; sw<5; sw++) for (gw=1; gw<5; gw++){ if (bw!=sw && bw!=gw && sw!=gw) {jsj++;printf("%d ",bw*100+sw*10+gw);if (jsj%5==0) printf("\n"); }}printf("\n无重复的数字共有%d个\n",jsj);} 【例2】试求两个已知正整数a、b的最大公约数与最小公倍数 分析:求两个正整数的最大公约数和最小公倍数最直观最简单的方法是采用穷举法实现。
穷举法又称列举法,其基本思想是逐一列举问题的所有可能的值,并根据问题提出的条件检验哪些是问题的解,哪些应予排除穷举通常用循环结构来实现在循环体中,根据所求解的具体条件,应用选择结构实施检验,求得所要求的解 在本例中,为表述方便,记: gcd(a,b)为正整数a,b的最大公约数; lcm(a,b)为正整数a,b的最小公倍数 注意到两整数a、b的最小公倍数与最大公约数有以下简单关系:gcd(a,b) * lcm(a,b)=ab 因而由求得的gcd(a,b)即可根据上式求得lcm(a,b),同样由求得的lcm(a,b)即可求得gcd(a,b)用穷举法求最大公约数程序如下:#include
其实,求解两个整数a,b的最大公约数效率最高的算法是欧几里得算法欧几里得算法也称作辗转相除法,其算法描述如下: (1) a除以b得余数r;若r=0,则b为所求的最大公约数 (2) 若r≠0,以b为a,r为b,继续(1)上述辗转相除过程中余数逐步变小,相除过程总会结束欧几里得算法的实质是a和b的最大公约数等于b和a%b的最大公约数,即gcd(a,b)= gcd (b, a%b)感兴趣的读者可以用数学方法证明#include
分析:(1) 定义4个计数变量letter,space,digit和other,分别用于统计字母、空格、数字及其他字符的个数2) 依次读入字符到变量c中,判断c属于哪一类,并使相应计数变量加13) 重复2直到c等于’\n’为止程序如下:#include
作为注释,应在它们的前面说明其功能,在循环条件判断语句行的后面,说明循环继续条件的含义,如下所示 1)for语句/*功能*/for(变量初始化;循环条件;变量增值) /*循环继续条件的含义*/ { …… }2)while语句/*功能说明*/while(循环条件)/*循环继续条件的含义*/ { …… }3)do...while语句/*功能说明*/do { …… }while(循环条件);/*循环继续条件的含义*/如果循环嵌套,还应说明每层循环各控制什么[Return]为了解决比较复杂的问题,本章介绍C语言提供的一种最简单的构造类型──数组6.1 一维数组的定义和引用一维数组的定义和引用6.2 二维数组的定义和引用二维数组的定义和引用6.3 字符数组与字符串字符数组与字符串6.4 数组应用举例数组应用举例[Return]第第6章章 数数 组组6.1 一维一维数组的定义和引用数组的定义和引用6.1.1 一维一维数组的定义数组的定义6.1.2 一维数组元素的引用一维数组元素的引用6.1.3 一维数组元素的初始化一维数组元素的初始化6.1.4 一维数组应用举例一维数组应用举例 [Return]6.1.1 一维数组的定义一维数组的定义[案案例例6.1] 从键盘上任意输入10个整数,要求按从小到大的顺序在屏幕上显示出来。
排序的方法有很多,本题采用冒泡法冒冒泡泡法法的的基基本本思思想想:通过相邻两个数之间的比较和交换,使排序码(数值)较小的数逐渐从底部移向顶部,排序码较大的数逐渐从顶部移向底部就像水底的气泡一样逐渐向上冒,故而得名由A[n]~A[1]组成的n个数据,进行冒泡排序的过程可以描述为:(1)首先将相邻的A[n]与A[n-1]进行比较,如果A[n]的值小于A[n-1]的值,则交换两者的位置,使较小的上浮,较大的下沉;接着比较A[n-1]与A[n-2],同样使小的上浮,大的下沉依此类推,直到比较完A[2]和A[1]后,A[1]为具有最小排序码(数值)的元素,称第一趟排序结束2)然后在A[n]~A[2]区间内,进行第二趟排序,使剩余元素中排序码最小的元素上浮到A[2];重复进行n-1趟后,整个排序过程结束/*案例代码文件名:AL6_1.C*//*功能:从键盘上任意输入n个整数,用冒泡法按从小到大地排序,并在屏幕上显示出来/#include "stdio.h"#define NUM 10/*定义符号常量(数据个数N)*/main(){ int data[NUM];/*定义1个一维整型数组data*/ int i,j,temp;/*定义循环变量和临时变量*/ clrscr();/*库函数clrscr():清屏*/ printf("Please input 10 numbers:\n"); for(i=0; i 一维数组是只有1个下标的数组,定义形式如下:数据类型数据类型 数组名数组名[常量表达式常量表达式][, 数组名数组名2[常量表达式常量表达式2]……];;(1)“数据类型”是指数组元素的数据类型2)数组名,与变量名一样,必须遵循标识符命名规则3)“常量表达式”必须用方括号括起来,指的是数组的元素个数(又称数组长度),它是一个整型值,其中可以包含常数和符号常量,但不能包含变量注意注意:C语言中不允许动态定义数组语言中不允许动态定义数组 特特别别说说明明:在数组定义时,“常量表达式”外的方括号;以及元素引用时,“下标表达式”外的方括号,都是C语言语法规则所要求的,不是本书所约定的可选项的描述符号!(4)数组元素的下标,是元素相对于数组起始地址的偏移量,所以从0开始顺序编号5)数组名中存放的是一个地址常量,它代表整个数组的首地址同一数组中的所有元素,按其下标的顺序占用一段连续的存储单元[Return] 6.1.2 数组元素的引用数组元素的引用 引用数组中的任意一个元素的形式: 数组名数组名[下标表达式下标表达式] 1.“下标表达式”可以是任何非负整型数据,取值范围是0~(元素个数-1)。 特特别别强强调调:在运行C语言程序过程中,系统并不自动检验数组元素的下标是否越界因此在编写程序时,保证数组下标不越界是十分重要的 2.1个数组元素,实质上就是1个变量,它具有和相同类型单个变量一样的属性,可以对它进行赋值和参与各种运算 3.在C语言中,数组作为1个整体,不能参加数据运算,只能对单个的元素进行处理[Return] 6.1.3 一维数组元素的初始化一维数组元素的初始化 初始化格式::数据类型数据类型 数组名数组名[常量表达式常量表达式]=={初值表初值表}(1)如果对数组的全部元素赋以初值,定义时可以不指定数组长度(系统根据初值个数自动确定)如果被定义数组的长度,与初值个数不同,则数组长度不能省略2)“初值表”中的初值个数,可以少于元素个数,即允许只给部分元素赋初值 3) 根 据 存 储 类 型 的 不 同 , 数 组 有 静 态 数 组(static)和动态数组(auto)之分;根据定义的位置不同,数组有内部数组(在函数内部定义的数组)和外部数组(在函数外部定义的数组)之分[Return]6.1.4 一维一维数组应用举例数组应用举例 [案例案例6.2] 已知某课程的平时、实习、测验和期末成绩,求该课程的总评成绩。 其中平时、实习、测验和期末分别占10%、20%、20%、50%/*案例代码文件名:AL6_2.C*//*功能:从键盘上循环输入某课程的平时、实习、测验和期末成绩,按10%,20%,20%,50%的比例计算总评成绩,并在屏幕上显示出来按空格键继续循环,其他键终止循环/#include “stdio.h”main(){ int i=1,j; char con_key=‘\x20’; /* ‘\x20’ 空格键的ASCII码*/ float score[5],ratio[4]={0.1,0.2,0.2,0.5}; /*定义成绩、比例系数数组*/ while(con_key=='\x20') while(con_key=='\x20') {clrscr(); printf("输入第%2d个学生的成绩\n", i++); printf("平时 实习 测验 期末成绩\n"); score[4]=0;/* score[4]:存储总评成绩*/ for(j=0; j<4; j++) {scanf("%f",&score[j]); score[4] += score[j] * ratio[j]; } printf("总评成绩为:%6.1f\n", score[4]); printf("\n按空格键继续,其它键退出"); con_key=getch(); /*getch()函数等待从键盘上输入一个字符*/ }}[程序演示程序演示][Return]6.2 二维二维数组的定义和引用数组的定义和引用6.2.1 二维二维数组的定义数组的定义与初始化与初始化6.2.2 二维数组元素的引用二维数组元素的引用6.2.3 二维二维数组应用举例数组应用举例 [Return][案例案例6.3] 给一个2*3的二维数组各元素赋值,并输出全部元素的值。 /*案例代码文件名:AL6_3.C*//*功能:从键盘上给2*3数组赋值,并在屏幕上显示出来/#define Row 2#define Col 3#include "stdio.h"main() { int i, j, array[Row][Col];/*定义1个2行3列的二维数组array*/ for(i=0; i 2. 设有一个m*n的数组x,则第i行第j列的元素x[i][j]在数组中的位置为:i*n+j(注意注意:行号、列号均从0开始计数) 3.可以把二维数组看作是一种特殊的一维数组:它的元素又是一个一维数组例如,对x[3][2],可以把x看作是一个一维数组,它有3个元素:x[0]、x[1]、x[2],每个元素又是一个包含2个元素的一维数组,如图6-4所示即把x[0]、x[1]、x[2]看作是3个一维数组的名字 [Return]6.2.2 二维二维数组元素的引用数组元素的引用引用二维数组元素的形式为:数组名数组名[行下标表达式行下标表达式][列下标表达式列下标表达式]1.“行下标表达式”和“列下标表达式”,都应是整型表达式或符号常量2.“行下标表达式”和“列下标表达式”的值,都应在已定义数组大小的范围内假设有数组x[3][4],则可用的行下标范围为0~2,列下标范围为0~33.对基本数据类型的变量所能进行的操作,也都适合于相同数据类型的二维数组元素[Return]6.2.3 二维二维数组元素的初始化数组元素的初始化1.按行赋初值数数据据类类型型 数数组组名名[行行常常量量表表达达式式][列列常常量量表表达达式式]=={{第第0行行初初值值表表},,{第第1行初值表行初值表},,……,,{最后最后1行初值表行初值表}};;赋值规则:将“第0行初值表”中的数据,依次赋给第0行中各元素;将“第1行初值表”中的数据,依次赋给第1行各元素;以此类推。 2.按二维数组在内存中的排列顺序给各元素赋初值数据类型数据类型 数组名数组名[行常量表达式行常量表达式][列常量表达式列常量表达式]=={初值表初值表};赋值规则:按二维数组在内存中的排列顺序,将初值表中的数据,依次赋给各元素如果对全部元素都赋初值,则“行数”可以省略注意注意:只能省略“行数” [Return]6.2.4 二维数组应用举例二维数组应用举例 [案例案例6.4] 有M个学生,学习N门课程,已知所有学生的各科成绩,编程:分别求每个学生的平均成绩和每门课程的平均成绩 /*案例代码文件名:AL6_4.C*//*功能:计算个人平均成绩与各科平均成绩,并在屏幕上显示出来/#define NUM_std 5/*定义符号常量人数为5*/#define NUM_course 4/*定义符号常量课程为4*/#include "stdio.h"main(){ int i,j; static float score[NUM_std+1][NUM_course+1]={{78,85,83,65}, {88,91,89,93}, {72,65,54,75},{86,88,75,60}, {69,60,50,72}}; for(i=0;i 例如: char c[10];定义了长度为10的字符数组c,每个元素都可存放一个字符字符数组也可以是二维或多维数组例如: char d[5][5];定义了5行5列的二维字符数组d 字符数组的初始化字符数组的初始化字符数组也允许在定义时初始化初始化的方法与前面介绍的其他类型数组初始化相同可以通过为每个数组元素指定初值字符来实现 char c[10]={ ‘c’, ‘ ‘, ‘p’, ‘r’, ‘o’, ‘g’, ‘r’, ‘a’,’m’};char num[][5]={{' ',' ','1',' ',' '},{' ','1','2','1',' '}, {'1','2','3', '2','1'},{' ','1','2','1',' '},{' ',' ','1',' ',' '}};6.3.2 字符数组的引用字符数组的引用(1)字符数组的输入 除了可以通过初始化使字符数组各元素得到初值外,也可以使用getchar()或scanf()函数输入字符 例如: char str[10];……for(i=0; i<10; i++) { scanf("%c", &str[i]); fflush(stdin);/*清除键盘输入缓冲区*/ }…… (2)字符数组的输出 字符数组的输出,可以用putchar()或printf()函数。 例如: char str[10]="c language";……for(i=0; i<10; i++) printf("%c", str[i]);printf("\n");…… 注意:逐个字符输入、输出时,要指出元素的下标,而且使用“%c”格式符另外,从键盘上输入字符时,无需输入字符的定界符──单引号;输出时,系统也不输出字符的定界符[Return][案例案例6.6] 字符数组的整体输入与输出 /*案例代码文件名:AL6_6.C*//*功能:将二维字符数组进行初始化,并在屏幕上输出*/main(){ int i; char name[5][9]={"张三山", "李四季", "王五魁", "刘六顺", "赵七巧"}; for(i=0;i<5;i++) printf("\n%s\t",name[i]); /*name[i]代表该行数组元素的首地址*/ getch();}[程序演示] 6.3.3字符串与字符串与printfprintf、、scanfscanf函数函数 在C语言中用char字符类型数组来存放字符串因此字符数组既可以存放字符,也可以存放字符串。 字符串总是以'\0'作为串的结束标识或者说以’\0’结束的字符称为字符串 (a)'\0'的机内存储 (b)‘0’的机内存储printf函数输出字符串printf()函数,不仅可以逐个输出字符数组元素,还可以整体输出存放在字符数组中的字符串include 其调用格式为: gets(s); 但gets 函数可以接收除换行符之外的所有字符 6.3.4 gets、、 puts函数函数#include 字符数组”中原来的结束标志,被“字符串”的第一个字符覆盖,而“字符串”在操作中未被修改3)使用说明 1)由于没有边界检查,编程者要注意保证“字符数组”定义得足够大,以便容纳连接后的目标字符串;否则,会因长度不够而产生问题 2)连接前两个字符串都有结束标志'\0',连接后“字符数组”中存储的字符串的结束标志'\0'被舍弃,只在目标串的最后保留一个'\0'6.3.5 常用字符串处理函数常用字符串处理函数2.字符串拷贝函数.字符串拷贝函数──strcpy()(1)调用方式:strcpy(字符数组, 字符串)其中“字符串”可以是串常量,也可以是字符数组2)函数功能:将“字符串”完整地复制到“字符数组”中,字符数组中原有内容被覆盖3)使用说明1)字符数组必须定义得足够大,以便容纳复制过来的字符串复制时,连同结束标志'\0'一起复制2)不能用赋值运算符“=”将一个字符串直接赋值给一个字符数组,只能用strcpy()函数来处理3.字符串比较函数.字符串比较函数──strcpy() /*案例代码文件名:AL6_7.C*//*功能:简单密码检测程序*/#include "stdio.h"main() {char pass_str[80]; /*定义字符数组passstr*/ int i=0; /*检验密码*/ while(1) {clrscr(); printf("请输入密码\n"); gets(pass_str); /*输入密码*/ if(strcmp(pass_str,“password”)!=0) /*口令错*/ printf("口令错误,按任意键继续"); else break; /*输入正确的密码,中止循环*/ getch(); i++; if(i==3) exit(0); /*输入三次错误的密码,退出程序*/ } /*输入正确密码所进入的程序段*/}[程序演示]4.求字符串长度函数.求字符串长度函数──strlen()(1)调用方式:strlen(字符串)(2)函数功能:求字符串(常量或字符数组)的实际长度(不包含结束标志)。 5.将字符串中大写字母转换成小写.将字符串中大写字母转换成小写──strlwr()函数函数(1)调用方式:strlwr(字符串)(2)函数功能:将字符串中的大写字母转换成小写,其它字符(包括小写字母和非字母字符)不转换6.将字符串中小写字母转换成大写.将字符串中小写字母转换成大写──strupr()函数函数(1)调用方式:strupr(字符串)(2)函数功能:将字符串中小写字母转换成大写,其它字符(包括大写字母和非字母字符)不转换[Return]6.3.6字符串应用举例字符串应用举例输入一字符串和一个字符,要求将字符串中出现的该字符删除 例如删除的字符是空格“ ” ,结果如下include #include 所以较大的C语言应用程序,往往是由多个函数组成的,每个函数分别对应各自的功能模块7.1函数的概念函数的概念7.2 函数的定义和函数的调用函数的定义和函数的调用7.3 函数的嵌套调用和递归调用函数的嵌套调用和递归调用7.4 数组作为函数参数数组作为函数参数7.5 内部变量与外部变量内部变量与外部变量7.6 变量的动态存储与静态存储变量的动态存储与静态存储 7.7 函数应用举例函数应用举例[Return]7.1 函数的概念函数的概念 函数是可以反复使用的一个程序段,从其他程序段中可以通过函数调用语句来执行这个程序段如果在程序的不同地方多次执行一系列相同的操作,就可以把这一系列操作从程序中独立出来,形成一个函数而在原来程序中进行这一系列操作的位置处,只需“调用函数”,从而达到简化程序的目的 建立函数称为函数定义,使用函数称为函数调用因此必须先建立(即定义)函数,之后才能使用(即调用)函数一个C程序各函数之间的关系如图从图中可以看出:(1)一个C程序总是从main函数开始运行,期间main函数可能调用其他函数后再返回到main函数,最后一定在main函数中结束整个程序运行因此一个C程序必须有,且只能有一个main函数。 main函数称为主函数2)通常把调用其他函数的函数称为“主调函数”,而被其他函数调用的函数称为“被调函数”C语言规定,main函数只能作为主调函数,而其他函数既可以作为被调函数,也可以作为主调函数图7-1带箭头的线条所表示函数调用关系,从中可以看出main函数和其他函数的调用关系:main函数调用其他函数、F2调用F4、F4调用库函数,F1函数自身调用7.2 函数的定义与调用函数的定义与调用7.2.1 7.2.1 函数的定义函数的定义7.2.2 7.2.2 函数的返回值与函数类型函数的返回值与函数类型7.2.3 7.2.3 对被调用函数的说明和函数原型对被调用函数的说明和函数原型7.2.4 7.2.4 函数的调用函数的调用7.2.5 7.2.5 函数的形参与实参函数的形参与实参 [Return]7.2 .1 函数的定义函数的定义1.任何函数(包括主函数main())都是由函数说明和函数体两部分组成根据函数是否需要参数,可将函数分为无参函数和有参函数两种1)无参函数的一般形式)无参函数的一般形式 函数类型 函数名( void ) { 说明语句部分; 可执行语句部分; }注注意意:在旧标准中,函数可以缺省参数表。 但在新标准中,函数不可缺省参数表;如果不需要参数,则用“void”表示,主函数main()例外((2)有参函数的一般形式)有参函数的一般形式函数类型 函数名( 数据类型 参数[,数据类型 参数2……] ) { 说明语句部分; 可执行语句部分; }有参函数比无参函数多了一个参数表调用有参函数时,调用函数将赋予这些参数实际的值为了与调用函数提供的实际参数区别开,将函数定义中的参数表称为形式参数表,简称形参表[案例7.1] 定义一个函数,用于求两个数中的大数/*案例代码文件名:AL7_1.C*//*功能:定义一个求较大数的函数并在主函数中调用*/int max(int n1, int n2) /*定义一个函数max()*/ { return (n1>n2?n1:n2); }main() { int max(int n1, int n2);/*函数说明*/ int num1,num2; printf("input two numbers:\n"); scanf("%d%d", &num1, &num2);printf("max=%d\n", max(num1,num2));getch();/*使程序暂停,按任一键继续*/ }[程序演示]2.说明.说明(1)函数定义不允许嵌套函数定义不允许嵌套。 在C语言中,所有函数(包括主函数main())都是平行的一个函数的定义,可以放在程序中的任意位置,主函数main()之前或之后但在一个函数的函数体内,不能再定义另一个函数,即不能嵌套定义2)空函数──既无参数、函数体又为空的函数其一般形式为:[函数类型] 函数名(void) { }(3)在老版本C语言中,参数类型说明允许放在函数说明部分的第2行单独指定 [Return]7.2.2 函数的返回值与函数类型函数的返回值与函数类型C语言的函数兼有其它语言中的函数和过程两种功能,从这个角度看,又可把函数分为有返回值函数和无返回值函数两种1.函数返回值与return语句有参函数的返回值,是通过函数中的return语句来获得的1)return语句的一般格式: return ( 返回值表达式 );(2)return语句的功能:返回调用函数,并将“返回值表达式”的值带给调用函数注注意意:调用函数中无return语句,并不是不返回一个值,而是一个不确定的值为了明确表示不返回值,可以用“void”定义成“无(空)类型”2.函数类型.函数类型在定义函数时,对函数类型的说明,应与return语句中、返回值表达式的类型一致。 如果不一致,则以函数类型为准如果缺省函数类型,则系统一律按整型处理良良好好的的程程序序设设计计习习惯惯:为了使程序具有良好的可读性并减少出错,凡不要求返回值的函数都应定义为空类型;即使函数类型为整型,也不使用系统的缺省处理[Return]7.2.3 对被调用函数的说明和函数原型对被调用函数的说明和函数原型 在ANSI C新标准中,采用函数原型方式,对被调用函数进行说明,其一般格式如下:函数类型函数类型 函数名函数名(数据类型数据类型[ 参数名参数名][, 数据类型数据类型[ 参数名参数名2]…]);; C语言同时又规定,在以下2种情况下,可以省去对被调用函数的说明: (1)当被调用函数的函数定义出现在调用函数之前时因为在调用之前,编译系统已经知道了被调用函数的函数类型、参数个数、类型和顺序 (2)如果在所有函数定义之前,在函数外部(例如文件开始处)预先对各个函数进行了说明,则在调用函数中可缺省对被调用函数的说明[Return]7.2.4 函数的调用函数的调用 在程序中,是通过对函数的调用来执行函数体的,其过程与其它语言的子程序调用相似。 C语言中,函数调用的一般形式为: 函数名函数名([实际参数表实际参数表]) 切切记记:实参的个数、类型和顺序,应该与被调用函数所要求的参数个数、类型和顺序一致,才能正确地进行数据传递在C语言中,可以用以下几种方式调用函数:(1)函函数数表表达达式式函数作为表达式的一项,出现在表达式中,以函数返回值参与表达式的运算这种方式要求函数是有返回值的2))函函数数语语句句C语言中的函数可以只进行某些操作而不返回函数值,这时的函数调用可作为一条独立的语句3)函函数数实实参参函数作为另一个函数调用的实际参数出现这种情况是把该函数的返回值作为实参进行传送,因此要求该函数必须是有返回值的说明说明:(1)调用函数时,函数名称必须与具有该功能的自定义函数名称完全一致2)实参在类型上按顺序与形参,必须一一对应和匹配如果类型不匹配,C编译程序将按赋值兼容的规则进行转换如果实参和形参的类型不赋值兼容,通常并不给出出错信息,且程序仍然继续执行,只是得不到正确的结果3)如果实参表中包括多个参数,对实参的求值顺序随系统而异有的系统按自左向右顺序求实参的值,有的系统则相反Turbo C和MS C是按自右向左的顺序进行的 。 [Return]7.2.5 函数的形参与实参函数的形参与实参函数的参数分为形形参参和实实参参两种,作用是实现数据传送形参出现在函数定义中,只能在该函数体内使用发生函数调用时,调用函数把实参的值复制1份,传送给被调用函数的形参,从而实现调用函数向被调用函数的数据传送 [案例案例7.3] 实参对形参的数据传递/*实参对形参的数据传递//*案例代码文件名:AL7_3.C*/void main() { void s(int n); /*说明函数*/ int n=100; /*定义实参n,并初始化*/ s(n); /*调用函数*/ printf("n_s=%d\n",n); /*输出调用后实参的值,便于进行比较*/ getch(); }/* */void s(int n) { int i; printf("n_x=%d\n",n); /*输出改变前形参的值*/ for(i=n-1; i>=1; i--) n=n+i; /*改变形参的值*/ printf("n_x=%d\n",n); /*输出改变后形参的值*/ }[程序演示]说明:(1)实参可以是常量、变量、表达式、函数等。 无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值,以便把这些值传送给形参因此,应预先用赋值、输入等办法,使实参获得确定的值2)形参变量只有在被调用时,才分配内存单元;调用结束时,即刻释放所分配的内存单元因此,形参只有在该函数内有效调用结束,返回调用函数后,则不能再使用该形参变量3)实参对形参的数据传送是单向的,即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参4)实参和形参占用不同的内存单元,即使同名也互不影响[Return]7.3 函数的嵌套调用和递归调用7.2.1 函数的嵌套调用函数的嵌套调用 函数的嵌套调用是指,在执行被调用函数时,被调用函数又调用了其它函数这与其它语言的子程序嵌套调用的情形是类似的,其关系可表示如图7-1[案例7.4] 计算s=1k+2k+3k+……+N k /*案例代码文件名:AL7_4.C*//*功能:函数的嵌套调用*/#define K 4#define N 5long f1(int n,int k)/*计算n的k次方*/ { long power=n; int i; for(i=1;i C语言允许函数的递归调用在递归调用中,调用函数又是被调用函数,执行递归函数将反复调用其自身每调用一次就进入新的一层为了防止递归调用无终止地进行,必须在函数内有终止递归调用的手段常用的办法是加条件判断,满足某种条件后就不再作递归调用,然后逐层返回[案例7.5] 用递归法计算用递归法计算n!/*案例代码文件名:AL7_5.C*//*功能:通过函数的递归调用计算阶乘*/long power(int n) { long f; if(n>1) f=power(n-1)*n; else f=1; return(f); }main() { int n; long y; printf("input a inteager number:\n"); scanf("%d",&n); y=power(n); printf("%d!=%ld\n",n,y); getch(); }[程序演示] [Return]7.4 数组作为函数参数数组作为函数参数数组用作函数参数有两种形式:一种是把数组元素(又称下标变量)作为实参使用;另一种是把数组名作为函数的形参和实参使用。 7.4.1 数组元素作为函数参数数组元素作为函数参数 7.4.2 数组名作为函数的形参和实参数组名作为函数的形参和实参 [Return]7.4.1 数组元素作为函数参数数组元素作为函数参数 数组元素就是下标变量,它与普通变量并无区别数组元素只能用作函数实参,其用法与普通变量完全相同:在发生函数调用时,把数组元素的值传送给形参,实现单向值传送[案例7.6] 写一函数,统计字符串中字母的个数/*案例代码文件名:AL7_6.C*//*功能:数组元素作为函数实参*/int isalp(char c) { if (c>='a'&&c<='z'||c>='A'&&c<='Z') return(1); else return(0); }main() { int i,num=0; char str[255]; printf("Input a string: "); gets(str); for(i=0;str[i]!='\0';i++) if (isalp(str[i])) num++; puts(str); printf("num=%d\n",num); getch(); }[程序演示]说明:(1)用数组元素作实参时,只要数组类型和函数的形参类型一致即可,并不要求函数的形参也是下标变量。 换句话说,对数组元素的处理是按普通变量对待的2)在普通变量或下标变量作函数参数时,形参变量和实参变量是由编译系统分配的两个不同的内存单元在函数调用时发生的值传送,是把实参变量的值赋予形参变量[Return]7.4.2 数组名作为函数的形参和实参数组名作为函数的形参和实参数组名作函数参数时,既可以作形参,也可以作实参数组名作函数参数时,要求形参和相对应的实参都必须是类型相同的数组(或指向数组的指针变量),都必须有明确的数组说明[案例案例7.7] 已知某个学生5门课程的成绩,求平均成绩/*案例代码文件名:AL7_7.C*/float aver(float a[ ]) /*求平均值函数*/{ int i; float av,s=a[0]; for(i=1;i<5;i++) s += a[i]; av=s/5; return av; }void main() { float sco[5],av; int i; printf("\ninput 5 scores:\n"); for(i=0;i<5;i++) scanf("%f",&sco[i]); av=aver(sco); /*调用函数,实参为一数组名*/ printf("average score is %5.2f\n",av); getch(); }[程序演示]说明说明:(1)用数组名作函数参数,应该在调用函数和被调用函数中分别定义数组,且数据类型必须一致,否则结果将出错。 例如,在本案例中,形参数组为a[],实参数组为sco[],它们的数据类型相同2)C编译系统对形参数组大小不作检查,所以形参数组可以不指定大小例如,本案例中的形参数组a[] 如果指定形参数组的大小,则实参数组的大小必须大于等于形参数组,否则因形参数组的部分元素没有确定值而导致计算结果错误[Return]7.5 内部变量与外部变量内部变量与外部变量 C语言中所有的变量都有自己的作用域变量说明的位置不同,其作用域也不同,据此将C语言中的变量分为内部变量和外部变量7.4.1 内部变量7.4.2 外部变量[Return]7.5.1 内部变量内部变量在一个函数内部说明的变量是内部变量,它只在该函数范围内有效也就是说,只有在包含变量说明的函数内部,才能使用被说明的变量,在此函数之外就不能使用这些变量了所以内部变量也称“局部变量”例如:int f1(int a) /*函数f1*/ { int b,c; …… }/*a,b,c作用域:仅限于函数f1()中*/ int f2(int x) /*函数f2*/ { int y,z; …… }/*x,y,z作用域:仅限于函数f2()中*/ main() { int m,n; …… }/*m,n作用域:仅限于函数main()中*/关于局部变量的作用域还要说明以下几点:1.主函数main()中定义的内部变量,也只能在主函数中使用,其它函数不能使用。 同时,主函数中也不能使用其它函数中定义的内部变量因为主函数也是一个函数,与其它函数是平行关系这一点是与其它语言不同的,应予以注意2.形参变量也是内部变量,属于被调用函数;实参变量,则是调用函数的内部变量3.允许在不同的函数中使用相同的变量名,它们代表不同的对象,分配不同的单元,互不干扰,也不会发生混淆4.在复合语句中也可定义变量,其作用域只在复合语句范围内 [Return]7.5.2 外部变量外部变量在函数外部定义的变量称为外部变量以此类推,在函数外部定义的数组就称为外部数组外部变量不属于任何一个函数,其作作用用域域是:从外部变量的定义位置开始,到本文件结束为止外部变量可被作用域内的所有函数直接引用,所以外部变量又称全局变量 [案案例例7.9] 输入长方体的长(l)、宽(w)、高(h),求长方体体积及正、侧、顶三个面的面积/*案例代码文件名:AL7_9.C*//*功能:利用全局变量计算长方体的体积及三个面的面积*/int s1,s2,s3;int vs(int a,int b,int c) { int v; v=a*b*c; s1=a*b; s2=b*c; s3=a*c;return v; } main() {int v,l,w,h; clrscr(); printf("\ninput length,width and height: "); scanf("%d%d%d",&l,&w,&h); v=vs(l,w,h); printf("v=%d s1=%d s2=%d s3=%d\n",v,s1,s2,s3); getch(); }[程序演示]对于全局变量还有以下几点说明:(1)外部变量可加强函数模块之间的数据联系,但又使这些函数依赖这些外部变量,因而使得这些函数的独立性降低。 从模块化程序设计的观点来看这是不利的,因此不是非用不可时,不要使用外部变量2)在同一源文件中,允许外部变量和内部变量同名在内部变量的作用域内,外部变量将被屏蔽而不起作用3)外部变量的作用域是从定义点到本文件结束如果定义点之前的函数需要引用这些外部变量时,需要在函数内对被引用的外部变量进行说明外部变量说明的一般形式为:extern 数据类型 外部变量[,外部变量2……]; 注意注意:外部变量的定义和外部变量的说明是两回事外部变量的定义,必须在所有的函数之外,且只能定义一次而外部变量的说明,出现在要使用该外部变量的函数内,而且可以出现多次[案例案例7.10] 外部变量的定义与说明/*案例代码文件名:AL7_10.C*/int vs(int xl,int xw) { extern int xh; /*外部变量xh的说明*/ int v; v=xl*xw*xh; /*直接使用外部变量xh的值*/ return v; }main() { extern int xw,xh; /*外部变量的说明*/ int xl=5; /*内部变量的定义*/ printf("xl=%d,xw=%d,xh=%d\nv=%d",xl,xw,xh,vs(xl,xw)); }int xl=3,xw=4,xh=5; /*外部变量xl、xw、xh的定义*/[程序演示][Return]7.6 变量的动态存储与静态存储简介变量的动态存储与静态存储简介 在C语言中,对变量的存储类型说明有以下四种:自动变量(auto)、寄存器变量(register)、外部变量(extern)、静态变量(static)。 自动变量和寄存器变量属于动态存储方式,外部变量和静态内部变量属于静态存储方式7.6.1 内部变量的存储方式内部变量的存储方式 7.6.2 外部变量的存储方式外部变量的存储方式[Return]7.6.1 内部变量的存储方式内部变量的存储方式 1.静态存储──静态内部变量(1)定义格式: static 数据类型 内部变量表;(2)存储特点1)静态内部变量属于静态存储在程序执行过程中,即使所在函数调用结束也不释放换句话说,在程序执行期间,静态内部变量始终存在,但其它函数是不能引用它们的2)定义但不初始化,则自动赋以"0"(整型和实型)或'\0'(字符型);且每次调用它们所在的函数时,不再重新赋初值,只是保留上次调用结束时的值!(3)何时使用静态内部变量1)需要保留函数上一次调用结束时的值2)变量只被引用而不改变其值2.动态存储动态存储──自动局部变量(又称自动变量)(1)定义格式定义格式:[auto] 数据类型 变量表;(2)存储特点存储特点1)自动变量属于动态存储方式在函数中定义的自动变量,只在该函数内有效;函数被调用时分配存储空间,调用结束就释放在复合语句中定义的自动变量,只在该复合语句中有效;退出复合语句后,也不能再使用,否则将引起错误。 2)定义而不初始化,则其值是不确定的如果初始化,则赋初值操作是在调用时进行的,且每次调用都要重新赋一次初值3)由于自动变量的作用域和生存期,都局限于定义它的个体内(函数或复合语句),因此不同的个体中允许使用同名的变量而不会混淆即使在函数内定义的自动变量,也可与该函数内部的复合语句中定义的自动变量同名建议:建议:系统不会混淆,并不意味着人也不会混淆,所以尽量少用同名自动变量! [案例案例7.13]自动变量与静态局部变量的存储特性/*案例代码文件名:AL7_13.C*/void auto_static(void) { int var_auto=0;/*自动变量:每次调用都重新初始化*/ static int var_static=0;/*静态局部变量:只初始化1次*/ printf(“var_auto=%d, var_static=%d\n”, var_auto, var_static); ++var_auto; ++var_static; }main() { int i; for(i=0; i<5; i++) auto_static(); }[程序演示]3.寄存器存储寄存器存储──寄存器变量一般情况下,变量的值都是存储在内存中的。 为提高执行效率,C语言允许将局部变量的值存放到寄存器中,这种变量就称为寄存器变量定义格式如下: register 数据类型 变量表;(1)只有局部变量才能定义成寄存器变量,即全局变量不行2)对寄存器变量的实际处理,随系统而异例如,微机上的MSC和TC 将寄存器变量实际当作自动变量处理3)允许使用的寄存器数目是有限的,不能定义任意多个寄存器变量[Return]7.6.2 外部变量的存储方式外部变量的存储方式外部变量属于静态存储方式: (1)静态外部变量──只允许被本源文件中的函数引用其定义格式为: static 数据类型 外部变量表;(2)非静态外部变量──允许被其它源文件中的函数引用定义时缺省static关键字的外部变量,即为非静态外部变量其它源文件中的函数,引用非静态外部变量时,需要在引用函数所在的源文件中进行说明:extern 数据类型 外部变量表;注意注意:在函数内的extern变量说明,表示引用本源文件中的外部变量!而函数外(通常在文件开头)的extern变量说明,表示引用其它文件中的外部变量 静态局部变量和静态外部变量同属静态存储方式,但两者区别较大:(1)定义的位置不同。 静态局部变量在函数内定义,静态外部变量在函数外定义2)作用域不同静态局部变量属于内部变量,其作用域仅限于定义它的函数内;虽然生存期为整个源程序,但其它函数是不能使用它的静态外部变量在函数外定义,其作用域为定义它的源文件内;生存期为整个源程序,但其它源文件中的函数也是不能使用它的 (3)初始化处理不同静态局部变量,仅在第1次调用它所在的函数时被初始化,当再次调用定义它的函数时,不再初始化,而是保留上1次调用结束时的值而静态外部变量是在函数外定义的,不存在静态内部变量的“重复”初始化问题,其当前值由最近1次给它赋值的操作决定 务务必必牢牢记记::把局部变量改变为静态内部变量后,改变了它的存储方式,即改变了它的生存期把外部变量改变为静态外部变量后,改变了它的作用域,限制了它的使用范围因此,关键字“static”在不同的地方所起的作用是不同的[Return]7.7 函数应用举例函数应用举例设计一个函数,实现在一维数组上顺序查找值为x的元素 #include 一个字符串是另一个字符串的子串,就是这个字符串完全出现在另一个字符串中例如:”tud”就是”student”的子串,因为”tud”出现在”student”中而”dents”就不是”student”的子串一般我们称”tud”为子串,”student”为主串 #include 当程序运行结束后,存放在内存中的数据被释放如果需要长期保存程序运行所需的原始数据,或程序运行产生的结果,就必须以文件形式存储到外部存储介质上8.1 C语言文件概述8.2 文件的打开与关闭8.3 文件的读写操作8.4 文件的随机读写8.5 出错检测[Return]8.1 C语言文件概述C语言文件概述 1.文件与文件名.文件与文件名 文件是指存放在外部存储介质上的数据集合为标识一个文件,每个文件都必须有一个文件名,其一般结构为:主文件名主文件名[.扩展名扩展名] 文件命名规则,遵循操作系统的约定2.文件分类.文件分类可以从不同的角度对文件进行分类:(1)根据文件的内容,可分为程序文件和数据文件,程序文件又可分为源文件、目标文件和可执行文件2)根据文件的组织形式,可分为顺序存取文件和随机存取文件(3)根据文件的存储形式,可分为ASCII码文件和二进制文件 ASCII码文件的每1个字节存储1个字符,因而便于对字符进行逐个处理但一般占用存储空间较多,而且要花费转换时间(二进制与ASCII码之间的转换)二进制文件是把内存中的数据,原样输出到磁盘文件中。 可以节省存储空间和转换时间,但1个字节并不对应1个字符,不能直接输出字符形式3.读文件与写文件.读文件与写文件所谓读文件是指,将磁盘文件中的数据传送到计算机内存的操作所谓写文件是指,从计算机内存向磁盘文件中传送数据的操作4.构成文件的基本单元与流式文件.构成文件的基本单元与流式文件C语言将文件看作是由一个一个的字符(ASCII码文件)或字节(二进制文件)组成的将这种文件称为流式文件而在其它高级语言中,组成文件的基本单位是记录,对文件操作的基本单位也是记录5.文件类型.文件类型FILE系统给每个打开的文件都在内存中开辟一个区域,用于存放文件的有关信息(如文件名、文件位置等)这些信息保存在一个结构类型变量中,该结构类型由系统定义、取名为FILE注意注意:结构类型名“FILE”必须大写6..ANSI C的缓冲文件系统的缓冲文件系统所谓缓冲文件系统是指,系统自动地在内存区为每个正在使用的文件开辟一个缓冲区从内存向磁盘输出数据时,必须首先输出到缓冲区中待缓冲区装满后,再一起输出到磁盘文件中从磁盘文件向内存读入数据时,则正好相反:首先将一批数据读入到缓冲区中,再从缓冲区中将数据逐个送到程序数据区。 [Return]8.2 文件的打开与关闭文件的打开与关闭对文件进行操作之前,必须先打开该文件;使用结束后,应立即关闭,以免数据丢失C语言规定了标准输入输出函数库,用fopen()函数打开一个文件,用fclose()函数关闭一个文件 8.2.1 文件的打开文件的打开──fopen()函数函数 1.用法: FILE *fopen("文件名文件名",,"操作方式操作方式"); 2.功能:返回一个指向指定文件的指针 3.函数原型:stdio.h 注注:对文件操作的库函数,函数原型均在头文件stdio.h中后续函数不再赘述(1)“文件名”是指要打开(或创建)的文件名如果使用字符数组(或字符指针),则不使用双引号2)“操作方式”有r,w等例如,FILE *fp; fp=fopen("data.99","r");3.说明(1)如果不能实现打开指定文件的操作,则fopen()函数返回一个空指针NULL (其值在头文件stdio.h中被定义为0)为增强程序的可靠性,常用下面的方法打开一个文件: if((fp=fopen("文件名文件名","操作方式操作方式"))==NULL) { printf("can not open this file\n"); exit(0); }●关于exit()函数1)用法:void exit([程序状态值程序状态值]);2)功能:关闭已打开的所有文件,结束程序运行,返回操作系统,并将“程序状态值”返回给操作系统。 当“程序状态值”为0时,表示程序正常退出;非0值时,表示程序出错退出2)“r(b)+”与“a(b)+”的区别:使用前者打开文件时,读写位置指针指向文件头;使用后者时,读写指针指向文件尾3)使用文本文件向计算机系统输入数据时,系统自动将回车换行符转换成一个换行符;在输出时,将换行符转换成回车和换行两个字符使用二进制文件时,内存中的数据形式与数据文件中的形式完全一样,就不再进行转换4)有些C编译系统,可能并不完全提供上述对文件的操作方式,或采用的表示符号不同,请注意所使用系统的规定5)在程序开始运行时,系统自动打开三个标准文件,并分别定义了文件指针: 1)标准输入文件——stdin:指向终端输入(一般为键盘)如果程序中指定要从stdin所指的文件输入数据,就是从终端键盘上输入数据2)标准输出文件——stdout:指向终端输出(一般为显示器)3)标准错误文件——stderr:指向终端标准错误输出(一般为显示器)8.2.2 文件的关闭文件的关闭──fcolse()函数函数1.用法: int fclose(FILE *文件指针文件指针);2.功能:关闭“文件指针”所指向的文件如果正常关闭了文件,则函数返回值为0;否则,返回值为非0。 例如,fclose(fp);/*关闭fp所指向的文件*/[Return]8.3 文件的读写操作文件的读写操作文件打开之后,就可以对它进行读与写的操作了8.3.1 读/写文件中的一个字符读/写文件中的一个字符 8.3.2 读/写一个字符串读/写一个字符串8.3.3 读/写一个数据块读/写一个数据块8.3.4 对文件进行格式化读/写对文件进行格式化读/写8.3.5 读/写函数的选用原则读/写函数的选用原则[Return]8.3.1 读/写文件中的一个字符读/写文件中的一个字符1.将一个字符写到文件中.将一个字符写到文件中──fputc()函数函数[案例案例8.1] 将键盘上输入的一个字符串(以“@”作为结束字符),以ASCII码形式存储到一个磁盘文件中/*案例代码文件名:AL8_1.C*//*程序功能:从键盘上输入一个字符串,存储到一个磁盘文件中*//*使用格式:可执行文件名 要创建的磁盘文件名*/#include “stdio.h”main(int argc, char *argv[]) { FILE *fp; char ch; if(argc!=2) /*参数个数不对*/ { printf("the number of arguments not correct\n\n"); printf(“Usage: 可执行文件名 filename \n”); exit(0); } if ((fp=fopen(argv[1],"w"))==NULL) /*打开文件失败*/ { printf("can not open this file\n"); exit(0); } /*输入字符,并存储到指定文件中*/ for( ; (ch=getchar()) != '@' ; ) fputc(ch,fp); /*输入字符并存储到文件中*/ fclose(fp); /*关闭文件*/} [程序演示程序演示] 程序运行情况: abcdefg1234567@←┘库函数库函数fputc():1)用法:int fputc(字符数据,文件指针字符数据,文件指针);其中“字符数据”,既可以是字符常量,也可以是字符变量。 2)功能:将字符数据输出到“文件指针”所指向的文件中去,同时将读写位置指针向前移动1个字节(即指向下一个写入位置)如果输出成功,则函数返回值就是输出的字符数据;否则,返回一个符号常量EOF(其值在头文件stdio.h中,被定义为-1)2.从文件中读入一个字符.从文件中读入一个字符──fgetc()函数和函数和feof()函数函数[案例案例8.2] 顺序显示[案例案例8.1]创建的磁盘ASCII码文件/*案例代码文件名:AL8_2.C*//*程序功能:顺序显示一个磁盘ASCII码文件*//*参数:带参主函数,使用格式:可执行文件名 源文件名*/#include "stdio.h"main(int argc, char *argv[]) { FILE *fp; char ch; if(argc!=2) /*参数个数不对*/ { printf("the number of arguments not correct\n"); printf(“\n Usage: 可执行文件名 源文件名"); exit(0); } if ((fp=fopen(argv[1],"r"))==NULL) { printf("can not open source file\n"); exit(0); } /*顺序输出文件的内容*/ for(; (ch=fgetc(fp))!=EOF; ) putchar(ch); /*顺序读入并显示*/ fclose(fp); /*关闭打开的文件*/} [程序演示程序演示] 程序运行情况: abcdefg1234567((1)库函数)库函数fgetc() 1)用法:int fgetc(文件指针文件指针); 2)功能:从“文件指针”所指向的文件中,读入一个字符,同时将读写位置指针向前移动1个字节(即指向下一个字符)。 该函数无出错返回值例如,fgetc(fp)表达式,从文件fp中读一个字符,同时将fp的读写位置指针向前移动到下一个字符2)关于符号常量)关于符号常量EOF 在对ASCII码文件执行读入操作时,如果遇到文件尾,则读操作函数返回一个文件结束标志EOF(其值在头文件stdio.h中被定义为-1)在对二进制文件执行读入操作时,必须使用库函数feof()来判断是否遇到文件尾 [案例案例8.3] 实现制作ASCII码文件副本的功能/*案例代码文件名:AL8_2.C*//*程序功能:制作ASCII码文件的副本*//*使用格式:可执行文件名 源文件名 目标文件名*/#include "stdio.h"main(int argc, char *argv[]) { FILE *input, *output;/* input:源文件指针, output:目标文件指针 */ char ch; if(argc!=3) /*参数个数不对*/ { printf("the number of arguments not correct\n"); printf("\n Usage: 可执行文件名 source-file dest-file"); exit(0); } if ((fp=fopen(argv[1],"r"))==NULL) /*打开源文件失败*/ { printf("can not open source file\n"); exit(0); } if ((fp=fopen(argv[2],"w"))==NULL) /*创建目标文件失败*/ { printf("can not create destination file\n"); exit(0); } /*复制源文件到目标文件中*/ for( ; (!feof(input)) ; ) fputc(fgetc(input),output); fclose(input); fclose(output);/*关闭源文件和目标文件*/}[程序演示程序演示] 库函数库函数feof():: 1)用法:int feof(文件指针文件指针); 2)功能:在执行读文件操作时,如果遇到文件尾,则函数返回逻辑真(1);否则,则返回逻辑假(0)。 feof()函数同时适用于ASCII码文件和二进制文件 例如,!feof(input))表示源文件(用于输入)未结束,循环继续[Return]8.3.2 读/写一个字符串读/写一个字符串──fgets()和和fputs()[案例案例8.4] 将键盘上输入的一个长度不超过80的字符串,以ASCII码形式存储到一个磁盘文件中;然后再输出到屏幕上/*案例代码文件名:AL8_4.C*//*参数:可执行文件名 要创建的磁盘文件名*/#include "stdio.h"main(int argc, char *argv[]) { FILE *fp; char string[81];/*字符数组用于暂存输入输出的字符串*/ if(argc>2) /*参数太多,提示 出错*/ { printf("Too many parameters…\n\n"); printf("Usage: 可执行文件名 filename\n"); exit(0); } if(argc= =1) /*缺磁盘文件名,提示输入*/ { printf("Input the filename: "); gets(string);/*借用string暂存输入的文件名*/ argv[1]=(char *)malloc(strlen(string)+1);/*给文件名参数申请内存空间*/ strcpy(argv[1],string);/*复制文件名到形参中*/ } if ((fp=fopen(argv[1],"w"))==NULL) /*打开文件失败*/ { printf("can not open this file\n"); exit(0); } /*从键盘上输入字符串,并存储到指定文件中*/ printf("Input a string: "); gets(string);/*从键盘上输入字符串*/ fputs(string, fp);/*存储到指定文件*/ fclose(fp); /*重新打开文件,读出其中的字符串,并输出到屏幕上*/ if ((fp=fopen(argv[1],"r"))==NULL) /*打开文件失败*/ { printf("can not open this file\n"); exit(0); } fgets(string, strlen(string)+1, fp);/*从文件中读一个字符串*/ printf("Output the string: "); puts(string); /*将字符串输出到屏幕上*/ fclose(fp); } [程序演示程序演示] (1)为增强程序的可靠性,程序中对参数过多的情况,提示出错、并终止程序运行;而遗漏文件名时,提示用户输入。 同时,为增强程序的人机交互性,凡是需要用户输入数据的地方,都设置提示输入的信息;凡是输出数据的地方,都设置输出说明信息((2)) 库函数库函数fputs()──向指定文件输出一个字符串向指定文件输出一个字符串1)用法:int fputs(字符串,文件指针字符串,文件指针);其中“字符串”可以是一个字符串常量,或字符数组名,或字符指针变量名2)功能:向指定文件输出一个字符串,同时将读写位置指针向前移动strlength(字符串长度)个字节如果输出成功,则函数返回值为0;否则,为非0值3)) 库函数库函数fgets()──从文件中读一个字符串从文件中读一个字符串 1)用法:char *fgets(指针,串长度指针,串长度+1,文件指针,文件指针); 2)功能:从指定文件中读入一个字符串,存入“字符数组/指针”中,并在尾端自动加一个结束标志'\0';同时,将读写位置指针向前移动strlength(字符串长度)个字节 如果在读入规定长度之前遇到文件尾EOF或换行符,读入即结束[Return]8.3.3 读/写一个数据块读/写一个数据块──fread()和和fwrite()实际应用中,常常要求1次读/写1个数据块。 为此,ANSI C 标准设置了 fread( ) 和fwrite()函数 1.用法:int fread(void *buffer,,int size,,int count,,FILE *fp);;int fwrite(void *buffer,,int size,,int count,,FILE *fp);; 2.功能:fread()──从fp所指向文件的当前位置开始,一次读入size个字节,重复count次,并将读入的数据存放到从buffer开始的内存中;同时,将读写位置指针向前移动size* count个字节其中,buffer是存放读入数据的起始地址(即存放何处)fwrite()──从buffer开始,一次输出size个字节,重复count次, 并将输出的数据存放到fp所指向的文件中;同时,将读写位置指针向前移动size* count个字节其中,buffer是要输出数据在内存中的起始地址(即从何处开始输出)如果调用fread()或fwrite()成功,则函数返回值等于countfread()和fwrite()函数,一般用于二进制文件的处理[Return]8.3.4 对文件进行格式化读/写对文件进行格式化读/写──fscanf()和和fprintf()函数函数 与scanf()和printf()函数的功能相似,区别在于:fscanf()和fprintf()函数的操作对象是指定文件,而scanf()和printf()函数的操作对象是标准输入(stdin)输出(stdout)文件。 int fscanf(文件指针,"格式符",输入变量首地址表); int fprintf(文件指针,"格式符",输出参量表); 例如,...... int i=3; float f=9.80; ...... fprintf(fp,"%2d,%6.2f", i, f); ...... fprintf()函数的作用是,将变量i按%2d格式、变量f按%6.2f格式, 以逗号作分隔符,输出到fp所指向的文件中:□3,□□9.80(□表示1个空格)[Return]8.3.5 读/写函数的选用原则读/写函数的选用原则从功能角度来说,fread()和fwrite()函数可以完成文件的任何数据读/写操作 但为方便起见,依下列原则选用: 1.读/写1个字符(或字节)数据时:选用fgetc()和fputc()函数 2.读/写1个字符串时:选用fgets()和fputs()函数 3.读/写1个(或多个)不含格式的数据时:选用fread()和fwrite()函数 4.读/写1个(或多个)含格式的数据时:选用fscanf()和fprintf()函数。 [Return]8.4 文件的随机读写文件的随机读写文件中有一个读写位置指针,指向当前的读写位置每次读写1个(或1组)数据后,系统自动将位置指针移动到下一个读写位置上 如果想改变系统这种读写规律,可使用有关文件定位的函数 8.4.1 位置指针复位函数位置指针复位函数rewind() 1.用法:int rewind(文件指针文件指针); 2.功能:使文件的位置指针返回到文件头 8.4.2 随机读写与随机读写与fseek()函数函数 对于流式文件,既可以顺序读写,也可随机读写,关键在于控制文件的位置指针 所谓顺序读写是指,读写完当前数据后,系统自动将文件的位置指针移动到下一个读写位置上所谓随机读写是指,读写完当前数据后,可通过调用fseek()函数,将位置指针移动到文件中任何一个地方 1.用法:int fseek(文件指针,位移量,参照点文件指针,位移量,参照点); 2.功能:将指定文件的位置指针,从参照点开始,移动指定的字节数1)参照点:用0(文件头)、1(当前位置)和2(文件尾)表示在ANSI C标准中,还规定了下面的名字: SEEK_SET──文件头, SEEK_CUR──当前位置, SEEK_END──文件尾(2)位移量:以参照点为起点,向前(当位移量>0时)或后(当位移量<0时)移动的字节数。 在ANSI C标准中,要求位移量为long int型数据fseek()函数一般用于二进制文件函数一般用于二进制文件8.4.3 返回文件当前位置的函数返回文件当前位置的函数ftell()由于文件的位置指针可以任意移动,也经常移动,往往容易迷失当前位置,ftell()就可以解决这个问题 1.用法:long ftell(文件指针文件指针); 2.功能:返回文件位置指针的当前位置(用相对于文件头的位移量表示) 如果返回值为-1L,则表明调用出错例如: offset=ftell(fp); if(offset= =-1L)printf(“ftell() error\n”);[Return]8.5 出错检测出错检测 8.5.1 ferror()函数函数 在调用输入输出库函数时,如果出错,除了函数返回值有所反映外,也可利用ferror()函数来检测 1.用法: int ferror(文件指针文件指针);; 2.功能:如果函数返回值为0,表示未出错;如果返回一个非0值,表示出错 (1)对同一文件,每次调用输入输出函数均产生一个新的ferror()函数值。 因此在调用了输入输出函数后,应立即检测,否则出错信息会丢失 (2)在执行fopen()函数时,系统将ferror()的值自动置为08.5.2 clearerr()函数函数1.用法: void clearerr(文件指针文件指针);;2.功能:将文件错误标志(即ferror()函数的值)和文 件 结 束 标 志 ( 即 feof()函 数 的 值 ) 置 为 0 对同一文件,只要出错就一直保留,直至遇到clearerr()函数或rewind()函数,或其它任何一个输入输出库函数[Return]第第9章章 自定义类型自定义类型为将不同数据类型、但相互关联的一组数据,组合成一个有机整体使用,C语言提供一种称为“结构”的数据结构9.1 枚举类型 9.2 结构体类型 9.3 共用体类型9.4 类型定义符typedef9.5 自定义数据类型应用程序举例[Return]9.1 枚举类型枚举类型1.枚举类型的定义 enum 枚举类型名枚举类型名 {取值表取值表};;例如,enum weekdays {Sun,Mon,Tue,Wed,Thu,Fri,Sat};2.枚举变量的定义──与结构变量类似(1)间接定义 例如,enum weekdays workday;(2)直接定义 例如,enum [weekdays] {Sun,Mon,Tue,Wed,Thu,Fri,Sat } workday;3.说明(1)枚举型仅适应于取值有限的数据。 例如,根据现行的历法规定,1周7天,1年12个月2)取值表中的值称为枚举元素,其含义由程序解释例如,不是因为写成“Sun”就自动代表“星期天”事实上, 枚举元素用什么表示都可以(3)枚举元素作为常量是有值的──定义时的顺序号(从0开始),所以枚举元素可以进行比较,比较规则是:序号大者为大!例如,上例中的Sun=0、Mon=1、……、Sat=6,所以Mon>Sun、Sat最大4)枚举元素的值也是可以人为改变的:在定义时由程序指定例如,如果enum weekdays {Sun=7, Mon=1 ,Tue, Wed, Thu, Fri, Sat};则Sun=7,Mon=1,从Tue=2开始,依次增1[Return]9.2 结构体类型结构体类型C语言中的结构类型,相当于其它高级语言中的“记录”类型9.2.1 结构类型定义结构类型定义struct 结构类型名 /* struct是结构类型关键字*/ {数据类型 数据项1; 数据类型 数据项2; …… …… 数据类型 数据项n; };/* 此行分号不能少!*/ [例例1] 定义一个反映学生基本情况的结构类型,用以存储学生的相关信息。 /*功能:定义一个反映学生基本情况的结构类型*/struct date /*日期结构类型:由年、月、日三项组成*/ {int year; int month; int day; };struct std_info/*学生信息结构类型:由学号、姓名、性别和生日共4项组成*/ {char no[7]; char name[9]; char sex[3]; struct date birthday; }; struct score/*成绩结构类型:由学号和三门成绩共4项组成*/ {char no[7]; int score1; int score2; int score3; }; (1)“结构类型名”和“数据项”的命名规则,与变量名相同2)数据类型相同的数据项,既可逐个、逐行分别定义,也可合并成一行定义 例如,本案例代码中的日期结构类型,也可改为如下形式: struct date {int year, month, day; };(3)结构类型中的数据项,既可以是基本数据类型,也允许是另一个已经定义的结构类型。 例如,本案例代码中的结构类型std_info,其数据项“birthday”就是一个已经定义的日期结构类型date4)本书将1个数据项称为结构类型的1个成员(或分量)9.2.2 结构变量定义结构变量定义用户自己定义的结构类型,与系统定义的标准类型(int、char等)一样,可用来定义结构变量的类型 1.定义结构变量的方法,可概括为两种:(1)间间接接定定义义法法──先定义结构类型、再定义结构变量例如,利用[例例1]中定义的学生信息结构类型std_info,定义了一个相应的结构变量student: struct std_info student;结构变量student:拥有结构类型的全部成员,其中birthday成员是一个日期结构类型,它又由3个成员构成注注意意:使用间接定义法定义结构变量时,必须同时指定结构类型名(2)直接定义法直接定义法──在定义结构类型的同时,定义结构变量例如,结构变量student的定义可以改为如下形式:struct std_info {…… } student;同时定义结构类型及其结构变量的一般格式如下: struct [结构类型名结构类型名] { …… } 结构变量表;结构变量表;2.说明(1)结构类型与结构变量是两个不同的概念,其区别如同int类型与int型变量的区别一样。 2)结构类型中的成员名,可以与程序中的变量同名,它们代表不同的对象,互不干扰[Return]9.3 共用体类型共用体类型 1.概念 使几个不同的变量占用同一段内存空间的结构称为共用型 2.共用类型的定义──与结构类型的定义类似 union 共用类型名 {成员列表;}; 3.共用变量的定义──与结构变量的定义类似(1)间接定义──先定义类型、再定义变量例如,定义data共用类型变量un1,un2,un3的语句如下: union data un1,un2,un3;(2)直接定义──定义类型的同时定义变量例如,union [data] { int i; char ch; float f; } un1, un2, un3; 共用变量占用的内存空间,等于最长成员的长度,而不是各成员长度之和例如,共用变量un1、un2和un3,在16位操作系统中,占用的内存空间均为4字节(不是2+1+4=7字节)。 4.共用变量的引用──与结构变量一样,也只能逐个引用共用变量的成员例如,访问共用变量un1各成员的格式为:un1.i、un1.ch、un1.f5.特点(1)系统采用覆盖技术,实现共用变量各成员的内存共享,所以在某一时刻,存放的和起作用的是最后一次存入的成员值例如,执行un1.i=1, un1.ch='c', un1.f=3.14后,un1.f才是有效的成员2)由于所有成员共享同一内存空间,故共用变量与其各成员的地址相同例如,&un1=&un1.i=&un1.ch=&un1.f3)不能对共用变量进行初始化(注意:结构变量可以);也不能将共用变量作为函数参数,以及使函数返回一个共用数据,但可以使用指向共用变量的指针4)共用类型可以出现在结构类型定义中,反之亦然[Return]9.4 类型定义符typedef除可直接使用C提供的标准类型和自定义的类型(结构、共用、枚举)外,也可使用typedef定义已有类型的别名该别名与标准类型名一样,可用来定义相应的变量 定义已有类型别名的方法如下:定义已有类型别名的方法如下: (1)按定义变量的方法,写出定义体; (2)将变量名换成别名; (3)在定义体最前面加上typedef。 [例例2] 给实型float定义1个别名REAL (1)按定义实型变量的方法,写出定义体:float f; (2)将变量名换成别名: float REAL; (3)在定义体最前面加上typedef:typedef float REAL;[例例3] 给如下所示的结构类型struct date定义1个别名DATEstruct date { int year, month, day; };(1)按定义结构变量的方法,写出定义体:struct date {……} d;(2)将变量名换成别名: struct date {……} DATE;(3)在定义体最前面加上typedef: typedef struct date {……} DATE;说明说明:(1)用typedef只是给已有类型增加1个别名,并不能创造1个新的类型就如同人一样,除学名外,可以再取一个小名(或雅号),但并不能创造出另一个人来2)typedef与#define有相似之处,但二者是不同的:前者是由编译器在编译时处理的;后者是由编译预处理器在编译预处理时处理的,而且只能作简单的字符串替换。 [Return]9.5 定义数据类型应用程序举例定义数据类型应用程序举例【例4】给定学生成绩如表9-1所示利用结构体数组计算表9-1中给定的每个学生三门课程的平均成绩,最后输出成绩单#include 由于汇编语言程序依赖于计算机硬件,其可读性和可移植性都很差;但一般的高级语言又难以实现对计算机硬件的直接操作(这正是汇编语言的优势),于是人们盼望有一种兼有汇编语言和高级语言特性的新语言2)C语言是贝尔实验室于70年代初研制出来的,后来又被多次改进,并出现了多种版本80年代初,美国国家标准化协会(ANSI),根据C语言问世以来各种版本对C语言的发展和扩充,制定了ANSI C标准(1989年再次做了修订)本书以本书以ANSI C新标准来介绍新标准来介绍(3)目前,在微机上广泛使用的C语言编译系统有visual studio C、Borland C等虽然它们的基本部分都是相同的,但还是有一些差异, 所以请大家注意自己所使用的C编译系统的特点和规定(参阅相应的手册)本书选定的上机环境是本书选定的上机环境是VC6.0((windows操作系统)操作系统) 2..C语言的特点语言的特点 C语言同时具有汇编语言和高级语言的优势1)语言简洁、紧凑,使用方便、灵活 (2)运算符极其丰富3)生成的目标代码质量高,程序执行效率高4)可移植性好(较之汇编语言)5)可以直接操纵硬件 3. 在C语言中,除实现顺顺序序、、选选择择和循循环环三种基本结构等的9条控制语句外,输入输出操作均由标准库函数(不是C语言的组成部分)来实现。 所以学学习习C语语言言,,不不仅仅要要学学习习这这9条条控控制制语语句句和和各各种种运算符,而且要学习并掌握常用标准库函数的使用运算符,而且要学习并掌握常用标准库函数的使用[Return]1.2 算法的概念与表示方法算法的概念与表示方法 算法就是解决问题的方法(或思路)对于同一个问题可以有不同的解题方法,也就是有不同的算法,一般应当选择方法简单、运算步骤少、运算快且占用内存小的算法算法应具有以下几个特征:(1)可行性指算法中的每一步都是计算机可以执行的,并能得到有效的结果2)确定性指算法中的每一步必须有明确定义,不能有任何歧义3)有穷性指算法必须在执行有限步后结束,而不能是无限的步骤,也不能陷入死循环4)可输入/输出信息 常用算法的流程图表示 (1)起止框:表示算法的开始或结束2)输入输出框:表示算法请求输入需要的数据或算法将某些结果输出3)处理框:表示算法的某个处理步骤4)判断框:对一个给定条件进行判断,根据判断结果决定如何执行其后的操作判断框有一个入口,两个出口5)流程线:指出了算法的执行方向6)连接点:用于将画在不同地方的流程线连接起来7)注释框:对流程图中某些框的操作做必要的补充说明, 1.3 C语言概述C语言概述1.2.1 C语言程序的总体结构C语言程序的总体结构 一个完整的C语言程序,是由一个main()函数(又称主函数)和若干个其它函数结合而成的,或仅由一个main()函数构成。 [案例案例1.1] 仅由main()函数构成的C语言程序/*案例代码文件名:AL1_1.C*//*功能:仅由main()函数构成的C语言程序示例*/main() { printf(“This is a C program.\n”); }程序运行结果: This is a C program. [程序演示][案例案例1.2] 由main()函数和1个其它函数max()构成的C语言程序/*案例代码文件名:AL1_2.C*//*功能:由main()函数和1个其它函数max()构成的C语言程序示例*/int max(int x, int y) { return( x>y ? x : y ); }main() { int num1,num2; printf(“Input the first integer number: ”); scanf(“%d”, &num1); printf(“Input the second integer number: ”); scanf(“%d”, &num2); printf(“max=%d\n”, max(num1, num2)); }程序运行情况: Input the first integer number:6←┘ Input the second integer number:9←┘ max=9 [程序演示][案案例例1.3] 改写[案案例例1.2],交换main()函数和max()函数的前后位置。 源程序略程序运行情况: Input the first integer number:6←┘ Input the second integer number:9←┘ max=91.函数是C语言程序的基本单位函数是C语言程序的基本单位main()函数的作用,相当于其它高级语言中的主程序;其它函数的作用,相当于子程序2.C语言程序总是从语言程序总是从main()函数开始执行函数开始执行一个C语言程序,总是从main()函数开始执行,而不论其在程序中的位置当主函数执行完毕时,亦即程序执行完毕习惯上,将主函数main()放在最前头 1.2.2 函数的一般结构函数的一般结构 任何函数(包括主函数main())都是由函数说明和函数体两部分组成其一般结构如下: [函数类型] 函数名(函数参数表) 函数说明部分 { 说明语句部分; 执行语句部分; 函数体部分 } 1. 使用的语法符号约定使用的语法符号约定 [...]──方括号表示可选(即可以指定,也可以缺省) ……──省略号表示前面的项可以重复 | ──多(含2)中选1 2.函数说明函数说明 由函数类型(可缺省)、函数名和函数参数表三部分组成,其中函数参数表的格式为: 数据类型 形参[, 数据类型 形参2……]例如,[案例1.2]中的函数max(),其函数说明各部分如图1-1所示。 函数类型 函数名 函数参数表 ↓ ↓ ↓ int max ( int x , int y ) 图1-1 函数说明部分结构图注意:注意:在旧标准中,函数可以缺省参数表3.函数体函数体在函数说明部分的下面、大括号(必须配对使用)内的部分函数体一般由说明语句和可执行语句两部分构成:(1)说明语句部分说明语句部分由变量定义、自定义类型定义、自定义函数说明、外部变量说明等组成 ((2)可执行语句)可执行语句 一般由若干条可执行语句构成图1-2是[案案例例1.2]的main()函数体的示意图/*主函数main()*/main() { int num1,num2; 变量定义部分 printf(“Input the first integer number: ”); scanf(“%d”, &num1); printf(“Input the second integer number: ”); 可执行语句部分 函数体 scanf(“%d”, &num2); printf(“max=%d\n”, max(num1, num2)); } 图1-2 函数体结构示意图 4.说明说明(1)函数体中的变量定义语句,必须在所有可执行语句之前。 下面程序中变量定义语句“int max;”的位置是非法的:main() { int x,y;/*变量定义语句:定义2个整型变量x、y*/ x=3; /*可执行的赋值语句:将3赋值给变量x*/ y=6;/*可执行的赋值语句:将6赋值给变量y*/ int max;/*变量定义语句:出现在可执行的 赋值语句“x=3;”和“ y=6;”之后,非法!*/ max=x>y?x:y; printf(“max=%d\n”,max); }解决办法很简单,请读者自己思考2)如果不需要,也可以缺省变量定义语句1.2.3 源程序书写格式源程序书写格式1.所有语句都必须以分号“;”结束,函数的最后一个语句也不例外2.程序行的书写格式自由,既允许1行内写几条语句,也允许1条语句分写在几行上例如,[案例案例1.2]的主函数main(),也可改写成如下所示的格式:……main() { int num1,num2; printf(“Input the first integer number: ”); scanf(“%d”, &num1); printf(“Input the second integer number: ”); scanf(“%d”, &num2); printf(“max=%d\n”, max(num1, num2)); }如果某条语句很长,一般需要将其分写在几行上。 3.允许使用注释C语言的注释格式为: /* …… */例如,在[案例1.1]和[案例1.2]中,以及本节其它部分给出的源程序中,凡是用“/*”和“*/”括起来的文字,都是注释1) “/*”和“*/” 必须成对使用,且“/”和“*”、以及“*”和“/”之间不能有空格,否则都出错 技技巧巧:为避免遗漏必须配对使用的符号,例如注释符号、函数体的起止标识符(花括号)、圆括号等等,在输入时,可连续输入这些起止标识符,然后再在其中进行插入来完成内容的编辑在起止标识符嵌套时,以及相距较远时,这样做更有必要 (2)注释的位置,可以单占1行,也可以跟在语句的后面 (3)如果1行写不下,可另起1行继续写 (4)注释中允许使用汉字在非中文操作系统下,看到的是一串乱码,但不影响程序运行 [Return]1.4 C程序的设计步骤与运行环境程序的设计步骤与运行环境 1.运行一个C语言程序的一般过程 2.VC的启动、退出与命令菜单 3.编辑并保存一个C语言源程序 4.编译、连接──单个源程序文件 5.运行与查看结果 6.编辑下一个新的源程序 [Return]1.运行一个C语言程序的一般过程运行一个C语言程序的一般过程 VC6.0是一个集源程序编辑、编译、连接、运行与调试于一体、 用菜单驱动的集成软件环境。 运行一个C语言程序的一般过程: (1)启动VC,进入VC集成环境2)编辑(或修改)源程序3)编译如果编译成功,则可进行下一步操作;否则,返回(2)修改源程序,再重新编译,直至编译成功 (4)连接如果连接成功,则可进行下一步操作;否则,根据系统的错误提示,进行相应修改,再重新连接,直至连接成功5)运行通过观察程序运行结果,验证程序的正确性如果出现逻辑错误,则必须返回(2)修改源程序,再重新编译、连接和运行,直至程序正确6)退出VC集成环境,结束本次程序运行[Return]2.VC的启动、退出与命令菜单的启动、退出与命令菜单 ((1))启启动动VC6.0:启动VC6.0后,进入如下环境 ((2)菜单栏的使用)菜单栏的使用2.建立新的源程序文件建立新的源程序文件 从菜单栏中选择“文件”|“新建”命令,新建 C++ Source File3.编辑源程序.编辑源程序在下图所示窗口中输入源程序 4.编译源程序文件编译源程序文件 源程序编辑完成后,点击“组建”按钮 ,源程序经过编译、连接后产生可执行程序sample1.exe。 程序正确编译后的窗口见下图 5.运行与查看结果运行与查看结果 (1)运行当前正在编辑的源程序文件 选择并执行Run | Run项(快捷键:^F9),程序运行结束后, 仍返回到编辑窗口 当你认为自己的源程序不会有编译、连接错误时,也可直接运行(即跳过对源程序的编译、连接步骤)这时,VC将一次完成从编译、连接到运行的全过程2)查看运行结果 选择并执行Run | User Screen项(快捷键:Alt+F5)查看完毕后,按任一键返回编辑窗口 如果发现逻辑错误,则可在返回编辑窗口后,进行修改;然后再重新编译、连接、运行,直至正确为止[Return] 5.运行程序.运行程序编译连接正确后,单击图1-11编译工具栏中的“运行”按钮,运行可执行程序通过键盘输入半径值2.5以及回车键后,出现如下运行结果:。












