Posted on 2008-04-19 23:31
silentneil 阅读(2329)
评论(0) 编辑 收藏 引用
C语言程序设计教案
教材类型:新世纪计算机基础教育从书
主教材:C程序设计(第二版)
编者:谭浩强 著
出版:清华大学出版社
辅教材:C 程序设计解题与上机指导(第二版)
编者:谭浩强 主编
出版:清华大学出版社
总学时:102 周数:17 周学时:4+2
目 录
1 C语言概述
1.1 C语言出现的历史背景
1.2 C语言的特点
1.3 简单的C程序介绍
1.4 C程序的上机步骤
1.5 Turbo C常用命令简介
2 程序的灵魂-算法
2.1 算法的概念
2.2 简单算法举例
2.3 算法的特性
2.4 怎样表示一个算法
2.5 结构化程序设计方法
3 数据类型、运算符与表达式
3.1 C的数据类型
3.2 常量和变量
3.3 整型数据
3.4 实型数据
3.5 字符型数据
3.6 变量赋初值
3.7 各类数值型数据间的混合运算
3.8 算术运算符和逗号表达式
3.9 赋值运算符和赋值表达式
3.10 逗号运算符和逗号表达式
4 顺序结构程序设计
4.1 C语句概念
4.2 赋值语句
4.3 数据输入输出的概念及在C语言中的实现
4.4 字符数据的输入与输出
4.5 格式输入与输出
4.6 顺序结构程序设计举例
5 选择结构程序设计
5.1 关系运算符和关系表达式
5.2 逻辑运算符和逻辑表达式
5.3 If语句
5.4 Switch语句
5.5 程序举例
6 循环结构程序设计
6.1 概述
6.2 goto语句以及用goto语句构成循环
6.3 while语句
6.4 do-while语句
6.5 for语句
6.6 循环的嵌套
6.7 几种循环的比较
6.8 break语句和continue语句
6.9 程序举例
7 数组
7.1 一维数组的定义和引用
7.2 二维数组的定义和引用
7.3 字符数组和字符串
8 函数
8.1 概述
8.2 函数定义的一般形式
8.3 函数参数和函数的值
8.4 函数的调用
8.5 函数的嵌套调用
8.6 函数的递归调用
8.7 数组作为函数参数
8.8 局部变量和全局变量
8.9 变量的存储类别
8.10 内部函数和外部函数
8.11 如何运行一个多文件的程序
9 预处理命令
9.1 宏定义
9.2 文件包含处理
9.3 条件编译
11 指针
10.1 地址和指10.2 针的概述
10.3 变量的指10.4 针和指10.5 向变量的指10.6 针变量
10.7 数组与指10.8 针
10.9 字符串与指10.10 针
10.11 指10.12 向函数的指10.13 针
10.14 返回指10.15 针值的函数
10.16 指10.17 针数组和指10.18 向指10.19 针的指10.20 针
10.21 有关指10.22 针的数据类型和指10.23 针运算小结
12 结构体与共用体
11.1 结构体概述
11.2 定义结构体类型变量的方法
11.3 结构体变量的引用
11.4 结构体变量的初始化
11.5 结构体数组
11.6 指11.7 向结构体类型数据的指11.8 针
11.9 用指11.10 针处理链表
11.11 共用体
11.12 枚举类型
11.10 用typedef定义类型
13 位运算
12.1 位运算符和位运算
12.2 位运算应用举例
12.3 位段
14 文件
13.1 C文件概述
13.2 文件类型指13.3 针
13.4 文件的打开与关闭
13.5 文件的顺序读写
13.6 文件的定位
13.7 出错的检测
13.8 文件输入输出小结
第1章 C语言概述
1.1 C语言出现的历史背景
C语言是国际上广泛流行的计算机高级语言,即可用来写系统软件,也可用来写应用软件。
C语言是在B语言的基础上发展起来的。
早期的C语言运行在UNIX操作系统上,后来运行在DOS操作系统上,现在的C语言可运行在Windos操作系统上。
C语言有许多版本,我们使用的是Turbo C 2.0。
P1,说明。
1.2 C语言的特点
C语言有许多优于其它语言的特点:
(1)语言简洁、紧凑,使用方便、灵活。
C语言一共只有32个关键字,9个控制语句,书写形式自由。
P2,表1.1。
(2)运算符丰富。
C共有34种运算符,如+、-等。
P2,说明。
(3)数据结构丰富。
C有整型、实型等多种数据结构。
P3,说明。
(4)具有结构化的控制语句。
C有if…else、while等多种结构化的控制语句。
P3,说明。
(5)语法限制不太严格,程序设计自由度大。
如对数组下标越界不作检查等。
P3,说明。
(6)C语言可进行位运算。
这是C区别于其它高级语言的主要特点。
P3,说明。
(7)生成目标代码质量高。
这也是C的优于其它高级语言之处。
P3,说明。
(8)C程序可移植性好。
即C程序可基本不做修改移到不同的计算机上运行。
P3,说明。
1.3 简单的C程序介绍
P4,例1.1,见ex1-1.c。
程序功能:打印一个字符串,并输出一个换行符。
P4,例1.2,见ex1-2.c。
程序功能:求两个数之和。
P5,例1.3,见ex1-3.c。
程序功能:求两个数的较大者。
分析这三个例子的执行过程。
说明:
4 C程序是由函数组成的。在上面的例子中的函数有:main、printf、scanf和max。其中main是主函数,printf、scanf是库函数,max是自定义函数。一个C程序一定要有一个主函数。库函数是放在*.h的库函数文件中,只要直接调用就可。自定义函数要由用户先定义后调用。
5 认识一下C函数
C函数定义的一般格式为:
函数类型 函数名(形参类型 形式参数,…)
{
数据声明部分;
函数执行部分;
}
C函数调用的一般格式为:
函数名(实际参数,…)
(3)一个C程序总是从main主函数开始执行的,而不论main函数在程序中的位置如何。主函数可以调用子函数,子函数还可以调用子子函数。因此C程序是层次结构的。
(4)C程序一行可以写多个语句,每个语句以“;”结束。C程序是区分大小写字母的。C程序本身没有输入输出语句,其输入输出是由库函数printf和scanf来完成的。/*…*/是C的注释语句。
1.4 C程序的上机步骤
C程序编写好后,要经过编辑、编译、连接与运行四个步骤,这四个步骤的作用分别是:
编辑:把C语言源程序输入计算机并进行修改存盘,生成*.c的源程序文件。
编译:用C编译程序对*.c的源程序文件进行编译,生成*.obj的二进制文件。
连接:把*.obj的二进制文件与系统标准模块进行连接,生成*.exe的可执行文件。
运行:执行*.exe的可执行文件,输出执行结果。
以上步骤均可在Turbo C的工作平台上进行,启动Turbo C,就可以进行编辑,打命令Ctrl+F9,就可以进行编译、连接和运行,打命令Alt+F5,就可看到执行结果。
举例说明,见ex1-1.c。
1.5 Turbo C常用命令简介
1. 启动和退出
启动:在DOS下打TC,或在Windows下创建快捷命令执行。
退出:Alt+X
2. 程序的编辑
简单编辑:Ins:插入/改写 Backspace:删除前一字符
Del:删除当前字符 Ctrl+Y:删除一行
块操作:Ctrl+KB、Ctrl+KK:定义块首、尾
Ctrl+KC、Ctrl+KV、Ctrl+KY:块复制、块移动、块删除
Ctrl+KH:取消块定义
3. 程序载入与存盘
F3:载入程序 F6:切换窗口
F2:存盘 Alt+FN:新建程序
4. 编译和运行
Ctrl+F9:编译连接执行程序 Alt+F5:查看执行结果
Ctrl+F7:添加监视表达式 F7:进入子函数单步执行
F8:越过子函数单步执行 Ctrl+F2:取消单步执行
举例说明,见ex1-1.c。
第2章 程序的灵魂-算法
一个程序应包括两个方面的内容:
3 对数据的描述:即程序中的数据要指定它的类型和组织形式,也称数据结构。
4 对操作的描述:即程序中对要做的事要指明它的操作步骤,也称算法。
算法是程序的灵魂,也就是说,要计算机解决实际中的问题,“怎么解”是程序设计的关键。
2.1 算法的概念
(1)算法的定义
计算机算法:就是要计算机解决问题的操作步骤。
P13,例。
(2)算法的分类
计算机算法可分为两类:数值算法和非数值算法。
P14,例。
2.2 简单算法举例
P14,例2.1。
注意:解决同一问题可有不同的算法,算法有优劣之分。
P15,例2.2。
注意:循环是算法中常用的手段。
2.3 算法的特性
算法具有如下特性:
(1)有穷性
即经过有限步就能够完成。
P14,例2.1。P15,例2.2。
(2)确定性
即每一步都是确定的。
P14,例2.1。P15,例2.2。
(3)有零个或多个输入
即一个算法必须输入的数据可以是零个或多个。
P14,例2.1。P15,例2.2。
(4)有一个或多个输出
即一个算法可以输出一个或多个数据。
P14,例2.1。P15,例2.2。
(5)有效性
即算法中每一步骤都能有效地执行,并得到确定的结果。
P14,例2.1。P15,例2.2。
2.4 怎样表示一个算法
算法的表示法有多种,叙述如下:
(1)用自然语言表示
即把算法用人们日常使用的语言表示出来。
P14,例2.1。P15,例2.2。
特点:常常具有不确定性,不宜采用。
(2)用流程图表示
即把算法用一些特定的符号和图形表示出来。
P20,例2.6,例2.7。
特点:这是一种较好的表示法,经常采用。
(3)用N-S图表示
即把算法用一些特定的符号和图形表示出来。
P26,例2.11,例2.12。
特点:这也是一种较好的表示法,经常采用。
(4)用伪代码表示
即把算法用一些称为伪代码的文字和符号表示出来。
P29,例2.16,例2.17。
特点:这也是一种较好的表示法,经常采用。
(5)用计算机语言表示
即把算法用某种计算机语言符号表示出来。
P31,例2.20,例2.21。
特点:这当然是一种很好的表示法,可以输入计算机执行。
2.5 结构化程序设计方法
算法有三种基本结构,它们是:
(1)顺序结构:即算法的执行是按顺序一步接着一步的执行。
(2)选择结构:即算法的执行是对某些步骤可有选择的执行。
(3)循环结构:即算法的执行是对某些步骤可有限次的重复执行。
这三种基本结构的流程图见P23,图2.14,图2.15,图2.16,图2.17。用这三种基本结构设计程序称为结构化程序设计。
结构化程序设计的方法指的是:
1 自顶向下
2 逐步细化
3 模块化设计
4 结构化编码
P32,例。
第3章 数据类型、运算符与表达式
3.1 C的数据类型
数据是程序的必要组成部分,也是程序处理的对象。C规定,在程序中使用的每一个数据必须属于某一数据类型。
C语言中所有的数据类型见P38。
3.2 常量与变量
在程序运行过程中,值保持不变的量称为常量,值可能发生变化的量称为变量。
3.2.1 常量与符号常量
1. 常量
常量是日常所说的常数、字符、字符串等。
P38,例。
2. 符号常量
用#define定义的用标识符来表示的常量。
格式:#define 常量名 常量
功能:定义一个符号常量
P38,例3.1。
说明:常量名必须是一个标识符。
3.2.2 变量
1. 标识符
标识符是用来表示符号常量、变量、数组、函数、过程、类型及文件的名字的。
标识符的命名规则:
(1)以字母或下划线开头,由字母、数字和下划线组成;
(2)不能与关键字同名,最好不要与库函数名同名;
(3)长度无限定,但不同版本的C编译时有自己的规定;
(4)区分大小写。
P40,例。
2. 变量的声明
格式:类型名 变量名,… ;
功能:声明变量。
说明:(1)变量名必须是一个标识符,变量必须先声明后使用;
(2)变量一旦声明,系统就为它开辟一个相应类型的存储空间;
(3)变量所占用的存储空间的首地址称为该变量的地址。
P40,例。
3. 变量的赋值
格式:变量名=表达式;
功能:把=号右边表达式的值赋给=号左边的变量。
P40,例。
3.3 整型数据
3.3.1 整型常量的表示方法
整型常量常用三种形式表示:
(1)十进制:直接写;
(2)八进制:前加0;
(3)十六进制:前加0X或0x。
P41,例。
3.3.2 整型变量
1. 整型数据在内存中的存放形式
整型数据在内存中采用定点表示。
定点表示有原码、反码、补码之分,一般在机内使用补码。
原码:最高位为符号位,小数点定在最低位之后,数值用二进制表示。
反码:正数的反码与原码一样,负数的反码除符号位外各位取反。
补码:正数的补码与原码一样,负数的补码是反码加1。
例1:整数10的16位定点表示
因:(10)10=(1010)2
故:整数10的16位定点表示为
原码:
0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0
反码:
0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0
补码:
0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0
例2:整数-10的16位定点表示
因:(-10)10=(-1010)2
故:整数-10的16位定点表示为
原码:
1 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0
反码:
1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 1
补码:
1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 0
现代计算机一般用补码表示。
2. 整型变量的分类
(1)有三种整型变量
整型: int
短整型:short [int]
长整型:long [int]
(2)整型变量的分类
每种整型变量都可以是无符号的,无符号前加unsigned,有符号前加signed或省缺,于是可有6类整型变量。
P42,例。
(3)整型变量占用的存储空间及取值范围
P43,表3.1。
3. 整型变量的声明
格式:[unsigned] int|short|long 变量名,…;
功能:声明整型变量。
P44,例,例3.2。
4. 整型数据的溢出
int型的取值范围为-32768~32767(-215~215-1),超出这个范围称为溢出,此时可能输出难以理解的结果。
P44,例,例3.3。
3.3.3 整型常量的类型
整型常量一般按整型数据的取值范围自动划定,但也可强制规定它是什么类型,规则是:
无符号整型后加u或U;
长整型后加l或L。
P45,(1)~(5)
3.4 实型数据
3.4.1 实型常量的表示方法
实型常量常用二种形式表示:
(1)十进制小数形式:直接写,要有小数点,前或后至少要有一个数;
(2)指数形式:用e或E的前后加数据表示,前面是一个小数,后面是一个整数。
P45,例。
3.4.2 实型变量
1. 实型数据在内存中的存放形式
实型数据在内存中采用浮点表示
方法:设总位数为16,高12位为尾数,低4位为阶码。尾数与阶码最高位为符号位,尾数小数点定在最高位之后,阶码小数点定在最低位之后。
例1:实数10.0的16位浮点表示
因:(10.0)10=(0.1)10×10(2)10=(0.1)2×10(10)2
故:实数10.0的16位浮点表示为
0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0
例2:实数-10.0的16位浮点表示
因:(-10.0)10=(-0.1)10×10(2)10=(-0.1)2×10(10)2
故:实数-10.0的16位浮点表示为
1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0
注意:(1)位数一般实数是32位,表示法类似;
(2)阶码与尾数的位数不同的计算机有不同的规定。
(3)数据进行转化表示时,尾数表示为±0.a…的形式,且a不为0,故表示是唯一的。
(4)以上阶码与尾数是原码表示,实际上应转成补码。
2. 实型变量的分类
(1)有三种实型变量
单精度: float
双精度: double
长双精度:long double
(2)占用的存储空间及取值范围
P46,表3.2。
(3)实型变量的声明
格式:float | double |long double 变量名,…;
功能:声明实型变量。
P46,例。
3. 实型数据的舍入误差
由于单精度实型只保留7位有效数据,故实型数据超出7位时会造成舍入误差。
P47,例3.4。
3.4.3 实型常量的类型
实型常量一般按双精度double来处理,但也可强制规定它是什么类型,规则是:
单精度后加f或F;
双精度后加l或L。
P47,例。
3.5 字符型数据
3.5.1 字符常量
(1)一般字符常量
是用单撇号括起来的一个字符。
P48,例。
(2)特殊字符常量
是以反斜扞“\”开头后跟一些字母或数字组成的字符。
P48,表3.3。
P49,例3.5。
3.5.2 字符变量
只有一种类型:char
声明格式:char变量名,…;
字符变量可以用来存放一个字符。
P49,例。
3.5.3 字符数据在内存中的存放形式
字符型数据在计算机内以ASCII码的形式存放,每个字符占用一个字节。
方法:查ASCII码表,最高位填0。
例:字符’a’的存储形式
因:(a)字符=(97)10进ASCII码=(1100001)2进ASCII码
故:字符’a’的存储形式为
0 1 1 0 0 0 0 1
P50,例3.6,例3.7。
注意:一般字符的ASCII码值范围为0~127,无符号字符的ASCII码值范围为0~255。
3.5.4 字符串常量
(1)字符串常量
是用双撇号括起来的若干个字符。
P52,例。
(2)字符串常量的存储
字符串常量的存储是每个字符占用一个字节,尾部再加一个\0作为结束符。于是长度为n的字符串占用n+1个字节的存储空间。
P52,例。
3.6 变量赋初值
格式:类型名 变量名=常量表达式,… ;
功能:声明变量并赋初值。
P53,例。
3.7 各类数值型数据间的混合运算
各类数值型数据间的混合运算时会自动进行转换。
规则:(1)char,short型转为int型;
(2)float型转为double型;
(3)不同类型由低向高转换,即int →unsigned →long →double
P54,图3.10。
P54,例。
3.8 算术运算符与算术表达式
3.8.1 C的运算符简介
C语言的运算符有13类,P55。
学习运算符注意如下几点:
(1)运算符的功能:如+号运算的意义。
(2)与运算量的关系:如单目、双目,运算量的类型等。
(3)运算的优先级:如先* /后+-。
(4)结合方向:如算术运算从左到右,赋值从右到左。
(5)结果的类型:如两个整型数相加还是整型数。
3.8.2 算术运算符和算术表达式
1. 基本的算术运算符
基本的算术运算符有:+、-、*、/、%
P55,例。
注意:(1)+、-可作单目运算符,也可作双目运算符。
(2)/ 运算对整形是封闭的,如5/3的值是1。
2. 算术运算符的优先级和结合方向
(1)优先级:①单目+、-②*、/、%③双目+、-
(2)结合方向:从左到右
P55,例。
3. 强制类型转换运算符
格式:(类型标识符)表达式
功能:把表达式强制为类型标识符指定的类型。
优先级:与单目+-相同。
注意:(1)强制转换是一种单目运算;
(2)被强制转换变量本身并未转换。
P56,例,例3.8。
4. 自增、自减运算符
(1)运算符:+ +、--
(2)优先级:与单目+、-相同。
(3)结合方向:从右到左
P57,例。
注意:(1)自增与自减运算符只能用于变量;
(2)前+ +、--:先增值后引用;
后+ +、--:先引用后增值。
5. 有关表达式使用中的问题说明
表达式是把常量、变量、函数用各种运算符连接起来的合法的式子。C中的表达式简练、高效,但有时会出现岐义性,使得程序理解有一定的困难,不同版本的C对表达式的解释也有所不同。
P58,(1)~(3)
3.9 赋值运算符和赋值表达式
1. 赋值运算符
(1)运算符:=
(2)优先级:仅高于逗号“,”运算,低于其它运算。
(3)结合方向:从右到左
P59,例。
2. 类型转换
当赋值运算两边的类型不一致,且都是数值类型或字符型时,会自动发生类型转换,转换以左边变量的类型为准。
转换规则:
(1)实型赋给整型:舍去小数。
(2)整型赋给实型:值不变。
(3)双精度赋给单精度:取其前7位有效数字,反之值不变。P59,例。
(4)字符型赋给整型:低8位照搬,高8位视符号位补0或1。P60,例。
(5)整型赋给字符型:低8位照搬,高8位丢失。P60,例。
(6)整型赋给长整型:值不变,反之低16位照搬。P60,例。
(7)无符号型赋给有符号型:长度相同时最高位变为符号位,长度不同时高位补0或截去高位。P61,例。
(8)有符号型赋给无符号型:长度相同时最高位失去符号位,长度不同时高位补0或截去高位。P61,例。
P61,例3.9。
3. 复合的赋值运算
(1)运算符:+=、-=、*=、/=、%= 等
(2)优先级:与赋值运算“=”相同;
(3)结合方向:从右到左。
P62,例。
4. 赋值表达式
由赋值语句购成的表达式称为赋值表达式,这种表达式还可以嵌套,从右到左逐一进行赋值运算,表达式的值是最后一次赋值的值。
P63,例。
注意:(1)结合方向是从右到左的;
(2)复合的赋值运算也可购成赋值表达式;
(3)赋值表达式可出现在输出的语句中。
3.10 逗号运算符和逗号表达式
1. 逗号运算符
(1)运算符: ,
(2)优先级:最低;
(3)结合方向:从左到右。
P63,例。
2. 逗号表达式
格式:表达式1,表达式2,… ,表达式n
求解过程:从左到右逐一求表达式的值,整个表达式的值为最后一个表达式的值。
P64,例。
第4章 顺序结构程序设计
4.1 C语句概述
1. C的程序结构
一个C程序由若干个源程序文件组成;一个源程序由预处理命令、全局变量说明和若干个函数组成;一个函数由函数首部和函数体组成;一个函数体由局部变量声明和执行语句组成。
P67,图4.1。
2. C程序的语句
C程序的语句的语句分为5类:
(1)控制语句
用来控制程序流程的语句。
P68,①~⑨
P68,例。
注意:( )表示其中是一个条件,~表示内嵌语句。
(2)函数调用语句
由一次函数调用加一个分号购成的语句。
P68,例。
注意:函数有库函数与自定义函数两种,自定义函数要先定义后调用。
(3)表达式语句
由一个表达式加一个分号购成的语句。
P68,例。
注意:表达式语句与表达式的区别在于有无分号。
(4)空语句
只由一个分号购成的语句。
P68,例。
注意:空语句不做任何事情。
(5)复合语句
把多个语句用{ }括起来的语句。
P69,例。
注意:复合语句构成一个分程序,内可包含数据声明和执行语句两部分。
4.2 赋值语句
赋值语句是表达式语句的一种最常用的形式,与其它高级语言相比,C的赋值语句有其独特之处:
(1)在C中“=”是一个运算符;
(2)在C中赋值语句可以包括在其它表达式中。
P69,例。
4.3 数据输入输出的概念及在C语言中的实现
(1)把数据从外部设备送到计算机内存称为输入,把数据从计算机内存送到外部设备称为输出。外部设备有键盘、显示器、磁盘等。
(2)C本身没有输入输出的语句,C的输入输出是由一批库函数来实现的。这些库函数有:scanf、printf、getchar、putchar、gets、puts等,它们放在名为stdio.h的库函数文件中。
(3)一般要使用这些库函数时,要在程序头加上
#include <stdio.h> 或 #include “stdio.h”
的预编译命令,其作用是把这些库函数包含到本程序中来。
P71,例。
4.4 字符数据的输入与输出
4.4.1 字符输出函数putchar
格式:putchar(字符变量);
功能:把字符变量中的字符输出到显示器。
注意:putchar函数一般作为一个语句来使用。
P71,例4.1。见ex4-1.c。
4.4.2 字符输入函数getchar
格式:getchar( )
功能:从键盘输入一个字符并通过函数名返回这个字符。
注意:getchar函数一般在在表达式中使用。
P72,例4.2。
4.5 格式输入与输出
4.5.1 格式输出函数printf
1. 一般格式
格式:printf(格式控制,输出表列);
功能:按照“格式控制”中的格式要求输出“输出表列”的值。
P72,例。
(1)“格式控制”是一个用双撇号括起来的字符串,它包括两种信息:
①格式说明:由%和格式字符组成,不同的格式字符指明了不同的输出方式。
②普通字符:即要原样输出的字符。
P72,例。
(2)“输出表列”是要输出的一些数据,可以是表达式。
P73,例。
2. 格式字符
(1)d格式符:用来输出十进制整数。
可有四种用法:%d,%md,%ld,%-d。
其中:m表示输出宽度,l表示输出长整数,-表示输出左对齐。
P73,例。
(2)o格式符:用来输出八进制整数。
同样可以附加m,l,- 等。
注意:符号位当成数据输出,不会输出负数。
P74,例。
(3)x格式符:用来输出十六进制整数。
同样可以附加m,l,- 等。
注意:符号位当成数据输出,不会输出负数。
P74,例。
(4)u格式符:用来输出无符号数据。
同样可以附加m,l,- 等。
P74,例4.3。
(5)c格式符:用来输出一个字符。
可以附加m,- 等。
P74,例4.4。
(6)s格式符:用来输出一个字符串。
除了可以附加m,- 外,还可以写成 %m.ns。
其中:m.n表示宽度为m,只输出字符串左边n个字符。
P75,例4.5。
(7)f格式符:用来小数形式输出一个实数。
除了可以附加m,- 外,还可以写成 %m.nf。
其中:m.n表示宽度为m,保留n位小数。
P76,例4.6,例4.7,例4.8。
(8)e格式符:用来指数形式输出一个实数。
除了可以附加m,- 外,还可以写成 %m.nf。
其中:m.n表示宽度为m,小(尾)数部分保留n位小数。
P77,例。
(9)g格式符:用来输出一个实数,形式自动取小数和指数中的较短者。
P77,例。
P77,表4.1。
4.5.2 格式输入函数scanf
1. 一般格式
格式:scanf(格式控制,地址表列);
功能:按照“格式控制”中的格式要求输入数据到“地址表列”的相应变量中。
(1)“格式控制”是一个用双撇号括起来的字符串,它包括两种信息:
①格式说明:由%和格式字符组成,不同的格式字符指明了不同的输入方式。
②普通字符:即要原样输入的字符。
P72,例。
(2)“地址表列”是要输入的变量的地址,一般用地址运算符&求得。
P79,例4.9。
2. 格式字符
scanf函数的格式字符与printf函数类似,但有微小区别。
P80,表4.3,表4.4。
说明:P80,(1)~(4)。
3. 使用scanf函数应请注意的问题
(1)“格式控制”后面是变量的地址,而不是变量。
P81,例。
(2)如果在“格式控制”中有格式说明符外的其它字符,要原样输入。
P81,例。
(3)用%c输入字符时,空格、回车符等都作为有效字符输入。
P82,例。
(4)在输入数据时,遇到空格、回车、跳格、限宽、非法等会结束输入。
P82,例。
4.6 顺序结构程序设计举例
P82,例4.10。见ex4-10.c。
P83,例4.11。见ex4-11.c。
P84,例4.12。见ex4-12.c。
第5章 选择结构程序设计
5.1 关系运算符和关系表达式
5.1.1 关系运算符及其优先次序
(1)运算符:>、>=、<、<=、= =、!=
(2)优先级:①>、>=、<、<= ②= =、!=
低于算术运算,高于赋值运算
(3)结合方向:从左到右
P88,例。
5.1.2 关系表达式
用关系运算符把两个表达式连接起来的式子称为关系表达式。
关系表达式的值为真(1)或假(0)。
P88,例。
5.2 逻辑运算符和逻辑表达式
5.2.1 逻辑运算符及其优先次序
(1)运算符:&&、||、!
(2)优先级:①! ②&& ③||
!与单目+、-同级,&&、||低于关系运算
(3)结合方向:! 从右到左,&&、|| 从左到右
P89,例。
5.2.2 逻辑表达式
用逻辑运算符把两个表达式连接起来的式子称为逻辑表达式。
逻辑表达式的值为真(1)或假(0),判断时非0是真、0是假。
P89,例。
注意:(1)a&&b&&c的判断,a为0则表达式为0,a为1、b为0则表达式为0,a为1、b为1、c为0则表达式为0,否则表达式为1。
(2)a||b||c的判断,a为1则表达式为1,a为0、b为1则表达式为1,a为0、b为0、c为1则表达式为1,否则表达式为0。
P91,例。
5.3 If语句
5.3.1 if语句的三种形式
1. 单分支if语句
格式1:if (表达式) 语句
功能1:如果表达式为真,则执行语句。
P91,例。
2. 双分支if语句
格式2:if (表达式) 语句1
else 语句2
功能2:如果表达式为真,则执行语句1,否则执行语句2。
P92,例。
3. 多分支if语句
格式3:if (表达式1) 语句1
else if (表达式2) 语句2
… …
else if (表达式n) 语句n
else 语句n+1
功能3:如果直到表达式i为真,则执行语句i,否则表达式全为假,则执行语句n+1。
P92,例。
注意:(1)每个语句都是以分号结束的;
(2)if或else后只能一个语句,如有多个语句要用{ }括起来。
P93,例5.1,例5.2。
5.3.2 if语句的嵌套
if语句可以嵌套,原则是else与它最近的if配对,如果在内层嵌套中要使用单分支if语句,要用{ }把它括起来。
P94,例,例5.3。
5.3.3 条件运算符
1 运算符:? :
2 优先级:低于逻辑运算,高于赋值运算
3 结合方向:从右向左
(4) 条件表达式:
格式:表达式1? 表达式2: 表达式3
功能:若表达式1为真,则条件表达式取表达式2,否则取表达式3。
P96,例。
注意:表达式2与表达式3二者的类型取高的。P37。
P98,例,例5.4。
5.4 Switch语句
格式:switch (表达式)
{case 常量表达式1:语句1
case 常量表达式2:语句2
… …
case 常量表达式n:语句n
[default:语句n+1]
}
功能:如果表达式的值等于常量表达式i,则执行语句i及其后面的语句,否则如果都不等,则执行语句n+1。
P99,例。
注意:(1)表达式可以是任何类型的;
(2)常量表达式的值不能相同;
(3)各case和default出现次序无关;
(4)可用break中断执行后续语句;
(5)多个case可共用一组执行语句。
P99,例。
5.5 程序举例
P100,例5.5。见ex5-5-1.c,ex5-5-2.c。
P101,例5.6。
P103,例5.7。见ex5-7。
第6章 循环结构程序设计
6.1 概述
在C语言中,构成循环的语句有4种:
1 用goto和if语句;
2 用while语句;
3 用do-while语句;
4 用for语句。
6.2 goto语句以及用goto语句构成循环
格式:goto 语句标号;
功能:无条件转到语句标号指定的语句中去执行。
注意:(1)语句标号应是合法的标识符,可放在任何语句的前面。
(2)用goto语句构成循环不是一种很好的方法。
P106,例,例6.1。
6.3 while语句
格式:while (表达式)
循环体;
功能:当表达式为真时执行循环体的语句,直到表达式为假时退出循环。
P107,例6.2。
注意:(1)循环体只能一个语句,如有多个语句要用{ }括起来。
(2)循环体内应有使循环趋于结束的语句,否则构成死循环。
(3)循环体可能一次也没执行到,当条件表达式为真时进入循环体,故也称当型循环。
6.4 do-while语句
格式:do
循环体;
while (表达式);
功能:先执行一次循环体,然后当表达式为真时再执行循环体,直到表达式为假时退出循环。
P108,例6.3,例6.4。
注意:(1)循环体只能一个语句,如有多个语句要用{ }括起来。
(2)循环体内应有使循环趋于结束的语句,否则构成死循环。
(3)循环体至少执行一次,直到条件表达式为假时退出循环,故也称直到型循环。
6.5 for语句
格式:for (初值表达式;条件表达式;修正表达式)
循环体;
功能:先执行一次初值表达式,再执行条件表达式,若为真则执行循环体,然后执行修正表达式,再次执行条件表达式进行判断,直到条件表达式为假时退出循环。
P110,例。
注意:(1)循环体只能一个语句,如有多个语句要用{ }括起来。
(2)可以明显看出循环体执行的次数,故也称计数循环。
(3)三个表达式在一定的条件下都可省。
P111,说明(1)~(7)。
6.6 循环的嵌套
四种循环可以互相嵌套,此时外层循环的每一取值,内层循环要转一圈。但是循环嵌套不得交叉进行。
P113,说明(1)~(6)。
6.7 几种循环的比较
4 四种循环可以用来处理同一问题,但一般不用goto循环。
5 while和do-while循环在循环体内应有使循环趋于结束的语句,for可用修正表达式来实现。
6 while和do-while循环在循环前应有初始化的操作,for可用初值表达式来实现。
7 while和do-while及for循环可用break语句跳出循环和用continue语句结束本次循环,而goto循环不可以用。
6.8 break语句和continue语句
6.8.1 break语句
格式:break;
功能:退出switch选择或while、do-while、for循环结构。
P114,例。
6.8.2 contiune语句
格式:contiune;
功能:本次while、do-while、for循环提前结束,进入下次循环。
P115,例。
P115,例6.5。
6.9 程序举例
P116,例6.6。见ex6-6。
P116,例6.7。见ex6-7。
P118,例6.8。
P118,例6.9。见ex6-9。
P119,例6.10。见ex6-10。
第7章 数组
数组是由相同类型的一组数据构成的。前面我们所学的类型都是基本类型,而本章所学的数组是一种构造类型。
7.1 一维数组的定义和引用
7.1.1 一维数组的定义
格式:类型标识符 数组名[常量表达式],…;
其中:数组名是标识符,常量表达式是元素个数。
功能:定义一维数组,其数组名由其“数组名”指定,元素个数由“常量表达式”指定,元素类型由“类型标识符”指定。
P122,例。
注意:(1)C语言中数组的下标从0开始;
(2)常量表达式中可以有符号常量,但不能含有变量;
(3)数组一旦定义,系统为它分配一个连续的存储空间。
7.1.2 一维数组元素的引用
格式:数组名[下标表达式]
功能:引用已定义的数组元素
P123,例,例7.1。
注意:(1)下标可以是表达式。
(2)下标的取值为0~常量表达式-1,超出范围可能有不可预料的后果。
7.1.3 一维数组的初始化
在定义一维数组时,可对数组进行初始化。
方法:在定义数组时在数组名后加上={初始值,初始值,…,初始值}
P123,例。
注意:(1)可对部分元素初始化。
(2)数组有进行初始化时常量表达式可省。
7.1.4 一维数组程序举例
P124,例7.2。
P124,例7.3。见ex7-3.c。
7.2 二维数组的定义和引用
7.2.1 二维数组的定义
格式:类型标识符 数组名[常量表达式][ 常量表达式],…;
功能:定义二维数组,其数组名由其“数组名”指定,每维下标的取值范围由该维的“常量表达式”指定,元素类型由“类型标识符”指定。
P125,例。
注意:(1)多维数组的定义与二维数组类似;
(2)二维数组常用来描述数学中的矩阵;
(3)对于一个m×n的二维数组,二维数组与一维数组元素的对应:
二维中第i,j个元素←→一维中第i×n+j个元素
P126,例。
7.2.2 二维数组的引用
格式:数组名[下标表达式] [下标表达式]
功能:引用已定义的二维数组元素
P126,例。
注意:设a是一个m×n二维数组;则
(1)a[i] (对任意固定的i=0,1,…,m-1)是一个长度为n的一维数组,它的数组名就是a[i],每个元素是a[i][j];
(2)a可认为是一个长度为m一维数组,它的数组名就是a,每个元素是a[i];
(3)由上可知,二维数组可认为是一个元素是一维数组的一维数组。
7.2.3 二维数组的初始化
在定义二维数组时,也可对数组进行初始化。
方法:在定义数组时在数组名后加上={{初始值,…},{初始值,…},…,{初始值,…}}或者加上={初始值,初始值,…,初始值}
P127,例。
注意:(1)可对部分元素初始化;
(2)二维以上数组有进行初始化时第一维的常量表达式可省。
P128,例。
7.2.4 二维数组应用举例
P128,例7.4。
P129,例7.5。见ex7-5.c。
7.3 字符数组和字符串
7.3.1 字符数组
字符数组:元素类型为字符型的数组称为字符数组。
格式:char 数组名[常量表达式],…;
P130,例。
注意:长度为n的字符数组可用来存放n个字符。
7.3.2 字符数组的初始化
与普通数组一样,可对字符数组进行初始化。
方法:在定义数组时在数组名后加上={字符,字符,…,字符}
P130,例。
注意:初始化时元素个数可不写。
7.3.3 字符数组的引用
字符数组的每个元素存放的是一个字符。
格式:数组名[下标表达式]
P131,例7.6,例7.7。
7.3.4 字符串和字符串结束标志
(1)字符串
由若干个字符两边用双撇号括起来的称字符串。
字符串存放时应在尾部加一个\0作为结束标志。
长度为n的字符存储时占用n+1个字节的存储空间。
P131,例。
(2)用字符数组存放字符串
长度为n的字符数组可用来存放一个长度为n-1的字符串。
字符数组可用字符串进行整体初始化,且此时会自动在尾部加一个\0。
P132,例。
7.3.5 字符数组的输入与输出
字符数组输入输出的方法有两种:
(1)逐个元素用scanf和printf函数输入输出
格式:scanf(“%c”,&数组元素);
printf (“%c”,数组元素);
功能:前者从键盘上取得一个字符送给相应的数组元素;
后者把数组元素中的字符输出到显示器上。
P131,例7.6。
(2)整个字符数组用scanf和printf函数输入输出
格式:scanf(“%s”,数组名);
printf (“%s”,数组名);
功能:前者从键盘上取得一个字符串送给相应的数组;
后者把数组中的整个字符串输出到显示器上。
P133,例。
注意:(1)整个字符数组中的字符串输出时,\0本身不输出, 且输出不换行;
(2)整个字符数组中的字符串输出时,是从首地址逐一输出的,直到遇到第一个\0为止;
(3)C语言中数组名表示该数组的首地址,故整个字符数组输入时不能在数组名前加&;
(4)整个字符数组输入时遇空格而停止,且会自动在尾部加一个\0。
P133,例。
7.3.6 字符串处理函数
1. 字符串输出函数puts
格式:puts(字符数组名);
功能:输出字符数组中的字符串。
P135,例。
2. 字符串输入函数gets
格式:gets(字符数组名);
功能:从键盘输入一个字符串到字符数组中。
P135,例。
注意:(1)gets与puts一次只能输入输出一个字符串;
(2)gets输入时不会遇空格而停止,而是遇换行符而停止,也会在尾部自动加上一个\0;
(3)puts输出时也是到\0为止,还会把\0转成换行符输出。
3. 字符串连接函数strcat
格式:strcat(字符串1, 字符串2);
功能:把字符串2的内容连接到字符串1之后,函数返回字符串1。
注意:连接时把第二个字符串的第一个字符覆盖到第一个字符串的\0上
P136,例。
4. 字符串拷贝函数strcpy
格式:strcpy(字符串1,字符串2);
功能:把字符串2的内容拷贝到字符串1中,函数返回字符串1。
注意:(1)拷贝时也是到第一个\0为止,连同\0一起拷贝;
(2)对字符串不可有赋值语句:字符串1=字符串2;
P136,例。
5. 字符串比较函数strcmp
格式:strcmp(字符串1,字符串2);
功能:比较字符串1与的字符串2内容:如果字符串1= =字符串2,则返回0;如果字符串1>字符串2,则返回正整数;如果字符串1<字符串2,则返回负整数。
注意:比较时是以字符的ASCII值进行的。
P137,例。
6. 测字符串长度函数strlen
格式:strlen(字符串)
功能:返回字符串的实际字符数。
注意:(1)测字符串长度包括空格,但不包括\0;
(2)遇到\开头的特殊字符也当一个字符对待。
P138,例。
7. 字符换小写函数strlwr
格式:strlwr(字符串)
功能:把字符串中的大写字母换成小写字母。
8. 字符换大写函数strupr
格式:strupr(字符串)
功能:把字符串中的小写字母换成大写字母。
7.3.7 字符数组应用举例
P138,例7.8。见ex7-8.c。
P140,例7.9。见ex7-9.c。
第8章 函数
8.1 概述
一个C程序是由函数组成的,所以函数是C语言中最重要的概念,本章专门讨论函数的定义、函数的调用及参数传递等问题。
P143,例8.1。
说明:
(1)一个源程序文件是由一个或多个C函数组成的,一个源程序文件是一个编译单位。
(2)一个C程序由一个或多个源程序文件组成,一个源程序文件可以为多个C程序共用。
(3)一个C程序中一定要有一个名为main的主函数,执行时总是从主函数开始,其它函数只有被调用时才会执行,执行完毕返回到调用处继续执行,正常情况下总是在主函数结束执行。
(4)所有的函数是平行的,即在定义时是互相独立的,主函数可以调用其它函数,其它函数之间可以互相调用,但其它函数不能调用主函数。
(5)从用户使用的角度看,函数可分为标准函数(库函数)和用户自定义函数。
(6)从函数的形式看,函数可分为无参函数和有参函数。
8.2 函数定义的一般形式
1. 无参函数的定义形式
格式:函数类型 函数名()
{
数据声明部分;
执行语句部分;
}
说明:(1)函数名:函数名是函数调用的依据,函数值的返回也是通过函数名实现的,函数名要符合标识符的定义。
(2)函数体:由数据声明和执行语句两部分组成,数据声明是对数据特征的描述,执行语句是对数据处理的描述,函数的功能由它们实现。
(3)函数类型:函数类型规定了函数返回值的类型,int或char可不写,如不要返回值可定义为void型。
P144,例。
2. 有参函数的定义形式
格式:函数类型 函数名(形式参数表列)
{
数据声明部分;
执行语句部分;
}
说明:(1)形式参数表列:由格式为“形参类型 形参名”组成的表列,规定了形参的类型及数目。
(2)形参是用来接收或传递函数调用时实参的数据的。
P145,例。
3. 空函数的定义形式
格式:函数类型 函数名()
{ }
说明:(1)空函数什么事情也不做,没有什么实际作用。
(2)编写程序时如果某处要写一个函数,可以先写一个空函数放在那里,等后面再来补写完整,这样做对编程是有益的。
4. 对函数声明的传统方式
格式:函数类型 函数名(形式参数名表列)
形式参数名表列类型说明;
{
数据声明部分;
执行语句部分;
}
P146,例。这种方法现一般不用,只了解一下就可。
8.3 函数参数和函数的值
8.3.1 形式参数和实际参数
函数定义时的参数称为形式参数,函数调用时的参数称为实际参数。形式参数和实际参数负责函数调用时的数据传递。
P146,例8.2。
说明:(1)函数定义中的形式参数,在函数未调用时并不占用存储空间,只有当函数调用时才分配存储空间,函数调用完毕这些存储空间被释放。
(2)实际参数可以是常量、变量或表达式,但它们一般必须有确定的值,函数调用时它们的值被传给形式参数。
(3)实参和形参的类型要相同或赋值兼容。对变量参数而言,实参对形参的数据传递是“值传递”,即数据有传入没传出。
P146,例8.2。
8.3.2 函数的返回值
函数调用后一般通过函数名返回一个值,但有的函数可能不需要返回值。
P146,例8.2。
说明:(1)函数的返回值是由return语句获得的;一个函数如果不需要返回值,可以不用return语句;一个函数也可以有多个return语句,执行到哪一个就那个return语句起作用。
P148,例。
(2)函数的类型指函数返回值的类型,由定义函数时的函数类型来确定。定义函数时return语句后表达式的类型要与函数的类型相一致。
(3)如果定义函数时return语句后表达式的类型与函数的类型不相一致,则以函数的类型为准进行强制类型转换。
P148,例8.3。
(4)如果函数没有return语句,则函数调用后将返回一个不确定的值。为了明确表示不需返回值可把函数定义为void类型。
P149,例。
8.4 函数的调用
8.4.1 函数的一般调用方法
格式:函数名(实际参数表列)
功能:调用函数名指定的函数。
说明:(1)如果函数定义时没有形参,则不要实参,但()不能省。
(2)实参要与形参在数目、类型、次序上一一对应。
(3)Turbo C中实参传递是从右到左进行的。
P150,例8.4。
8.4.2 函数调用的方式
按函数在程序中出现的位置来分,函数有三种调用方式:
1. 函数语句
就是把函数调用作为一个语句,此时函数的返回值无法使用。
P151,例。
2. 函数表达式
就是把函数调用放在一个表达式中,此时函数的返回值参加表达式的运算。
P151,例。
3. 函数参数
就是把函数调用作为另一个函数调用的实参,此时函数的返回值将传给另一个函数的形参。
P151,例。
8.4.3 函数的声明
1. 函数调用的条件
(1)被调用的函数必须是已存在的函数,即要么是库函数要么是已定义好的函数。
(2)如果是库函数,一般要在本文件头用#include命令把有关库函数文件(*.h)包含到本文件中来。
P152,例。
(3)如果是用户自定义函数,函数定义必须在函数调用之前,否则要在函数调用之前进行函数声明。
P152,例8.5。
2. 函数声明的方法
格式:函数类型 函数名(形参类型 形参,…);
功能:声明一个函数,以便在程序中调用。
P152,例8.5。
说明:(1)函数声明就是把函数头重抄一遍(故函数声明也叫函数原型),形参可省或形参及形参类型都省。
P153,例。
(2)函数类型为int的函数调用之前还未定义也可不要声明,但最好还是声明一下。
P146,例8.2。
(3)如果函数定义出现在函数调用之前,则不需要作函数声明。
P154,例。
(4)如果函数声明在所有的函数之前,则不必每个函数中再作声明,每个函数都可以调用这个函数。
P154,例。
8.5 函数的嵌套调用
在C语言中,函数不能嵌套定义,但可以嵌套调用。即主函数可以调用子函数,子函数可以调用子子函数。
P155,图8.5。
P155,例8.6。
说明:P157,(1)~(4)
8.6 函数的递归调用
在C语言中,函数可以调用它本身,函数自己调用自己称为函数的递归调用。递归调用有两种情况:直接递归和间接递归。
P158,图8.9,图8.10。
P158,例8.7。
注意:编写递归程序的关键是写出问题的递归描述。
P160,例8.8。
8.7 数组作为函数参数
1. 数组元素作为函数的参数
数组元素作为函数的参数,其用法与普通变量相同,数组元素可以是一维的也可以是多维的。
P164,例8.10。
说明:数组元素其实与普通变量的性质一样,故数组元素作为函数的参数,其传递是“值传递”。即变量的数据有传入没传出。
2. 一维数组名作为函数的参数
一维数组名也可作为函数的参数,这时实参和形参都是一维数组。
P165,例8.11。
说明:(1)实参数组与形参数组应分别在它们所在函数中定义,但数组名可以不一样。
(2)实参数组与形参数组的类型要一致,否则出错。
(3)形参数组定义中的元素个数不起作用,程序编译时并不对形参数组的元素个数进行检查。
(4)形参数组定义中的元素个数可空,并可另设一个变量形参用来传递数组元素个数。
P166,例8.12。
(5)数组名作为函数的参数,是把实参数组的首地址传给形参数组,即让两个数组共享同一存储空间,其传递是“地址传递”,即对数组而言,其数据有传入也有传出。
P166,例8.13。
3. 多维数组名作为函数的参数
二维数组名也可作为函数的参数,这时实参和形参可以都是二维数组,也可以实参是二维数组而形参是一维数组。
P168,例8.14。
说明:(1)如果二维数组作为形参,其第一维的元素个数可空。
(2)如果二维数组作为实参而一维数组作为形参,则数据按二维数组与一维数组元素的对应关系进行传递。
8.8 局部变量和全局变量
8.8.1 局部变量
在一个函数的内部定义的变量称为局部变量,它从定义时刻开始到本函数结束范围内有效。
P169,例。
说明:(1)主函数内定义的变量也只在主函数内有效。
(2)不同函数可以使用同名的变量,它们互相没有关系。
(3)形式参数也是局部变量。
(4)在一个函数内部中的复合语句可以定义自己的变量,它只在本复合语句内有效。
P169,例。
8.8.1 全局变量
在一个函数的外部定义的变量称为全局(外部)变量,它从定义时刻开始到本文件结束范围内有效。
P170,例。
说明:(1)设全局变量的作用是增加了函数间数据联系的渠道,最好全局变量第一个字母大写。
P170,例8.15。
(2)建议在不必要时不要作用全局变量,因为:①可节省存储空间,②可使程序通用性强,③可使程序可读性强。
(3)如果全局变量与局部变量不同名,则全局变量与局部变量在本函数内均有效,如果全局变量与局部变量同名,则当进入本函数时,全局变量会隐藏起来,局部变量起作用,一旦退出本函数,全局变量恢复原值。
P172,例8.16。
8.9 变量的存储类别
8.9.1 动态存储方式和静态存储方式
静态存储方式:程序运行期间分配固定的存储空间;
动态存储方式:程序运行期间分配动态的存储空间。
程序运行期间用户使用的存储区域称为用户区,C语言中用户区由三部分组成:
①程序区:用于存放用户程序;
②静态存储区:用于存放需要固定存储空间的数据;
③动态存储区:用于存放随时可能建立或撤消的数据。
P173,例。
8.9.2 自动(auto)变量
定义:在函数内部定义的前加auto或省缺的变量。
特征:放在动态存区,定义变量时建立,退出本函数时撤消。
P173,例。
说明:(1)自动变量是局部变量
(2)自动变量在赋值前其值是不确定的。
(3)在函数多次被调用的过程中,自动变量的值是不保留的。
8.9.3 局部静态(static)变量
定义:在函数内部定义的前加static的变量。
特征:放在静态存区,程序编译时创建,结束执行时撤消。
P173,例8.17。
说明:(1)静态变量的存储空间在整个程序运行期间是固定的。
(2)静态变量的初始化是在程序编译时进行的,未显式初始化时自动赋0或空串。
(3)在函数多次被调用的过程中,静态变量的值具有继承性。
(4)局部静态变量只能在本函数中使用。
P175,例8.18。
8.9.4 寄存器(register)变量
定义:在函数内部定义的前加register的变量。
特征:放在寄存器,定义变量时建立,退出本函数时撤消。
P175,例8.19。
说明:(1)只有局部自动变量和形式参数可以作为寄存器变量。
(2)寄存器变量与自动变量性质一样,但速度快、数量有限。
(3)局部静态变量不能定义为寄存器变量。
P176,例。
8.9.5 外部变量及其扩展(extern)
定义:定义在所有函数之外的变量称为外部变量。
特征:(1)放在静态存区,程序编译时创建,结束执行时撤消。
(2)外部变量可以用extern来扩展它的作用域。
1. 作用域扩充到本文件内
方法:在本文件要用的地方之前使用extern重声明。
P176,例8.20。
2. 作用域扩充到其它文件
方法:在其它文件要用的地方之前使用extern重声明。
P176,例8.21。
注意:含有多个文件的C程序的执行见P183,8.11如何运行一个多文件的程序。
8.9.6 外部静态(static)变量
定义:在函数外部定义的前加static的变量。
特征:放在静态存区,程序编译时创建,结束执行时撤消。
P178,例。
说明:(1)外部静态变量具有静态变量的所有性质;
(2)外部静态变量只能在本文件中使用,而不能被其它文件引用。
8.9.7 关于变量的声明和定义
在C语言中,定义和声明两个词是混淆的,实际上,我们可把声明分为定义性声明和引用性声明。
定义性声明(简称定义):是要分配存储空间的。如int a;
引用性声明(简称声明):是不要分配存储空间的。如extern a;
P179,例。
说明:一个变量定义只能一次,声明可以多次。
8.9.8 存储类别小结
可从不同的角度来分类归纳:
(1)作用域:可分为全局的和局部的。
(2)存放时间:可分为动态存储和静态存储。
(3)存放位置:可分为动态存区、静态存区和寄存器。
P180,小结。
说明:(1)作用域、存放时间、存放位置是不同的概念,它们有区别也有联系。
(2)static对局部变量和全局变量的作用不同。
P181,例。
8.10 内部函数和外部函数
8.10.1 内部函数
定义:在函数定义前加static的函数,称为内部函数或静态函数。
说明:内部函数只能在本文件中被调用,而不能被其它文件调用。
P182,例。
8.10.1 外部函数
定义:在函数定义前加extern或省缺的函数,称为外部函数。
说明:外部函数可以在其它文件中被调用,使用前要用extern重声明。
P177,例8.21。见ex8-21。
P182,例8.22。
8.11 如何运行一个多文件的程序
C程序可以由多个文件组成,由多个文件组成的C程序可有两种编译运行方法:
1. 用Turbo C的集成环境
多个文件组成的C程序执行的步骤为:
4 先把多个文件的内容编辑并存盘为file1.c,file2.c,…,filen.c
5 在编辑状态下建立一个项目文件,内容为:file1.c file2.c …filen.c,并存盘为:file.prj
6 把Project菜单的子菜单project neme的值修改为:file.prj
7 打编译执行的命令Ctrl+F9,并用Alt+F5查看结果。
P177,例8.21。见ex8-21-1.c,ex8-21-2.c,ex8-21.prj。
P184,例8.22。
注意:项目文件的内容中文件之间用空格隔开,扩展名.c可省,也可以写成一列。
2. 用#include命令
多个文件组成的C程序执行的步骤为:
4 先把多个文件的内容编辑并存盘为file1.c,file2.c,…,filen.c
5 设file1.c中含有main函数,则在file1.c的开头加入如下#include命令:#include “file2.c”
… … …
#include “filen.c”
8 打编译执行的命令Ctrl+F9,并用Alt+F5查看结果。
P185,例8.22。
注意:此时实际上编译程序不再认为是多个文件,而是用#include命令把其它文件包含到本文件中来一起进行编译。
第9章 预处理命令
C程序中可以加入一些预处理命令,其目的是改进程序设计环境,提高编程效率。这类命令主要包括:宏定义、文件包含和条件编译三种,为了区别一般的C语句,这类命令都以#开头。
9.1 宏定义
9.1.1 不带参数的宏定义
格式:#define 宏名 宏体
其中:宏名是一个标识符,宏体是一个表达式字符串。
功能:程序编译时,用宏体代替宏名。
P187,例,例9.1。
说明:P188,(1)~(9)
P188,例,例9.2。
9.1.2 带参数的宏定义
格式:#define 宏名(形参表) 宏体
其中:宏名是一个标识符,宏体是一个带有形参的表达式字符串。
功能:程序编译时,用实参代替形参,再用宏体代替宏名(形参表)。
P190,例,例9.3。
说明:P190,(1)~(2)
9.1.3 带参数的宏与函数的区别
P191,(1)~(6)
P191,例9.4,例9.5。
9.2 文件包含处理
格式1:#include “文件名”
格式2:#include <文件名>
其中:文件名一般是 *.h 的函数库文件,也可以是 *.c 的源程序文件,且可带盘符路径。
功能:把文件名指定的文件内容包含到当前文件中来。
注意:使用格式1时,编译程序先在当前目录上找指定文件,如没找到就到系统规定的目录上找找指定文件。使用格式2时,编译程序只在系统规定的目录上找找指定文件。
P195,例9.6。
说明:P196,(1)~(5)。
9.3 条件编译
条件编译是指某些程序段一定的条件下参加编译或不参加编译,有关条件编译的预处理命令有三种格式:
1 #ifdef格式
格式:#ifdef 标识符
程序段1
[#else
程序段2]
#endif
功能:如果标识符用#define命令定义过,则编译程序段1,否则编译程序段2。
P197,例。
2 #ifndef格式
格式:#ifndef 标识符
程序段1
[#else
程序段2]
#endif
功能:如果标识符未用#define命令定义过,则编译程序段1,否则编译程序段2。
P198,例。
3 #if格式
格式:#if 表达式
程序段1
[#else
程序段2]
#endif
功能:如果表达式的值为真,则编译程序段1,否则编译程序段2。
P198,例。
半期考试
试卷讲评
第10章 指第11章 针
指针是C语言中一个最重要而又较难掌握的一个概念,也是C语言优于其它高级语言的关键所在。掌握指针的应用,可以使程序简洁、紧凑、高效。
10.1 地址和指10.2 针概述
1. 地址与地址运算
地址:计算机中存储单元的编号称为地址。在内存中每一个字节都有地址,一个存储区域的地址是这个区域的第一个字节的地址。
地址运算符&:求出变量所占用存储区域的地址
P201,例。
注意:(1)地址运算符是单目运算,与单目+、-相同;
(2)结合方向同:从右到左。
2. 指针与指针变量
指针:一个存储区域的地址称为指针。
指针变量:用来存放存储区域的地址的变量称为指针变量。
P202,例。
注意:(1)变量的值可以通过变量直接访问,也可通过指针变量间接访问;
(2)指针变量只能用来存放地址,不能存放其它类型数据。
10.3 变量的指10.4 针和指10.5 向变量的指10.6 针变量
1. 变量的指针和指向变量的指针变量
指向变量的指针:一个变量的地址称为指向该变量的指针。
指向变量的指针变量:用来存放变量的地址的变量称为指向该变量的指针变量。
例:int a;则&a就是指向a的指针;若p为指针变量,且p=&a;则p是指向a的指针变量。
2. 指针运算符
指针运算符*:求出指针变量所指向存储区域的值或所指向变量的值
例:int a;若p为指针变量,且p=&a;则*p是p指向的存储区域的值,即*p的值就是a的值。
注意:(1)指针运算符是单目运算,与单目+、-相同;
(2)结合方向同:从右到左。
P203,例。
10.2.1 指针变量的定义
1. 指针变量的定义
格式:类型名 *指针变量名,…;
功能:定义指向类型名变量的指针变量。
例:int *p;定义一个指向整形变量的指针p。
P203,例。
2. 指针变量的赋值
格式:指针变量=&变量;
功能:把=号右边变量的地址赋给=号左边的指针变量。
P203,例。
注意:(1)指针变量赋值后的图表示。
(2)指向不同类型的指针不能互相赋值。
(3)加了#include “stdio.h”后,指针变量可赋值为NULL。
10.2.2 指针变量的引用
指针变量的引用主要用到地址运算符&和指针运算符*。
P204,例10.1。见ex10-1.c。
说明:P204,(1)~(4).
注意:(1)若p=&a;则&*p为a的地址,即&a。P205。
(2)若p=&a;则*&a为a的值,即就是a。
(3)(*p)++与a++等价,因*与++同级,又结合方向为从右向左,故在此()不可省,否则变为*(p++)。若i=3;p=&i;则这两个表达式的值都为3,但执行后前者p仍指向i,且i的值会加1,后者p指向i的后一个区域,i的值未加1。见ex205.c。
P206,例10.2。
说明:此例中p1,p2的指向进行变换,而a,b的值并未交换。
10.2.3 指针作为函数参数
用指针作为函数的参数,可以实现“通过被调函数改变主调函数中变量的值”的目的。
P207,例10.3。
说明:此例中p1,p2的指向并未进行变换,而它们指向的值进行了交换。
注意:(1)用指针作为函数的参数,就其指针变量而言仍然是有传入没传出,但它传送的是地址,故这时是传址调用,即对指针所指向的值是有传入也有传出,故改变指针指向的值可以实现上述目的。
(2)用指针作为函数的参数,不能通过改变形参指针的值来达到“改变主调函数中变量的值”的目的。P209。
P210,例10.4。
10.7 数组与指10.8 针
10.3.1 指向数组元素的指针
设a为元素个数为n的一维数组,p为指向数组a的元素类型的指针,如果p=a或p=&a[0],即p指向a[0],则p+i指向a[i],此时可把a[i]写成p[i]。
P211,例。
注意:(1)一维数组名a表示数组a的首地址,即a[0]的地址,故a与&a[0]等价。
(2)一维数组a的第i个元素a[i]的地址可以用a+i表示,故a+i与&a[i]等价。
10.3.2 通过指针引用数组元素
设a为元素个数为n的一维数组,p为指向数组a的元素类型的指针,如果p=a或p=&a[0],则数组a的第i个元素有两种表示法:
a[i] 或p[i] 下标表示法
*(a+i)或*(p+i) 地址表示法
P212,例。
P212,例10.5。见ex10-5-1.c,ex10-5-2.c,ex10-5-3.c。
说明:三种方法比较,P213,(1)~(3)
注意:(1)可以改变p的值,但不能改变a的值;
(2)要注意指针的当前值。P214,例10.6。
(3)指针值超出数组范围时系统不提示出错。
(4)要注意指针变量的运算。P215①~⑤。
10.3.3 用数组名作为函数参数
在函数的参数中,实参与形参可以都是数组,也可以都是指针,还可以一个是数组一个是指针。
P216,例,P221,(1)~(4)。
P217,例10.7。见ex10-7-1.c,ex10-7-2.c。
P219,例10.8。
注意:(1)用指针和数组作为参数,它们传送的是地址,故是传址调用,它们所指向的数组的值是有传入也有传出的。
(2)当数组作为形式参数时,数组名不再是常量,与指针意义相同。
P217,例。
P222,例10.9。见ex10-9-1.c,ex10-9-2.c。
P223,例10.10。
10.3.4 多维数组与指针
1. 多维数组元素的地址
设a为元素个数为m×n的二维数组,则a+i表示第i行a[i]的地址,*(a+i)+j表示第i行第j个元素a[i][j]的地址,于是数组a的第i,j个元素有三种表示法:
a[i][j] 下标表示法
*(a[i]+j) 下标地址表示法
*(*(a+i)+j) 二级地址表示法
P225,例。
P227,例10.11。
注意:(1)二维数组名a表示数组a的第0行的地址,即a[0]的地址,故a与&a[0]等价。
(2)二维数组a的第i个元素a[i]表示第i行第0个元素的地址,即a[i][0]的地址,故a[i]与& a[i][0]等价。
2. 指向多维数组元素的指针变量
(1)指向数组元素的指针
设a为元素个数为m×n的二维数组,p为指向a的元素类型的指针,如果p=a[0],即p指向a[0][0],则p+i×n+j指向a[i][j]。
P228,例10.12。
(2)指向一维数组的指针
指向一维数组的指针称为数组指针。
格式:类型名 (*数组指针名)[常量表达式],…;
功能:定义指向元素个数为常量表达式的一维数组的指针。
注意:数组指针用来存放一维数组的首地址;
P229,例10.13。
(3)数组指针与二维数组的行
数组指针可用来指向二维数组的行,故也称行指针。
设a为元素个数为m×n的二维数组,p为指向元素个数为n的一维数组的指针,如果p=a,即p指向a[0],则p+i指向a[i],* (p+i)+j指向a[i][j]。
P229,例10.13。
3. 用指向数组的指针作为函数的参数
普通指针作为函数的参数,因为可以让p+i指向a[i](一维数组元素),故可以用来传递一维数组元素的地址;同样的道理,指向数组的指针作为函数的参数,因为可以让p+i指向a[i](二维数组的行),故可以用来传递二维数组的行地址。
P230,例10.14。
P231,例10.15。
10.9 字符串与指10.10 针
10.4.1 字符串的表示形式
在C语言中,字符串有两种表示形式。
1 用字符数组存放一个字符串;
2 用字符指针指向一个字符串。
P232,例10.16,例10.17。
注意:(1)字符数组占有固定的存储空间,字符数组名是常量,故不能赋值、不能自增减。
(2)字符指针只是用来存放字符串的首地址,字符指针是变量,故可以赋值、可以自增减。
P234,例10.18,例10.19。
10.4.2 字符串指针作为函数的参数
把字符串从一个函数传递到另一个函数,可有两种方法。
1 用存放一个字符串的字符数组;
2 用指向一个字符串的字符指针。
P235,例10.20。
解法:(1)用字符数组作为形参,P235。
(2)用字符指针作为形参,P236。
(3)对copy_string函数的简化,P237,①~⑥。
10.4.3 对使用字符指针和字符数组的讨论
(1)字符数组存放的是若干个字符,字符指针存放的是字符串的首地址。
(2)字符数组不能对数组名赋值,字符指针可以对指针名赋值。P238。
(3)字符数组和字符指针都可以初始化。P239。
(4)字符数组定义后有分配存储空间存放字符串,字符指针只分配一个单元存放字符地址(字符串的首地址)。P239。
(5)字符数组名不能增值,字符指针名可以增值。P240,例10.21,例10.22。
(6)当字符数组存放一个字符串或字符指针指向一个字符串时,可用作printf语句的格式控制。P240。
10.11 指10.12 向函数的指10.13 针
10.5.1 用函数指针调用函数
一个函数是一个指令的序列,函数执行时是从第一条指令开始直到最后一条指令结束,第一条指令的地址称为函数的入口地址,函数名代表这个函数的入口地址。用来存放函数入口地址的指针称为指向函数的指针,简称函数指针。
(1)指向函数的指针定义
格式:类型名 (*函数指针变量名)( );
功能:定义一个指向函数的指针。
P241,例。
(2)指向函数的指针的赋值和引用
格式:函数指针变量=函数名;
(*函数指针变量)(实参,…)
功能:前者是把函数的入口地址赋给指向函数的指针,后者是用指向函数的指针调用该函数。于是函数的调用方法有两种:
函数名(实参,…) 用函数名调用
(*函数指针变量)(实参,…) 用函数指针调用
P242,例。
P241,例10.23。
注意:(1)用函数指针调用函数,必须先给函数指针赋函数名;
(2)函数指针虽然是变量,但p+n、p++、p--等无意义。
10.5.2 用函数指针作为函数的参数
有了函数指针,可以用一个语句调用不同的函数;用函数指针作为函数的参数,可以把不同的函数传递到同一个子函数。因此函数指针可以简化多个函数的调用。
P243,例。
P243,例10.24。
10.14 返回指10.15 针值的函数
一个函数的返回值可以是指针类型的,这样的函数称为返回指针值的函数,简称指针函数。
格式:函数类型 *函数名(形式参数表列)
{
数据声明部分;
执行语句部分;
}
功能:定义一个指向类型名的指针函数。
P246,例10.25。
P247,例10.26。
注意:字符串运算函数strcat、strcpy等都是返回指针的函数。
P136。
10.16 指10.17 针数组和指10.18 向指10.19 针的指10.20 针
10.7.1 指针数组的概念
数组的元素为指针类型的数组称为指针数组。
格式:类型名 *指针数组名[常量表达式],…;
功能:定义指向类型名的指针数组。
注意:(1)指向字符型的指针数组称为字符指针数组;
(2)m×n的二维字符数组可以用来存放m个长度为n-1的字符串;
元素个数为m的字符指针数组可用来指向m个随意长度的字符串。
P249,例。
P249,例10.27。
10.7.2 指向指针的指针
(1)二级指针与多级指针
指向指针的指针称为二级指针。
格式:类型名 **指针变量名,…;
功能:定义二级指针。
P251,例。
注意:同理可以定义多级指针。
(2)二级指针与多级指针的引用
设p为二级指针,则*p为一级指针,**p为所指类型的变量。
P251,例。
注意:不同级别的指针不能互相赋值。
P252,例10.28。
P252,例10.29。
*10.7.3 指针数组作为main的形参
(1)main函数的参数
main函数一般是不带参数的,因为没有函数可以调用main函数。但main函数实际上也是可以带参数的,一般格式为:
main(int argc,char *argv[])
其中:形参argc是一个整型变量,形参argv是一个字符指针数组。
(2)DOS下执行程序的命令行
C源程序*.c被编译连接后生成可执行程序*.exe,可以DOS下通过命令行执行该程序。命令行的一般格式为:
可执行程序名 参数 参数 …↙
其中:可执行程序名、参数、参数等都是字符串,↙表示回车符。
P253,例。
(3)命令行与源程序的参数传递
当用户键入命令行执行时,字符串:可执行程序名、参数、参数、…将传送给argv[0]、argv[1]、argv[2]、…。Argc将取得命令行中字符串的个数。
P254,例。
10.21 有关指10.22 针的数据类型和指10.23 针运算小结
10.8.1 有关指针的数据类型小结
涉及到指针的类型主要有:
变量,一级指针,一维数组,指针数组,数组指针,函数,指针函数,函数指针,二级指针等。
P255,表10.2。
10.8.2 指针运算小结
(1)指针与整数相加减
设指针p是指向某类型的,这个类型占用c个字节,i为整数,则
1 p++,2 p--,3 p+i,4 p-i,5 p+=i,6 p-=i等都是合法的;
7 p+i的值(地址)=p的值(地址)+i×c
P256,例。
(2)指针变量的赋值
可以给指针变量赋值的有:
1 相应类型变量的地址值;
2 一维数组名或其元素的地址值;
3 函数的入口地址;
4 相应类型指针变量。
P256,例。
(3)指针变量可以有空值
空指针值用NULL表示,它是一个符号常量,它在stdio.h中,可以把它赋给指针变量,这时表示指针变量有确定值但没有指向任何有用单元。
P256,例。
注意:定义了指针变量还末赋值前它是一个不确定的地址值,不是空指针值。
(4)两个指针的相减
指向同一数组元素的两个指针可以相减,其值为两个指针所指元素之间的元素个数。
P257,例。
(5)两个指针的比较
指向同一数组元素的两个指针可以比较大小,其大小取决于所指向元素的序号,相等表示它们指向同一元素。
P257,例。
10.8.3 void指针类型
指向void(空)类型的指针只能用来存放一个地址,但这个地址不与任何类型挂钩。不同类型的指针之间不能相互赋值,但可强制转换后进行赋值。
P257,例。
第12章 结构体与共用体
11.1 结构体类型概述
结构体是由不同类型的一组数据构成的。与数组比较,数组是由相同类型的一组数据构成的。结构体与数组都是一种构造类型。
结构体类型的定义:
格式:struct 结构体类型名
{类型名 成员名;
… …
};
其中:类型名 成员名;… … 称为“成员表列”。
功能:定义一个结构体类型。
P260,例。
注意:这是我们所见的第一个用户自定义类型,以前我们学过的类型全是C系统预定义的。数组类型虽然也是构造类型,但不需用户自定义类型。
11.2 定义结构体类型变量的方法
定义了结构体类型后,就可以用它来定义结构体类型的变量。结构体类型变量的定义方法有三种:
1. 分步定义
格式:struct 结构体类型名 结构体变量名,…;
其中:结构体类型名是事先已定义的。
功能:用已定义的结构体类型定义结构体变量。
P261,例。
2. 同时定义
格式:struct 结构体类型名
{类型名 成员名;
… …
}结构体变量名,…;
其中:结构体类型名事先是未定义的。
功能:同时定义结构体类型与结构体变量。
P262,例。
3. 直接定义
格式:struct
{类型名 成员名;
… …
}结构体变量名,…;
其中:结构体类型被定义但并未取名。
功能:直接定义结构体变量。
P262,例。
说明:
(1)定义一个结构体类型,系统并未为它分配存储空间。用结构体类型定义变量后才为变量分配存储空间,其空间大小等于各成员所占空间之和。P261,例。
(2)结构体类型中的成员相当于普通变量,但它们与普通变量属于不同的层次,故成员与程序中的普通变量可以同名。P262,例。
(3)成员也可以是结构体变量,即结构体类型可以嵌套。P262,例。
(4)系统没有预定义结构体类型,要用结构体类型,必须先定义后使用。
P261,例。
11.3 结构体变量的引用
定义了结构体变量后,我们可以引用结构体变量及其成员,引用结构体变量的成员格式为:
格式:结构体变量.成员名
功能:引用结构体变量的一个成员
说明:(1)“.”称为成员运算符,其优先级最高,与( )相同。
(2)“结构体变量.成员名”的类型与结构体类型定义时的成员名类型相同。
P263,例。
引用规则:
(1)结构体变量不能整体输入与输出,必须要用成员引用的方法来进行。P263,例。
(2)如果成员本身又属于一个结构体类型,则要用多个成员运算符,一级一级地找到最低一级的成员。P263,例。
(3)结构体变量的成员可象普通变量一样进行各种运算。P264,例。
(4)可以引用结构体变量成员的地址,也可以引用结构体变量的地址。
P264,例。
(5)两个相同类型的结构体变量可以整体赋值,但结构体变量不能整体赋给一组常量。P262,例。
11.4 结构体变量的初始化
在定义结构体变量时,可对结构体变量进行初始化。
方法:在定义结构体变量时加上={初始值,初始值,…,初始值}
P264,例11.1。
注意:(1)结构体变量不能整体赋给一组常量。
(2)两个相同类型的数组不可以整体赋值。
11.5 结构体数组
每个元素为结构体类型的数组称为结构体数组。
11.5.1 结构体数组的定义
与定义普通数组一样,定义结构体数组只要在定义变量的后面加[常量表达式]即可。如int a; 是定义整型变量a;
int a[5]; 是定义整型数组a;
因为定义结构体变量的方法有三种,故定义结构体数组的方法也有三种:
(1)分步定义
(2)同时定义
(3)直接定义
P265,例。
11.5.2 结构体数组的初始化
在定义结构体数组时,可对结构体数组进行初始化。
方法:在定义结构体数组时加上={{初始值,…},…,{初始值,…}}
P266,例。
11.5.3 结构体数组的应用举例
P266,例11.2。
说明:(1)引用结构体数组某一元素的成员要写成:结构体数组[i].成员名;
(2)注意leader[j].count++的运算次序。
11.6 指11.7 向结构体类型数据的指11.8 针
11.6.1 指向结构体变量的指针
用来存放结构体变量的地址的指针称为结构体指针。
1. 结构体指针的定义
与定义普通指针一样,定义结构体指针只要在定义变量的前面加个*即可。如 int a; 是定义整型变量a;
int *a; 是定义整型指针a;
因为定义结构体变量的方法有三种,故定义结构体指针的方法也有三种:
(1)分步定义
(2)同时定义
(3)直接定义
P268,例11.3。
2. 结构体指针的引用
定义了结构体指针p后,可以用来存放结构体变量s的地址,即p=&s;这时,设s有成员num,则结构体变量的成员有三种等价的表示法:
1 s.num
2 (*p).num
3 p->num
P268,例11.3。
注意:“->”称为指向运算符,优先级最高,与( )相同。
P269,例。
11.6.2 指向结构体数组元素的指针
结构体指针可以用来存放结构体数组的首地址或数组元素的地址。
设p为结构体指针,stu为结构体数组,且p=stu或p=&stu[0],则p++指向结构体数组stu的下一个元素。于是其下个元素的成员num可表示为:(*p). num或p->num。
P269,例11.4。
注意:(1)(++p)->num与(p++)->num的含义;
(2)p不能用来存放结构体数组元素成员的地址,但可强制转换。
P270,例。
11.9 用指11.10 针处理链表
11.7.1 链表概述
链表的定义:
4 有一个首指针,指向第一个结点;
5 每个结点有一个或多个数据成员和一个指针成员,指针成员指向下一个结点;
6 末结点指针成员的值为NULL。
P273,图11.10。
注意:(1)链表是一种常见的数据结构,如一个班的学生成绩可用链表来存放,一个程序(指令的有序集)在计算机内也是用链表的方式来存放的;
(2)链表结构可以是动态地分配存储空间的,即结点是可以动态的建立或删除的;
(3)链表的一个结点是一个结构体类型的存储空间,可用结构体类型来描述。
P273,例。
11.7.2 简单链表
建立和输出一个简单链表的步骤:
2 定义一个含有数据成员和指针成员的结构体类型;
3 用这个结构体类型定义若干个变量(即开创若干个结点空间)和一个首指针及一个遍历指针;
4 对这些变量的数据成员输入数据,并用首指针和这些这些变量的指针成员把结点连接成一个链表;
5 用遍历指针遍历所有的结点,输出各结点数据成员的值。
P274,例11.7。见ex11-7.c。
注意:用这种方法建立链表还不是动态分配存储空间的,因为需要几个结点必须事先用变量来定义,故称为静态链表。
11.7.3 处理动态链表所需的函数
建立动态链表需要如下几个库函数:
1. malloc函数
原型:void *malloc(unsigned size);
功能:在内存开辟一个大小为为size个字节的存储空间,并返回这个存储空间的首地址。
例:int *p;
p=(int *)malloc(2);
2. calloc函数
原型:void *calloc(unsigned n,unsigned size);
功能:在内存开辟n个大小为为size个字节的存储空间,并返回这个存储总空间的首地址。
例:int *p;
p=(int *)calloc(5,2);
通过p++可以遍历这5个大小为两个字节的存储空间。
3. free函数
原型:void free(void *p);
功能:释放由malloc或calloc开辟的且由p指向的存储空间,本函数无返回值。
例:int *p;
p=(int *)malloc(2);
free(p);
11.7.4 建立动态链表
建立一个动态链表的步骤:
4 用结构体类型定义一个首指针、一个开辟指针和一个末指针;
5 用开辟指针和malloc函数开辟一个结点,并对这个结点的数据成员输入数据;
6 当这个结点的数据成员的值不为0,则用首指针或前一结点的指针成员指向它,并让末指针也指向它;
7 用开辟指针和malloc函数开辟一个新结点,并对这个结点的数据成员输入数据,回到(3);
8 置末结点的指针成员值为NULL。
P276,例11.8。见ex11-8.c。
注意:用这种方法建立链表是动态分配存储空间的,因为需要几个结点事先并未确定,故称为动态链表。
11.7.5 输出动态链表
输出一个动态链表的步骤:
2 用结构体类型定义一个遍历指针;
3 用遍历指针遍历所有的结点,输出各结点数据成员的值。
P279,例11.9。见ex11-8.c。
11.7.6 动态链表的删除结点
动态链表删除结点的步骤:
3 用结构体类型定义一个搜索指针和一个跟踪指针;
4 用搜索指针遍历所有的结点,目的是查找要删除的结点,并用跟踪指针跟踪搜索指针指向结点的前一个结点;
5 如果搜索指针找到要删除的结点,则让跟踪指针所指结点的指针成员指向搜索指针所指结点的后一结点(即删除了搜索指针所指的结点)。
P280,例11.10。见ex11-8.c。
11.7.7 动态链表的插入结点
动态链表插入结点的步骤:
4 用结构体类型定义一个插入指针、一个搜索指针和一个跟踪指针;
5 用搜索指针遍历所有的结点,目的是查找要插入的位置,并用跟踪指针跟踪搜索指针所指结点的前一个结点;
6 如果搜索指针找到要(前)插入结点的位置,则让跟踪指针所指结点的指针成员指向插入指针所指的结点,让插入指针所指结点的指针成员指向搜索指针所指的结点(即在搜索指针所指结点之前插入新结点)。
P282,例11.11。见ex11-8.c。
11.7.8 动态链表的综合操作
动态链表的综合操作步骤:
2 在所有函数外定义一个含有数据成员和指针成员的结构体类型;
3 在主函数中定义一个首指针,一个删除数据变量和一个插入结点;
4 调用建立链表、输出链表进行链表的建立与输出的操作;
5 输入必要的数据,调用删除结点、插入结点的子函数进行删除与插入的操作,并输出操作之后的链表。
P284,例。见ex11-8.c。
11.11 共用体
11.8.1 共用体类型的概念
共用体类型一种与结构体类型有点类似的构造类型。
格式:union 共用体类型名
{类型名 成员名;
… …
};
其中:类型名 成员名;… … 称为“成员表列”。
功能:定义一个共用体类型。
与结构体类型类似,共用体类型变量的定义有三种:(1)分步定义,(2)同时定义,(3)直接定义。
P287,例。
结构体与共用体的区别:
(1)结构体每个成员占用不同的存储空间,故结构体变量占用的存储空间是各成员占用空间的总和。
(2)共用体每个成员占用相同的存储空间,故共用体变量占用的存储空间是各成员占用空间的最大者。
P288,例。
11.8.2 共用体变量的引用
格式:共用体变量.成员名
功能:引用共用体变量的一个成员
说明:可见形式上引用方法与结构体相同。
P288,例。
11.8.3 共用体类型数据的特点
(1)每一瞬时只有一个成员起作用,其它成员不起作用。
(2)起作用的成员是最后一次存放的成员,其它成员的值无意义。
(3)各成员的地址是相同的。
(4)不能对共用体变量赋值,也不能进行初始化。
(5)不能把共用体变量作为函数的参数,但可以用指向共用体变量的指针。
(6)定义共用体与结构体类型时可以互相嵌套。
P289,例。
P289,例11.12。
11.12 枚举类型
枚举类型是可以把变量的可能值一一列出的一种构造类型。
格式:enum 枚举类型名
{枚举值,…,枚举值};
功能:定义一个枚举类型。
枚举类型变量的定义也有三种:(1)分步定义,(2)同时定义,(3)直接定义。
P291,例。
定义了枚举型变量后,可以使用枚举型变量,但它的取值只可能是这些枚举值之一。
说明:
3 枚举值是常量,不能对枚举值赋值。
4 枚举值的值就是定义它时的序号(从0开始,按次序递增),定义时也可改变枚举值的值。
5 枚举值可以作关系运算,大小取决于它的序号。
6 枚举变量不能直接赋给一个整数,但可强制转换后进行赋值。
P291,例。
P292,例11.13。
11.13 用typedef定义类型
用typedef可以定义新的类型名,主要有如下几种情况:
(1)简单的类型名替换
格式:typedef 原类型名 新类型名
P294,例。
(2)定义一个类型名代表一个结构体类型
格式:typedef strut
{成员列表;
}类型名;
P294,例。
(3)定义一个类型名代表某一个数据类型
格式:typedef 数组元素类型 类型名[元素个数];
typedef 指针指向类型 *类型名;
typedef 函数返回类型 (*类型名)( );
P295,例。
定义新类型名方法步骤小结:
1 先按定义变量的方法写出定义体;
2 将变量名换成新类型名;
3 在最前面加上typedef;
4 然后用可以用新类型名去定义变量。
P295,例。
第13章 位运算
可以进行位运算是C语言的重要特色,因此,C语言具有高级语言的特点,又具有低级语言的功能。
12.1 位运算符和位运算
位运算符共有6个,见P298表12.1。
说明:(1)~是单目运算,其它是双目运算。
(2)运算量只能是整型或字符型。
(3)优先级:① ~ ②<<,>>③ & ④ ^ ⑤ |
12.1.1 按位与运算&
运算规则:0&0=0,0&1=0,1&0=0,1&1=1。
P298,例。
按位与运算的用途:
(1)指定位清0:用一个原数指定位上为0的数进行按位与运算。
(2)取指定位:用一个原数指定位上为1的数进行按位与运算。
(3)保留指定位:与取指定位相同。
P299,例。
12.1.2 按位或运算|
运算规则:0|0=0,0|1=1,1|0=1,1|1=1。
P299,例。
按位或运算的用途:
(1)指定位置1:用一个原数指定位上为1的数进行按位或运算。
P300,例。
12.1.3 按位异或运算^
运算规则:0^0=0,0^1=1,1^0=1,1^1=0。
P300,例。
按位异或运算的用途:
(1)指定位翻转:用一个原数指定位上为1的数进行按位异或运算。
(2)保留指定位:用一个原数指定位上为0的数进行按位异或运算。
(3)交换两个值:只要执行a=a^b;b=b^a;a=a^b;则a,b值交换。
P300,例。
12.1.4 按位反运算~
运算规则:~0=1,~1=0。
P301,例。
按位反运算的用途:
(1)最低位清0:只要执行a=a&~1;则a的最低位被清0。
P301,例。
12.1.5 按位左移运算<<
运算规则:低位补0,高位丢失。
P302,例。
按位反运算的用途:
(1)在不溢出的情况下,左移n位,相当于原数乘以2n。
P302,例。
12.1.6 按位右移运算>>
运算规则:(1)无符号数,高位补0,低位丢失;
(2)有符号数,补与高位相同的数,低位丢失。
P302,例。
按位反运算的用途:
(1)右移n位,相当于原数除以2n。
P303,例。
12.1.7 位运算赋值
位运算赋值符有:
&=、|=、>>=、<<=、^=
其意义与“+=”等类似,也是复合赋值运算符。
P303,例。
12.1.8 不同长度的位运算
运算规则:(1)无符号数,较短的高位补0,再参与运算;
(2)有符号数,较短的补与高位相同的数,再参与运算。
P303,例。
12.2 位运算应用举例
P303,例12.1。见ex12-1.c。
P304,例12.2。
12.3 位段
1. 位段的定义
位段是由若干个位组成的,C语言充许对由若干个位组成的位段进行存取操作。位段用类似于结构体成员的方式来描述,定义格式如下:
格式:struct 结构体类型名
{类型名 成员名:位数;
… …
};
其中:“类型名 成员名:位数”是定义位段成员。
功能:定义一个含有位段成员的结构体类型。
P306,例。
注意:定义位段成员的类型名必须是unsigned或int。
2. 位段的引用
定义了含有位段成员的结构体类型后,可以用来声明这种结构体类型的变量,方法仍有分步定义、同时定义、直接定义三种。
P306,例。
含有位段成员结构体变量的位段成员的引用,方法与结构体变量成员的引用一样,用“.”成员运算符。
P307,例。见ex12-3.c。
注意:位段成员值不能溢出;位段不能引用地址。
说明P307(1)~(7)
第14章 文件
13.1 C文件概述
文件:是存储在外部介质上的指令或数据的集合。
分类:(1)文件可分为程序文件和数据文件;
(2)文件保存有ASCII形式和二进制形式两种;
(3)文件中数据的输入输出要有一个缓冲区;
(4)缓冲区可由系统自动开辟(缓冲文件系统)和人工开辟(非缓冲文件系统)。
注意:本章只讨论缓冲文件系统下数据文件的读写。
P309,例。
13.2 文件类型指13.3 针
在C中,文件的读写是通过文件类型指针来进行的。
1. 文件类型
文件类型是一个结构体类型,已由系统预定义,且放在库函数文件“stdio.h”中,名为FILE。
P310,文件类型定义原型。
注意:(1)要使用文件类型,程序头要有:#include “stdio.h”
(2)FILE是系统预定义的,无须用户定义,只能大写。
2. 文件指针
格式:FILE *文件指针名;
功能:定义一个文件指针。
P311,例。
注意:(1)文件指针是用来指向文件中的数据的,一般开始指向文件中的第一个数据,即开始存放的是文件的起始地址。
(2)系统预定义了两个文件指针:stdin和stdout,分别指向键盘和显示器。
13.4 文件的打开与关闭
13.3.1 文件的打开
格式:fopen(文件名,文件使用方式)
其中:(1)文件名是一个字符串,指明了要打开的文件的路径和名字;
(2)文件使用方式由特定字符串组成,含义见P312表13.1。
功能:以指定的使用方式打开文件,为该文件开辟一个缓冲区,并返回该文件的起始地址。
P311,例。
注意:(1)以读的方式打开,若不存在该文件,或无法打开,则出错,返回NULL;
(2)以写的方式打开,若已存在该文件,则覆盖;若不存在该文件,则新建;
(3)文件使用方式要与文件的类别(文本还是二进制)相匹配。
13.3.2 文件的关闭
格式:fclose(文件指针)
其中:文件指针是指向要关闭的文件的。
功能:关闭文件指针所指向的文件,并释放该文件的缓冲区。
P312,例。
注意:fclose也有一个返回值,正常关闭返回0,否则返回EOF(-1)。
13.5 文件的顺序读写
13.4.1 输入和输出一个字符
1. 把一个字符写到文件中
格式:fputc(ch,fp)
功能:把ch中的字符写到fp指向的文件中。
P314,例。
注意:(1)fputc函数正常返回字符ch,输出失败返回EOF(-1)。
(2)fputc(ch,stdout)等价于putchar(ch)。
2. 从文件中读取一个字符
格式:fgetc(fp)
功能:从fp指向的文件中读取一个字符。
P314,例。
注意:(1)fgetc函数正常返回一个字符,输入失败返回EOF(-1)。
(2)fgetc(stdin)等价于getchar()。
(3)可用feof(fp)来检测是否读到文末符,是返回1,不是返回0。
3. fput和fget函数应用举例
P315,例13.1。见ex13-1.c。
P316,例13.2。见ex13-2.c。
(下面的次序与书不同,见P332)
13.4.2 输入和输出一个整数或一个字符串
1. 输入和输出一个整数
格式:putw(i,fp)
功能:把i中的整数写到fp指向的文件中。
格式:getw(fp)
功能:从fp指向的文件中读取一个整数。
P322,例。见ex13-6.c。
注意:(1)有的C语言不提供putw与getw函数,这时我们可以自己定义;
(2)Turbo C提供putw与getw函数。
2. 输入和输出一个字符串
格式:fputs(str,fp)
功能:把字符串str写到fp指向的文件中,但不写\0。
格式:fgets(str,n,fp)
功能:从fp指向的文件中读取n-1个字符到str中,包括\n并自动加上\0。
P323,例。
(下面的内容见P321)
13.4.3 格式化输入和输出
格式:fprintf(fp,格式控制,输出表列)
功能:把输出表列中的数据按格式控制写到fp指向的文件中,但不写\0。
格式:fscanf(fp,格式控制,输入表列)
功能:从fp指向的文件中按格式控制读取数据到输入地址表列的变量中,如果是字符串会自动加上\0。
P321,例。
注意:(1)读取时的格式要与写入文件时的格式相匹配。
(2)fprintf(stdout,格式控制,输出表列)等价于printf(格式控制,输出表列)
(3)fscanf(stdin,格式控制,输入表列) 等价于scanf(格式控制,输入表列)
(下面的内容见P317)
13.4.4 按记录输入和输出
格式:fwrite(buffer,size,count,fp)
功能:从buffer指向的存储区域中count次读取大小size的数据写到fp指向的文件中。
格式:fread(buffer,size,count,fp)
功能:从fp指向的文件中count次读取大小size的数据送到buffer指向的存储区域中。
其中:buffer 为内存中要读写数据的存储地址;
size 为要读写数据的字节数;
count 为要读写数据的次数;
fp 为要进行读写操作的文件指针。
P318,例。
注意:(1)按记录读写只能是二进制文件;
(2)函数的返回值是成功读写的次数。
P318,例13.3。见ex13-3.c。
(下面的内容见P323)
13.6 文件的定位
13.5.1 指针重置文首函数rewind
格式:rewind(fp);
功能:使fp重新指向文件开头。
P323,例13.4。
13.5.2 指针重定位函数fseek
格式:fseek(fp,m,n);
其中:(1)m为字节数,要在后面加L;
(2)n为起始点,可取0、1、2,见P324,表13.2。
功能:使fp移到离起始点n的m个字节处。
P324,例13.5。
13.7 出错的检测
略
13.8 文件输入输出小结
P326,表13.3。