程序设计基础复习纲要Word文件下载.docx
《程序设计基础复习纲要Word文件下载.docx》由会员分享,可在线阅读,更多相关《程序设计基础复习纲要Word文件下载.docx(17页珍藏版)》请在冰点文库上搜索。
![程序设计基础复习纲要Word文件下载.docx](https://file1.bingdoc.com/fileroot1/2023-5/10/298e0459-f762-4f59-84cc-5e8c38b3e853/298e0459-f762-4f59-84cc-5e8c38b3e8531.gif)
而m=n+7;
(设变量m已用intm;
定义)将变量n对应“盒子”中的内容5取出来去和7相加,再把结果12放入变量m的盒子中。
2.[理解、识记]变量的命名规则(§
3.7):
程序中的变量可以取什么名字?
几乎所有编程语言对变量的名字都有限制。
C++的变量命名规范(其实也是函数名、类型名等用户自定义标识符的命名规范)是:
C++中的合法的变量名必须是字母或下划线开头的字母、数字或下划线的字符序列。
建议用户不要使用下划线开头的变量名,因为这是留给编译器或标准库的开发人员用的。
U.S.A(错)$123(错)tan(对)do(错)_123(对,但不建议).abc(错)li_ling(对)-abc(错)
3.[理解、重点]变量使用的两条基本原则:
①先声明,后引用;
②首次引用(作右值使用)前,已被正确地初始化。
4.[理解、重点、难点]类型安全的概念?
安全的类型转换?
不安全的类型转换?
例如:
char→int和int→double都是安全的类型转换;
而int→char及double→int都是不安全的类型转换。
5.[理解、重点、难点]区分初始化和赋值:
intn=3;
为初始化;
而intn;
n=3;
则为赋值。
6.[补充]进制转化的基础知识。
重点:
十进制、二进制、八进制及十六进制之间的相互转化。
1.ex3-2
2.ex3-4
3.ex3-8
4.ex3-10
5.关于进制转化的补充习题
Chapter4计算
1.[理解、重点、难点]计算的基本概念:
Wirth公式:
算法+数据结构=程序
2.[理解、重点、难点]程序员的目标:
将计算表达出来,并且追求正确性、简单性和高效性这三条基本原则。
3.[理解、重点、难点]抽象和分治:
系统(软件或硬件、甚至建筑、机械等其他行业)设计与实现中的最主要敌人是复杂性。
目前,对付复杂性的主要手段是:
将大的、复杂的计算任务分解为一系列小的、较易处理的小任务(“大事化小,小事化了”)。
这一技术主要有两类方法:
抽象(abstraction)和分治(divideandconquerit)。
抽象体现了分层化的思想,分治则体现了模块化的思想。
4.[理解、重点、难点]表达式——程序的最基本单元(§
4.3):
1)区分左值和右值:
当一变量作左值时指这个对象本身;
而当它作右值时,表示这个对象的值。
2)常量表达式(例:
constdoublepi=3.14159;
)。
好的编程风格:
避免直接使用魔数(magicconstant)而代之以符号常量。
这也是C++引入const关键字的原因。
3)运算符:
区分==及=
不等式a<
x<
b的表示:
不能直接这么写,而应写成a<
x&
&
b;
&
和||的副作用(见p70例子):
e1&
e2当e1值为0时,e2表达式并不求值!
类似地,e1||e2当e1值非零时,e2也不求值。
4)类型转换:
注意5/2==2,而5.0/2==2.5,也可以强制类型转换:
double(5)/2==2.5,特别地,int(x+0.5)具有四舍五入取整的功效
5.[理解、重点、难点]语句(§
4.4):
1)声明语句:
intn=1;
//变量n的定义性声明
externintk;
//变量k的引用性声明
doublesquare(double);
//函数square的声明
2)表达式语句=表达式;
3)控制语句:
控制程序执行流程的语句,又分为:
i.选择结构:
ii.循环结构:
初学者注意:
当循环体不止一条语句时,应该用{…}将循环体包含;
区分break和continue
iii.[补充]:
结构化编程中表达算法的三种基本结构:
顺序结构、选择结构、循环结构。
它们的共同点:
单入口、单出口。
这有效降低了调试和测试的难度。
循环结构可以用选择结构和跳转指令来实现。
任何非结构化的程序都可转换为一个逻辑上与之等效的结构化程序。
6.[理解、重点、难点]函数(§
4.5):
1)何时需要函数?
当需要将部分计算任务独立实现的时候。
优点:
实现计算逻辑的分离;
使代码更清晰(函数名相当于给分计算命名);
利用函数,使得同样的一份代码在程序中可被多次使用;
减少了程序调试的工作量。
设计建议:
设计函数时,需考虑接口的清晰和易用。
一般地,一个函数只完成单一的逻辑功能,尽量不要让一个函数同时做几件功能不同的事。
尤其是,当你要设计一组相互配合的函数来完成某个计算任务的时候,更应遵循这个设计原则,同时各个函数的功能也不能有重叠。
此所谓的正交性设计。
记住UNIX实用工具程序的一条设计哲学:
一次只做一件事,但要做得足够好。
2)区分函数的原型声明和定义:
doublesquare(double);
为函数原型声明,而doublesquare(doublex){…}为函数定义。
3)函数使用的原则:
先声明、后引用(同变量)。
C++中,允许将函数的声明、定义及使用三者分离。
这体现了接口与实现的分离。
7.[理解、重点、难点]向量(§
4.6):
用以表示一组相关的数据。
例如考虑存取一组传感器的温度记录并进行相关统计的应用需求。
向量元素的访问:
通过下标运算来访问元素。
vector<
int>
v(6);
则访问向量v的有效下标是v[0]~v[5];
又如vector<
string>
names(4);
则有效的向量元素是names[0]~names[3]。
向量的一些基本操作:
v.size();
求向量v的元素个数;
v.push_back(x)在向量v尾部添加新的元素x;
sort(v.begin(),v.end)对向量元素进行排序(小→大)。
8.[补充、重点、难点]自顶向下、逐步求精的结构化(过程式)程序设计技术。
这是分层化、模块化思想的具体体现,也是教材中“抽象”和“分治”方法的具体展示。
[经典例程]:
计算水仙花数。
9.[补充、难点]Euclid辗转相除法求最大公约数。
其算法效率比传统的从定义出发计算最大公约数的算法要高效得多。
1.补充例程:
百分制→五分制转换(用if实现或switch实现)
2.试一试(p63,p64,p66)
3.ex4-2
4.ex4-3
5.ex4-4(二分法)
6.ex4-11(打印100以内的所有素数)
7.补充例程:
打印水仙花数
8.补充例程:
Euclid辗转相除法计算两整数的最大公约数。
Chapter5错误
1.[理解、重点、难点]错误的分类(§
5.1):
按错误出现的时期,可分为编译时错误、连接时错误、运行时错误以及逻辑错误。
一般地,越后面发现的错误越难以处理。
记住,错误是越早发现越好。
2.[了解]本课程的错误处理要求:
1)对于所有合法输入应输出正确结果。
2)对于所有非法输入应输出错误信息。
3)无须操心硬件故障。
4)无须操心系统软件故障。
5)发现一个错误后,允许程序终止。
3.[理解]编写高质量软件的途径:
1)精心组织软件以使错误最小化(强调设计);
2)通过调试和测试,消除大部分程序错误;
3)确定余下的错误不重要。
4.[了解]错误的来源:
1)缺少规划
2)不完备的程序
3)意外的参数
4)意外的输入
5)意外的状态
6)逻辑错误
5.[了解]编译时错误:
语法错误;
类型错误;
警告
6.[了解]连接时错误:
下列情形将产生连接时错误:
当某个调用的函数仅有声明,没有定义时;
或定义函数时,参数的个数或类型与声明函数时不一致。
7.[考点、重点、难点]运行时错误:
经常发生在函数调用上。
1)
2)错误处理的两个基本方面:
3)错误处理的几种方案:
I.主调方和被调方均不检测,也不处理错误。
II.主调方检测并处理错误。
III.被调方检测并处理错误。
IV.被调方检测错误,而主调方处理错误。
这就引来新的问题:
低层的被调方如何向高层的调用方报告错误?
目前主要有三种报告方式:
4)异常的基本思想及其优点(§
5.6)。
异常的基本思想是:
如果被调函数发现一个自己不能处理的错误,它不是正常返回,而是通过抛出异常来表示检测到错误的发生(同时终止自己的执行)。
任何一个其直接或间接的主调函数都可以捕捉到这一异常,并确定应该如何处理这个错误。
这体现了机制与策略的分离:
底层被调函数具有检测错误的机制,高层主调函数则有决定错误处理策略的权利。
异常方式的优点:
异常不可忽略。
即,一旦低层被调函数(比如库函数)检测到错误导致抛出异常,高层的主调方(直接或间接主调函数)一定要处理,如果直到main()也不处理该异常,则程序将终止运行。
这种做法有效地防止错误无意中继续转播。
它允许主调方将处理正常逻辑的代码与处理异常逻辑的代码适当分离,代码更简洁、更清晰,当然可读性也更好。
最后,顺便提一句,错误处理(尤其是如何让系统从错误中恢复过来)本质上就是很困难的问题,异常方式也不可能让它变得很容易,异常只是让错误处理更容易一些(相比于其他方式)。
5)[了解]常见的几种运行时错误:
错误参数;
范围错误;
输入错误;
截断错误。
当然还有其它一些错误,比如标准库中提供的域错误、上溢、下溢等。
8.[理解]逻辑错误:
在一些输入下程序的输出结果不正确。
逻辑错误通常是算法有问题引起的,此类错误是最难被发现和排除的,因为有些情况下,程序对大多数输入都能输出正确结果。
教材§
5.7的例子就是个典型的例子。
9.[理解、重点]调试:
查找并排除错误的过程。
调试可简单地描述为:
让程序编译通过;
让程序正确连接;
让程序完成我们希望它做的工作。
对待调试的正确态度:
调试是编程中最乏味、最费时间的工作,因此应该不遗余力地做好设计和编码工作,以使除错的时间降到最低。
10.[理解、重点]不变式、断言、前置条件、后置条件。
不变式是指永远成立的条件。
陈述一个不变式的语句称作断言。
最常用的两种断言是前置条件和后置条件,它们提供了基本的程序完整性检查。
前置条件是函数的入口处参数必须满足的关系式,后置条件是函数出口处(返回时)必须满足的关系式。
断言是一种实用的调试技术。
给函数增加前件和后件有助于我们避免设计错误和及早发现错误,能有效降低调试和测试的难度。
11.[理解、重点]测试及测试用例。
测试是一种系统地查找错误的方法。
基本上,测试是以一个较大的、经过系统选择的数据集作为输入来执行一个程序,然后把相关结果与期望值进行比较。
基于一组给定输入的一次程序运行称为一个测试用例。
测试用例的选择应该尽可能地全面系统:
既包含正确的输入数据,也包含不正确的输入数据。
忠告:
尽早测试、经常测试。
12.[理解]为了达到本课程的错误处理要求,今后我们错误处理的代码框架类似于p96的结构:
intmain()
{
try{
……/*yourcode*/
keep_window_open();
return0;
}
catch(exception&
e){
cerr<
<
"
error:
<
e.what()<
'
\n'
;
return1;
catch(...){
Oops:
unkownexception!
\n"
return2;
}
1.摄氏温度与开氏温度的转换(ex5-2、ex5-3、ex5-4、ex5-5)
2.[补充]e4-6_2.cpp、e4-7_3.cpp
Chapter6编写一个程序
1.[了解]基本哲学:
程序设计就是问题理解!
(p22、p100)
2.[理解、重点、难点]软件开发的几个阶段(§
6.2.1)
●分析:
主要是确定做什么(whattodo)?
即问题是什么?
具体地,收集用户需求、评估可行性、根据用户需求设计一些测试用例。
●设计:
从策略上(宏观战略层面)考虑如何做(howtodo)?
具体地,为了解决问题(即达到需求分析中的功能目标),系统应具有怎样的总体结构?
(系统由哪些功能模块构成?
这些模块之间又如何交互?
)
●实现:
从细节上(微观战术层面)实施如何做(howtodo)的详细步骤?
具体地,将设计里的各个模块自顶向下、逐步求精细化到代码层面、再进行调试和测试。
因此,实现包含了编码、调试和测试。
值得注意的是,这些阶段并不是简单的瀑布型流程,而是会反复经历。
这里有个关键的概念是反馈(§
1.6p22):
测试有助于改正和改进代码、编码中的问题可能表明设计有问题、设计的过程中也可能会发现分析中的疏漏和矛盾之处、系统的实际使用通常会暴露分析中的问题。
反馈是高效率软件开发的根本。
不仅如此,反馈的概念在硬件设计中也极为重要。
比如:
用于构建CPU寄存器、存储器等硬件的时序电路本质上=组合电路+反馈。
又例:
I/O设备中断的概念在计算机体系结构的发展演化过程中是一场革命,而中断概念的核心思想就是反馈。
3.[了解]在本章里,作者推荐了一种较实用的软件开发策略:
1)弄清问题,并作可行性评估
2)将大任务分解为易于处理的小任务
3)原型系统开发方法(本质上,就是为了尽早获得反馈,哪怕最初版本只是问题的部分解决方案):
a)先设计并实现一个受限版本,但能解决问题的关键部分;
在开发的早期,避免“功能蔓延”很重要。
(P109L2)
b)再在此基础上,逐步扩充完善,最后得到完整的解决方案。
分阶段实现一个大程序比一次完成要简单得多。
(P109L3)
4.[了解、重点、难点]实用编程技术:
token(单词)及tokenize(词法分析)
5.[了解、重点、难点]实用编程技术:
grammar([补充]:
文法的语法图表示以及BNF范式表示)及analyzer(语法分析)
6.[重点]用户自定义类型(user-definedtype,简称UDT)和class关键字。
为了保证软件的可维护性,本课程强调的程序设计理念是代码必须直接体现要表达的思想,也即用代码直接描述问题域(即应用领域)中的概念(§
1.6,p21L-4)。
这导致的直接后果是程序员常常发现编程语言提供的内建类型(built-intype)不能直接满足要求,须想方设法创建自己所需的类型,为此高级语言通常都提供创建用户自定义类型(user-definedtype)的机制。
在C++语言中,用以创建用户自定义类型(UDT)的最主要的关键字是class。
C++的这种做法体现了一种“积木块”的思想,语言本身只提供少数通用的内建类型,程序员可把它们当作“积木块”搭建自己所需的任何UDT。
这再次体现了机制与策略的分离:
语言提供构建UDT的机制(各种内建类型及class关键字),程序员提供如何定义UDT的策略(一般是直接将问题域的概念映射为相应的UDT)。
教材中的类Token、类Token_stream都是很好的UDT范例。
7.[了解、重点、难点]数据成员和成员函数以及public和private。
基本上,数据成员对应“类型”里“值”的概念,而成员函数则对应“类型”里“操作”的概念。
至于访问控制符public和private的引入,其实是区分了类型的用户和实现者这两种不同的角色:
UDT的用户只关心逻辑上它是什么?
它提供哪些服务?
这就是所谓的公有接口,它反映了用户感兴趣的部分,这些内容应放入class的public区;
UDT的实现者则不同,他必须考虑如何才能将UDT实现出来以提供用户所要求的公有接口?
为了达到此目的,他可能需要定义相关的数据结构和辅助函数,此所谓的私有实现,这些反映了实现UDT所需的而对用户透明(即用户完全不关心)的东西,它们应该放入class的private区。
教材中的类Token_stream是很好的设计范例。
8.[了解、重点、难点]构造函数及函数重载。
构造函数是一种特殊的成员函数,它用于新生对象的初始化。
它有一些显著的特征:
没有返回值;
函数名与类名相同,等等。
一个类可以定义多个构造函数,这就引出了函数重载的概念。
函数重载指的就是若干个函数,它们的名字相同,但参数特征(参数的类型或数目或顺序)不同。
教材中的类Token是一个好的范例。
9.[了解]函数的互递归调用及前置声明(forwarddeclare):
当几个函数出现相互调用的情形时,必须有函数要作前置声明(§
6.9,p128调用关系图)。
1.ex6-2
2.ex6-5
3.ex6-9
4.ex6-10
Chapter7完善一个程序
1.[理解、重点]“完善程序”的概念:
在软件初步版本的基础上,对程序作进一步的完善和优化。
具体地,包括:
改进用户接口(界面)、测试(早测试、常测试)、增强错误处理——实用系统还应该具有一定的错误恢复能力(即,容错能力)、清理代码(目的是让代码清晰可读,具体措施有:
使用符号常量代替魔数、使用函数封装功能相对独立的操作、调整代码格式、完善注释等)、添加新功能等举措。
2.[理解、重点]测试(§
7.3):
当完成程序的初步版本后,你应该做的第一件事是:
尽力让程序崩溃——也就是给它各种输入(合法的,非法的——尤其是刁难的、极端情形的输入)期望它表现出错误的行为。
记住:
尽早测试,经常测试(P141L-13)。
另外,也不应指望系统地测试就一定能发现软件系统中的所有错误。
关于这点,伟大的计算机科学家Dijkstra有句名言:
“测试只能证明程序有错,而不能证明程序没有错误!
”。
3.[理解、重点、难点]错误处理(§
7.7):
我们应尽力避免在错误处理的过程中产生新的错误(类比:
医生在给病人做心脏手术的过程中自己心脏病突发!
因此,一般用于“清理遗留故障”的错误恢复代码会偏于底层。
4.[理解、重点、难点]清理代码(§
7.6):
目的是使代码清晰可读(即易于理解)。
具体措施有:
使用符号常量代替“魔数”;
函数的设计所遵循正交性原则:
每个函数只做单一的逻辑操作(即独立的逻辑功能),不同的函数做互不重叠的事。
这样的好处:
降低了系统的复杂度,改进了可理解性、可维护性;
注释的要点:
①最好的注释就是让代码本身来表达其意图。
因此,代码的清晰性对于程序的理解和维护都非常重要;
②注释的抽象度要高于代码,一般用于代码本身很难表达思想的情形。
换言之,代码说明了它做什么?
而注释则表达了代码的意图。
清理代码时很重要的一点是,要让注释与代码相一致。
5.[理解、重点、难点]添加新功能(§
7.8)。
要点是:
①尽力避免在开发的早期陷入“功能蔓延”,分阶段实现比一次完成所有功能要简单得多;
②添加新功能时,要综合衡量用户需求和开发代价(开发期限、难度、成本等)两方面的诸多制约因素,避免提供对用户“华而不实”的功能。
6.[了解、重点、难点]实用编程技术:
错误恢复技术——计算器如何从错误的输入中恢复过来(§
7.7)。
最主要的是“对症下药”——分析输入错误会影响哪个数据结构(比如,对于计算器程序而言,“Token_streamts;
”就是这样的数据结构,所有的计算——文法分析函数都基于此数据结构)?
数据结构如何清除错误状态?
7.[了解、重点、难点]实用编程技术:
符号表(symboltable)——跟踪变量的机制(§
7.8.1)。
借助符号表,我们最终为计算器添加了定义变量和符号常量这两个比较cool的功能。
[编程题]
1.Ex7-1
2.Ex7-3
3.Ex7-4
4.实验一:
设计并实现支持任意次回退操作的单词流。
Chapter8函数相关的技术细节
1.[理解、重点]声明和定义。
声明(declaration)作用:
将名字引入作用域;
定义(definition):
所声明实体完整描述的声明。
广义上,定义也是一种声明,而狭义上,声明指“不是定义的声明”,两者的区别反映了接口(如何使用一个实体)与实现(该实体如何完成它的功能)的分离。
C++中,标识符(变量名、符号常量名、函数名、类型名)的使用原则:
先声明,后使用。
变量在首次使用前必须先被正确地初始化,符号常量必须在定义时就初始化。
定义只能一次,声明可以多次。
2.[理解、重点、难点]头文件(header)。
头文件中通常放的是变量、函数等的声明,UDT的定义通常也放在头文件中。
为防止头文件重复包含时引起类型重复定义的错误,通常我们对头文件要做一次包含处理。
有一种良好的编程风格:
将接口的声明、实现及使用相分离。
具体地,将全局变量、函数(全局函数或类的成员函数)的声明放在一头文件中,将其定义(尤其是函数的实现)放在一个C++源文件中,而客户端代码为包含该头文件的另一个C++源文件。
这体现了模块化的思想:
模块的接口/界面与实现相分离,而外界(客户端代码)通过其提供的接口来访问模块(即获取模块的服务)。
这就是所谓C/S模式,即客户(Client)/服务器(Server)模式。
其实核心思想就是:
(各个模块)接口与实现的分离、机制与策略的分离——各基本模块只提供每个模块的基本服务的机制(包括设计接口及实现接口),而客户代码(尤其是主框架代码)则决定如何综合利用这些接口来解决