2.1 二级公共基础知识选择题高频考点
1.1 计算机系统
考点1:计算机概述
1、计算机的发展历程:
(1)世界公认的第一台电子数字计算机是ENIAC,1946年诞生于宾夕法尼亚大学,计算速度每秒5000次加减法或300多次乘法;
(2)计算机时代分为4个阶段:电子管(1946年至20世纪50年代)、晶体管(20世纪50年代至20世纪60年代中期)、中小规模集成电路(20世纪60年代中期至20世纪70年代初期)、大规模和超大规模集成电路(20世纪70年代初期至今);
2、计算机体系结构:
(1)ENIAC没有存储器、电路繁琐;
(2)冯诺伊曼提出“存储程序控制”思想;
(3)EDAVC于1951年问世,其特点:
在计算机内部,程序和数据用二进制表示;
程序和数据存放在存储器中,即采用程序存储的概念;
计算机硬件组成:运算器、控制器、存储器、输入设备、输出设备;
3、计算机系统的基本组成:
(1)硬件系统借助光、电、磁等原理构成的各种物理部件的有机组合,是计算机赖以工作的实体,硬件系统也称裸机,只能识别0和1;
(2)软件系统是为运行、管理和维护计算机而编制的各种程序、数据和文档的总称;
(3)软件是用户与硬件之间的接口,用户可以通过软件使用计算机用箭上的数据信息资源;
(4)计算机软件按照面向应用对象的不同主要分为系统软件和应用软件;
考点2:计算机硬件系统
1、计算机硬件系统主要包含中央处理器、主存储器和其他外部设备,它们之间通过总线连接在一起;
2、中央处理器:
(1)中央处理器(CPU):计算机的运算和控制核心,是计算机的“大脑”,其功能主要是处理计算机的指令和软件中的数据;
(2)CPU主要包括运算器和控制器两个部件,它们都包含寄存器,通过总线连接起来;
3、中央处理器各部分功能:
(1)运算器对数据进行加工处理;
(2)控制器负责对程序所规定的指令进行分析、控制并协调输入、输出操作以及对主存储
器的访问;
(3)寄存器是高速存储区域,用来暂时存放参与运算的数据和运算结果;
(4)CPU的主要技术性能指标有字长、主频和运算速度等;
字长是指CPU一次能处理的二进制数据的位数,在工作频率和CPU体系结构相似的前提下,字长越长,CPU的数据处理速度越快;
主频是指CPU的时钟频率,计算机的操作在时钟信号的控制下分步执行,每个时钟信号周期完成一步操作,主频越高,CPU的运算速度就越快;
运算速度通常是指CPU每秒能执行的加法指令次数,常用百万次/秒来表示。这个指标能更直观地反映计算机的速度;
4、存储器
(1)存储器是存储程序和数据的部件,它可以自动完成程序或数据的存取;
(2)存储器的分类(存储介质):半导体存储器丶磁表面存储器、磁芯存储器、光盘存储器等;
(3)存储器的分类(存取方式):随机存储器RAM、只读存储器ROM、串行访问存储器、直接存取存储器等;
(4)存储器的分类(作用):主存储器(内存)、高速缓冲存储器(cache)、辅助存储器(外存)等;
(5)主存储器:存储器中最重要的是主存储器,它一般采用半导体存储器,包括RAM和ROM两种。
RAM具有可读写性,易失性(断电后数据丢失),分为静态RAM(集成度低,价格高,存储速度快,不需要刷新)和动态RAM(又称DRAM,集成度高,价格低,存储速度慢,需要刷新;DRAM用于计算机内存条;
ROM中信息只能读出不能写入,ROM中的信息掉电后不丢失,根据半导体制造工艺不同,可将其分为可编程只读存储器(PROM)、可擦除可编程只读存储器(EPROM)、电可擦除可编程存储器(EEPROM)、掩膜式只读存储器(MROM);
高速存储器是介于CPU和内存之间的一种小容量、可高速存取信息的芯片,用于解决它们之间速度不匹配问题,高速缓冲存储器一般由速度高的SRAM元件组成,其速度与CPU相当,但价格较高;
辅助存储器容量一般都比较大,而且大部分可以移动,便于不同计算机之间进行信息交流,辅助存储器中的数据被读入内存后,才能被CPU读取,CPU不能直接访问辅助存储
器;
存储器主要有3个性能指标:速度、容量、价格。一般来说,速度越快,位价格越高;容量越大,位价格越低,而且容量越大,速度越慢;
5、外部设备
(1)外部设备的分类:计算机中的CPU和主存储器构成主机,除主机以外,围绕着主机设置的各种硬件装置称为外部设备(外设)。外设的种类有很多,应用比较广泛的有输入/输出设备、辅助存储器及终端设备。
(2)输入/输出设备:
输入设备:向计算机输入数据和信息;
输出设备:将数据和信息以特定形式表现出来;
有些设备同时有输入和输出功能;
(3)辅助存储器:
辅助存储器可存放大量程序和数据,断电后程序和数据不丢失,常见的有硬盘、闪存等;
(4)终端设备:
终端设备是指经由通信设施向计算机输入程序和数据或接收计算机输出的来处理结果的设备;终端设备分为通用终端和专用终端设备两类;
(5)硬盘:硬盘是计算机主要的外部存储设备,具有容量大、存取速度快等优点;
(6)硬盘分类:分为固定磁头、活动磁头两种;磁头和磁臂是硬盘的重要组成部分;
(7)硬盘的信息分布:
记录面:硬盘通常由重叠的一组盘片构成,每个盘片的两面都可作记录面,每个记录面对应一个磁头,所以记录面号就是磁头号;
圆柱面:在一个硬盘中,各记录面上相同编号的磁道构成一个圆柱面。例如,某硬盘有8片(16面),则16个0号磁道构成0号圆柱面,硬盘的圆柱面数等于一个记录面上的磁道数,圆柱面号就对应磁道号;
扇区:通常将一个磁道划分为若干弧段,每个弧段称为一个扇区或扇段,扇区从1开始编号。
因此,硬盘寻址用的磁盘地址应该由硬盘号(一台计算机可能有多个硬盘)、记录面(磁头)号、圆柱面(磁道)号、扇区号等字段组成;
磁盘存储器的主要性能指标包括存储密度、存储容量、平均存取时间及数据传输率等;
(8)I/O接口:用于主机和外设之间的通信,通过接囗可实现主机与外设之间的信息交换;
(9)接口的功能:实现主机和外设的通信联络控制、进行地址译码和设备选择、实现数据缓书以匹配速度、信号格式的转换、传输控制命令和状态信息;
(10)I/O方式:包括程序查询方式、程序中断方式、直接存储器存取方式和I/O通道控制方式等。
程序查询方式:一旦某一外设被选中并启动,主机将查询这个外设的状态位,看其是否准备就绪,若未准备就绪,主机将再次查询;若已准备就绪,则执行一次I/O操作。这种方式控制简单,但系统效率低;
程序中断方式:在主机启动外设后,无须等待查询,继续执行原来的程序,外设在做好输入/输出准备时,向主机发送中断请求,主机接到请求后就暂时终止原来执行的程序,转去执行中断服务程序并对外部请求进行处理,在中断处理完毕后返回原来的程序继续执行;
DMA方式:在主存储器和外设之间开辟直接的数据通道,可以进行基本上不需要CPU介入的内存和外设之间的信息传递,这样不仅保证了CPU的高效率,也能满足高速外设的需要;
I/O通道控制方式:是DMA方式的进一步发展,系统中设有通道控制部件,每个通道有若干外设。主机执行I/O指令启动有关通道,通道执行通道程序,完成输入/输出操作。通道是一种独立于CPU的专门管理I/O的处理机制,它控制设备与内存直接进行数据交换。通道有自己的通道指令,通道指令由CPU启动,并在操作结束时向CPU发出中断信号。
6、总线:
总线是一组能被多个部件“分时共享”的公共信息传输线路。分时是指同一时刻总线上只能传输一个部件发输的信息;共享是指总线上可以“挂接”多个部件,各个部件之间相互交换的信息都可以通过这组公共线路传输。
(1)总线的分类:片内总线、系统总线、通信总线;
片内总线:指芯片内部的总线;
系统总线:指计算机系统内各功能部件之间相互连接的总线,也称内部总线。系统总线按传输的信息不同,又分为数据总线、地址总线及控制总线;
通信总线:用于计算机设备之间或计算机设备与其他设备(远程通信设备、测试设备)之间信息传输的总线,也称外部总线。依据总线的不同传输方式,通信总线又分为串行通信总线和并行通信总线。
(2)总线的基本结构:单总线结构、双总线结构、三总线结构;
单总线结构:只有一条系统总线,CPU、内存、I/O设备都挂在该总线上,允许I/O设备之间、I/O设备与CPU之间或I/O设备与内存之间直接交换信息。
双总线结构:将低速I/O设备从单总线上分离出来,实现内存总线与I/O总线分离;
三总线结构:各部件之间采用了条各自独立的总线来构成信息通道。内存总线用于在CPU和内存之间传输地址、数据及控制信息;I/O总线用于在CPU和外设之间通信;直接内存访问总线用于在内存和高速外设之间直接传输数据。
(3)总线的性能指标:周期、时钟周期、工作频率、宽度、带宽、时钟同步/异步、复用、信号线数;
总线周期:一次总线操作(包括申请阶段、寻址阶段、传输阶段及结束阶段)所需的时间简称总线周期。总线周期通常由若干总线时钟周期构成;
总线时钟周期:即计算机的时钟周期;
总线的工作频率:总线上的各种操作的频率,为总线周期的倒数。若总线周期=N*时钟周期,则总线的工作频率=时钟频率/N;
总线宽度:通常指数据总线的根数,用位表示,如数据总线有32根则称该总线为32位总线;
总线带宽:可理解为总线的数据传输率,即单位时间内总线上传输数据的位数,通常用每秒传输信息的字节数来衡量,单位可用MB/s(兆字节每秒)来表示。例如,总线工作频率为33MHz,总线宽度为32位(4B),则总线带宽为33*(32/8)=132MB/s。
时钟同步/异步:数据与时钟同步工作的总线称为同步总线,数据与时钟不同步的总线称为异步总线。
总线复用:一种总线在不同的时间传输不同的信息。
信号线数:地址总线、数据总线及控制总线3种总线数的总和。
(4)总线仲裁:为了保证同一时刻只有一个申请者使用总线,总线控制机构中设有总线判优和仲裁控制逻辑,即按照一定的优先次序来决定哪个部件首先使用总线,只有获得总线使用权的部件才能开始数据传输。总线判优按其仲裁控制机构可分为两种:集中式控制(总线控制逻辑基本上集中于一个设备CPU中,将所有的总线请求集中起来,利用一个特定的裁决算法进行裁决)、分布式控制(不需要中央处理器,即总线控制逻辑分散在连接于总线上的各个部件或设备中)。
(5)总线操作:在总线上的操作主要有读和写、块传输、写后读或读后写、广播和广集等。
(6)总线标准:总线标准是国际上公布或推荐的连接各个模块的标准,是把各种不同的模块组成计算机系统时必须遵守的规范。
常见的系统总线标准有工业标准体系结构ISA、扩展的ISA(EISA)、美国电子工业协会推行的串行通信总线标准(RS一232C)和通用串行总线(USB)等。
7、计算机的工作原理
计算机在执行程序时须将要执行的程序和数据先放入内存中,在执行时CPU根据当前程序指针寄存器的内容取出指令并执行,然后再取下一条指令并执行,如此循环直到程序结束时才停止执行。其工作过程就是不断地取指令和执行指令,最后将计算的结果放入指令指定的存储器地扯中。
(1)计算机指令格式:指令是指计算机完成某个基本操作的命令。指令能被计算机硬件理解并执行。一条计算机指令是用一串二进制代码表示的,它通常包括两方面的信息:操作码和操作数(地址码);
操作码指明指令所要完成操作的性质和功能,即指出进行什么操作。操作码也是二进制代码。对同一种类型的计算机来说,各种指令的操作码互不相同,分别表示不同的操作。因此,指令中操作码的二进制位数决定了该类型计算机最多能具有的指令条数。
操作数指明操作码执行的操作对象。操作数可以是数据本身,也可以是存放数据的内存单元地址或寄存器名称。根据指令中操作数的性质,操作数又可以分为原操作数和目的操作数两类。例如,减法指令中减数和被减数为源操作数,它们的差为目的操作数。
如果指令中的操作码和操作数共占n字节,则称该指令为n字节指令。
(2)计算机指令的寻址方式:
寻址方式是指查找当前正在执行指令的数据地址和下一条将要执行指令的地址的方法;
寻址方式分类两类:找到下一条将要执行的指令,称为指令寻址;找到当前正在执行指令的数据地址,称为数据寻址;
指令寻址分为顺序寻址和跳跃寻址两种。常见的数据寻址有立即寻址、直接寻址、隐含寻址、间接寻址、寄存器寻址、寄存器间接寻址、基址寻址、变址寻址、相对寻址及堆栈寻址等。
(3)计算机指令系统:
一台计算机所能执行的全部指令的集合,称为计算机的指令系统。不同类型的计算机的指令系统的指令数目与格式也不同。但无论哪种类型的计算机,指令系统都应该具有以下功能指令。
数据传输类指令:用来实现数据在内存和CPU之间的传输;
运算类指令:用来进行数据的运算;
程序控制类指令:用来控制程序中指令的执行顺序;
输入/输出指令:用来实现外设与主机之间的数据传输;
处理器控制与调试指令:用来实现计算机的硬件管理等;
(4)指令的执行过程:
指令的执行过程可分为取指令、分析指令和执行指令3个步骤;
取指令:按照程序规定的次序,从内存取出当前执行的指令,并送到控制器的指令寄存器中;
分析指令:对所取得指令进行分析,即根据指令中的操作码确定计算机应进行什么操作。由指令中的地址码确定操作码存放的地址;
执行指令:根据指令分析结果,由控制器发出完成操作所需的一系列操控电位,以便指挥计算机有关部件完成这一操作。同时,为取下一条指令做好准备。
一般把计算机完成一条指令所花费的时间称为一个指令周期。指令周期越短,指令执行就越快。
考点3:数据的内部表示
1、计算机中的数据及其存储单位
(1)计算机中的数据。
计算机内部均使用二进制数表示各种信息,但计算机在与外部沟通中会采用人比较熟悉和方便阅读的形式,如十进制数。其间的转换,主要由计算机系统的硬件和软件来实现。
二进制只有“0”和“1”两个数,相对十进制而言,二进制不但运算简单、易于物理实现、通用性强,而且所占的空间和所消耗的资源也少得多,计算机可靠性较高。
(2)计算机中数据的存储单位。
位(bit)时计算机中数据的最小单位,二进制数码只有0和1,计算机中采用多个数码表示一个数,每个数码称为1位。
字节(byte,B)是存储容量的基本单位,一个字节由8位二进制位组成。在计算机内部一个字节可以表示一个数据,也可以表示一个英文的字母或其他特殊符号,两个字节可以表示一个汉字。为了便于衡量存储器的大小,统一以字节为单位。表2.1所示为常用的存储单位。
存储单位 | 名称 | 换算 | 说明 |
KB | 千字节 | 1KB=1024B=210 | 适用于文件计量 |
MB | 兆字节 | 1MB=1024KB=220 | 适用于内存、软盘、光盘计量 |
GB | 吉字节 | 1GB=1024MB=230 | 适用于硬盘计量 |
TB | 太字节 | 1TB=1024GB=240 | 适用于硬盘计量 |
随着电子技术的发展,计算机的并行处理能力越来越强,人们通常将计算机一次能够并行处理的二进制数的个数称为字长,也成为计算机的一个“字”。字长是计算机的一个重要指标,直接反映一台计算机的计算能力和精度,字长越长,计算机的数据处理速度越快。计算机的字长通常是字的整数倍,如8位、16位、32位。发展到今天,微机的字长已达到64位,大型机的字长已达到128位。
2、进位计数及其转换
(1)进位计数制
数的表示规则称为数制。如果用R表示任意整数,进位计数制为“逢R进一”。处于不同位置的数码代表的值不同,与它们所在位置的权值有关。任意一个R进制数D均可展开为(D)R = i=-mn-1ki*Ri
;
此时,R为计数的基数,数指中固定的基本符号称为“数码”。i称为位数,ki是第i位的数码,位0~R-1中的任意整数,Ri
称为第i位的权,m、n为最低位和最高位的位序号。常见的数制为二进制、八进制、十六进制。
数制 | 基数 | 数码 | 权 | 进位 | 形式表示 |
二进制 | 2 | 0,1 | 2i | 逢二进一 | B |
八进制 | 8 | 0,1,2,3,4,5,6,7 | 8i | 逢八进一 | O |
十进制 | 10 | 0,1,2,3,4,5,6,7,8,9 | 10i | 逢十进一 | D |
十六进制 | 16 | 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F | 16i | 逢十六进一 | H |
通常用圆括号加数制基数作为下标的方式来表示不同的进制数,如二进制(1100)B、八进制数(3567)O
、十进制数(5820)D
,也可以直接表示为(1100)2
、(3567)8
、(5820)10
。十六进制除了数码0~9之外,还使用了6个英文字母A、B、C、D、E、F,相当于十进制的10、11、12、13、14、15。十进制数、二进制数、八进制数、十六进制数的对照关系如下:
十进制数 | 二进制数 | 八进制数 | 十六进制数 | 十进制数 | 二进制数 | 八进制数 | 十六进制数 |
0 | 0000 | 00 | 0 | 8 | 1000 | 10 | 8 |
1 | 0001 | 01 | 1 | 9 | 1001 | 11 | 9 |
2 | 0010 | 02 | 2 | 10 | 1010 | 12 | 10 |
3 | 0011 | 03 | 3 | 11 | 1011 | 13 | A |
4 | 0100 | 04 | 4 | 12 | 1100 | 14 | B |
5 | 0101 | 05 | 5 | 13 | 1101 | 15 | C |
6 | 0110 | 06 | 6 | 14 | 1110 | 16 | D |
7 | 0111 | 07 | 7 | 15 | 1111 | 17 | E |
(2)R进制数转换为十进制数:
R进制数转换为十进制数的方法是“按权展开”。如下:
二进制数转换为十进制数:(11010)2=1*24
+1*23
+0*22
+1*21
+0*20
=(26)10
;
八进制数转换为十进制数:(140)8=1*82
+4*81
+0*80
=(96)10
;
十六进制数转换为十进制:(A2B)16=10*162
+2*161
+11*160
;
(3)十进制数转换为R进制数:
将十进制数转换为R进制数时,可将此数分成整数与小数两部分分别转换,然后拼接起来即可。下面以十进制转换为二进制数为例进行介绍。
十进制转换为二进制整数的方法是“除二取余法”,具体步骤如下。
步骤1:把十进制数除以2得到商和余数,商再除以2得到商和余数……依次除下去直到商是0为止;
步骤2:以最先除得的余数为最低位,最后除得的余数位最高位,从最高位到最低位依次排列。
十进制小数转换为二进制小数采用“乘2取整法”,具体步骤如下。
步骤1:把小数部分乘以2得到一个新数,然后取整数部分,剩下的小数部分继续乘以2,然后取整数部分,剩下的小数部分再乘以2,一直取到小数部分为0为止。
步骤2:以最先乘得得乘积整数部分为最高位,最后乘得得乘积整数部分为最低位,从高位向低位依次排列。
将0.125转换为二进制小数,步骤如表所示。
步骤 | 1 | 2 | 3 |
乘法算式 | 0.125*2 | 0.25*2 | 0.5*2 |
乘积 | 0.25 | 0.5 | 1 |
小数部分 | 0.25 | 0.5 | 0 |
整数部分 | 0 | 0 | 1 |
将整数部分从高位向低位排列,即(0.001)2;
将十进制转换为八进制、十六进制数,均可以采用类似的“除以8取余”“除以16取余”“乘8取整”“乘16取整”的方法来实现转换。
(4)二进制数、十六进制数、八进制数之间的转换。
①二进制转化为十六进制数:
将二进制数转换为十六进制数的操作步骤如下。
步骤1:二进制数从小数点开始,整数部分向左、小数部分向右,每4位分成1节;
步骤2:整数部分最高位不足4位或小数部分最低位不足4位时补“0”;
步骤3:将每节4位二进制数依次转换成1位十六进制数,在把这些十六进制数连接起来内即可。
二进制数 | 0101 | 1110 | 0101 | . | 0001 | 1001 | 1010 |
十六进制数 | 5 | E | 5 | . | 1 | 9 | A |
十六进制数按顺序连接,即(5E5.19A)16;
同理,将二进制数转换为八进制数,只要将二进制数按每3位为1节划分,并分别转换为1位八进制数即可。
②十六进制数转换为二进制数:
将十六进制数转换为二进制数,就是对每1位十六进制数,用与其等值的4位二进制数替代;
十六进制 | 1 | A | C | 0 | . | 6 | D |
二进制 | 0001 | 1010 | 1100 | 0000 | . | 0110 | 1101 |
二进制数顺序连接,即(0001101011000000.01101101)2;
同理,将八进制转换为二进制数,只需分别将每1位8进制数转换为3位二进制数即可。
3、无符号数和带符号数:
在计算机中,采用数字化方式表示数据,数据有无符号和带符号之分。
(1)无符号数。
无符号数是指整个计算机字长的全部二进制位均表示数值位(没有符号位),相当于数的绝对值。字长为n的无符号数的表示范围为0~2n-1。若计算机字长为8位,则无符号数的表示范围为0~28
-1,即0~255;
(2)带符号数。
日常生活中,把带有“+”或“-”符号的数称为真值。在计算机中,数的“+”“-”是无法识别的,因此需要把符号数字化。通常,约定二进制的最高位为符号位,0表示正号,1表示负号。这种把符号数字化的数称为机器数。常见的机器数有原码、反码、补码和移码等不同的表示形式。
原码。原码是机器数中最简单的一种表示形式,符号位为0表示正数,符号位为1表示负数,数值位即真值的绝对值。用原码实现乘除运算的规则很简单,但实现加减运算的规则很复杂。
反码。正数的反码与原码相同;负数的反码对该数的原码除符号位以外的各位取反(将0变成1,将1变成0).
补码。正数的补码与原码相同;负数的补码是该数的反码的最低位(即最右边1位)加1。
移码。一个真值的移码和补码只差一个符号位,若将补码的符号位由0改为1,或由1改为0,则得到该真值的移码。
4、机器数的定点表示和浮点表示:
根据小数点的位置是否固定,在计算机中有两种方法表示小数点,即定点表示和浮点表示。定点表示的及其称为定点数,浮点表示的机器数称为浮点数。
(1)定点表示:
定点表示即约定机器数中的小数点位置是固定不变的,小数点不再使用”.”表示,而是约定它的位置。在计算机中通常采用两种简单的约定:将小数点的位置固定在最高位之前、符号位之后,或固定在最低位之后。一般常称前者为定点小数(纯小数),后者为定点整数(纯整数)。
定点数的运算除了加、减、乘、除外,还有移位运算。移位运算根据操作对象不同分为算数移位(带符号的数的移位)和逻辑移位(无符号数的移位)。
(2)浮点表示:
计算机中处理的数不一定数纯小数或纯整数(如圆周率3.1416),而且在运算中常常会遇到非常大会非常小的数值,用定点表示它们会非常不方便,但可以用浮点表示。
浮点表示是指以适当的形式将比例因子表示在数据中,让小数点的位置根据需求而浮动。例如,679.32=6.7932*102=6793.2*10-1
=0.67932*103
。
通常,浮点数被表示成N=S*Rj
其中,N为浮点数,S为其尾数,j为其阶码,R为其阶码的底(隐含,在机器数中不出现)。通常,R=2,j和S都是带符号的定点数。可见,浮点数由阶码和尾数两部分组成。
阶码是整数,阶符jf和阶码的位数m共同反映浮点数的表示范围和小数点的实际位置;数符Sf
反映浮点数的正/负;尾数的n位反映浮点数的精度。
为了提高运算的精度,浮点数的尾数必须为规格化数(即尾数的最高位必须是一个有效值)。如果不是规格化数,需要修改阶码并左/右移尾数,使其变成规格化数。将非规格化数转化为规格化数的过程称为规格化操作。例如,二进制数0.0001101可以表示为0.001101*2-01、0.01101*2-10
、0.1101*2-11
……,而其中只有0.1101*2-11
是规格化数。
现代计算机中,浮点数一般采用IEEE754标准。IEEE754标准浮点数的格式:
ms | E(阶码数值部分) | M(尾数数值部分,尾数用原码表示) |
这种标准规定常用的浮点数格式有短浮点数(单精度、float型)、长浮点数(双精度、double型)、临时浮点数,除临时浮点数外,短浮点数和长浮点数的尾数用隐藏位的原码表示,阶码用移码表示。
类型 | 数符 | 阶码 | 尾数数值 | 总位数 | 偏置值 | |
十六进制 | 十进制 | |||||
短浮点数 | 1 | 8 | 23 | 32 | 7FH | 127 |
长浮点数 | 1 | 11 | 52 | 64 | 3FFH | 1023 |
临时浮点数 | 1 | 15 | 64 | 80 | 3FFFH | 16383 |
以短浮点数为例,最高位为数符位;其后是8位阶码,以2为底,用移码表示,阶码的偏置值为28-1-1=127;其后23位是原码表示的尾数数值位。对于规格化的二进制浮点数,数值的最高位总是“1”,为了能使尾数多表示一位有效数,将这个“1”隐藏,因此尾数数值实际是24位。隐藏的“1”是一位整数。在浮点数格式中表示的23位尾数是纯小数。例如(12)10
=(1100)2
,将它规格化后结果为1.1*23
,其中整数部分的1将不存储在23位尾数内。
考点4:操作系统
1、操作系统概述
(1)操作系统的功能与任务。
操作系统是现代计算机系统中最核心的系统软件之一所有其他软件都依赖于操作系统的支持。
操作系统是配置在计算机上的第1层软件,是对硬件系统的首次扩充。其主要作用是管理好硬件设备,提高它们的利用率和系统吞吐量,并为用户和应用程序提供一个简单的接口,便于用户使用。
如果把操作系统看成计算机系统资源的管理者,则操作系统的任务及其功能主要有以下5个方面。
处理器管理:对进程进行管理。其主要功能有创建和撤销进程,对多个进程的运行进行协调,实现进程之间的信息交换,以及按照一定的算法把处理器分配给进程。
存储器管理:为多道程序的运行提供良好的环境,提高存储器的利用率,方便用户使
用,并能从逻辑上扩充内存。因此,存储器管理应具有内存分配和回收、内存保护、地址映射和内存扩充等功能。
设备管理:完成用户进程提出的I/O请求,为用户进程分配所需的I/O设备,并完成指定的I/O操作;提高CPU和I/O设备的利用率,提高I/O速度,方便用户使用I/O设备。因此,设备管理应具有缓冲管理、设备分配、设备处理以及虚拟设备等功能。
文件管理:对用户文件和系统文件进行管理以方便用户使用,并保证文件的安全性。因此,文件管理应具有对文件存储空间的管理、目录管理、文件的读/写管理以及文件的共享与保护等功能。
提供用户接口:为了方便用户使用计算机和操作系统,操作系统向用户提供了“用户和操作系统的接口”。
(2)操作系统的发展。
操作系统经历了如下的发展过程:手工操作(无操作系统)、批处理系统、多道程序系统、分时系统、实时操作系统、个人计算机操作系统。
(3)操作系统的分类。
根据使用环境和对作业处理方式的不同,操作系统分为多道批处理操作系统、分时操作系统、实时操作系统、网络操作系统、分布式操作系统、嵌入式操作系统等。
2、进程管理
(1)程序的并发执行。
程序只有经过执行才能得到结果,程序的执行又分为顺序执行和并发执行。
一个具有独立功能的程序独占处理器直至执行结束的过程称为程序的有顺序执行。顺序执行具有顺序性、封闭性及可再现性等特点。
程序顺序执行时,虽然可以给程序员带来方便,但系统资源的利用率低。为此,在系
统中引入了多道程序技术,使程序或程序段间能并发执行。程序的并发执行是指一组在逻辑上互相独立的程序或程序段在执行过程中,其执行时间在客观上相互重叠,即一个程序段的执行尚未结束,另一个程序段的执行已经开始的执行方式。
并发程序在执行过程中有以下几个特点:失去了封闭性、不可再现性、间断性(即程序之间可以相互制约);
并发程序具有并行性和共享性,而顺序程序则以顺序性和封闭性为基本特征。
(2)进程的基本概念。
进程是指一个具有具有一定独立功能的程序关于某个数据集合的运行活动。简单地说,进程是指可以并发执行的程序的执行过程。
进程与程序有关,但它与程序又有本质的区别,主要反映在以下几个方面:
进程是程序在处理器上的一次执行过程,它是动态的概念。程序只是一组指令的有序集合,其本身没有任何运行的含义,它是一个静态的概念。
进程具有一定的生命周期,它能够动态地产生和消亡。程序可以作为一种软件资源长期保存,它的存在是永久的。
进程包括程序和数据。进程还包括记录进程相关信息的“进程控制块”
一个程序可能对应多个进程。
一个进程可以包含多个程序。
(3)进程的状态及其转换。
进程从创建、产生、撤销直至消亡的整个生命周期,有时占有处理器并运行,有时虽可运行但分不到处理器,有时虽有空闲处理器但因等待某个事件发生而无法运行,这说明进程是活动的且有状态变化。一般来说,一个进程的活动情况至少可以划分为以下5种基本状态。
运行状态:进程占有处理器,正在运行的状态。
就绪状态:进程具备运行条件、等待系统分配处理器以便运行的状态。
等待状态:又称阻塞状态和睡眠状态,指进程不具备运行条件,正在等待某个事件完成的状态。
创建状态:进程正在创建过程中、尚不能运行的状态。
终止状态:进程运行结束的状态。
处于运行状态的进程个数不能大于处理器的个数,处于就绪和等待的进程可以有多个。进程的几种基本状态之间在一定条件下是可以相互转换的。
(4)进程控制块。
每个进程有且仅有一个进程控制块。它是进程存在的唯一标识,是操作系统用来记录和刻画进程状态的数据结构,是进程动态特征的汇集,也是操作系统掌握进程的唯一资料和管理进程的主要依据。PCB包括进程执行时的状况,以及进程让出处理器之后所处的状态、断点等信息。
PCB中通常应包括以下基本内容:
进程名:唯一标识对应进程的一个标识符或数字,系统根据该标识符来识别一个进程。
特征信息:反映该进程是不是系统进程等信息。
执行状态信息:说明对应进程当前的状态。
通信信息:反映该进程与其他进程间的通信关系。
调度优先数:用于分配处理器时参考的一种信息,它决定在所有就绪的进程中,究竟哪一个进程先得到处理器。
现场信息:在对应进程放弃处理器时,将处理器的一些现场信息(如指令计数器的值、各寄存器的值等)保留在该进程的进程控制块中,当下次恢复运行时,只需按保存值重新装配即可继续运行。
系统栈:主要反映对应进程在执行时的一条嵌套调用路径上的历史。
进程映象信息:用于说明该进程的程序和数据存储情况。
资源占有信息:指明对应进程所占有的外设种类、设备号等。
族关系:反映该进程与其他进程间的隶属关系。
除此之外,PCB中还包含文件信息、工作单元等内容。
(5)进程的组织
进程的物理组织方式通常有线性方式、链接方式和索引方式。
线性方式:将系统中所有的PCB都组织在一张线性表中,将该表的首地址存放在内存的一个专用区域中。该方式实现简单、开销小,但每次查找时都需要扫描整张表,因此适合进程数目不多的系统。
链接方式:把具有相同状态进程的PCB分别通过PCB中的链接字链接成一个队列,这样可以形成就绪队列、若干个阻塞队列及空白队列等。在就绪队列中,往往按进程将PCB从高到低进行排列,将优先级高的进程的PCB排在队列的前面。
索引方式:系统根据所有进程不同的状态,建立几张索引表,如就绪索引表、阻塞索引表,并把各索引表在内存的首地址记录在内存的一些专用单元中,在每张索引表的表目中,记录具有相应状态的某个PCB在PCB表中的地址。
(6)进程调度:
进程调度是指按一定策略动态地把CPU分配给处于就绪队列中的某一进程并使之执行的过程。进度调度亦可称为处理器调度或低级调度,相应的进程调度程序可称为分配程度或低级调度程序。进程调度仅负责对CPU进行分配。
进程调度方式有抢占方式和非抢占方式。抢占方式指就绪队列中一旦有优先级高于当前正在运行的进程出现时,系统便立即把CPU分配给高优先级进程,并保存被抢占了CPU的进程的有关状态信息,以便以后恢复。对于非抢占方式,一旦CPU分给了某进程,即使就绪队列中出现了优先级比它高的进程,高优先级进程也不能抢占先行进程的CPU。
基本的进程调度算法有先来先服务调度算法、时间片轮转调度算法、优先调度算法等。
(7)其他概念:
线程。线程是比进程更小的能独立运行的基本单位,用它来提高程序的并行程度,减少系统开销,从而可进一步提高系统的吞吐量。
死锁。由于个进程互相独立地动态获得,不断申请和释放系统中的软硬件资源,这就有可能使系统中若干个进程均因互相“无知地”等待对方所占有的资源而无限地等待。这种状态称为死锁。
3、存储管理
存储管理是操作系统地重要组成部分,管理的主要对象是内存。操作系统的主要任务之一是尽可能方便用户使用和提高内存利用率。此外,有效的存储管理也是多道程序设计技术的关键支撑。
(1)存储管理的功能。
地扯变换、内存分配、存储共享与保护、存储器扩充。
(2)地址重定位。
地址变换:当用户程序进入内存执行时,必须把用户程序中的所有相对地址(逻辑地址)转换为内存中的实际地址(物理地址)。
地址重定位:在进行地址转换时,必须修改程序中所有与地址有关的项,也就是要对程序中的指令地址和指令中有关地址的部分(有效地址)进行调整。
地址重定位建立用户程序的逻辑地址与物理地址之间的对应关系,实现方式包括静态地址重定位和动态地址重定位。
静态地址重定位是在程序执行之前由操作系统的重定位将其装入内存完成,程序必须占用连续内存空间,且一旦装入内存后,程序不便于移动。
动态地址重定位则在程序执行期间进行,由专门的硬件机构来完成,通常采用一个重定位寄存器,在每次进行存储访问时,将取出的逻辑地址加上重定位寄存器的内容形成物理地址。
动态地址重定位的优点是不要求程序装入固定的内存空间,在内存中允许程序再次移动位置,而且可以部分地装入程序运行,同时也便于多个作业共享同一程序的副本。动态地址重定位技术被广泛应用。
(3)存储管理技术。
①连续存储管理。
基本特点:内存空间被划分成一个个分区,一个作业占一个分区,即系统和用户都以分区为单位享用内存。
在连续存储管理中,地址重定位采用静态地址重定位,分区的存储保护可分为上、下界寄存器保护方式。
分区分配方式分为固定分区和可变分区。固定分区存储管理的优点是简单,要求的硬件支持少;缺点是容易产生内部碎片。可变分区避免了固定分区中每个分区都可能有剩余空间的情况,但由于它的空闲区域仍是离散的,因此会出现外部碎片。
②分页式存储管理。
在分页式存储管理中,当作业提出存储分配请求时,系统首先根据存储块大小把作业分成若干页,每一页可存储在内存的任意一个空白块内。这样,只要建立起程序的逻辑页和内存的存储块之间的对应关系,借助动态地址重定位技术,分散在不连续物理存储块中的用户作业就能够正常运行。
分页式存储的优点是能有效解决碎片问题,内存利用率高,内存分配与回收算法也比较简单;缺点,是采用动态地址变换机构增加了硬件成本工,也降低了处理器的运行速度。
③分段式存储管理。
在分段式存储管理中,作业的地址空间由若干个逻辑段组成,每一段是组逻辑意义完整的信息集合,并有自己的名字(段名)。每一段都是以0开始的、连续的、一维地址空间,整个作业则构成了二维地址空间。
分段式存储管理是以段为基本单位分配内存的,且每一段必须分配连续的内存空间,但各段之间不要求连续。由于各段的长度不一样,因此分配的内存空间大小也不一样。
分段式存储管理较好地解决了程序和数据的共享以及程序动态链接等问题。与分页式存储管理一样,分段式存储管理采用动态重定位技术进行地址转换。分页式存储管理的优点体现在内存空间的管理上,而分段式存储管理的优点体现在地址空间的管理上。
④段页式存储管理。
段页式存储管理是分页和分段两种存储管理方式的结合,它同时具有两者的优点。
段页式存储是目前使用较多的一种存储管理方式,它有如下特点。
将作业地址空间分成若干个逻辑段,每段都有自己的段名。
每段再分成若干大小固定的页,每段都从0开始为自己的各页依次编写连续的页号。
对内存空间的管理仍然和分页管理一样,将其分成若干个与页面大小相同的物理块,对内存空间的分配是以物理块为单位的。
作业的逻辑地址包含3个部分:段号、段内页号及页内位移。
⑤虚拟存储器管理。
连续存储管理和分页/分段式存储管理技术必须为作业分配足够的内存空间,装入其全部信息,否则作业将无法运行。把作业的全部信息装入内存后,实际上并非同时使用这些信息,有此部分运行一次,有些部分暂时不用或在某种条件下才使用。让作业全部信息驻留于内存是对内存资源的极大浪费,会降低内存利用率。
虚拟存储器管理技术的基本思路是把内存扩大到大容量外存上,把外存空间当内存的一部分,作业过程中可以只让当前用到的信息进入内存,其他当前未用的信息留在外存;而当作业进一步运行,需要用到外存中的信息时,再把已经用过但暂时还不用的信息换到外存,把当前要用的信息换到已空出的内存中,从而给用户提供一个比实际内存空间大得多的地址空间。这种大容量的地址空间并不是真实行这种大容量的地址空间并不是真实的存储空间,而是点而是虚拟的,因此,这样的存储器称为虚拟存储器。
虚拟存储器主要采用请求页式存储管理、请求段式存储管理及请求段页式存储管理技术实现。
4、文件管理。
在操作系统中,无论是用户数据,还是计算机系统程序和应用程序,甚至各种外设,都以文件形式存在。文件管理就是对用户文件和系统文件进行管理,以方便用户使用,并保证文件的安全性,提高外存空间的利用率。
(1)文件与文件系统的概念。
文件是指一组带标识的(文件名)、具有完整逻辑意义的相关信息的集合。用户作业、源程序、目标程序、初始数据、输出结果、汇编程序、编译程序、连接装配程序、编辑程序、调试程序和诊断程序等,都是以文件的形式存在的。
各种操作系统的文件命名规则略有不同,文件的格式和长度因系统而异。一般来说,文件名由文件名和扩展名两部分组成,前者用于识别文件,后者用于区分文件类型,中间用“.”隔开。
操作系统中与管理文件有关的软件和数据的集合称为文件系统。它负责为用户建立、撤销、读/写、修改及复制文件,还负责对文件的按名存取和存取控制。常用的、具有代表性的文件系统有EXT2/4、NFS、HPFS、FAT、NTFS等。
(2)文件类型。
文件依据不同标准可以有多种类型,具体如表所示:
划分标准 | 文件类型 |
按用途划分 | 系统文件、库文件、用户文件 |
按性质划分 | 普通文件、目录文件、 特殊文件 |
按保护级别划分 | 只读文件、读写文件、可执行文件、不保护文件 |
按文件数据的形式划分 | 源文件、目标文件、可执行文件 |
(3)文件系统模型。
文件系统的传统模型为层次模型,该模型由许多不同的层组成。每一层都会使用下一层的功能特性来创建新的功能,为上一层服务。层次模型比较适合支持单个文件系统。
(4)文件的组织结构。
①文件的逻辑结构。
文件的逻辑结构是用户可见的结构。根据有无逻辑结构,文件可分为记录式文件和流式文件。
在记录式文件中,每个记录都用于描述实体集中的一个实体,各记录有着相同或不同数目的数据项。记录的长度可分为定长和不定长两类。
流式文件内的数据不再组成记录,只有一串有顺序的信息集合(有序字符流)。这种文件的长度以字节为单位。可以把流式文件看作记录式文件的一个特例:一个纪录仅有一个字节。
②文件的物理结构。
文件按不同的组织方式在外部存储介质上存放,就会得到不同的物理结构。文件的物理结构有时也称为文件的“存储结构”。
文件在外存上有连续存放、链接块存放及索引表存放3种不同的存放方式,其对应的存储结构分别为顺序结构、链接结构及索引结构。
(5)文件目录管理。
①为了能对一个文件进行正确的存取,必须为文件设置用于描述和控制文件的数抿描述和控制文件的数据结构,称为文件控制块(FCB)。FCB一般应包括以下内容。
有关文件存取控制的信息:文件名、用户名、文件主存取权限、授权者存取权限、文件类型及文件属性等。
有关文件结构的信息:记录类型、记录个数、记录长度、文件所在设备名及文件物理结构类型等。
有关文件使用的信息:已打开文件的进程数、文件被修改的情况、文件最大长度及文件当前大小等。
有关文件管理的信息:文件建立日期、最近修改日期和最后访问日期等。
文件与FCB一一对应,人们把多个FCB的有序集合称为文件目录,即个文件控制块就是一个文件目录项。通常,一个文件目录也被看作一个文件,可称为目录文件。
对文件目录的管理就是对FCB的管理。对文件目录的管理除了要解决存储空间的有效利用问题外,还要解决快速搜索、文件命名冲突以及文件共享等问题。
②文件目录结构。
文件目录根据不同结构可分为单级目录、二级目录、多层级目录、无环图结构目录及图环结构目录等。
单级目录的优点是简单,缺点是查找速度慢,不允许重名,不便于实现文件共享。
二级目录提高了检索目录的速度;在不同的用户目录中,可以使用相同的文件名;不同用户还可以使用不同的文件名访问系统中的另一个共享文件。但对同一用户目录,也不能有,建两个同名的文件存在。
多层级目录也叫树结构目录,既可以方便用户查找文件,又可以把不同类型和不同用途文件分类;允许文件重名,不但不同用户目录可以使用相同名称的文件,同一用户目录也可以使用相同名称的文件;利用多级层次结构关系,可以更方便地设置保存,二可以更方便地设置保护文件的存取权限,有利于文件的保护。其缺点为不能直接支持文件或目录的共享等。
为了使文件或目录可以被不同的目录所共享,出现了结构更复杂的无环图结构目录和图状结构目录等。
③存取权限。
存取权限可通过建立访问控制表和存取权限表来实现。
大型文件系统主要采用两个措施来进行安全性保护:一是对文件和目录进行权限设置,二是对文件和目录进行加密。
(6)文件存储空间管理。
存储空间管理是文件系统的重要任务之一。文件存储空间管理实质上是空闲块管理问题,它包括空闲块的组织、空闲块的分配及空闲块的回收等问题。
空闲块的管理方法主要有空闲文件项、空闲区表、空闲块链、位示图、空闲块成组链接法(UNIX操作系统中)等。
5、I/O设备管理
I/O设备类型繁多,差异又非常大,因此I/O设备管理是操作系统中最庞杂和琐碎的部分之一。
(1)I/O软件的层次结构。
I/O软件的设计目标是将I/O软件组织成一种层次结构,每一次都是利用其下层提供的服务,完成输入/输出功能中的某些子功能,并屏蔽这些功个并屏蔽这些功能并屏蔽这些功能实现的细节,向上层提供服务。
通常把I/O软件组织成4个层次,如图2.6所示,途中的箭头表示I/O的控制流。各层次功能如下:
用户层软件:用于实现与用户交互的接口,用户可以直接调用该层所提供的、与I/O操作有关的库函数对设备进行操作。
设备独立性软件:用于实现用户程序与设备驱动器自统一接口、设备命名、设备的保护以及设备的分配与释放等,同时为设备管理和数据传送提供必要的存储空间。
设备驱动程序:与硬件直接相关,用于具体实现系统对设备发出的操作指令,是驱动I/O设备工作。
中断处理程序:用于保持被中断进程的CPU环境,转入相应的中断处理程序进行处理,处理完毕再恢复被中断进程的现场,并返回被中断的进程。
(2)中断处理程序。
当一个进程请求I/O操作时,该进程将被“挂起”,直到I/O设备完成I/O操作后,设备控制器便向CPU发送一个中断请求,CPU响应后便转向中断处理程序。中断处理过程如下。
CPU检查响应中断的条件是否满足。
如果条件满足,CPU响应中断,则CPU关中断,使其进入不可再次响应中断的状态。
保存被中断进程的CPU环境。
分析中断原因,调用中断处理子程序。
执行中断处理子程序。
退出中断,恢复被中断进程的CPU现场或调度新进程占用CPU。
开中断,CPU继续执行。
I/O操作完成后,去从程序必须检查I/O操作中是否发生了错误,并向上层软件报告,最终向调用者报告本次I/O的执行情况。
(3)设备驱动程序。
设备驱动程序是驱动物理设备和DMA控制器或I/O控制器等直接进行I/O操作的子程序的集合。它负责启动I/O设备进行I/O操作,指定操作的类型二号数据流向等。设备驱动程序有如下功能。
接收由设备独立性软件发来的命令和参数,并将命令中的抽象要求转换为与设备相关的低层次操作序列。
检查用户I/O请求的合法性,了解I/O设备的工作状态,传递与I/O设备操作有关的参数,设置设备的工作方式。
发出I/O命令,如果设备空闲,便立即启动I/O设备,完成指定的I/O操作;如果设备忙碌,则将请求者的请求挂在设备队列上等待。
即使响应由设备控制器发来的中断请求,并根据其中断类型,调用相应的中断处理程序进行处理。
(4)设备独立性软件。
为了实现设备独立性,必须在设备驱动程序之上设置一层软件,称为与设备无关的I/O软件,或设备独立性软件。其主要功能:①向用户层软件提供统一接口;②设备命名;③设备保护;④提供一个独立于设备的块尺寸;⑤缓冲技术;⑥设备分配和状态跟踪;⑦错误处理和报告等。
(5)用户层软件。
用户层软件在层次结构的最上层,它面向用户,负责与用户和设备无关的I/O软件通信。当接受到用户的I/O指令后,该层会把具体的请求发送到与设备无关的I/O软件进一步处理。它主要包含用于I/O操作的库函数和SPOOLing系统。此外,用户层软件还会用到缓冲技术。
(6)设备的分配和回收。
由于设备、控制器及通道资源的有限性,因此不是每一个进程都能随时随地得到这些资源。进程必须首先向设备管理程序提出资源申请,然后,由设备分配程序根据相应的分配算法为进程分配资源。如过申请进程得不到它所申请的资源,将被放入资源等待队列中等待,知道所需要的资源被释放。如果进程得到了它所需要的资源,就可以使用该资源完成相关的操作,使用完之后通知系统,系统将及时回收这些资源,以便其他进程使用。
2.1.2数据结构与算法
考点1:什么是算法
1、算法及其基本特征
算法是指对解题方案准确而完整的描述。简单地说,算法就是解决问题的操作步骤。
算法不等于数学上的计算方法,也不等于程序。程序可以描述算法。
算法的基本特征如下。
(1)可行性:步骤可以实现;执行结果达到预期目的。
(2)确定性:步骤明确,不模棱两可,不准有多义性。
(3)有穷性:有限的时间内完成。
(4)拥有足够的情报:当拥有足够多的输入信息和初始化信息时,算法才是有效的;当提供的情报不够时,算法可能无效。
2、算法复杂度
算法复杂度用来衡量算法的优劣,它包括算法的时间复杂度和算法的空间复杂度。
(1)算法的时间复杂度。
算法的时间复杂度是指执行算法所需要的计算工作量。
算法的时间复杂度不等于算法程序执行的具体时间。算法程序执行的具体时间受到所使用的计算机、程序设计语言,以及算法实现过程中的许多细节的影响,而算法的时间复杂度与这些因素无关。
算法所需的计算工作量是用算法所执行的基本运算次数来度量的。算法所执行的基本运算次数与问题规模有关。
当分析一个具体算法工作量时,在同一个问题规模下,算法所执行的基本运算次数还可能与特定的输入有关。也就是说输入不同时,算法所执行的基本运算次数也不同。
(2)算法的空间复杂度。
算法的空间复杂度是指执行这个算法所需要的存储空间。
执行算法所需的存储空间包括3个部分:输入数据所占的存储空间、程序本身所占的存储空间、算法执行过程中所需要的额外空间。其中,额外空间包括算法执行过程中的
工作单元,以及某种数据结构所需要的附加存储空间。如果额外空间量相对问题规模(即输入数据所占的存储空间)来说是常数,即额外空间量不随问题规模的变化而变化,则称该算法是原地工作的。
为了降低算法的空间复杂度,只要应减少输入数据所占的存储空间和额外空间,通常采用压缩存储技术来实现。
考点2:数据结构的基本概念
1、什么是数据结构
数据结构是相互关联的数据元素的集合。,它包含两个要素,即“数据”和“结构”。
数据是需要处理的数据元素的集合。一般来说,这些数据元素具有某个共同的特征。
所谓“结构”,就是关系,是集合中各个数据元素之间存在的某种关系(或联系)。在数据处理领域中,通常把数据元素两两之间的关系用前/后件关系(或直接前驱/直接后继关系)来描述。
数据结构分为数据的逻辑结构和数据的存储结构。数据的逻辑结构指反映数据元素之间逻辑关系(前后件关系)的数据结构。数据的存储结构又称为数据的物理结构,是数据的逻辑结构在计算机存储空间中的存放方式。
2、数据结构的表示
数据的逻辑结构的数学形式定义——数据结构是一个二元组:B=(D,R),其中,B表示数据结构;D是数据元素的集合;R是D上关系的集合,它反映了D中各数据元素之间的前后件关系。前后件关系也可以用一个二元组来表示。
一个数据结构除了用二元关系表示外,还可以用图形来表示。用中间标有元素值的方框表示的数据元素,一般称为数据节点,简称节点。对于每一个二元组,用一条有向线段从前件指向后件。
节点基本概念
基本概念 | 含义 | 例子 |
根节点; | 数据结构中,没有前件的节点; | |
终端节点(或叶子节点); | 数据结构中,没有后件的节点; | |
内部节点; | 数据结构中,除了根节点和终端节点以外的节点; |
3、线性结构与非线性结构
类型 | 含义 |
线性结构 | 一个非空的数据结构如果满足以下两个条件就称为线性结构: (1)有且只有一个根节点; (2)每个节点最多有一个前件,最多有一个后件; |
非线性结构 | 不满足以上两个条件,只要指树形结构和网状结构; |
如果一个数据结构中没有数据元素,则称该数据结构为空的数据结构。在只有一个数据元素的数据结构中,删除该数据元素,就得到一个空的数据结构。
考点3:线性表及其顺序存储结构
- 线性表的基本概念
数据结构中,线性结构习惯称为线性表,线性表是最简单、也是最常用的一种数据结构。
线性表是由n(n>=0)各数据元素构成的有限序列,表中除第1个元素外的每一个元素,有且只有一个前件,除最后一个元素外,有且只有一个后件。
线性表要么是空表,要么可以表示为(a1,a2
,…,ai
,…,an
)其中,ai
是线性表中的数据元素,也成为线性表的一个节点。同一线性表中的数据元素必定具有相同的特性,即属于同一数据对象。数组、矩阵、向量等都是线性表。
非空线性表具有以下结构特征:
只有一个根节点,即节点a1,它无前件;
有且只有一个终端节点,即节点an,它无后件;
除根结点和终端节点外,其他节点均有一个前件和一个后件;
节点数n称为线性表的长度,当n=0时,称为空表。
2、线性表的顺序存储结构
通常,线性表可以采用顺序存储结构和链式存储两种存储结构;
顺序存储是存储线性表最简单的存储,具体做法:将线性表中的元素一个接一个地存储在一片相邻的存储区域中,这种顺序存储的线性结构也成为顺序表。
顺序表具有以下两个基本特征:
线性表中所有元素所占存储空间是连续的;
线性表中各数据元素在存储空间中是按逻辑依次存放的。
在顺序表中,其前、后件两个元素在存储空间中是紧邻的,且前件元素一定存储在后件元素的前面。
考点4:栈和队列
1、栈及其基本运算
栈是一种特殊的线性表,它所有的插入与删除都在限定的表的同一端进行,允许插入与删除的一段称为栈顶,不允许插入与删除的一段称为栈底。当栈中没有元素时,称为空栈。
栈的修改原则是“先进后出”或“后进先出”。
通常用指针top来指示栈顶的位置,用指针buttom来指向栈底。栈顶指针top反映了栈不断变化的状态。
假设栈S=(a1,a2
,…,an
),则称a1
为栈底元素,an
为栈顶元素。栈中元素按a1
,a2
,…,an
进栈,退栈的第一个元素应为栈顶元素an
。图2.8所示为栈结构与入栈、退栈示意。
栈的基本运算有3种:入栈、退栈及读栈顶元素。
栈的一般线性表的存储方法类似,通常也可以采用顺序存储和链式存储。
2、队列及其基本运算
(1)队列的定义。
队列是指允许在一端进行插入,而在另一端进行删除的线性表。允许进行删除运算的一端称为队头(排头),允许进行插入运算的一端称为队尾。若有队列:Q=(q1,q2
,…,qn
),那么,q1
为队头元素(排头元素),qn
为队尾元素。队列中的元素是按照q1
,q2
,…,qn
的顺序进入的,退出队列也只能按照这个次序依次退出。与栈相反,队列又称为“先进先出”或“后进后出”的线性表。
(2)队列的运算。
可以用顺序存储的线性表来表示队列。为了指示当前执行退队运算的队头位置,需要一个队头指针(排头指针)front;为了指示当前执行入队运算的队尾位置,需要一个队尾指针rear。队头指针front总是指向队头元素的前一个位置,而队尾指针rear总是指向队尾元素。队尾元素rear和队头指针front共同反映了队列中元素动态变化的情况。
(3)循环队列及其运算。
在实际应用中,队列的顺序存储结构一般采用循环队列的形式。
所谓循环队列,就是将队列存储的最后1个位置绕道第1个位置,形成逻辑上的环状空间,供队列死循环使用。
在循环队列中,用队尾指针rear指向队列中的队尾元素,用队头指针front指向排头元素的前一个位置。因此,从队头指针front指向的后一个位置直到队尾指针rear指向的位置之间所有的元素均为队列中的元素。
循环队列初始状态为空,即front=rear=m。
在循环队列中,当front=rear时,不能确定队列是满还是空。在实际使用循环队列时,通常会增加一个标志s来区分队列是满还是空。当s=0时表示队列空;当s=1且front=rear时表示队列满。
考点5:线性链表
1、线性链表的基本概念。
(1)线性链表
线性链表是指线性表的链式存储结构,简称链表。这种链表每个节点只有一个指针域,又称单链表。
在线性链表中,第1个元素没有前件,因此指向链表中的第一个节点的指针,只一个特殊的指针,称为这个链表的头指针(HEAD)。最后一个元素没有后件,因此,线性链表最后一个节点的指针域为空,用NULL或0表示。
线性链表的存储单元是任意的,即各数据节点的存储序号可以是连续的,也可以是不连续的;各节点在存储空间中的位置关系与逻辑关系不一致,前/后件关系又存储节点的指针来表示。当线性链表指向第1各数据元素的头指针等于NULL或0时,该表称为空表。 在某些应用中,对线性链表的每个节点设置两个指针,一个指针与存放前件的地址名称为左指针(Llink);一个指针域存放后件的指针,称为右指针(Rlink)。这样的线性链表称为双向链表。
(2)带链的栈
栈也可以采用链式存储结构表示,可以把栈组织成一个单链表,这种数据结构称为带链的栈。
(3)带链的队列
与栈类似,队列也可以用链式存储结构表示。带链的队列就是用一个单链表来表示队列,队列中的每一个元素对应链表中的一个节点。
(4)顺序表和链表的优缺点比较。
类型 | 优点 | 缺点 |
顺序表 | (1)可以随机存取表中的任意节点; (2)无需为表示节点间的逻辑关系额外增加存储空间; | (1)插入和删除运算的效率很低; (2)存储空间不便于扩充; (3)不便于对存储空间进行动态分配; |
链表 | (1)当进行插入和删除运算时,只需要改变指针即可,不需要移动元素; (2)存储空间易于扩充并且方便空间的动态分配; | (1)需要额外的空间(指针域)来表示数据元素之间的逻辑关系,存储密度比顺序表低; |
2、循环链表
在单链表的第1个节点前增加一个表头结点,队头指针指向表头节点,最后一个节点的指针域的值由NULL改为指向表头结点,这样的链表称为循环链表。在循环链表中,所有节点的指针构成一个环状链。
在循环链表中,只要指出表中任何一个节点的位置,就可以从它出发访问到表中其他所有的节点。并且,由于表头节点是循环链表固有的节点,因此,及时在表中没有数据元素的情况下,表中也至少有一个节点存在,从而使空表和非空表的运算统一。
考点6:树与二叉树
1、树的概念
树是一种简单的非线性结构。
树的相关术语:
基本概念 | 含义 | 例子 |
父节点(根) | 在树结构中,每一个节点只有一个前件,称为该节点的父节点;没有前件的节点只有一个,称为树的根节点,简称树的根; | 图2.14的A节点; |
子节点和叶子节点 | 在树结构中,每一个节点可以有多个后件,称为该节点的子节点。没有后件的节点称为叶子节点; | 图2.14的D、H、J、F、G; |
度 | 在树结构中,一个节点所拥有的后件个数称为该节点的度,所有节点中最大的度称为树的度; | 图2.14中,根节点A和节点E的度为2,节点B的度为3,节点C的度为1,叶子节点的度为0。所以,该树的度为2; |
深度 | 定义一棵树的根节点所在的层次为1,其他节点所在的层次等于它的父节点所在的层次加1。树的最大层次称为树的深度; | 图2.14的深度为4; |
子树 | 在树中,以某节点的一个子节点为根构成的树称为该节点的一颗子树; | 在图2.14中,节点A有2棵子树,它们分别以B、C为根节点。节点B有3棵子树,它们分别以D、E、F为根节点,其中,以D、F为根节点的子树实际上只有根节点一个节点; |
树中的节点数等于树中所有的节点度之和再加1。
2、二叉树及其基本性质
(1)二叉树的定义
二叉树与树不同,但它与树的结构很相似,如图2.15
二叉树的特点如下。
①二叉树可以为空,空的二叉树没有节点,非空二叉树有且只有一个根节点。
②每个节点最多有两棵子树,即二叉树中不存在度大于2的节点。
③二叉树的子树有左右之分,其次序不能任意颠倒。
(2)二叉树的性质。
二叉树具有以下几个性质。
性质1:在二叉树的第k层上,最多有2k-1(k>=1)个节点;
性质2:深度为m的二叉树中,最多有2m-1个节点;
性质3:对任何一颗二叉树,度为0的节点(即叶子节点)总的比度为2的节点多一个。
性质4:具有n个节点的二叉树,其深度至少为[log2n]+1,其中,[log2n
]表示取log2n
的整数部分。
(3)满二叉树和完全二叉树。
满二叉树是指除最后一层外,每一层上的所有节点都有两个子节点的二叉树。即满二叉树在其第k层有2k-1个节点,且深度为m的满二叉树共有2m
-1个节点。
完全二叉树是指除最后一层外,每一层上的节点数均达到最大值,在最后一层上只缺少右边若干节点的二叉树。
由完全二叉树可知,满二叉树一定是完全二叉树,完全二叉树不一定是满二叉树。
完全二叉树具有以下特点:
①叶子节点只可能在最后两层出现;
②对于任一节点,若其右子树的深度为m,则该节点左子树的深度为m或m十1。
性质5:具有n个节点的完全二叉树的深度为log2n+1。
3、二义树的存储结构
在计算机中,二叉树通常采用链式存储结构。用于存储二又树中元素的存储节点由数据域和指针域两部分构成。由于每一个元素可以有两个后件,因此用于存储二叉树的存储节点的指针域n两个:一个用于指向该节点的左子节点,即左指针域;另一个用于指向该节点的右子节点,即右指针域。
由于二叉树的存储结构中每一个存储节点有两个指针域,因此二叉树的链式存储结构也称二又链表。
满二又树及完全二又树可以按层次进行顺序存储。
4、二叉树的遍历
二叉树的遍历是指不重复地访问二义树中的所有节点。
在遍历二又树的过程中,一般先遍历左子树,再遍历右子树。在先左后右的原则下,根据访问根节点的不同次序,二叉树的遍历可以分为3种:前序遍历(DLR)、中序遍历(LDR)、后序遍历(LRD)。
(1)前序遍历。
首先访问根结点,然后遍历左子树,最后遍历右子树;并且在遍历左子树和右子树时,仍然先访问根结点,然后遍历左子树,最后遍历右子树。图2.19中的二叉树进行前序遍历的结果(或称为该二叉树的前房遍历序列)为A、B、D、H、E、I、C、F、G。
(2)中序遍历
首先遍历左子树,然后访问根结点,最后遍历右子树;并且在遍历左子树和右子树时,仍然首先遍历左子树,然后访问根结点,最后遍历右子树。对图2.19中的二又树进行中序遍历的结果(成称为该二叉树的中序遍历序列)为H、D、B、E、I、A、C、F、G。
(3)后序遍历
首先遍历左子树,然后遍历右子树,最后访问根节点;并且在遍历左子树和右子树时,仍然首先遍历左子树,然后遍历右子树,最后访问根节点。对图2.19中的二叉树进行后序遍历的结果(或称为该二又树的后序遍历序列)为H、D、I、E、B、G、F、C、A。
如果已知一棵二又树的前序遍历序列和中序遍历序列,可以唯一确定这棵二又树;已知一棵二又树的后序遍历序列和中序遍历序列,也可以唯一确定这棵二叉树。但是,已知一棵二又树的前序遍历序列和后序遍历序列,不能唯一确定这棵二叉树。
考点7:查找
1、顺序查找
基本思想:从线性表的第1个元素开始,逐个将线性表中的元素与被查元素进行比较,若相等,则查找成功,停止查找;若整个线性表扫描完毕,仍未找到与被查元素相等的元素,则表示线性表中没有要找的元素,查找失败。
最好的情况下,第1个元素就是要查找的元素,比较的次数为1。
最坏情况下,最后一个元素才是要找的元素,或者在线性表中,没有要查找的元素,则需要与线性表中所有的元素比较,比较的次数为n。
平均情况下,大约需要比较n/2次。
在以下两种情况中,顺序查找是唯一的选择:
(1)线性表为无序表(即表中的元素是无序的),则不管采用的是顺序存储结构还是链式存储结构,都只能用顺序查找。
(2)即使线性表是有序的,如果采用的是链式存储结构,也只能用顺序查找。
2、二分法查找
能使用二分法查找的线性表必须满足以下两个条件:用顺序存储结构、线性表为有序表。此处的“有序“特指元素按非递减顺序排列,即从小到大排列,但允许相邻元素相等。
对于长度为n的有序线性表,利用二分法查找元素ⅹ的过程如下。
将x与线性表的中间项比较过程如下。
如果×的值与中间项的值相等,则查找成功,结束查找。
如果X小于中间项的值,则在线性表的前半部分以二分法继续找。
如果X大于中间项的值,则在线性表的后半部分以二分法继续查找。
顺序查找每比较一次,只将查找范围缩小1,而二分法查找,每比较一次,可将查找范围缩小为原来一半,效率大大提高。对于长度为n的有序线性表,在最坏情况下,二分法查找只需比较log2n次。
考点8:排序
排序是指将一个无序序列整理成按值非递减顺序排列的有序数列。
1、交换类排序
交换类排序是借助数据元素的“交换“来进行排序的一种方法;
(1)冒泡类排序
在数据元素的序列中,对于某个元素,如果其后存在一个元素小于它,则称之为存在一个逆序。冒泡排序的基本思想就是通过两两相邻数据元素之间的比较和交换,不断地消去逆序,直到所有数据元素有序为止。
在最坏情况下,对长度为n的线性表排序,冒泡排序需要比较的时间为n(n-1)/2。
(2)快速排序
基本思想:在待排序的n个元素中取一个元素K(通常取第1个元素),以元素K作为分割标准,把所有小于K的数据元素都移到K的前面,把所有大于K的元素都移到K后面。这样,以K为分界线,把线性表分割为两个子表,这称为一趟排序。然后,对K前后的两个子表分别重复上述过程,直到分割的子表长度为1为止。这时线性表已经排好序。
快速排序最坏的情况下需要进行n(n-1)/2次比较,但实际的排序效率要比冒泡排序高得多。
2、插入类排序
插入类排序是每次将一个待排序元素,按其元素值大小插入前面已经排好序的子表的适当位置,直到全部元素插入完成为止。
(1)简单插入排序
简单插入排序是把n个待排序元素看成一个有序表和一个无序表。开始时,有序表兄包含一个元素,而无序表包含另外n-1个元素。每次取无序表中的第1个元素插入到有序表的正确位置,使之成为增加一个元素的新的有序表。插入元素时,插入位置及其后的记录依次向后移动。最后有序表的长度为n,而无序表为空,此时排序完成。
在最坏情况下,简单插入排序需要进行n(n-1)/2次比较。
(2)希尔排序
希尔排序的基本思想是,先取一个整数(称为增量)d1<n,把全部数据元素分成d1
个组,所有距离为d1
倍数的元素放在一个组里,组成一个子序列,对每个子序列分别进行简单插入排序。然后取d2
<d1
重复上述分组与排序工作,直到di
=1,即所有记录在一组中为止。
希尔排序的效率与所选取的增量序列有关。在最坏情况下,希尔排序需要比较的次数为nr(1<r<2)。
3、选择类排序
选择类排序的基本思想是通过每一次从待排序序列中选出值最小的元素,然后将其顺序放在已经排好序的有序子表的后面,直到全部序列满足排序要求为止。
(1)简单选择排序
基本思想:先从所有n个带排序元素中选出最小的元素,将该元素与第一个元素交换,再从剩下的n-1个元素中选出最小的元素与第二个元素交换。重复这样的操作直到所有的元素有序为止。
简单选择排序在最坏情况下需要比较n(n-1)/2次。
(2)堆排序
若有n个元素的序列(h1,h2
,…,hn
),将元素按顺序组成一棵完全二叉树,该树当且仅当满足下列条件时称为堆。
hi>=h2i
、hi
>=h2i+1
或者hi<
=h2i
、hi
<=h2i+1
,其中i=1,2,3,…,n/2。
第1种情况成为大根堆,所有节点的值大于或等于左右子节点的值。第2种情况称为小根堆,所有节点的值小于或等于左右子节点的值。
堆排序在最坏情况下需要比较nlog2n次。
2.1.3 程序设计基础
考点1:程序设计风格
程序的质量主要受到程序设计的方法、技术及风格等因素的影响。“清晰第一,效率第二”是当今主导的程序设计风格,即首先要保证程序的清晰、易读,其次考虑提高程序的执行速度、节省系统资源;
要形成良好的程序设计风格,主要应注重和考虑下属因素。
①源程序文档化。
②数据说明风格:次序应规范化;变量安排有序化;使用注释来说明复杂数据的结构等。
③语句的结构:不要在统一行内写多个语句;首先保证程序正确,然后要求提高速度;尽可能使用库函数;避免不必要的转移等。
④输入和输出:对所有的输入数据都要进行检验,,确保输入数据的合法性;在采用交互式输入/输出方式进行输入时,在屏幕上使用提示符明确提示输入的请求,同时在数据的输入过程中或输出结束时,应在屏幕上给出状态信息;给所有的输出加注释;并设计良好的输出报表格式等。
考点2:结构化程序设计
就程序设计方法的发展而言,只要经历了结构化程序设计和面向对象的程序设计两个阶段。
1、结构换程序设计的原则
结构化程序设计方法的重要原则时自顶向下、逐个求精、模块化及限制使用goto语句;
2、结构化程序设计的基本结构
结构换程序设计的方法是使用“顺序结构”“先择结构”及“循环结构”3种基本结构就足以表达其他各种结构的程序设计方法。它们的共同特征是:只有一个入口和一个出口。
遵循结构化程序的设计原则,按此原则设计出的程序具有以下优点。
程序易于理解、使用及维护。
提高了编程工作的效率,降低了软件开发成本。
考点3:面向对象方法
1、面向对象方法的优点
与人类习惯的思维方法一致;
稳定性好;
可重用性好;
便于开发大型软件产品;
可维护型好。
2、面向对象方法的基本概念
(1)对象
面向对象方法种的抽象由两部分组成。
①数据,也称为属性,即对象所包含信息,表示对象的状态;
②方法,也称为操作,即对象能执行功能,所具有的行为;
对象的基本特点如图所示:
特点 | 描述 |
标识唯一性 | 对象是可区分的,且由对象的本质来区分,而不是通过描述来区分; |
分类性 | 指可以将具有相同属性和操作的对象抽象成类; |
多态性 | 指同一操作可以是不同对象的行为,不同对象执行同一操作可以产生不同的结果; |
封装性 | 从外面看只能看到对象的外部特征,对象的内部对外是不可见的; |
模块独立性好 | 由于完成对象功能所需的元素都被封装在对象内部,因此模块独立性好; |
(2)类和实例
类是具有共同属性、共同方法的对象的集合,是关于对象的抽象描述,反映属于该对象类型的所有对象的性质。一个具体对象则是其对应类的一个实例。
类是对象性质的描述,它同对象一样,包括一组数据属性和在数据上的一组合法操作。
(3)消息
消息传递是对象间通信的手段,一个对象通过向另一个对象发送消息来请求其服务。
(4)继承
在面向对象的程序设计中,类与类之间可以继承,一个子类可以直接继承其父类的全部描述(数据和操作)。这些属性和操作在子类中不必定义,此外,子类还可以定义它自己的属性与操作。
继承具有传递性,如果类Z继承类Y,类Y继承类X,则类Z继承类X。
需要注意的是,类与类之间的继承应根据需要来做,并不是任何类都要继承。
(5)多态性
在面向对象的软件技术中,多态性是指子类对象可以像父类对象那样使用,同样的消息(如方法)既可以发给父类对象,也可以发给子类对象。
2.1.4 软件工程基础
考点1:软件工程的基本概念
1、软件定义域软件特点
计算机软件是由程序、数据及相关文档构成的完整集合,它与计算机硬件一起组成计算机系统。其中,程序和数据是机器可执行的,文档是及其不可执行的。
软件具有以下特点。
(1)软件是一种逻辑实体,具有抽象性;
(2)软件没有明显的制作过程;
(3)软件在使用期间不存在老化、磨损问题;
(4)软件对硬件和环境具有依赖性;
(5)软件复杂性高,成本高;
(6)软件开发涉及诸多的社会因素。
2、软件的分类
计算机软件按功能分为系统软件、应用软件、支撑软件(或工具软件);
(1)系统软件是管理计算机的资源,提高计算机使用效率,为用户提供各种服务的软件。如操作系统、数据库管理系统、编译程序、汇编程序及网络软件等。系统软件是最靠近计算机硬件的软件。
(2)应用软件是为了用于特定的领域而开发的软件。我们熟悉的办公软件,即时通信、杀毒软件、财务管理软件等属于应用软件。
(3)支撑软件是介于系统软件和应用软件之间,协助用户开发软件的工具软件,其中包括帮助程序开发人员开发和维护产品的工具软件,也包括帮助管理人员控制开发进程和项目管理的工具软件。
3、软件工程
软件工程是试图用工程、科学及数学的原理与方法研制、维护计算机软件的有关技术和管理方法,是应用于计算机的软甲定义、开发和维护的一整套方法、工具、文档、时间标准与工序。软件工程包含3个要素:方法、工具及过程。
抽象、信息隐蔽、模块化、局部化、确定性、一致性、完备性及可验证性是软件工程的原则。
4、软件过程
软件过程是把输入转化为输出的一组彼此相关的资源和活动。软件过程是为了获得高质量软件所需要完成的一系列任务的框架,它规定了完成各项任务的工作步骤。软件过程所进行的基本活动主要由软件规格说明、软件开发或软件设计与实现、软件确认、软件演进。
5、软件生命周期
软件开发应遵循软件生命周期。通常把软件陈品从问题定义、可行性研究、需求分析、概要设计、详细设计、软件实现、软件测试、使用、维护和退役的过程称为软件生命周期。软件生命周期分为3个时期,共8个阶段
各阶段的任务:
(1)问题定义:确定要解决的问题是什么。
(2)可行性研究:决定该问题是否存在一个可行的解决办法,确定完成开发任务的实施计划;
(3)需求分析:对待开发软件提出的需求进行分析并给出详细定义。编写软件规格说明书与初步的用户手册,提交评审。
(4)软件设计:通常又分为概要设计和详细设计两个阶段,其目的是给出软件的结构、模块的划分、功能的分配以及流程处理等。软件设计阶段提交评审的文档有概要设计说明书、详细设计说明书及测试计划初稿。
(5)实现:在软件设计的基础上编写程序。该阶段完成的文档有用户手册、操作手册等面向用户的文档,以及为下一步做准备而编写的单元测试计划。
(6)测试:在设计测试用例基础上,检验软件的各个组成部分。编写测试分析报告。
(7)使用和维护:将已交付的软件投入运行,同时不断地维护,进行必要而且可行的扩充和删改。
考点2:需求分析及其方法
- 需求分析:
(1)需求分析相关概念
需求分析是发现需求、求精、建模及定义需求的过程。需求分析将创建所需的数据模型、功能模型及控制模型。
需求分析阶段的工作可以分为4个方面:需求获取、需求分析、编写需求规格书及需求评审。
(2)需求规格说明书
需求规格说明书是需求分析阶段的最后成果。需求规格说明书应重点描述软件的目标,如软件的功能需求、性能需求、外部接口、属性及约束条件等。
需求规格说明书的特点:正确定、无歧义性、完整性、可验证性、一致性、可理解性、可修改性、可追踪性。
(3)需求分析方法
需求分析方法可以分为结构化分析方法和面向对象分析方法两大类。
①结构化分析方法。结构化分析方法只要包括面向数据流的结构化分析方法、面向数据结构的系统开发方法、面向数据结构的结构化数据系统开发方法。
②面向对象分析方法。面向对象分析是面向对象软件工程方法的第1个环节,包括概念原则、过程步骤、表示方法、提交文档等规范要求。
另外,从需求分析建模的特性来划分,需求分析方法还可以分为静态分析方法和动态分析方法。
2、结构化分析方法的常用工具
结构换分析方法是使用数据流图、数据字典、结构化英语、判定表及判定树的工具建立一种新的、被称为结构化规格说明的目标文档。
需求分析的结构化分析方法中常用的工具是数据流程图,数据流图的主要数据元素如表;
名称 | 图形元素 | 说明 |
数据流(data flow) | → | 沿箭头方向传输数据,一般在旁边标注数据流名。 |
加工(process) | Ο | 又称转换,表示数据处理 |
存储文件(file) | = | 又称数据源,表示处理过程中存放各种数据的文件 |
源/宿(source/sink) | □ | 数据起源的地方或目的地 |
为使构造的数据流图表达完整、准确、规范,应遵循如下构造会泽和注意事项:
(1)数据流图上的每个元素都必须被命名;
(2)对加工处理建立唯一、层次性的编号,并且每个加工处理通常要求既有输入,又有输出;
(3)数据存储之间不应该有数据流;
(4)数据流图的一致性,即输入/输出、读/写的对应;
(5)父图、子图关系与平衡规则:子图个数不大于父图中的处理个数。所有子图的输入/输出数据流和父图中相应处理的输入/输出数据流必须一致。
考点3:软件设计及其方法
1、软件设计的基本概念
软件设计的基本目标是用比较抽象、概括的方式确定目标系统如何完成预定的任务。也就是说,软件设计是确定系统的物理模型。
软件设计是开发阶段最重要的步骤之一。从工程管理角度看,软件设计可分为两步:概要设计和详细设计。从技术方面来看,软件设计包括结构设计、数据设计、接口设计、过程设计4个步骤。
将软件功能分解为组成模块,是概要设计的主要任务。划分模块要本着提高独立性的原则。模块独立性高低决定设计的好坏,而设计又决定软件质量的关键环节。模块的独立性可以由两个定性标准度量:耦合性和内聚性。
(1)耦合性衡量不同模块彼此间相互依赖(连接)的紧密程度。
(2)内聚性衡量一个模块内部各个元素彼此结合的紧密程度。
模块的内聚性越高,模块间的耦合性就越低,可见模块的耦合性和内聚性是相互关联的,因此,好的软件设计,应尽量做到高内聚、低耦合。
2、概要设计
(1)概要设计的任务。
概要设计又称总体设计,软件概要设计的基本任务如下。
①设计软件系统结构。
②设计数据结构和数据库;
③编写概要设计文档:概要设计阶段的文档有概要设计说明书、数据库设计说明书及集成测试计划等。
④评审概要设计文档。
(2)结构图。
在概要设计中,常用的软件结构设计工具是结构图,也称为程序结构图。它反映了整个系统的功能实现以及模块之间的联系。
结构图的基本图符及其含义 表2.16
概念 | 含义 |
模块 | 一个矩形代表一个模块,矩形内注明模块的名字和主要功能; |
调用关系 | 矩形之间的箭头(或直线)表示模块间的调用关系; |
信息 | 用带注释的箭头表示模块调用过程中来回传递的信息。如果希望进一步标明传递的信息是数据信息还是控制信息,则可用带实心圆的箭头表示控制信息,带空心圆的箭头表示数据信息。 |
软件结构图是一种层次化的表示,它指出了软件各个模块之间的关系,软件结构图术语,如图2.21所示。
表2.17 软件结构图术语及其含义
术语 | 含义 |
上级模块 | 控制其他模块的模块 |
从属模块 | 被另一个模块调用的模块 |
原子模块 | 树中位于叶子节点的模块,也就是没有从属节点的模块 |
深度 | 表示控制的层数 |
宽度 | 最大模块数的层的控制跨度 |
扇入 | 调用一个给定模块的模块个数 |
扇出 | 由一个模块直接调用的其他模块个数 |
好的软件设计结构通常顶层扇出多,中间较低扇出,底层扇入多。
3、详细设计
详细设计的任务是为软件结构图中的每一个模块确定实现算法和局部数据结构,用某种选定的表达工具表示算法和数据结构的细节。
常用的设计工具有程序流程图、N-S图、问题分析图、HIPO图、判定表、过程设计语言。
考点4:软件测试
1、软件测试的目的和准则
软件测试的目的是在软件投入运行以前,尽可能多地发现软件中的错误。软件测试是保证软件质量、可靠性的关键步骤。它是对软件规格说明、设计和编码的最后复审。
软件测试应遵循如下准则。
(1)所有测试都应追溯到用户需求;
(2)在测试之前指定测试计划,并严格执行;
(3)充分注意测试中的群集现象;
(4)避免由程序的编写者测试自己的程序;
(5)不可能进行穷举测试;
(6)妥善保管测试计划、测试用例、出错统计和最终分析报告,为维护提供方便。
2、软件测试方法
软件测试方法较多,如果根据软件是否需要被执行,可以分为静态测试和动态测试;如果根据功能划分,可以分为百合测试和黑盒测试。
(1)静态测试和动态测试
①静态测试。静态测试包括代码检查、静态结构分析、代码质量度量等。其中代码检查分为代码审查,代码走查、桌面检查、静态分析等具体形式。静态测试不实际运行软件,主要通过江进行分析。
②动态测化。动态测试就是通常所说的上机测试,通过运行软件来检验软件中的动态行为和运行结果的正确性。
动态测试的关键是设计高效、合理的测试用例。测试用例就是为测试设计的数据,由测试输入数据和预期的输出结果两部分组成。
(2)白盒测试与黑盒测试
①白盒测试。白盒测试假设程序装在一只透明的白盒子里,测试者完全了解程序的结构和处理过程。它根据程序的内部逻辑来设计测试用例,检查程序中的逻辑通路是否都按预定的要求正确地工作。
白盒测试的主要技术有逻辑覆盖测试、基本路径测试等。其中逻辑覆盖测试又分为语句覆盖、路径覆盖、判定覆盖、条件覆盖及判断―条件覆盖。
②黑盒测试。黑盒测试又称功能测试或数据驱动测试,着重测试软件功能,假设程序装在一个黑盒子里,测试者完全不了解或不考虑程序的结构和处理过程。它根据规格说明书的功能来设计测试用例,检查程序的功能是否符合规格说明书的要求。
常用的黑盒测试方法和技术有等价类划分法、边界值分析法及因果图等。
3、软件测试的实施
软件测试的实施过程主要有4个步骤:单元测试、集成测试、确认测试及系统测试。
(1)单元测试。
单元测试也称模块测试,模块是软件设计的最小单位,单元测试是对模块的正确性进行检验,以期尽早发现各模块内部可能存在的各种错误。
单元测试通常在编码阶段进行,单元测试的依据除了源程序还有详细设计说明书。
单元测试可以采用静态测试或者动态测试。动态测试通常以白盒测试为主,测试程序的结构;以黑盒测试为辅,测试程序的功能。
(2)集成测试。
集成测试也称组装测试,它是对各模块按照设计要求组装成的程序进行测试,主要目的是发现与接口有关的错误(系统测试与此类似)。
集成测试主要发现设计阶段产生的错误。集成测试的依据是概要设计说明书,通常采用黑盒测试。
集成的方式可以分为非增量方式(一次性组装方式)集成和增量方式集成两种。增量方式包括自顶向下、自底向上,以及自顶向下和自底向上相结合的混合增量方式。
(3)确认测试。
确认测试的任务是检查软件的功能,性能及其他特征是否与用户的需求一致,它是以需求规格说明书作为依据的测试。确认测侙通常采用黑盒测试。
(4)系统测试。
在确认测试完成后,把软件系统整体作为一个元素,与计算机硬件、支持的软件、数据、人员及其他计算机系统的元素组合在一起,在实际运行环境下对计算机系统进行一系列的集成测试和确认测试,这样的测试称为系统测试。
考点5:程序调试
1.程序调试的基本概念
调试,也称为排错,是在成功测试之后出现的步骤。也就是说,调试是在测试发现错误之后排除错误的过程。程序调试的任务是诊断和改正程序中的错误。
程序调试由两部分组成。
(1)根据错误的迹象确定程序中错误的确切性质、原因和位置。
(2)对程序进行修改,改正这个错误。
2、调试方法
从是否跟踪和执行程序的角度,调试分为静态调试和动态调试。静态调试是主要的调试手段,是指通过人的思维来分析源程序的代码和排错。而动态调试是静态测试的辅助手段,主要调试方法有强行排错法、回溯法、原因排除法(二分法、归纳法及演绎法)等。
2.1.5数据库设计基础
考点1:数据库的基本概念
1.基本概念
(1)数据
描述事物的符号记录称为数据。数据库系统中的数据具有长期保存的特点,它们通常称为持久性数据,而把一般存放在计算机内存中的数据称为临时性数据。
(2)数据库
数据库是指长期存储在计算机内的、有组织的、可共享的数据集合。
通俗理解,数据库就是存放数据的仓库,只不过,数据库存放数据是按数据所提供的数据模式存放的。数据库中的数据具有两大特点:集成与共享。
(3)数据库管理系统
数据库管理系统是数据库的机构,它是一个系统软件,负责数据库中的数据组织,数据操纵,数据维护、控制及保护,数据服务等。
数据库管理系统是数据库系统的核心,它位于用户和操作系统之间,从软件分类的角度来看,它属于软件系统。
数据库管理系统的主要功能包括:数据模式定义;数据存取的物理构建;数据操纵;数据完整性、安全性的定义与检查;数据库的并发控制与故障恢复;数据的服务等。
为了完成以上6个功能,数据库管理系统提供了相应的数据语言。
①数据定义语言。该语言负责数据的模式定义与物理存取构建。
②数据操纵语言。该语言负责数据的操纵,包括增删改查等操作。
③数据控制语言。该语言负责数据的完整性、安全性的定义与检查,以及并发控制,故障恢复等功能。
(4)数据库管理员。
由于数据库的共享性,数据库的规划、设计、维护、监视等都需要有专人(数据库管理员)管理。其主要工作是设计数据库、维护数据库、改善系统性能、及提高系统效率等。
(5)数据库系统。
数据库系统由以下几部分组成:数据库、数据库管理系统、数据库管理员、系统平台之一―硬件平台、系统平台之二―软件平台。数据库管理系统是一个以数据库管理系统为核心的、完整的运行实体。
(6)数据库应用系统。
在数据库系统的基础上,如果使用数据库管理系统软件和数据库开发工具编写出应用程序,用相关可视化工具开发出相应界面,则构成了数据库应用系统。数据库应用系统包括数据库、数据库管理系统、人员,硬件平台、软件平台应用软件,应用界面7个部分。
2.数据管理技术的发展
数据管理技术的发展经历了3个阶段:人工管理阶段、文件系统阶段,数据库系统阶段。背景和特点如表2.18。
人工管理阶段 | 文件系统阶段 | 数据库系统阶段 | ||
背景 | 应用目的 | 科学计算 | 科学计算、管理 | 大规模管理 |
硬件背景 | 无直接存取设备 | 磁盘、磁鼓 | 大容量磁盘 | |
软件背景 | 无操作系统 | 有文件系统 | 有数据库管理系统 | |
处理方式 | 批处理 | 联机实时处理、批处理 | 分布处理、联机实时处理和批处理 | |
特点 | 数据管理者 | 人 | 文件系统 | 数据库管理系统 |
数据面向的对象 | 某个应用程序 | 某个应用程序 | 现实世界 | |
数据共享程度 | 无共享,冗余度大 | 共享性差,冗余度大 | 共享性好,冗余度小 | |
数据的独立性 | 不独立,完全依赖于程序 | 独立性差 | 具有高度的物理独立性和一定的逻辑独立性 | |
数据的结构化 | 无结构 | 记录内由结构,整体无结构 | 整体结构化,用数据模型描述 | |
数据控制能力 | 由应用程序控制 | 由应用程序控制 | 由数据库管理系统提供数据安全性、完整性、并发控制及恢复 |
3、数据库系统的基本特点
与人工管理和文件系统相比,数据库系统具有基本特点:数据的集成性、数据的高共享性和低冗余度、数据独立性、数据统一管理与控制;
数据库系统的数据独立性,是指数据库中数据独立于应用程序而不依赖于应用程序,及数据的逻辑结构、存储结构与存取方式的改变不会影响应用程序。数据独立性一般分为物理独立性和逻辑独立性两级。
4、数据库系统的内部结构体系
数据库系统在其内部分为三级模式和两级映射,如图2.23 所示。
(1)数据库系统的三级模式。
数据库系统在其内部分为三级模式,即概念模式、内模式及外模式。
①概念模式。概念模式也称为模式,是对数据库系统中全局数据逻辑结构的描述,是全体用户的公共数据视图。对它的描述可用数据库系统、对它的描述可用数据库系统中的数据定义语言定义。
②外模式。外模式也称子模式或者用户模式,是用户的数据视图,也就是用户能够看见和使用的局部数据的逻辑结构和特征的描述,是与某一应用有关的数据的逻辑表示。外模式通常是概念模式的子集。
③内模式。内模式也称物理模式,是数据物理结构和存储方“是数据物理结构和存储方式的描述,是数据在数据库内部的表示方式。
三级模式反映了模式的3个不同环境和它们的不同要求。其中内模式处于最内层,它反映了数据在计算机物理结构中的实际存储形式;概念模式处于中层,它反映了设计者的数据全局逻辑要求;而外模式处于最外层,它反映了用户对数据的要求。
一个数据库只有一个概念模式和一个内模式,有多个外模式。
(2)数据库系统的两级映射。
数据库系统在三级模式之间提供了两级映射:外模式/概念模式的映射和概念模式/内模式的映射。两级映射保证了数据库中的数据具有较高的逻辑独立性和物理独立性。
考点2:数据模型
1、数据模型的基本概念
(1)数据模型的概念
数据模型是对数据特征的抽象,通俗来讲,数据模型就是对现实世界的模拟、描述或表示,建立数据模型的目的是建立数据库来处理数据。
(2)数据模型的3要素
数据模型通常由数据结构、数据操作及数据约束3部分组成。
①数据结构:主要描述数据的类型、内容、性质以及数据间的联系等。
②数据操作:主要描述在相应数据结构上的操作类型与操作方式的操作类型与操作方式。
③数据约束:主要描述数据结构内数据间的语法、语义联系,它们之间的制约与依存关系,以及数据动态变化的规则,以保证数据的正确、有效及相容。
(3)数据模型的类型
数据模型按照不同的应用层次分为以下3种类型。
①概念模型:着重于对现实世界复杂事物的描述,及对它们内在联系的刻画。目前,著名的概念模型有实体联系模型(E-R模型)、面向对象模型、谓词模型。
②数据模型:是面向数据库系统的模型,着重于在数据库系统一级的实现。成熟并大量使用的数据模型有层次模型、网状模型、关系模型及面向对象模型等。
③物理模型:是面向计算机物理实现的模型。此模型给出了数据模型在计算机上物理结构的表示。
2、E-R模型
E-R模型是广泛使用的概念模型。它采用了3个基本概念:实体、属性及联系。
(1)E-R模型的基本概念。
①实体。客观存在并且可以相互区别的事物称为实体。实体可以是一个实际的事物,如一本书;也可以是一个抽象的事件,如一场演出。
②属性。描述实体的特性称为属性。如一个学生可以用学号、姓名等来描述。
③联系。实体之间的对应关系称为联系,它反映现实世界事物之间的相互关联。
实体间联系根据一个实体中可能出现的每一个实体与另一个实体型中有多少个具体实体存在联系,可归纳为3种类型。
类型 | 实例 |
一对一联系 | |
一对多联系 | |
多对多联系 |
(2)E-R模型3个基本概念之间的连接关系
E-R模型的3个基本概念是实体、联系及属性,但现实世界是有机联系的整体,为了表示现实世界,必须把这三者连接起来。
①实体(集)与联系的连接关系。一般来说,实体集之间必须通过联系来建立连接关系。
②属性与实体(集/联系)的连接关系。实体和联系是概念世界的基本元素,而属性是附属于实体和联系的,它本身兵不是独立的单位。
联系也可以附有属性。联系和它的属性构成了联系的完整描述。
(3)E-R图
E-R模型可以用图形来表示,该图形称为E-R图。E-R图可以直观地表达E-R模型。-在E-R图中我们分别用下面不同的集合图形表示E-R模型中的3个概念。
概念 | 含义 |
实体集表示法 | E-R图用矩形表示实体集,并在矩形内写上实体集的名字; |
属性表示法 | E-R图用椭圆形表示属性,在椭圆形内写上该属性的名称; |
联系表示法 | E-R图用菱形表示联系,在菱形内写上联系名; |
3个基本概念分别用3种集合图形表示,它们之间的连接关系也可以用图形表示。
3、关系模型
(1)关系模型的数据结构
关系模型是目前最常用的数据模型之一,关系模型的数据结构非常单一,在关系模型中,现实世界的实体与实体间的各种联系均用关系来表示。关系模型中常用的术语如表2.21所示。
术语 | 含义 | 实例 |
关系 | 关系模型采用二维表来表示关系,简称表,由表框架和表的元组组成。一个二维表就是一个关系; | 表2.22所示的二维表就是一个关系; |
属性 | 二维表中的一列称为属性;二维表中属性的个数称为属性元数; | 表2.22所示的属性有学号、姓名、系号等;表2.22中的关系属性元数为“5”; |
值域 | 每个属性的取值范围; | 表2.22所示的年龄属性的值域不能为负数; |
元组 | 二维表中的一行称为元组; | 表2.22所示的(06001,方铭,01,22,男)就是一个元组; |
候选码 | 二维表中能唯一标识元组的最小属性集; | 在表2.22中,当姓名不允许重名时,学号和姓名都是候选码; |
主键或主码 | 若一个二维表有多个候选码,则选定其中一个作为主键供用户使用; | 在表2.22中,存在两个候选码:学号和姓名,若选中学号作为唯一标识,那么,学号就是“学生登记表”关系的主码; |
外键或外码 | 若表M中的某属性集是表N的候选键或者主键,则称该属性集为表M的外键或外码; | 如果表2.23所示关系的主码是“系号”,那么“学生登记表”中的“系号”就是外码; |
表2.22 学生登记表
学号 | 姓名 | 系号 | 年龄 | 性别 |
06001 | 方铭 | 01 | 22 | 男 |
06003 | 张静 | 02 | 22 | 女 |
06234 | 白穆晕 | 03 | 21 | 男 |
表2.23 系信息表
系号 | 系名 | 主任 |
01 | 计算机 | 张庆 |
02 | 电气工程 | 李梅 |
03 | 外语 | 陈大海 |
关系具有以下7个性质。
①元组个数的有限性:二维表中元组的个数是有限的;
②元组的唯一性:二维表中任意两个元组不能完全相同;
③元组的次序无关性:二维表中元组的次序,即行的次序可以任意交换。
④元组分量的原子性:二维表中元组的分量是不可分割的基本数据项;
⑤属性名的唯一性:二维表中不同的属性要有不同的属性名;
⑥属性的次序无关性:二维表中不同的属性要有不同的属性名;
⑦分量值域的同一性:二维表属性的分量具有与该属性相同的值域,或者说列是同质的。
满足以上7个性质的二维表称为关系,以二维表为基本结构所建立的模型称为关系模型。
(2)关系模型的完整性约束。
关系模型有3种完整性约束:实体完整性约束,参照完整性约束及用户定义的完整性约束。在这种完整性约束种,前两种约束是任何一个关系数据库都必须满足的,由关系数据库管理系统自动支持。
①实体完整性约束。若属性M是关系的主键,则属性M的属性值不能为空。如在“学生登记表”中,主键为“学号”,则“学号”不能取空值。
②参照完整性约束。若属性(或属性组)A是关系M的外键,它与关系N的主键相对应,则关系M中的每个元组在A上的值:要么为空(A的每个属性值均为空);要么等于关系N中某个元组的主键值。
如对于“学生登记表”和“系信息表”,学生登记表中每个元组的“系号”属性只能取两类值:空值,表示尚未给学生分配系;非空值,这是该值必须是系信息表中某个元组的“系号”值,表示该学生不可能分配到一个不存在的系。
考点3:关系代数
关系代数就是关系与关系之间的运算。在关系代数中,进行运算的对象都是关系,运算的结果也是关系(即表)。
1、差运算
关系R和关系S经过差运算后得到的关系由属于关系R但不属于关系S的元素组成,记为R-S。图2.26所示为对关系R和关系S做差运算的示例。
2、交运算
假设有n元关系R和n元关系S,它们经过交运算得到的关系仍然是一个n元关系,该关系由属于关系R且属于关系S的元组构成,并记作R∩S。R∩S=R-(R-S)。图2.27所示为对关系R和关系S做交运算的示例。
3、并运算
关系R和关系S经过并运算后得到的关系由属于关系R和关系S的元组构成,记作R∪S。图2.28所示为对关系R和S做并运算的示例。
4、笛卡尔积运算
设有n元关系R和m元关系S,它们分别p和q个元组,则关系R与关系S的笛卡尔积记为R*S。它是一个m+n元关系,元组格式是p*q。图2.29所示为对关系R和关系S做笛卡尔积运算的示例。
关系R
A | B | C |
a | b | 21 |
b | a | 19 |
c | d | 18 |
d | f | 22 |
关系S
A | B | C |
b | a | 19 |
d | f | 22 |
f | H | 19 |
关系T=R*S
R.A | R.B | R.C | S.A | S.B | S.C |
a | b | 21 | b | A | 19 |
a | b | 21 | D | F | 22 |
a | b | 21 | F | H | 19 |
b | a | 19 | B | A | 19 |
b | a | 19 | D | F | 22 |
b | a | 19 | F | H | 19 |
c | d | 18 | B | A | 19 |
c | d | 18 | D | F | 22 |
c | d | 18 | F | H | 19 |
d | f | 22 | B | A | 19 |
d | f | 22 | D | F | 22 |
d | f | 22 | F | H | 19 |
图2.29 笛卡尔积运算示例
5、投影运算
从关系模型中指定若干个属性组成新的关系称为投影。
对关系R进行投影运算的结果记为πA(R),其形式定义如下:πA
(R)={t[A]|t∈R},其中,A为R的属性列。
如对关系R中的“系”属性进行投影运算,记为π系(R),得到无重复元组的新关系S,如图2.30所示。
关系R
姓名 | 性别 | 系 |
李明 | 男 | 新闻 |
赵刚 | 男 | 建筑 |
张圆 | 女 | 通信 |
王晓 | 男 | 电子 |
李健 | 男 | 数学 |
李文 | 男 | 建筑 |
投影后得到的新关系S
系 |
新闻 |
建筑 |
通信 |
电子 |
数学 |
6、选择运算
从关系中找出满足给定条件的元组操作称为选择。选择的条件以逻辑表达式给出,使得逻辑表达式为真的元组将被选取。
选择是在二维表中选出符合要求的行,并形成新的关系的过程。选择运算用公式表示为:
σF(R)={t|t∈R且F(t)为真}
其中,,F表示条件,它是一个逻辑表达式,取逻辑值“真”或“假”。逻辑表达式F由逻辑运算符┐、∧、∨连接各算术表达式组成。算术表达式的基本形式为:XΘY,其中,Θ表示比较运算符>、<、<=、>=、=、或!=。X、Y等为属性名、常量,或简单函数。属性名也可以用它的序号来代替。
如果关系R中选择出“系”和“建筑”的学生,表示为σ系=建筑(R),得到新的关系S,如图2.31所示。
关系R
姓名 | 性别 | 系 |
李明 | 男 | 新闻 |
赵刚 | 男 | 建筑 |
张圆 | 女 | 通信 |
王晓 | 男 | 电子 |
李健 | 男 | 数学 |
李文 | 男 | 建筑 |
选择后得到的新关系S
姓名 | 性别 | 系 |
赵刚 | 男 | 建筑 |
李文 | 男 | 建筑 |
图2.31 选择运算示例
7、除运算
除运算可以近似地看作笛卡尔积的逆运算,当S*T=R时,则必有R/S=T,T称为R除以S的商。
设关系R有属性M1,M2
,…,Mn
,此时有:
R/S=πM1,M2,…,Mn-s(R)-(πM1,M2,…,Mn-s
(πM1,M2,…,Mn-s
(R)*S)-R)
关系R、S,如图3.32(a)、(b)所示,求T=R/S,结果如图3.32(c)所示。
关系R:
关系R:
A | B | C | D |
a | b | 19 | d |
a | b | 20 | f |
a | b | 18 | b |
b | c | 20 | f |
b | c | 22 | d |
c | d | 19 | d |
c | d | 20 | f |
关系S:
C | D |
19 | D |
20 | F |
关系T=R/S
A | B |
A | b |
C | d |
图2.32 除运算示例
8、连接运算
连接运算也称Θ连接,是对两个关系进行的运算,其意义是从两个关系的笛卡尔积中选择满足给定属性间一定条件的元组。
设m元关系R和n元关系S,则R和S两个关系的连接运算用公式表示为
其中,A和B分别为关系R和关系S上度数相等且可比的属性组。连接运算从关系R和关系S的笛卡尔积R*S中,找出关系R在属性组A上的值与关系S在属性组B上的值满足Θ关系的所有元组。
当Θ为“=”时,该运算称为等值连接;当Θ为“<”时,该运算称为小于连接;当Θ为“>”时,该运算称为大于连接;
设关系R和关系S如图2.33(a)、(b)所示,对图中的关系R和关系S做连接运算的结果如图2.33(c)、(d)所示。
在实际应用中,最常用的连接是自然连接。自然连接要求两个关系中进行比较的是相同的属性,并且进行等值连接,相当于Θ恒为“=”,在结果中还要把重复的属性列去掉,自然连接可以标记为
考点4:数据库设计
1、数据库设计概述
基本思想:过程迭代和逐步求精。
方法:面向数据的方法面向过程的方法。
设计过程:需求分析->概念设计->逻辑设计->物理设计->编码->测试->运行->进一步修改。
2、数据库设计的需求分析
需求收集和分析是数据库设计的第一阶段,常采用结构化分析方法(自顶向下、逐层分解)和面向对象方法,主要工作有绘制数据流程图、分析数据和功能、确定功能处理模块和数据间关系等。
数据字典包括数据项、数据结构、数据流、数据存储和处理过程,是对系统中数据的详尽描述。
3、数据库的设计
(1)数据库的概念设计:分析数据间内在的语义关联,以建立数据的抽象模型。
(2)数据库的逻辑设计:从E-R图向关系模型转换,逻辑模式规范化,关系视图可以根据用户需求随时创建。实体转换为元组,属性转换为关系的属性,联系转换为关系。
(3)数据库的物理设计:对数据在物理设备上的存储结构与存取方法进行设计,目的是对数据库内部物理结构进行调整并选择合理的存取路径,以提高速度和存储空间;
4、范式
关系数据库中的关系需要满足一定条件,满足不同程度要求的关系为不同的范式。满足最低要求的关系叫第一范式,简称1NF。在满足第一范式的基础上,进一步满足更多要求的关系是第二范式。然后在满足第二范式的基础上,还可以满足第三范式,以此类推。
对于关系,若其中的每一个属性不能再分为简单项,则它属于第一范式。
若某个关系R为第一范式,并且R中每一个非主属性完全依赖于R的某个候选键,则称其为第二个范式。第二范式消除了非主属性对主键部分的依赖,满足第二范式:
S1(学号,姓名,所在系,系主任,年龄)
C(课程号,课程名)
SC1(学号,课程号,成绩)
如果R是第二范式,并且每个非主属性都不传递依赖于R的候选键,则称R为第三范式。(传递依赖:在关系模式中,如果Y->X,X->A,且X不决定Y,A不属于X,那么Y->A是传递依赖。)
如在关系S1中,学号->所在系,所在系->系主任,所以“系主任”传递依赖于主属性“学号”。对关系S1进行如下分解,即可消除传递依赖,满足第三范式:
S2(学号,姓名,所在系,年龄)
D(所在系,系主任)
C(课程号,课程名)
SC1(学号,课程号,成绩)
比第三范式更高级的是BC模式,它属于所有属性都不传递依赖于关系的任何候选项。
关系模式进行规范化的目的是使关系结构更加合理,消除存储异常,使数据容量尽量小,便于进行插入、删除和更新等操作。
2.2 二级C语言程序设计选择题高频考点
2.2.1 C语言概述
考点1:C语言基础知识
1、C语言的构成
(1)源程序由函数构成,每个函数完成相对独立的功能。
(2)每个源程序中必须有且只有一个主函数,其可以放在任何为止,但程序总是从主函数开始执行。
(3)函数体是函数后面用一对花括号括起来的部分;
(4)每个语句以分号结束,但预处理命令、函数头不能加分号;
(5)注释括在“/*”与”*/”之间,没有空格,允许出现在程序的任何位置;
(6)预处理命令是以“#”开头的语句。
2、C程序的生成过程
(1)C程序的生成过程为先由源文件经编译生成目标文件,然后经过链接生成可执行文件。
(2)源程序的扩展名为.c,目标程序扩展名为.obj,可执行程序扩展名为.exe。
考点2:常量、变量和数据类型
1、标识符
(1)标识符的命名规则。
只能由数字、字母、下划线构成;
第一个字母必须是字母或下划线,不能是数字;
区分大小写;
(2)标识符的分类。
C语言的标识符分为3类。
关键字:C语言规定专用的标识符,它们有着固定的含义,不能更改;
预定义标识符:在C语言中预先定义并具有特定含义的标识符。允许把这样的标识符重新定义,但不建议这样做。
用户标识符:由用户根据需要定义的标识符。命名时要注意“见名知义”,不能与关键字同名。
2、常量
定义:在程序运行中,其值不能被改变的量。
常量的类型:整型常量、实型常量、字符常量、字符串常量及符号常量。
(1)整型常量:
①表示形式:十进制整型常量、八进制整型常量、和十六进制整型常量;
②书写形式。
十进制整型常量:基本数字范围为0~9;
八进制整型常量:以0开头,基本数字范围为0~7;
十六进制整型常量:以0x开头,基本数字范围为0~15写为A~F或a~f。
(2)实型常量:
①表示形式:小数形式和指数形式;
②书写形式:十进制小数形式、指数形式(e前面必须有数字,e后面必须为整数);
(3)字符常量:
一个字符常量代表ASCII字符集里的一个字符,在程序中用单撇号(“)标识,区分大小写。
转义字符以“\“开头,后面跟不同的字符标识不同的意思。
\n:换行;
\\:反斜杠字符;
\ddd:1~3位八进制数所代表的一个ASCII字符;
\xhh:1~2位十六进制数所代表的一个ASCII字符;
(4)字符串常量。
字符串常量是用双撇号(““)标识的一个或一串字符。
(5)符号常量。
符号常量是由预处理命令“#define“定义的常量,在C程序中可用标识符代表一个常量。
3、变量
定义:值可以改变的量。
变量要有变量名,在使用前必须先定义;
在内存单元中占据一定的存储单元,不同类型的变量占据的存储单元大小不同;
存储单元里存放的是该变量的值;
变量的类型:整型变量、实型变量、字符变量。
(1)整型变量。
①分类:基本型、短整型、长整型和无符号型。
②数值范围:整型16位,短整型16位,长整型32位,无符号整型16位,无符号长整型32位。
(2)实型变量。
①分类:单精度类型、双精度类型;
②定义方法:float a;double m;
③所占字节:float类型4各字节,double类型8个字节。单精度提供7~8位有效数字,双精度提供15~16位有效数字。
④实型常量:不分float型和double型,一个实型常量可以赋给一个float型或double型变量,但变量根据其自身类型截取实型常量中相应的有效数字。
(3)字符变量。
①作用:用来存放字符常量;
②定义:用关键字char定义,每个字符变量中只能存放一个字符;
③定义形式:char ch1,ch2;
④赋值:ch1=’a’;
⑤存储方法:存储字符对应的ASCII到内存单元中;
字符型数据与整型数据之间可以通用,一个字符能用字符的形式输出,也能用整数的形式输出。
字符型数据进行算数运算,相当于对它们的ASCII进行运算。
4、类型的自动转换和强制转换
(1)类型的自动转换。
①当同一表达式中各数据的类型不同时,编译程序会自动把它们转变成同一类型后在进行计算。
②转换优先级为char<int<float<double,左边的类型向右边转换;
③当做赋值运算时,若赋值运算符左右两边的类型不同,则赋值运算符右边的类型向左边的类型转换;若右边的类型高于左边的类型,则在转换时对右边的数据进行截取。
(2)类型的强制转换。
表示形式:(类型)(表达式);
2.2.2 运算符与表达式
考点1:常考的C语言运算符
1、C语言运算符简介
算术运算符:+、-、*、/、%;
关系运算符:>、>=、<、<=、==、!=;
位运算符:>>、<<、~、&、|、∧;
逻辑运算符:!、||、&& ;
条件运算符:?:;
指针运算符:&、*;
赋值运算符:=;
逗号运算符:,;
字节运算符:sizeof;
强制运算符:(类型名)(表达式);
初等运算符:圆括号(()),下标运算符([])及结构体成员运算符(->)。
2、运算符的结合性和优先级
(1)结合性。所有的单目运算符、条件运算符、赋值运算符及其扩展运算符,结合方向都是从右向左,其余运算符的结合方向是从左向右。
(2)优先级比较。初等运算符>单目运算符>算术运算符>关系运算符>逻辑运算符>条件运算符>赋值运算符>逗号运算符。
3、强制类型转换运算符
(1)可以利用强制类型转换运算符将一个表达式转换成所需类型;
(2)一般形式:(类型名)(表达式);
4、逗号运算符和逗号表达式
(1)逗号表达式:用逗号运算符将几个表达式连接起来;
(2)一般形式:表达式1,表达式2,…,表达式n;
(3)求解过程:先求解表达式1,然后依次求解表达式2到表达式n的值。表达式n的值就是整个逗号表达式的值。
考点2:算术运算符和算术表达式
1、基本的算数运算符
(1)分类:加法运算符或正值运算符(+)、减法运算符或负值运算符(-)、乘(*)、除(/)和求余(%)。
其中,求余运算符的两端必须都是整型,其余运算符的对象可以是整型或者实型;
(2)双目运算符两边的数值类型必须一致才能进行运算,如果不一致,系统会先进行一致性转换。转换规则:char->short->int->unsigned->long->float->double。
(3)所有实数的运算都是以装精度方式进行的,若是单精度数,则需要在位数后面补0转换为双精度数。
2、算术表达式和运算符的优先级与结合性
(1)定义:用算术运算符和括号将运算对象连接起来的、符合C语言语法规则的表达式。
(2)运算对象:函数、常量和变量等;
(3)运算规则:
可使用多层圆括号,但圆括号必须配对。运算时由内向外依次计算个表达式的值;
对于不同优先级的运算符,按其优先级由高到低进行运算,若优先级相同,则按结合方向进行运算。
若运算符两侧的运算对象类型不同,则先利用自动转换或强制类型转换,使其类型相同然后进行运算。
3、自增、自减运算符
(1)作用:自增运算符(++)使运算变量的值增1,自减运算符(--) 使运算变量的值减1;
(2)均是单目运算符。运算对象可以是整型或实型变量,但不能是常量和表达式;
(3)均可作为前缀运算符,也可作为后缀运算符构成一个表达式;
++i,--:在使用i之前,先使i的值自增1(自减1),再使用变化后的变量值参加表达式运算;
i++,i--:i的值先参加表达式运算,在执行自增1(自减1);
(4)结合方向:自右向左;
考点3:赋值运算符和赋值表达式
1、赋值运算符和赋值表达式
(1)“=”称为赋值运算符,作用是将一个数值赋给一个变量或将一个变量的值赋给另一个变量,由赋值运算符组成的表达式称为赋值表达式。
(2)一般形式:变量名=表达式。
赋值运算符的优先级高于逗号运算符;
赋值运算符(=)和等于运算符(==)有很大差别;
赋值运算符的左侧只能是变量,而不能是常量或者表达式。赋值运算符的右侧可以是表达式,包括表达式,包括赋值表达式;
规定最左侧变量所得到的新值就是整个赋值表达式的值;
2、复合的赋值运算符
在赋值运算符之前加上其他运算符可以构成复合赋值运算符。例如+=、-=、*=、/=、%=等;
两个符号之间不能有空格;
符合赋值运算符的优先级与赋值运算符的优先级相同;
3、赋值运算中的类型转换
如果赋值运算符两侧的类型不一致,在赋值前系统将自动先把右侧表达式求得的数值按赋值运算符左侧变量的类型进行转换(也可以用强制类型转换的方式)。
考点4:位运算
1、C语言提供6种位运算符
按位与(&):若两个相应的二进制位都为1,则该位的结果为1,否则为0;
按位或(|):若两个相应的二进制位中有一个为1,则该位的结果为1,否则为0;
按位异或(∧):若两个二进制位相同,结果为0,否则为1;
按位求反(~):按位取反,0变成1,1变成0;
左移(<<):将一个数的二进制位全部左移若干位;
右移(>>):将一个数的二进制位全部右移若干位;
2、说明:
位运算中除按位求反以外,均为双目运算符,要求两侧各有一个运算对象;
运算对象只能为整型或字符型数据,不能为实型数据;
2.2.3 基本语句
考点1:单个字符的输入与输出
1、字符输出函数putchar()
向终端输出一个字符;
2、字符输入函数getchar()
作用:接收终端输入的一个字符;
getchar()函数没有参数,函数值就是从输入设备得到的字符;
考点2:数据格式的输入与输出
1、格式化输出函数printf()
printf()函数是C语言提供的标准输出函数,它的作用是向终端(或系统隐含指定的输出设备)按指定的格式输出若干个数据。
(1)printf()函数的一般形式:printf(格式控制字符串,输出列表);
①格式控制字符串:用双撇号标识的字符串是格式控制字符串,它包含两种信息。格式转换信息(由%和格式字符组成)、需要原样输出的字符也写在格式控制字符串内;
②输出列表:需要输出的一些数据,可以是常量、变量或表达式。输出列表中各输出项用逗号隔开。
(2)格式字符。
可在“%”与格式字符之间插入“宽度说明”、左对齐符号“-”、前导零符号“0”等。
d格式字符,用于输出十进制数;
o格式字符,以八进制形式输出整数;
x格式字符,以十六进制格式输出整数;
u格式字符,用于输出unsigned型数据,即输出无符号的十进制数;
c格式字符,用于输出一个字符;
s格式字符,用于输出一个字符串;
f格式字符,用于输出实型(包括单、双精度),以小数形式输出,使整数部分全部输出;
e格式字符,以指数形式输出实数;
g格式字符,用于输出实数;
(3)使用printf()函数时的注意事项:
在格式控制字符串中,格式说明与输出项个数要相等;
在格式控制字符串中,可以包含任意的合法字符(包括转义字符),这些字符在输出时将被“原样输出”;
如果要输出“%”,则应该在格式控制字符串中用两个连续的百分号”%%”来表示。
2、格式化输出函数scanf()
(1)scanf()函数的一般形式:scanf(格式控制字符串,地址列表);
其中,scanf时函数名,格式控制字符串的含义同printf()函数中“格式控制”的含义,地址列表由若干个变量地址组成,既可以时变量的地址,也可以是字符串的首地址;
(2)格式说明。
scanf()函数中的格式说明也是以%开始,以一个格式字符结束,中间可以加入附加的字符。
对unsigned型变量的数据,可以用%d、%o、%x格式输入;
在scanf()函数中格式字符前可以用一个整数指定输入数据所占宽度,但若输入的是实型数据,则不能指定其小数的位的宽度;
在格式控制字符串中,格式说明的个数应该与输入项的个数相等,且类型要匹配;
(3)使用scanf()函数时的注意事项;
scanf()函数中的输入项只能是地址表达式,而不能是变量名或其他内容;
如果在格式控制字符串中除了格式说明以外还有其他字符,则在输入数据时应输入与这些字符相同的字符;
当用“%c”格式输入字符时,空格字符和转义字符都可以作为有效字符输入;
当输入数据时,若遇到以下情况则认为输入结束:空格、回车(Enter)、跳格(Tab),上述字符可统称为“间隔符”。
2.2.4 选择结构
考点1:关系运算符和关系表达式
1、关系运算符及其优先次序
C语言提供了6中关系运算符:小于(<)、小于等于(<=)、大于(>)、大于等于(>=)、等于(==)、不等于(!=)。
(1)结合性:自左向右;
(2)优先级。
前4种关系运算符(<、<=、>、>=)的优先级相同,后两种关系运算符(==、!=)的优先级相同。
前4种关系运算符的优先级高于后两种。
关系运算符的优先级低于算术运算符,高于赋值运算符。
2、关系表达式
(1)定义:由关系运算符组成的表达式。关系运算符的两边可以是C语言中任意合法的表达式。
(2)关系运算符的结果是一个整数值——“0或者非0”,用非0值来表示“真”,用0值表示“假”。
(3)当关系运算符两边值的类型不一致时,系统将自动转换使其一致。
考点2:逻辑运算符和逻辑表达式
1、逻辑运算符及其优先级:
C语言提供了3种逻辑运算符:逻辑与(&&)及逻辑或(||)及逻辑非(!)。其中&&和||是双目运算符,而!是单目运算符,且要求其必须出现在运算对象的左边。
(1)结合性:自左至右;
(2)优先级:!>&&>||;
2、逻辑表达式:
(1)逻辑表达式由逻辑运算符和运算对象组成。
(2)参与逻辑运算的对象可以是一个具体的值,还可以是C语言中任意合法的表达式。
(3)逻辑表达式的运算结果为1(真)或者为0(假)。
A&&B运算中,只有A和B 都为真时结果才为真;
A||B运算中,只有A、B同为假时才为假;
关系运算符不能连用,既不能写成0<x<10,可以改写成“0<x&&x<10”;
考点3:if语句和用if语句构成的选择结构
1、if语句的几种形式
形式1:if(表达式)语句
if是C语言的关键字;
表达式两侧的括号不能少,并且只能是圆括号;
紧跟着的语句,称为if子句,如果在if子句中需要多个语句,则应该使用花括号标识,使一组语句构成符合语句;
形式2:
if(表达式)语句1
else 语句2
形式3:
if(表达式1)语句1
else if(表达式2)语句2
else if(表达式3)语句3
…
else 语句n
“语句1”是if子句,“语句2…语句m”是else子句。这些子句在语法上要求是一条语句,当需要执行多条语句时,应该使用花括号把这些语句标识为复合语句。
else必须与if配对,共同组成if-else语句。
2、if语句的嵌套
在if语句中又包含一个或多个if语句结构,称为if语句的嵌套。
3、条件运算符构成的选择结构
(1)条件运算符:?:。
(2)条件表达式的一般形式:表达式1?表达式2:表达式3。
(3)求解过程:先求表达式1的值,当表达式1的值非0时,以表达式2作为整个条件表达式的值,当表达式1的值是0时,以表达式3的值作为整个条件表达式的值。
4、优先级
条件运算符高于赋值运算符,但低于逻辑运算符、关系运算符及算术运算符。
考点4:switch语句
switch语句是C语言提供的多分支选择语句,用来实现多分支选择结构。
一般形式:
switch(表达式)
{
case 常量表达式1:语句1
case 常量表达式2:语句2
…
case 常量表达式n:语句n
default:语句n+1
}
switch后面用花括号标识的部分是switch语句体;
switch后面用圆括号标识的“表达式”,可以是C语言中任意合法的表达式,但表达式两侧的圆括号不能省略。
case与其后面的常量表达式合称case语句标号,常量表达式的类型必须与switch后面的表达式的类型相匹配,且各case语句标号的值各不相同,不能重复。
default也是关键字,起标号的作用,代表除了以上所有case标号之外的那些标号,default标号可以出现在语句中任何标号位置上,当然,也可以没有。
case语句标号后的语句1、语句2等,可以是一条语句,也可以是若干条,在必要时,case语句标号后的语句可以省略不写。
2.2.5 循环结构
考点1:while循环语句
(1)一般形式。
while(表达式)循环体
while是C语言的关键字;
紧跟其后的表达式可以是C语言中任意合法的表达式。该表达式是循环条件,由它来控制循环体是否执行。
循环体只能是一条可执行语句,当多条语句需要多次重复执行时,可以使用复合语句;
(2)执行过程。
①计算紧跟while后圆括号中表达式的值,当表达式的值非0时,则接着执行while语句中的内嵌语句;当表达式值为0时,则跳过该while语句,执行该while结构后的其他语句。
②执行循环体内嵌语句;
③返回执行步骤①,直到条件不满足,即表达式的值为0,退出循环,while循环结束。
(3)特点。
先对表达式进行条件判断,后执行语句。
考点2:do-while语句
(1)一般形式:
do{
循环体语句;
}while(表达式);
do是C语言的关键字,必须和while联合使用,不能独立出现;
do-while循环由do开始,至while结束;
while后面的圆括号中的表达式,可以是C语言中人以合法的表达式,由它控制循环是否执行,且圆括号不可省略。
按照语法规则,do和while之间只能有一条语句,如需要执行多条语句,须使用复合语句。
while(表达式)后的分号不可省略。
(2)执行过程。
①先执行一次指定的循环体语句。
②执行完后,判别while后面的表达式的值,当表达式的值非0(真)时,程序流程返回,重新执行循环体语句。
③如此反复,直到表达式的值为0(假)为止,此时循环结束。
(3)特点。
先执行循环体一次,然后判断循环条件是否成立。
考点3:for语句
(1)一般形式。
for(表达式1;表达式2;表达式3)
圆括号中通常是3个表达式。for语句中的表达式可以部分或者全部省略,但两个”;”是不可省略的。
各个表达式之间用“;”隔开,且圆括号不可省略;
按照语法规则,循环体只能包含一条语句,如需要执行多条语句,须使用符合语句;
(2)执行过程。
①先求表达式1的值;
②求表达式2的值,若其值非0(真),则执行for语句中指定的内嵌语句,然后执行下面步骤③;若其值为0(假),则退出循环,执行for语句以下的其他语句。
③求表达式3的值;
④重复执行步骤②;
考点4:循环的嵌套
(1)定义:在某一个循环体内又包含了另一个完整的循环结构,称为循环的嵌套。
(2)前面介绍的3种类型的循环都可以相互嵌套。循环的嵌套可以多层,但要保证每一层循环在逻辑上必须是完整的。
考点5:几种循环的比较
while和do-while循环,只在while后面指定循环条件,循环体内应包含使循环趋于结束的语句。for中使循环趋于结束的操作可以包含在“表达式3”中。
由while完成的循环,用for循环都能完成。
考点6:break语句和continue语句
1、break语句
(1)在break语句后面加上分号就可以构成break语句。break语句还可以用于从循环体内跳出,即提前结束循环。
(2)说明。
break语句只能出现在循环体内及switch语句内,不能用于其他语句。
当break出现在循环体的switch语句体内时,起作用只是跳出该switch结构体。当break出现在循环体中,但并不在switch语句体内时,则在执行break后,跳出本层循环,当然也不再进行条件判断;
2、continue语句
(1)一般形式。
continue;
作用:结束本次循环,即跳过循环体中的continue语句下面尚未执行的语句,转而去重新判定循环条件是否成立,从而确定下一次循环是否继续执行。
2.2.6 数组
考点1:一维数组的定义和引用
1、一维数组的定义
一维数组是指数组中每一个元素只带有一个下标的数组。一般形式:类型说明符 数组名[常量表达式];
2、一维数组元素的引用
数组元素的引用形式:数组名[下标表达式];
一个数组元素实质上是一个变量名,代表内存中的一个存储单元,一个数组占据的是一连串连续的存储单元;
引用数组元素时,数组的下标可以是整型常量,也可以是整型表达式;
数组必须先定义后使用;
只能逐个引用数组元素而不能一次引用整个数组。
3、一维数组的初始化
当数组定义后,系统会为该数组在内存中开辟一串连续的存储单元,但这些存储单元中并没有确定的值。可以在定义数组时为所包含的数组元素赋初值,例如:
int a[6]={1,2,3,4,5,6};
所赋初值放在一对花括号中,数据类型必须与所定义类型一致;
所赋初值之间用逗号隔开,系统将这些数值的排列顺序,从a[0]元素开始依次给数组a中的元素赋初值;
不能跳过前面的元素给后面的元素赋初值,但是允许将前面元素赋值为0;
当所赋初值个数少于所定义数组的元素个数时,将自动给后面的其他元素补初值0;
可以通过赋初值来定义一维数组的大小,定义数组时方括号中可以不指定数组的大小;
考点2:二维数组的定义和引用
1、二维数组的定义
(1)在C语言中,二维数组中元素排列的顺序是按行存放,即在内存中先存放1行的元素,再存放第2行的元素。二维数组元素的存储总是占用一块连续的内存单元。
(2)一般形式。
类型说明符 数组名[常量表达式1][常量表达式2];
2、二维数组元素的引用
数组元素的引用形式:数组名[下标表达式1][下标表达式2];
数组的下标可以是整型表达式;
数组元素可以出现在表达式中,也可以被赋值;
3、二维数组的初始化
可以在定义二维数组的同时给二维数组的个元素赋值;
全部初值放在一对花括号中,每一行的初值又分别标识在一对花括号中,之间用逗号隔开;
当某行一对花括号内的初值个数少于该行中元素的个数时,系统将自动地给后面的元素赋值0;
不能跳过每行前面的元素而给后面的元素赋初值;
4、通过赋初值定义二维数组的大小
对于一维数组,可以在数组定义语句中省略括号中的常量表达式,通过所赋初值的个数来确定数组的大小;对于二维数组,只可以省略第1个方括号中的常量表达式,而不能省略第2个方括号中的常量表达式。
考点3:字符数组
1、字符数组的定义
字符数组就是数组中每个元素都是字符。定义方法同普通数组的定义方法相同,即逐个对数组元素赋值。
2、字符数组的初始化及引用
(1)初始化。对字符数组初始化,可逐个元素地赋值,即把字符逐个赋给数组元素;
如果花括号中提供的初值个数(即字符个数)大于数组长度,则编译时会按语法错误处理;
如果初值个数小于数组长度,则将这些字符赋给数组中前面那些元素,其余的元素赋值为空字符(\0);
(2)引用形式。采用下标引用,即数组名[下标]。
3、字符串和字符串结束标志
C语言中,将字符串作为字符数组来处理。为了测定字符串的实际长度,C语言规定了一个字符串结束标志,即字符’\0’。也就是说,遇到字符’\0’,标识字符串结束,由它前面的字符组成字符串。
4、字符数组的输入/输出
字符数组的输入/输出有以下两种方法。
用“%c”格式符,将字符逐个输入或输出;
用“%s”格式符,将整个字符串依次输入或输出;
5、字符串处理函数
C语言没有提供对字符串进行整体操作的运算符,但在C语言的函数库中提供了一些用来处理字符串的函数。在调用这些函数前,须在程序前面的命令行中包含头文件”string.h”。
puts():调用形式为puts(字符数组),将一个字符串(以\0结束)输出到终端设备;
gets():调用形式为gets(字符数组),从终端输入一个字符串到字符数组中,并且得到一个函数值。
strcpy():调用形式为strcpy(字符数组1,字符数组2),把字符数组2所指字符串内容复制到字符数组1所指的存储空间中。函数返回字符数组1的值,即目标字符串的首地址。
strcat():调用形式为strcat(字符数组1,字符数组2),该函数将字符数组2所指字符串内容连接到字符数组1所指的字符串后面,并自动覆盖字符数组1字符串末尾的‘\0’。该函数返回字符数组1的地址值;
strlen():调用形式strlen(字符数组),此函数计算出以“字符数组”为起始地址的字符串的长度,并将其作为函数值返回。
strcmp():调用形式strcmp(字符数组1,字符数组2),该函数用来比较字符数组1和字符数组2所指字符串的大小。若字符数组1大于字符数组2,则函数返回大于0(正数);若字符数组1等于字符数组2,则函数返回0,若字符数组1小于字符数组2,则函数小于0(负数)。
2.2.7 函数
考点1:函数概述
在C语言中,子程序的作用是由函数实现的。一个C程序可由一个主函数和若干个其他函数构成,且只能有一个主函数。由主函数来调用其他函数,其他函数之间也可以相互调用。
C程序的执行总是从main()函数开始。调用其他函数完毕后,程序流程回到main()函数,继续执行主函数中的其他语句,直到main()函数结束,则整个程序运行结束。
从用户使用的角度看,函数分类如下。
标准函数,即库函数。这些函数由系统提供,可以直接使用;
自定义函数:用于解决用户需要时设计并定义的函数;
从函数的形式看,函数分为无参函数和有参函数;
考点2:函数参数和函数返回值
1、形式参数和实际参数
当定义函数时,函数名后面圆括号中的变量称为“形式参数”(简称形参);
在主调函数中,函数名后面圆括号中的参数(可以是一个表达式)称为“实际参数”(简称实参)。
2、函数的返回值
(1)定义:函数的返回值就是通过函数调用使主函数得到一个确定的值。
(2)表达形式:
return 表达式;
或者return(表达式);
或者return;
return语句中的表达式值得类型与函数首部所说明的类型一致。若类型不一致,则以函数值得类型为准,由系统自动进行强制转化。
当函数没有指明返回值,或没有返回语句时,函数返回一个不确定的值。为了使函数不返回任何值,可以使用void定义无类型函数。
考点3:函数的调用
1、函数调用的一般形式:
函数名(实参列表);
函数的调用可分为调用无参函数和调用有参函数两种;
调用无参函数,不能用“实参列表”,但圆括号不能省略;
调用有参函数时,若实参列表中由多个实参,则各参数见用逗号隔开。实参和形参要求类型一致。
2、函数的说明
C语言中,除了主函数外,对于用户定义的函数要遵循先定义后使用的规则。若把函数的定义放在调用之后,则应该在调用之前对函数进行说明(或函数原型说明)。
函数说明的一般形式:
类型名 函数名(参数类型1,参数类型2,…,参数类型n);
或者
类型名 函数名(参数类型1 参数名1,参数类型2 参数名2,…,参数类型n 参数名n);
考点4:函数的嵌套调用与递归调用
1.函数的嵌套调用
C语言函数定义都是独立的、互相平行的,C语言不允许嵌套定义函数。即一个函数内不能定义另一个函数,但可以嵌套调用函数,即在调用一个函数的过程中,又调用另一个函数。
- 函数的递归调用
在调用一个函数的过程中又出现直接或间接地调用该函数本身。
使用递归法解决问题,需符合的条件如下:
可以把要解决的问题转化为一个新的问题。 而这个新问题的解决方法仍与原来问题的解决方法相同,只是所处理的对象有规则地递增或递减。
可以应用这个转化过程使问题得到解决。
必须有一个明确的递归结束条件。
考点5:数组元素和数组名作为函数实参
1、数组元素作为函数实参
数组元素可以作为函数实参,与变量作为实参一样,按照单向值传递的方式传递。
2、数组名作为函数实参
可以用数组名作为函数实参。此时函数的形参是与数组类型一致的指针变量,这里的数组名是整个数组的首地址。
|
考点6:全局变量和局部变量
在函数内部定义的变量称为局部变量,只能在本函数内部使用。
在函数外部定义的变量称为外部变量,外部变量是全局变量。全局变量可以为本文件中其他函数所共用,它的有效范围从定义变量开始到本文件结束。
如果在同一个源文件中,外部变量与局部变量同名,则在局部变量作用范围内,外部变量被“屏蔽”,即它不起作用。
考点7:变量的存储类别
1、auto变量
当在函数内部或复合语句中定义变量时,如果没有指定存储类别,或使用了auto说明符,系统就认为所定义的变量具有自动类别。
2、register变量
Register变量也是自动类变量。它与auto变量的区别在于:用register说明变量是建议编译程序变量的值保留在CPU的寄存器中,而不是像一般变量那样占用内存单元。
3、静态存储类别的局部变量
当函数体(或复合语句)内部用static来说明一个变量时,可以称该变量为静态局部变量。它与auto变量、register变量的本、质区别如下。
在整个程序运行期间,静态局部变量在内存中的静态存储区中占据永久性的存储单元。即使退出函数,下次再进入该函数时,静态局部变量仍使用原来的存储单元。由于不释放这些存储单元,这些存储单元中的值得以保留,因此可以继续使用存储单元中原来的值。
静态局部变量的初值是在编译时赋予的,在程序执行期间不再赋以初值。对未赋值的局部变量,C语言编译程序自动给它赋初值0。
2.2.8指针
考点1:地址和指针
在C语言中,将地址形象地称为”指针“。一个变量的地址称为变量的指针。用来存放另一个变量的地址的变量(即指针),称为指针变量。
考点2:变量的指针和指向变量地址的指针变量
1、指针变量的定义
定义指针变量的一般形式:
类型名 *指针变量名1,*指针变量名2,…;
例如:int *p,*t;
2、指针变量的引用
指针变量中只能存放地址(指针),与指针相关的两个运算符是“&“(取地址运算符)和”*“(指针运算符)。
3、指针变量作为函数参数
指针类型数据可以作为函数参数来进行传递。
作用:将一个变量的地址传送到另一个函数中,参与该函数的运算。
考点3:数组与指针
1、指向数组元素的指针
C语言规定数组名代表数组的首地址,也就是数组中第0号元素的地址。定义指向数组元素的指针变量的方法,与定义指向变量的指针变量相同。
2、通过指针引用数组元素
如果指针变量p已指向数组中的一个元素,则p十1指向同一数组中的下一个元素。
3、数组名作为函数实参
当数组名作为参数被传递时,若形参数组中各元素发生了变化,则原实参数组各元素的值也随之变化。
如果用数组元素作为实参,情况就与变量作为实参时一样,是”值传递“方式。
4、指向多维数组的指针和指针变量
多维数组可以看作一维数组的延伸,多维数组的内存单元也是连续的内存单元。C语言实际上是把多维数组当成一维数组来处理的。
考点4:字符串与指针
1、字符串的表示形式
用字符数组存放一个字符串,然后输出该字符串。
用字符指针指向一个字符串。用字符指针指向字符串中的字符。
2、字符串指针作为函数参数
将一个字符串从一个函数传递到另一个函数,可以用地扯传递的方法,即用字符数组名作为参数或用指向字符串的指针变量作为参数,进行传递。
3、字符数组和字符指针变量的区别
字符数组由若干个元素组成,每个元素中存放一个字符,而字符指针变量中存放的是地址,不是将字符串的内容存放到字符指针变量中;
赋值方式不同;
字符数组可以在定义时对其整体赋初值,但在赋值语句中不能完成整体赋值。而字符指针变量既可以在定义时赋初值,也可以在赋值语句中赋初值;
编译时不同;
在程序中指针变量的值可以改变。而数组名虽然代表了地址,但它的值是一个固定值,不能改变。
考点5:指向函数的指针
指针变量可以指向一个函数,编译时,一个函数将被分配给一个入口地址,这个入口地址称为函数的指针。因此,可以通过使用一个指向函数的指针变量调用此函数。
说明:
指向函数的指针变量一般定义形式如下:数据类型 (*指针变量名)();
当给函数指针变量赋值时,只需给出函数名而不必给出参数;
当用函数指针变量调用函数时,只需将(*s)代替函数名即可(s为已经定义过的指向函数的指针变量名),在(*s)之后的圆括号中根据需要写上实参。
对指向函数的指针变量,有些运算如++s、--s、s++等都是没有意义的。
考点6:指针数组和指向指针的指针
1、指针数组的概念
若在一个数组中,其元素均为指针类型数据,这样的数组称为指针数组。
定义-维指针数组的一般形式:类型名 *数组名[数组长度];
2、指向指针的指针
指向指针数据的指针变量,简称为指向指针的指针,通常称为二级指针。
定义一个指向指针数据的指针变量的一般形式:类型名 **指针变量名;
2.2.9编译预处理和动态存储分配
考点1:宏定义
1、不带参数的宏定义
(1)定义形式:
#define 宏名 替换文本
或者
#define 宏名
(2)说明:
在define 宏名和宏替换文本之间要用空格隔开;
可以用#undef命令终止宏定义的作用域;
当进行宏定义时,可以引用已定义的宏名;
同一个宏名不能重复定义;
2、带参数的宏定义
(1)定义形式
#define 宏名(参数表)字符串
宏定义不只进行简单的字符串替换,还可进行参数替换;
(2)执行过程
如果程序中由带实参的宏,则按#define命令行中指定的字符串从左到右进行置换;
如果字符串中包含宏定义的形参(如x、y),则将程序语句中相应的实参(可以是常量、变量或表达式)代替形参。
如果宏定义的字符串中的字符不是参数字符(如(x*y)中的“*”号),则保留。这样就形成了置换的字符串。
考点2:关于动态存储的函数
malloc()函数的原型:void *malloc(unsigned int size);
malloc()函数的作用:系统自动在内存的动态存储区,分配长度为size的一段连续连续空间。若此函数执行成功,则函数返回值为指向被分配域的起始地址的指针(该函数的返回值基本类型为void)。若该函数执行失败(如内存空间不足的情况),则函数返回值为空指针(NULL)。
2.2.10 结构体和共用体
考点1:用typedef说明一种新类型
(1)一般形式。
typedef 类型名 标识符;
其中,“类型名”一定是在此语句之前已有定义的类型标识符。“标识符”是一个由用户定义标识符,用来标识新的类型名。
(2)typedef语句的作用:用标识符来代表已存在的类型名,并没有产生新的数据类型,因此,原类型名依然有效。
(3)声明一个新的类型名的具体步骤如下。
按定义变量的方法写出定义的主体(如float a);
将变量名换成新类型名(如将a换成flo);
在最左侧加上关键字typedef(如typedef float FLO);
用新类型名去定义其他的变量(如FLO b);
考点2:结构体数据类型
(1)声明一个结构体类型的一般形式如下:
struct 结构体名{成员列表};
(2)结构体类型可以用以下形式说明。
struct 结构体标识名
{
类型名1 结构体成员名表1;
类型名2 结构体成员名表2;
…
类型名n 结构体成员名表n;
};
说明:
“结构体标识名”和“结构体成员名表”都必须是合法的用户定义的标识符;
每个结构体成员名表都可以含有多个同类型的成员名,他们之间用逗号分隔;
结构体类型说明中的“类型名1”~“类型名n”,不仅可以是简单数据类型,也可以是某种结构体类型。当结构体说明中又包含结构体时,称为结构体的嵌套;
美国国家标准学会(ANSI)对C语言标准规定结构体至多允许嵌套15层,并且允许内嵌结构体成员的名字与外层成员的名字相同。
考点3:结构体类型变量的定义
1、先声明结构体类型再定义变量名
例如,已经定义了一个结构体类型struct time,则
struct time time1,time2;
结构体类型名 结构体变量名;
time1和time2为struct time类型变量,即它们都具有struct time类型的结构。
2、在声明类型的同时定义变量
一般形式:
struct 结构体名{成员列表} 变量名列表;
3、直接定义结构体类型变量
一般形式:
struct {成员列表}变量名列表;
即不出现结构体名。
考点4:结构体类型变量的引用
引用结构体变量时应注意如下几点。
对结构体变量中的数据可以逐步引用成员进行操作。结构体变量中的成员用以下方式引用:结构体变量名.成员名。
如果结构体的某个成员本身又是一个结构体类型,则可以使用若干个成员运算符”.”,一级一级地找到最低的一级成员。只能对最低一级的成员进行赋值、存取及运算。
结构体变量的初始化,是指逐个对结构体变量的各个成员进行初始化的过程。
考点5:结构体数组
(1)一般形式:struct 结构体变量名 {成员列表} 数组名[常量表达式];
(2)结构体数组的初值应顺序地放在一对花括号中。
考点6:指向结构体类型数据的指针
1、指向结构体变量的指针
->称为指向运算符;
”结构体变量.成员名””(*结构体指针变量名).成员名””结构体指针变量名->成员名”这3种形式是等价的。
2、指向结构体数组的指针
结构体数组及其元素也可以用指针变量来指向。当使用指针变量指向结构体数组时,只要把该结构体数组中的每个元素当作普通的结构体变量使用即可。
3、结构体变量和指向结构休的指针作为函数参数
将一个结构休变量的值传递给另一个函数,有如下方法。
结构体变量的成灾作为实参传递给主调函数。
可以用结构体变量作为一个整体实参。
C语言中,允许将结构体变量的地址作为实参传递,这时,对应的形参应该是一个与基类型相同的结构体类型的指针。
考点7:链表
1、链表的概念
(1)定义:链表是一种常见的、重要的数据结构,它是一种动态地进行存储单元分配的结构。
(2)说明。
链表的各个元素在内存中不一定是连续存放的。
一个节点中应包含一个指针变量,用于存放下一个节点的地址。
链表的最后一个节点的指针域设置成’\0’值,标志着链表的结束。
每一个链表都用一个”头指针”变量来指向链表的开始,该指针称为head指针。在head指针中存放了链表第1个节点的地扯。
2、顺序访问链表中各节点的数据域
所谓“访问”,可以理解为读取各节点的数据域中的值以进行各种运算、修改各节点的数据域中的值等一系列的操作。
输出单向链表个节点数据域中的内容的算法比较简单,,只需利用一个工作指针(p),从头到尾依次指向链表中的每个节点。当指针指向某个节点时,就输出该节点数据域中的内容,直到遇到链表结束标志为止。如果是空链表,就只输出提示信息并返回调用函数。
3、删除链表中的节点
为了删除单向链表中的某个节点,首先要找到待删除的节点前趋节点(即当前要删除节点的前面一个节点),然后将此前趋节点的指针指向待删除节点的后续节点(即当前要删除节点的下一个节点),最后释放被删除节点所占的存储空间即可。
2.2.11 文件
考点1:C语言文件的概念
C语言把文件分为ASCII文件和二进制文件。ASCII文件又称文本文件。
在C语言中,文件是一个字节流或二进制流,也就是说,对于输入/输出的数据都按“数据流”的形式进行处理。
文件输入/输出方式也称“存取方式”,C语言中,文件有两种存取方式:顺序存取和直接存取;
考点2:文件类型指针
可以用该结构体类型来定义文件类型的指针变量,一般形式:FILE *fp;
fp是一个指向FILE结构体类型的指针变量。
考点3:文件的打开与关闭
1、fopen()函数
(1)调用形式:fopen(文件名,文件使用方式);
函数返回一个指向FILE类型的指针;
无论使用哪种方式,当打开文件时出现了错误,fopen函数都将返回NULL;
(2)最常用的文件打开方式及其含义如下:
“r”:为读而打开文本文件;
“rb”:为读而打开二进制文件;
“w”:为写而打开文本文件;
“wb”:为写而打开一个二进制文件;
“a”:在文件后面添加数据而打开文本文件;
“ab”:在文件后面添加数据而打开一个二进制文件,其余功能与a相同;
“r+”:为读和写而打开文本文件;
“rb+”:为读和写而打开一个二进制文件;
“w+”:首先创建一个新文件,进行写操作,随后可以从头开始读。如果指定的文件已存在,则文件原有的内容将全部消失;
“wb+”:功能与”w+”相同,知识在随后的读和写时,可以由为止函数设置读和写的起始位置。
“a+”:功能与”a”相同,知识在文件尾部添加新的数据之后,可以从头开始读;
“ab+”:功能与”a+”相同,知识在文件尾部添加新的数据之后,可以与位置函数设置读的起始位置。
2、fclose()函数
调用形式:fclose(文件指针);
若对文件的操作为“读”方式,则经以上函数调用之后,要使文件指针与文件脱离联系,可以重现分配文件指针去指向其他文件;
若对文件的操作方式为“写”方式,则系数首先把该文件缓冲区中的剩余数据全部输出到文件中,然后使文件指针与文件脱离联系;
在完成了对文件的操作之后,应当关闭文件,否则文件缓冲区中的剩余数据就会丢失;
当执行了关闭操作后,若关闭成功则函数返回0,否则返回非0;
考点4:文件的读写
- fread()函数和fwrite函数
当要求一次性读/写一组数据时,如一个实数或一个结构体变量的值,就可以使用fread()函数和fwrite()函数,它们的一般调用形式:
fread(buffer,size,count,fp);
fwrite(buffer,size,count,fp);
其中,buffer代表的是一个指针变量;size代表的是要读写的字节数;count用来指定每读/写一次,输入/输出数据块的个数(每个数据块具有size个字节);fp是文件类型指针;
2、fscanf()函数和fprintf()函数
fscanf()函数和fprintf()函数都是格式化的读和写函数,与scanf()和printf()函数作用相似,但fscanf()和fprintf()函数读写对象是磁盘文件上的数据。
它们的一般调用形式为:
fscanf(文件指针,格式字符串,输入列表);
fprintf(文件指针,格式字符串,输出列表);
3、fputs()函数
fputs()函数是用来把字符串输出到文件中,调用形式:fputs(str,fp);
其中,str是要输出的字符;fp是文件指针,字符串末尾的‘\0’不输出;
考点5:文件的定位
rewind()函数的调用形式:rewind(fp);
该函数的功能是使文件的为止指针重新返回到文件的开头,其中fp为文件指针,且该函数没有返回值。
2.3 二级C语言程序设计操作题高频考点
2.3.1 C语言设计基础
考点1:C程序结构特点
(1)1个C程序有且仅有一个main()函数,程序执行总是从main()函数开始;
(2)函数体必须用花括号{}括起来;
(3)每个执行语句都必须以分号结尾,预处理命令、函数头和花括号之后不加分号;
(4)区分大小写;
考点2:常量与变量
1、整型数据:
(1)整型常量:即整常量,包括十进制整数(如123、-456、0)、八进制整数(以0开头,如0123,即(123)8
)、十六进制数(以0x开头,如0x123,即(123)16
)。
(2)整型变量:可分为有符号基本整型([signed] int)、无符号基本整型([unsigned] int)、有符号短整型([signed ] shrot [int])、有符号长整型([signed] long [int])、无符号长整型(unsigned long [int])。
2、实型数据
(1)实型常量:实型常量也称浮点型常量,有两种表示形式,即十进制小数形式(如.123、123.、123.0)和指数形式(如123.456e3,表示123.456*103
)。
(2)实型变量:可分为单精度型(float)、双精度型(double)和双精度型(long double)。
3、字符型数据
(1)字符常量:用单撇号标识的一个字符(如’a’、’+’、‘\0’)。
(2)字符变量:用来存储单个字符;
(3)字符串常量:用双撇号标识的字符序列(如“hello”、“12345”)。字符串常量占用的内存字节数等于字符串中字符数加1,最后一个字节存放字符‘\0’(ASCII值为0),即字符串结束标志。
4、变量的初始化
定义的变量在使用之前,需要赋给一个确定的初值来初始化它。初始化有两种方法:先定义后初始化(如int a;a=5;),在定义时直接初始化(如int a=5;)。当遇到循环时,循环变量需要先定义,然后才能在循环结构中应用。
常见考察形式:
(1)判断是否到达字符串的结尾,即判断当前字符是否为字符串结束标志(‘\0’)。
如果要遍历字符串s,使用整型变量n存放下标,那么判断当前字符字符是否为字符串结束标志(‘\0’),可表示为while(s[n]!=’\0’){…}。
注:也可以使用指针实现,若指针p指向最后一个字符,则可以表示为while(*p=’\0’){…}。
(2)对字符串操作结束后,添加字符串结束标志(‘\0’)。
如下标n为字符串中最后一个字符的下标,要添加字符串结束标志,可表示为s[++n]=‘\0’。
注:也可以用指针实现,若指针p指向最后一个字符,则可表示为*(++p)=’\0’。
考点3:运算符与表达式
(1)算术运算符:圆括号()、求正+、求负-、乘*、除/、求余%、加+、减-。
(2)复合赋值运算符:+=、-=、*=、/=、%=。
(3)自增自减运算符:i++表示i参加运算后再加1,++i表示i增加1后参加运算,对于i—和—i同理。
(4)逻辑运算符:&& 逻辑与、||逻辑或、!逻辑非;
优先级:!>&&>||;
应用逻辑运算符可以组成复杂的逻辑关系表达式。判断一个量是否为真的依据是其值是否为0.若为0,则为假,否则为真。
题型剖析:
(1)运算符优先级问题;
(2)整数除法问题;
(3)除法运算符与求余运算(注意四舍五入);
(4)自增自减运算符的特点及其区别;
(5)赋值运算符与等于运算符的区别;
考点4:强制类型转化
利用强制类型转换运算符,可以将一个表达式转换为所需类型,其一般形式如下:
(类型名)(表达式);例如,(char)(x+y)表示将表达式(x+y)的值强制转化为字符;
2.3.2 C语言的基本结构
考点1:格式化输入/输出
1、printf()函数
printf()函数用于格式化输出数据,其语法格式如下:printf(格式控制字符串,输出列表);
其中,格式控制字符串使用双撇号标识的部分,它包括两种信息:格式转换说明和原样输出的字符。输出列表是需要输出的一些数据,可以是常量、变量或表达式。
(1)printf(“Hello World!!”);
原样输出字符串Hello World!!
(2)printf(“%5d”,123);
输出: 123,123前面有两个空格;
(3)printf(“%2d”,123);
输出:123,因实际长度超过设定值,按照实际长度输出;
(4)printf(“%c”,c);
输出字符型变量c,其中c一定被赋过值;
(5)printf(“%s”,”string”);
输出:字符串string;
(6)printf(“%f”,a);
输出:单精度变量a;
(7)printf(“%2.2f”,1.2);
输出1.20,小数点后有两位有效数字;
2、scanf()函数
scanf()函数用于格式化输入数据,其语法格式如下:scanf(格式控制字符串,地址列表);其中,格式控制字符串与printf()函数相同,知识没有小数位数的设置。
值得注意的是,格式化输入字符的时候,空格也会被当作一个有效字符输入,所以连续输入多个字符的时候,中间一定不能添加空格,例如:
scanf(“%c%c%c”,&a,&b,&c);输入:abc
scanf(“%c %c %c”,&a,&b,&c);输入:a b c
3、putchar()函数
putchar()函数用于向终端输出一个字符,其语法格式如下:putchar(字符型变量);
putchar(a’);输出:a
putchar(65);输出:a
char a=’c’,putchar(a);输出:c
4、getchar()函数
getchar()函数用于从终端获得一个字符,其语法格式如下:getchar();
5、题型剖析:
(1)格式控制:根据输出列表判断格式格式控制的形式;
(2)输出列表:根据题目要求输入不同的数据;
(3)地址列表,根据题目要求输入不同的数据。使用scanf()函数接收终端输入的时候,待赋值变量一定要加上取地址符&,否则可能出现未初始化或者计算错误等问题。
考点2:条件与分支
1、if语句
if语句可以有两种形式:if(exp){}或者if(exp){}else{}。在嵌套结构中,else只与其前面最近的且未匹配的if匹配,或者在嵌套结构中直接应用{}将if-else匹配关系表达清楚。
三目运算符:(exp1)?(exp2) : (exp3);
2、switch语句
分支语句switch是多分支选择语句,用来实现多分支选择结构。其语法格式如下:
switch(exp){
case constexp1:exp1;
…
case constexpn-1:exp n-1;
default:expn;
}
3、题型剖析:
(1)if语句的条件表达式;
(2)if 语句体;
(3)if语句嵌套;
考点3:循环:
1、常用的循环语句
while(exp){循环体}
do{循环体}while(exp);
for(exp1;exp2;exp3);
2、跳出循环语句
continue:表示跳出本次循环,而继续执行下一次循环;
break:表示跳出整个循环体,直接执行该循环体之后的语句;
3、提醒剖析:
(1)while语句中的条件语句;
(2)while语句中循环体;
(3)do-while循环体与条件表达式;
(4)for 循环条件设置;
(5)循环嵌套;
2.3.3 函数
考点1:函数的定义、调用与参数传递
1、函数的定义
函数定义的语法格式如下。
类型说明符 函数名([形参列表])
{
…
}
2、函数的参数和返回值
函数的参数分为形式参数与实际参数。在定义函数时,函数名后面的圆括号中的变量称为形式参数;在主调函数中,函数名后面圆括号中的参数(也可以是一个表达式)称为实际参数。形参与实参应该类型相同且数量相等;
函数的返回值是通过函数调用,使主调函数得到一个确定的值。返回值的类型应与函数类型标识符指定的类型相同。
3、函数的调用
函数调用的语法格式如下:函数名(实参列表);
函数调用的方式有以下几种:
(1)把函数调用作为一条语句,此时该函数不要求有返回值,只需要执行一定的操作;
(2)函数出现在一个表达式中,因为要参议表达式的运算,所以要求函数有对应数据类型的返回值;
(3)函数参数,把函数调用作为一个函数的实参;
4、参数的传递
形参与实参的值传递:函数名(实参列表);
形参与实参的地址传递: 函数名(&参数…);
它们的区别:在值传递时,参数在函数执行过程中所产生的变化不被记录,即形参不影响实参;而在地址传递时,形参可以改变实参;
5、题型剖析:
(1)函数返回值类型考察;
(2)函数参数类型考察;
考点2:迭代算法与递归算法
迭代算法:使用计算机解决问题的一种就基本方法,它利用计算机运行速度快、适合做重复性操作的特点,让计算机对一组指令(或一定的步骤)进行重复执行,让每次执行这组指令(或这些步骤)时,都从变量的原值推出一个新值。迭代算法常用来求方程的近似根。
递归算法:在调用一个函数的过程中直接或间接调用其函数本身的方法,称为函数的递归调用。
题型剖析:
#include<stdio.h>
long fun(int n)
{
if(n>1) return(n*fun(n-1));
return 1;
}
void main()
{
printf(“10!=%ld\n”,fun(10));
}
2.3.4 指针
考点1:指针变量的定义
如果有一个变量专门用来存放地址,那么这个变量是指针变量,即存放变量地址的变量是指针变量。
指针的定义格式如下:基类型 *指针变量名
例如:
int a=0;
int *i = &a;
注意:int *i定义了一个指向int类型变量的指针,该指针的变量名为i;定义指针时要在*前面声明指针的类型;对指针赋值时,指针的类型应与其指向的值类型一致;对*p=a来说,p和&a表示变量a的地址,*p和a表示变量a的值;p++表示指针p移动1个存储单元,(*p)++表示指针指向的数据加1。
题型剖析:
(1)指针变量的声明;
(2)指针变量的赋值;
考点2:函数之间的地址传递
在2.3.3小节中已经讲过,传递至不修改原参数的值,但是如果参数是一个指针,就可以修改指针指向内存地址中存放的数据。例如:
#include<stdio.h>
void change(int *);
void main()
{
int a=0;
int *p=&a;
change(p);
printf(“%d\n”,a);
}
void change(int *p)
{
(*p)++;
}
输出结果为1;
题型剖析:
(1)根据函数的实参,确定指针形参的类型。例如:
int *p3,*p4;
swap(p3,p4);
void swap(int *p1,*p2);
(2)根据函数的形参,确定函数的实参名。
2.3.5 数组
考点1:一维数组
1、定义方法
类型说明符 数组名[常量表达式];其中,类型说明符是指数组元素的数据类型;常量表达式是一个整型值,指定数组元素的个数,即数组的长度,数组的长度必须用[]标识;常量表达式可以是常量或符号常量,不能包含变量。
例如:int array[5];
2、一维数组的初始化
一般在定义的时候为数组赋值。
例如:
int array[5]={1,2,3,4,5}; //赋值为1 2 3 4 5
int array[5]={1,2}; //赋值为1 2 0 0 0
int array[5]={0}; //全部赋值为0
int array[]={1,2,3,4,5}; //赋值为1 2 3 4 5
3、一维数组元素的输入/输出
如果需要逐个输入或输出数组元素,可以使用循环语句实现。数组名本身就是一个指向数组内存区域的首地址的指针,其类型与数组元素类型相同。也就是说,数组元素a[i]可以写成*(a+i);
题型剖析:
(1)数组元素的引用:注意下标和指针两种方式;
(2)数组的遍历,常使用循环语句实现;
考点2:排序算法:
1、冒泡排序算法;
2、选择排序算法;
#include<stdio.h>
int main()
{
int raw_array[10]={0};
int out_array[10]={0};
int input_num=0;
int rank01=0;
int rank02=0;
int temp=0;
//数ºy据Y输º?入¨?
printf("please input 10 ints:\n");
for(input_num=0;input_num<10;input_num++)
{
scanf("%d",&raw_array[input_num]);
}
getchar();
for(input_num=0;input_num<10;input_num++)
{
printf("raw_array[%d]=%d\n",input_num,raw_array[input_num]);
}
//冒¡ã泡Y排?序¨°
/*for(rank01=0;rank01<9;rank01++)
{
for(rank02=0;rank02<9-rank01;rank02++)
{
if(raw_array[rank02]>raw_array[rank02+1])
{
temp = raw_array[rank02];
raw_array[rank02]=raw_array[rank02+1];
raw_array[rank02+1]=temp;
}
}
}*/
//选?择?排?序¨°
for(rank01=0;rank01<10;rank01++)
{
for(rank02=rank01+1;rank02<9;rank02++)
{
if(raw_array[rank01]>raw_array[rank02])
{
temp = raw_array[rank01];
raw_array[rank01]=raw_array[rank02];
raw_array[rank02]=temp;
}
}
}
//
for(input_num=0;input_num<10;input_num++)
{
out_array[input_num]=raw_array[input_num];
}
for(input_num=0;input_num<10;input_num++)
{
printf("out_array[%d]=%d\n",input_num,out_array[input_num]);
}
return 0;
}
考点3:二维数组
1、定义方法
类型说明符 数组名[常量表达式1][常量表达式2];
例如:int array[3][4];
注意:二维数组的定义不能写成int array[3,4];二维数组中元素是按行排列的,即存放完第1行的元素之后接着存放第2行的元素,数组名array代表二维数组首地址,a[0]代表数组第0行的首地址,a[i]代表数组第i行的首地址;允许定义多维数组。
2、二维数组的初始化
(1)int a[3][4]={{0,1,2,3},{4,5,6,7},{8,9,10,11}};
(2)int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};
(3)int a[3][4]={{0},{1},{2}};
(4)int a[][4]={0,1,2,3,4,5,6,7,8,9,10,11};
3、二维数组的输入/输出
如果需要逐个输入/输出数组元素,则需要使用一个两层循环实现;
提醒剖析:
(1)二维数组元素的引用多使用数组下标实现,常用于矩阵的运算。
(2)二维数组的遍历,常使用嵌套循环语句实现,此时要注意内外两层循环分别表示的意义。
2.3.6 字符串
考点1:字符串的表示
由于没有字符串变量,在C语言中,用一维字符数组存储字符串,其定义、初始化均为一般的数组相仿。
如果没有声明字符数组的同时初始化数组,则可以不规定数组的长度,系统在存储字符串常量时,会在字符串尾自动加上一个字符串结束标志’\0’,字符串结束标志在字符数组中也要占用一个元素的存储空间,因此在声明字符数组长度时,要预留出该字符的位置。
当然,还可以采用循环语句进行输入/输出;
提醒剖析:
(1)字符与字符常量的表示形式和输出形式。字符常量用’’表示,输入/输出时使用格式字符”%c”;字符串与字符串常量的表示形式和输出形式分别为””和“%s“。
(2)字符串结束标志’\0’。根据’\0’来判断字符串是否结束。
考点2:指向字符串的指针
定义格式:char *指针变量;
初始化方法:char *p=”abc”;
使用方法:while(*p){}
注意:只有字符数组才可以应用数组名直接将整个数组中的元素输出,其他类型的数组不具备这种特征。
题型剖析:
(1)程序填空题中,常常要求根据函数的调用,写出参数中字符串指针的正确形式,如a、b是两个数组,对于函数void fun(char *a,char *b),其调用形式为fun(a,b)。
(2)使用指针对字符串进行操作。如字符串s=”hello”,指针p指向字符串s,要求将字符串中的字母1转换为字符a,程序如下:
while(p)
{
if(*p==’1’)
*p=’a’;
p++;
}
考点3:字符串处理函数
1、字符串复制函数---strcpy()
例如:
char a[]=“abc“;
char b[]=”b”;
strcpy(a,b);
2、字符串连接函数---strcat()
例如:
char a[]=”abc”;
char b[]=”b”;
strcat(a,b); //a=”abcb”
3、字符串长度函数(从其实指针到’\0’处为止的字符总数)---strlen()
例如:
char a[100]=”abc”;
int b=strlen(a); /*调用后b=3*/
4、字符串比较函数---strcmp()
例如:
int a[]=”abc”;
int b[]=”b”;
int c=strcmp(a,b);//调用结束后c=-1
2.3.7 结构体、共用体和用户定义类型
考点1:结构体变量的定义与表示方法
1、结构体的声明
struct 结构体名
{
类型标识符 成员名;
类型说明符 成员名;
…
}
2、结构体变量的声明
(1)可以直接跟在结构体声明之后。例如:
struct{
…
}array[10];
(2)先声明结构体类型,再单独定义。例如:
struct student{
…
};
struct student array[10];
(3)先声明一个结构体类型名,再用新类型名来定义变量。例如:
typedef struct{
…
}ST;
ST array[10];
3、结构体变量的引用
结构体变量名.成员名
可以将一个结构体的变量直接赋给另一个结构体变量,结构体嵌套时逐级引用。
考点2:链表
1、指针指向结构体的引用方法
例如:
struct student *p=a;
若变量b为结构体student的一个成员,则下面3种引用成员的方式是一致的。
a.b;
(*p).b;
p->b;
2、链表的组成
(1)头指针,存放第一个数据节点的地址。
(2)节点,包括数据域和指针域;
结构:
头指针->数据域 指针域->数据域 指针域->…->数据域 NULL;
3、链表的操作
链表是一种重要的数据结构,可以动态地进行数据存储和分配。对链表的操作包括链表的建立、链表节点的插入和删除等。
(1)插入节点:如果再节点a、b之间插入节点c,则需要将指针指向a,然后将 “c->next=a->next;a->next=c;“,便得到”a->c->b;“;
(2)删除节点:如果在a、c、b这3个连续节点中删除c,则将指针指向a后,再将”a->next=c->next;free(c);”;
题型剖析:
1、单个链表元素:
(1)结构体指针的定义,要注意先赋值再使用。
(2)结构体内的成员用指针的引用同直接用结构体变量名引用形式上的区别。结构体变量和结构体变量指针引用结构体成员赋值,尤其要注意字符数组的赋值。
2、链表:
多考察于程序填空题和程序修改题,主要是对链表节点的插入、删除操作,往往还连着前后元素的链接关系,所以需要特别注意指针指向的调整以及元素的先后顺序。
考点3:typedef说明一种新类型名
typedef 定义体 新名称
例如:
typedef int INT
之后便可以使用INT来定义一个int型的变量,如INT a=0于int a=0等价。
考点4:宏定义
1、不带参数的宏定义
#define 宏名 替换文本
例如:
#define R 13
#define PI 3.14
2、带参数的宏定义
#define 宏名(参数列表) 字符串
例如:
#define MV(x,y) ((x)*(y))
3、题型剖析:不带参数的宏替换比较简单,只需要将宏名替换成相应的常量即可。进行带参数的宏替换时要注意,程序不会将预定义字符串的运算结果进行替换,而是执行简单的字符替换,如#define MV(x,y) x*y于#define MV(x,y) (x)*(y)是不同的,当程序引用MV(a+3,5)时,该表达式被分别替换为MV(a+3*5)和MV((a+3)*5);
2.3.8 文件
考点1:文件的打开与关闭
1、文件的定义
文件是存储在外部介质上数据的集合,是操作系统进行数据管理的基本单位。文件分为ASCII文件和二进制文件。C语言把文件看作一个字符(字节)的序列,即由一个个字符(字节)的数据顺序组成。一个输入/输出流就是一个字节流或二进制流。
2、文件的打开与关闭
(1)文件类型指针:FILE *fp;
(2)打开文件:fp=fopen(文件名,文件使用方式);
(3)关闭文件:fclose(fp);
注意:文件打开函数和关闭函数的形式,其参数和返回值为文件指针。文件打开时,自动生成一个文件结构体;关闭后,结构体自动释放。
文件的打开方式如表2.24所示。
方式 | 功能 | 方式 | 功能 |
r/rb | 只读 | r+/rb+ | 读、写 |
w/wb | 只写 | w+/wb+ | 读、写 |
a/ab | 追加 | a+/ab+ | 读、写 |
考点2:文件的读/写
fputc(ch,fp); //将字符(ch的值)输出到fp所指的文件中;
fgetc(fp); //从fp所指的文件中返回一个字符串;
fgets(char *str,int n,FILE *fp); //从指定的文件读入一个字符串;
fputs(const str,FILE *fp); //向指定的文件输出一个字符串;
fprintf(文件指针,格式字符串,输出列表);//将字符串输出到文件;
fscanf(文件指针,格式字符串,输入列表); //从文件读入一个字符串
fread(buffer,size,count,fp);
fwrite(buffer,size,count,fp);
//数据块读/写函数,用于向文件读/写一组数据,其中,buffer是一个指针,表示起始地址,size是要读/写的字节数;count表示要读/写多少个size字节的数据项。
考点3:文件检测函数
int feof(FILE *stream);
功能:检测文件是否结束,如果结束,返回1,否则返回0;
ferror(*fp);
功能:返回0表示文件未出错,否则表示出错。
fseek(文件类型指针,位移量,起始点);
起始点有:
文件开头: SEEK_SET 0
文件当前位置: SEEK_CUR 1
文件结尾: SEEK_END 2
题型剖析:
int a=2;fseek(fp,0,a);