1清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础乔 林计算机程序设计基础
Email,qiaolin@cic.tsinghua.edu.cn
Tel,62792961
2清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础第五章 结构化程序设计概论
学习目标
– 熟悉数据的基本概念,掌握数据的表示方法
– 熟悉代码的基本概念,掌握代码的控制方法
– 熟悉算法的基本概念,了解算法、程序与代码的关系
– 掌握结构化程序设计的一般方法
– 了解问题规模与程序控制结构之间的关系
– 掌握程序测试的基本方法与手段
– 了解代码优化的基本策略
3清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
5.1 数据的基本概念
数据与信息
数据与地址
数据类型
文字常量
变 量
声 明
4清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础数据与数据类型
数据与信息
– 数据:数据特征、数据名称与特征值
– 信息:数据所具有的意义
– 数据并不能解释自身,程序不了解数据的意义
数据类型:对数据进行分类
– 每一类数据具有同样的存储表示(存储分配格式),同样的操作集
– 基本数据类型(预定义数据类型)与用户自定义类型(用户可按需创建新的数据类型)
5清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础文字与量
文字常量:程序中出现的值
– 只能以值的形式标识,其值不可改变
– 若要声明严格意义的常量,使用 C99 的 const
– 文字常量不可寻址,而普通常量可以寻址
变量:程序中定义和命名的数据对象
– 四个基本特征,VANT
– 先声明后使用
– 在程序执行期间,可改变变量的值,不能改变变量的名称、类型与地址
6清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础声 明
数据标识的目的:区分数据
– 模拟世界中各种数据的联系,构造具有复杂结构的数据
声明的目的
– 将程序执行时数据对象的名字与类型信息通知编译器,
在数据对象与数据值及存储位置间建立关联
– 辅助编译器选择合适的存储表示
– 使得类型检查静态化,减少程序错误
声明与定义
– 声明并不一定就是定义,声明虽引入名字,但只有那些确实在程序中引入了实体的声明才是定义
7清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
5.2 代码的基本概念
表达式语义
赋值与初始化
代码与计算
控制流
断言与程序不变量
8清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础表达式语义
表达式语义:表达式的求值顺序
– C 语言未规定表达式求值顺序,一般由操作符的优先级与结合性决定
例外情况
– 递增递减操作符满足特定计算规则
– 不同编译器的实现可能不同:出于优化的目的,编译器可能重排部分代码,表达式的求值顺序可能会发生用户事先无法察觉的变化
既是优点(程序设计可以高度灵活)也是缺点(错误的求值顺序带来错误的计算结果)
– 明确表达设计意图,尽量不在表达式中使用带副作用的操作符,表达式应尽量简短
9清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础赋值与初始化
赋值:将数据对象与某个具体值相关联的基本操作
– 左值:出现在赋值号左边的数据对象具有左值,在程序中表现为数据对象的地址
– 右值:出现在赋值号右边的数据对象具有右值,在程序中表现为数据对象的值
– 例,x = x;
初始化
– 初始化不是赋值:赋值可以在程序运行期间执行多次,
初始化只在为变量分配存储空间时执行一次
– 未初始化的数据对象只有左值没有右值,其存储内容维持原先位序列,所以 不要引用未初始化的数据对象!
10清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础代码与控制流
代码与计算:代码是计算的简洁表达
– 操作为程序的基本单位,一系列的操作构成计算以及计算的顺序
静态代码文本与动态执行过程
– 程序在运行期间根据静态代码文本产生计算过程,即动态执行过程
– 两者并不相同,优秀的程序员应保证两者尽可能匹配,
例如少用甚至不用 goto语句
控制流
– 控制程序流向的程序结构:复合、分支、循环
11清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础断言与程序不变量
断言与不变量的含义
– 断言:程序中存在某些特定位置,在该处某些判断永真,该判断式即为断言
– 不变量:无论程序如何执行,断言的值都应保持不变(具有恒定属性)
断言与不变量的意义
– 若断言值未保持,说明程序必然发生了错误
– 断言在编程时非常重要,一个优秀程序员的第一行 C 代码应该从断言开始书写!
12清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础断言与程序不变量示例
在程序中使用 assert() 表达断言
#include <assert.h>
void ProcessString(char* str)
{
assert( str != NULL );
assert( *str != '\0' );
<<
}
assert() 是宏而不是函数,位于头文件,assert.h”中如果不希望在编译后的程序中出现断言代码,在程序开头声明 NDEBUG 宏后再编译上述代码需要对字符串 str进行处理。在进行处理前,程序必须保证该字符串既不能不存在也不能为空串。如果断言未满足,则程序会在输出错误信息后终止执行
13清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
5.3 算法及其表示方法概要
程序的辨证统一:数据与代码
– 数据表示:指定程序使用的数据结构与组织形式
– 代码组织:数据上所进行操作的描述与组织形式
算法的基本概念
– 为解决某类问题而设计或采取的方法或步骤
– 算法必须能够转化为计算机可执行的指令序列(代码)
– 算法基本特征:有穷性、确定性、输入、输出与有效性
代码与伪代码
– 均可以用来表达算法设计思想与算法执行步骤
14清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础代码与伪代码
给定两个正整数 m与 n,设计求解最大公因子的算法
int gcd( int m,int n )
{
int r;
start:
r = m % n;
if( r == 0 )
return n;
m = n;
n = r;
goto start;
}
代码以计算机语言书写,计算机易理解,程序员不易理解伪代码界于自然语言与计算机语言之间,一般用符号或文字表示算法的实际执行步骤,程序员易理解,计算机不理解输入:整数 m与 n
输出,m与 n的最大公因子步骤 1,m除以 n,余数为 r
步骤 2:若 r为 0,则 n为所求,算法终止;否则步骤 3:将 n作为新 m,r作为新 n,
返回第 1步重新计算
15清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
5.4 结构化程序的组织
程序的结构化
程序的一般结构
结构化与函数抽象
程序范型
16清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础程序的结构化
结构化
– 结构化语句:满足单入口单出口条件的语句
复合语句、分支语句与循环语句都是结构化语句
– 结构化程序:使用结构化语句设计的程序
– 结构定理:所有程序都可使用上述三类结构化语句实现
结构化优点
– 单入口单出口的控制流易于确定程序动态计算过程,易于理解
注意事项
– 结构化程序并不一定是好程序,程序的合理组织最重要!
17清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础程序的一般结构
根据用户输入的底面半径与高度,计算圆柱体体积
#include <stdio.h> /* 包含必要的头文件 */
#define PI 3.14159265 /* PI宏定义,一次定义多次使用 */
float radius,height,volume; /* 全局变量声明 */
void main() /* 主函数 */
{
/* 输入半径与高度 */
printf(“This program computes the volume of the cylinder.\n“);
printf(“Please input the radius value:,);
scanf(“%f“,&radius);
printf(“Please input the height value:,);
scanf(“%f“,&height);
/* 计算体积 */
volume = PI * radius * radius * height;
/* 输出体积 */
printf(“The volume of the cylinder is %f\n“,volume);
}
主函数包括输入、计算与输出三部分程序无非是对特定输入数据进行处理并输出处理结果的指令序列,所以任何程序都应包括输入、计算与输出三部分
18清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础结构化与函数抽象
程序设计过程
– 按照功能需求,进行自顶向下的功能分解与逐步求精,
最终形成代码
大多数问题的求解过程非常复杂,如何合理地控制程序规模和复杂性呢?
– 程序的分割与结构化:着重于安排操作序列而不是数据结构,使程序易于创建、理解与维护
函数抽象:结构化程序设计的主要工具
– 体现要执行的命令、计算或任务,这些抽象构成了函数
– 用户只关心抽象的语法和该抽象提供的功能或服务,不关心如何实现该功能
19清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础结构化与函数抽象示例
根据用户输入的底面半径与高度,计算圆柱体体积
#include <stdio.h> /* 包含必要的头文件 */
#define PI 3.14159265 /* PI宏定义,一次定义多次使用 */
float radius,height,volume; /* 全局变量声明 */
void Input(); /* 输入半径与高度,将实际的输入操作隐藏在函数内部 */
void Compute(); /* 计算体积,将实际的计算过程隐藏在函数内部 */
void Output(); /* 输出体积,将实际的输出操作隐藏在函数内部 */
void main() /* 主函数,表现为对上述函数的调用,无其他代码 */
{
Input();
Compute();
Output();
}
主函数是否更容易理解?
没有复杂的输入、计算与输出的实现细节,理解主函数一点都不困难在主函数层次,只需了解一旦声明三个全局变量,连续调用上述三个函数即能完成主函数的计算任务就可以了
20清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础结构化与函数抽象示例(续)
void Input()
{
printf(“This program computes the volume of the cylinder.\n“);
printf(“Please input the radius value:,);
scanf(“%f“,&radius);
printf(“Please input the height value:,);
scanf(“%f“,&height);
}
void Compute()
{
volume = PI * radius * radius * height;
}
void Output()
{
printf(“The volume of the cylinder is %f\n“,volume);
}
只有在确实必要的时候才需要了解这三个函数的具体实现细节与代码通过程序分割与逻辑分组,
程序分离成一个一个的模块
——在需要的时候,我们可以使用这些模块像积木一样构造整个程序
21清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
5.4 程序范型
范型:实现特定程序代码的通用模式
– 有助于形成函数抽象
– 编写出的代码容易重用:不加修改或部分修改就可以适应其他场合
示例:数据输入模式具有重复性
– 输出提示信息,接受用户输入输入:提醒用户输入数据的提示信息输出:数据值步骤 1:输出提示信息步骤 2:获取数据值并输出
22清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础程序范型示例
float radius,height,volume;
float GetFloatValue(char* prompt);
float GetFloatValue(char* prompt)
{
float t; printf(“%s“,prompt); scanf(“%f“,&t); return t;
}
void Input()
{
printf(“This program computes the volume of the cylinder.\n“);
/* 调用 GetFloatValue函数进行 radius值的实际输入操作 */
radius = GetFloatValue(“Please input the radius value:,);
/* 调用 GetFloatValue函数进行 height值的实际输入操作 */
height = GetFloatValue(“Please input the height value:,);
}
23清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础功能分解与逐步求精
自顶向下的功能分解
– 先从整体考虑问题,将原始问题分解成逻辑上相互独立的多个部分;一一实现分解后的各部分,将上述实现组装成原始问题的解
– 功能分解必须按照程序需求进行,分解后的各部分应能实现为单入口单出口的函数
逐步求精
– 对于复杂系统,功能分解可能不会一步到位,对于某些部分可能需要重复上述功能分解步骤
– 在功能分解与逐步求精过程中,我们最关心的既不是数据对象,也不是具体算法,而是算法模式(程序范型)
24清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
5.5 程序测试与代码优化
程序测试
– 顺序结构:一般一次测试
– 分支结构:所有分支路径都需测试
– 循环结构:第一次迭代,最后一次迭代,中间一次迭代
程序调试:查找与改正错误
– 语法错误与逻辑错误
程序效率与代码优化
– 正确性不是程序设计的全部,效率同样重要
25清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
1,8 3 2fc
程序测试示例
编程实现摄氏温度到华氏温度的转换,温度转换公式为,c 为摄氏温度值,f 为转换后的华氏温度值
#include <stdio.h> /* 包含必要的头文件 */
float f,c; /* 全局变量声明 */
float GetFloatValue(char* prompt); /* 获取用户输入的浮点数据 */
void Input(); /* 输入数据,将实际的输入过程隐藏在函数内部 */
void Compute(); /* 温度转换,将实际的计算过程隐藏在函数内部 */
void Output(); /* 输出结果,将实际的输出操作隐藏在函数内部 */
void main() /* 主函数,表现为对上述函数的调用,无其他代码 */
{
Input();
Compute();
Output();
}
26清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础程序测试示例(续)
float GetFloatValue(char* prompt)
{
float t; printf(“%s“,prompt); scanf(“%f“,&t); return t;
}
void Input()
{
c = GetFloatValue(“Please input temperature value(C):,);
}
void Compute()
{
f = c * 1.8 + 32;
}
void Output()
{
printf(“Temperature Value(F),%f\n“,f);
}
功能分解的好处:本例主函数的实现与体积计算程序完全相同,程序结构也相同
27清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础程序调试示例
下述程序存在一些错误,请找出
#include <stdio.h>
float f,c;
float GetFloatValue(char* prompt);
void Input();
void Compute();
void Output();
void main()
{
Input();
Comput();
Output();
}
绝对零度的概念必须遵守:程序不能脱离所解决问题的物理世界而存在如何改正?
使用断言!
#include <assert.h>
assert(c > –273.13);
#define ABSOLUTE_ZERO–273.13
ABSOLUTE_ZERO);
28清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础代码优化示例
如何优化下述代码,提高程序执行效率?
#include <stdio.h>
#include <assert.h>
#define ABSOLUTE_ZERO–273.13
float f,c;
void Compute()
{
f = c * 1.8 + 32;
}
void main()
{
Input();
assert(c > ABSOLUTE_ZERO);
Compute();
Output();
}
f的计算需要三次类型转换,c为 float,
1.8为 double,而 32为 int,乘法运算前 c
需先转换成 double,加法运算前 32需先转换成 double,结果为 double,再转换成 float赋值给 f,转换过程浪费了时间
F
F + 32.0F;
修改后代码不需要类型转换,效率更高
29清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础作 业
第 132页:第三题(编程题)
– 第 1,8小题
计算机程序设计基础乔 林计算机程序设计基础
Email,qiaolin@cic.tsinghua.edu.cn
Tel,62792961
2清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础第五章 结构化程序设计概论
学习目标
– 熟悉数据的基本概念,掌握数据的表示方法
– 熟悉代码的基本概念,掌握代码的控制方法
– 熟悉算法的基本概念,了解算法、程序与代码的关系
– 掌握结构化程序设计的一般方法
– 了解问题规模与程序控制结构之间的关系
– 掌握程序测试的基本方法与手段
– 了解代码优化的基本策略
3清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
5.1 数据的基本概念
数据与信息
数据与地址
数据类型
文字常量
变 量
声 明
4清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础数据与数据类型
数据与信息
– 数据:数据特征、数据名称与特征值
– 信息:数据所具有的意义
– 数据并不能解释自身,程序不了解数据的意义
数据类型:对数据进行分类
– 每一类数据具有同样的存储表示(存储分配格式),同样的操作集
– 基本数据类型(预定义数据类型)与用户自定义类型(用户可按需创建新的数据类型)
5清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础文字与量
文字常量:程序中出现的值
– 只能以值的形式标识,其值不可改变
– 若要声明严格意义的常量,使用 C99 的 const
– 文字常量不可寻址,而普通常量可以寻址
变量:程序中定义和命名的数据对象
– 四个基本特征,VANT
– 先声明后使用
– 在程序执行期间,可改变变量的值,不能改变变量的名称、类型与地址
6清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础声 明
数据标识的目的:区分数据
– 模拟世界中各种数据的联系,构造具有复杂结构的数据
声明的目的
– 将程序执行时数据对象的名字与类型信息通知编译器,
在数据对象与数据值及存储位置间建立关联
– 辅助编译器选择合适的存储表示
– 使得类型检查静态化,减少程序错误
声明与定义
– 声明并不一定就是定义,声明虽引入名字,但只有那些确实在程序中引入了实体的声明才是定义
7清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
5.2 代码的基本概念
表达式语义
赋值与初始化
代码与计算
控制流
断言与程序不变量
8清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础表达式语义
表达式语义:表达式的求值顺序
– C 语言未规定表达式求值顺序,一般由操作符的优先级与结合性决定
例外情况
– 递增递减操作符满足特定计算规则
– 不同编译器的实现可能不同:出于优化的目的,编译器可能重排部分代码,表达式的求值顺序可能会发生用户事先无法察觉的变化
既是优点(程序设计可以高度灵活)也是缺点(错误的求值顺序带来错误的计算结果)
– 明确表达设计意图,尽量不在表达式中使用带副作用的操作符,表达式应尽量简短
9清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础赋值与初始化
赋值:将数据对象与某个具体值相关联的基本操作
– 左值:出现在赋值号左边的数据对象具有左值,在程序中表现为数据对象的地址
– 右值:出现在赋值号右边的数据对象具有右值,在程序中表现为数据对象的值
– 例,x = x;
初始化
– 初始化不是赋值:赋值可以在程序运行期间执行多次,
初始化只在为变量分配存储空间时执行一次
– 未初始化的数据对象只有左值没有右值,其存储内容维持原先位序列,所以 不要引用未初始化的数据对象!
10清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础代码与控制流
代码与计算:代码是计算的简洁表达
– 操作为程序的基本单位,一系列的操作构成计算以及计算的顺序
静态代码文本与动态执行过程
– 程序在运行期间根据静态代码文本产生计算过程,即动态执行过程
– 两者并不相同,优秀的程序员应保证两者尽可能匹配,
例如少用甚至不用 goto语句
控制流
– 控制程序流向的程序结构:复合、分支、循环
11清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础断言与程序不变量
断言与不变量的含义
– 断言:程序中存在某些特定位置,在该处某些判断永真,该判断式即为断言
– 不变量:无论程序如何执行,断言的值都应保持不变(具有恒定属性)
断言与不变量的意义
– 若断言值未保持,说明程序必然发生了错误
– 断言在编程时非常重要,一个优秀程序员的第一行 C 代码应该从断言开始书写!
12清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础断言与程序不变量示例
在程序中使用 assert() 表达断言
#include <assert.h>
void ProcessString(char* str)
{
assert( str != NULL );
assert( *str != '\0' );
<<
}
assert() 是宏而不是函数,位于头文件,assert.h”中如果不希望在编译后的程序中出现断言代码,在程序开头声明 NDEBUG 宏后再编译上述代码需要对字符串 str进行处理。在进行处理前,程序必须保证该字符串既不能不存在也不能为空串。如果断言未满足,则程序会在输出错误信息后终止执行
13清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
5.3 算法及其表示方法概要
程序的辨证统一:数据与代码
– 数据表示:指定程序使用的数据结构与组织形式
– 代码组织:数据上所进行操作的描述与组织形式
算法的基本概念
– 为解决某类问题而设计或采取的方法或步骤
– 算法必须能够转化为计算机可执行的指令序列(代码)
– 算法基本特征:有穷性、确定性、输入、输出与有效性
代码与伪代码
– 均可以用来表达算法设计思想与算法执行步骤
14清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础代码与伪代码
给定两个正整数 m与 n,设计求解最大公因子的算法
int gcd( int m,int n )
{
int r;
start:
r = m % n;
if( r == 0 )
return n;
m = n;
n = r;
goto start;
}
代码以计算机语言书写,计算机易理解,程序员不易理解伪代码界于自然语言与计算机语言之间,一般用符号或文字表示算法的实际执行步骤,程序员易理解,计算机不理解输入:整数 m与 n
输出,m与 n的最大公因子步骤 1,m除以 n,余数为 r
步骤 2:若 r为 0,则 n为所求,算法终止;否则步骤 3:将 n作为新 m,r作为新 n,
返回第 1步重新计算
15清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
5.4 结构化程序的组织
程序的结构化
程序的一般结构
结构化与函数抽象
程序范型
16清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础程序的结构化
结构化
– 结构化语句:满足单入口单出口条件的语句
复合语句、分支语句与循环语句都是结构化语句
– 结构化程序:使用结构化语句设计的程序
– 结构定理:所有程序都可使用上述三类结构化语句实现
结构化优点
– 单入口单出口的控制流易于确定程序动态计算过程,易于理解
注意事项
– 结构化程序并不一定是好程序,程序的合理组织最重要!
17清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础程序的一般结构
根据用户输入的底面半径与高度,计算圆柱体体积
#include <stdio.h> /* 包含必要的头文件 */
#define PI 3.14159265 /* PI宏定义,一次定义多次使用 */
float radius,height,volume; /* 全局变量声明 */
void main() /* 主函数 */
{
/* 输入半径与高度 */
printf(“This program computes the volume of the cylinder.\n“);
printf(“Please input the radius value:,);
scanf(“%f“,&radius);
printf(“Please input the height value:,);
scanf(“%f“,&height);
/* 计算体积 */
volume = PI * radius * radius * height;
/* 输出体积 */
printf(“The volume of the cylinder is %f\n“,volume);
}
主函数包括输入、计算与输出三部分程序无非是对特定输入数据进行处理并输出处理结果的指令序列,所以任何程序都应包括输入、计算与输出三部分
18清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础结构化与函数抽象
程序设计过程
– 按照功能需求,进行自顶向下的功能分解与逐步求精,
最终形成代码
大多数问题的求解过程非常复杂,如何合理地控制程序规模和复杂性呢?
– 程序的分割与结构化:着重于安排操作序列而不是数据结构,使程序易于创建、理解与维护
函数抽象:结构化程序设计的主要工具
– 体现要执行的命令、计算或任务,这些抽象构成了函数
– 用户只关心抽象的语法和该抽象提供的功能或服务,不关心如何实现该功能
19清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础结构化与函数抽象示例
根据用户输入的底面半径与高度,计算圆柱体体积
#include <stdio.h> /* 包含必要的头文件 */
#define PI 3.14159265 /* PI宏定义,一次定义多次使用 */
float radius,height,volume; /* 全局变量声明 */
void Input(); /* 输入半径与高度,将实际的输入操作隐藏在函数内部 */
void Compute(); /* 计算体积,将实际的计算过程隐藏在函数内部 */
void Output(); /* 输出体积,将实际的输出操作隐藏在函数内部 */
void main() /* 主函数,表现为对上述函数的调用,无其他代码 */
{
Input();
Compute();
Output();
}
主函数是否更容易理解?
没有复杂的输入、计算与输出的实现细节,理解主函数一点都不困难在主函数层次,只需了解一旦声明三个全局变量,连续调用上述三个函数即能完成主函数的计算任务就可以了
20清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础结构化与函数抽象示例(续)
void Input()
{
printf(“This program computes the volume of the cylinder.\n“);
printf(“Please input the radius value:,);
scanf(“%f“,&radius);
printf(“Please input the height value:,);
scanf(“%f“,&height);
}
void Compute()
{
volume = PI * radius * radius * height;
}
void Output()
{
printf(“The volume of the cylinder is %f\n“,volume);
}
只有在确实必要的时候才需要了解这三个函数的具体实现细节与代码通过程序分割与逻辑分组,
程序分离成一个一个的模块
——在需要的时候,我们可以使用这些模块像积木一样构造整个程序
21清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
5.4 程序范型
范型:实现特定程序代码的通用模式
– 有助于形成函数抽象
– 编写出的代码容易重用:不加修改或部分修改就可以适应其他场合
示例:数据输入模式具有重复性
– 输出提示信息,接受用户输入输入:提醒用户输入数据的提示信息输出:数据值步骤 1:输出提示信息步骤 2:获取数据值并输出
22清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础程序范型示例
float radius,height,volume;
float GetFloatValue(char* prompt);
float GetFloatValue(char* prompt)
{
float t; printf(“%s“,prompt); scanf(“%f“,&t); return t;
}
void Input()
{
printf(“This program computes the volume of the cylinder.\n“);
/* 调用 GetFloatValue函数进行 radius值的实际输入操作 */
radius = GetFloatValue(“Please input the radius value:,);
/* 调用 GetFloatValue函数进行 height值的实际输入操作 */
height = GetFloatValue(“Please input the height value:,);
}
23清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础功能分解与逐步求精
自顶向下的功能分解
– 先从整体考虑问题,将原始问题分解成逻辑上相互独立的多个部分;一一实现分解后的各部分,将上述实现组装成原始问题的解
– 功能分解必须按照程序需求进行,分解后的各部分应能实现为单入口单出口的函数
逐步求精
– 对于复杂系统,功能分解可能不会一步到位,对于某些部分可能需要重复上述功能分解步骤
– 在功能分解与逐步求精过程中,我们最关心的既不是数据对象,也不是具体算法,而是算法模式(程序范型)
24清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
5.5 程序测试与代码优化
程序测试
– 顺序结构:一般一次测试
– 分支结构:所有分支路径都需测试
– 循环结构:第一次迭代,最后一次迭代,中间一次迭代
程序调试:查找与改正错误
– 语法错误与逻辑错误
程序效率与代码优化
– 正确性不是程序设计的全部,效率同样重要
25清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础
1,8 3 2fc
程序测试示例
编程实现摄氏温度到华氏温度的转换,温度转换公式为,c 为摄氏温度值,f 为转换后的华氏温度值
#include <stdio.h> /* 包含必要的头文件 */
float f,c; /* 全局变量声明 */
float GetFloatValue(char* prompt); /* 获取用户输入的浮点数据 */
void Input(); /* 输入数据,将实际的输入过程隐藏在函数内部 */
void Compute(); /* 温度转换,将实际的计算过程隐藏在函数内部 */
void Output(); /* 输出结果,将实际的输出操作隐藏在函数内部 */
void main() /* 主函数,表现为对上述函数的调用,无其他代码 */
{
Input();
Compute();
Output();
}
26清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础程序测试示例(续)
float GetFloatValue(char* prompt)
{
float t; printf(“%s“,prompt); scanf(“%f“,&t); return t;
}
void Input()
{
c = GetFloatValue(“Please input temperature value(C):,);
}
void Compute()
{
f = c * 1.8 + 32;
}
void Output()
{
printf(“Temperature Value(F),%f\n“,f);
}
功能分解的好处:本例主函数的实现与体积计算程序完全相同,程序结构也相同
27清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础程序调试示例
下述程序存在一些错误,请找出
#include <stdio.h>
float f,c;
float GetFloatValue(char* prompt);
void Input();
void Compute();
void Output();
void main()
{
Input();
Comput();
Output();
}
绝对零度的概念必须遵守:程序不能脱离所解决问题的物理世界而存在如何改正?
使用断言!
#include <assert.h>
assert(c > –273.13);
#define ABSOLUTE_ZERO–273.13
ABSOLUTE_ZERO);
28清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础代码优化示例
如何优化下述代码,提高程序执行效率?
#include <stdio.h>
#include <assert.h>
#define ABSOLUTE_ZERO–273.13
float f,c;
void Compute()
{
f = c * 1.8 + 32;
}
void main()
{
Input();
assert(c > ABSOLUTE_ZERO);
Compute();
Output();
}
f的计算需要三次类型转换,c为 float,
1.8为 double,而 32为 int,乘法运算前 c
需先转换成 double,加法运算前 32需先转换成 double,结果为 double,再转换成 float赋值给 f,转换过程浪费了时间
F
F + 32.0F;
修改后代码不需要类型转换,效率更高
29清华大学计算中心 http://learn.tsinghua.edu.cn
计算机程序设计基础作 业
第 132页:第三题(编程题)
– 第 1,8小题