欢迎光临散文网 会员登陆 & 注册

第五、六讲

2021-02-02 21:10 作者:你算是哪块小饼干吖  | 我要投稿

第五讲  程序组织与软件开发方法  

一  库与接口

1  库与程序文件

  • 程序文件:源文件(.cpp)、头文件(.h、 *.hpp、 *)

  • :源文件与头文件

2  接 口

  • 通过接口使用库:包括指定库的头文件与源文件

  • 优势:不需了解库的实现细节,只需了解库的使用方法  

3  标准库

  • C标准库 标准输入输出库、工具与辅助函数库、字符串库

  • C++标准库 输入输出流库、字符串库、标准模板库  

4  数学库

  • 数学库 头文件: math.h/cmath

    库文件: libm 链接方式: g++ -lm main.cpp  (linux系统下)

5  标准辅助函数库

  • 工具与辅助函数 头文件: stdlib.h/cstdlib

  • 常用函数 void exit( int status ); void free( void * p ); void * malloc( size_t size ); int rand(); void srand( unsigned int seed );


二  随机数库

1  随机数的生成

 #include <iostream>
 #include <cstdlib>
 #include <ctime>
 using namespace std;
 int main()
 {
 int i;
 cout << "On this computer, the RAND_MAX is " << RAND_MAX << ".\n";
 cout << "Five numbers the rand function generates as follows:\n";
 srand( (int)time(0) );
 for( i = 0; i < 5; i++ )
 cout << rand() << "; ";
 cout << "\n";
 return 0;
 }


2  库的设计原则

  • 用途一致 接口中所有函数都属于同一类问题

  • 操作简单 函数调用方便,最大限度隐藏操作细节

  • 功能充足 满足不同潜在用户的需要

  • 性能稳定 经过严格测试,不存在程序缺陷  


3  随机数库接口

 void Randomize();
 int GenerateRandomNumber( int low, int high );
 double GenerateRandomReal( double low, double high );


4  随机数库实现

 #include <iostream>
 #include <cstdlib>
 #include <ctime>
 #include "random.h"
 using namespace std;
 void Randomize()
 {
 srand( (int)time(NULL) );
 }
 int GenerateRandomNumber( int low, int high )
 {
 double _d;
 if( low > high )
 {
 cout << "GenerateRandomNumber: Make sure low <= high.\n";
 exit( 1 );
 }
 _d = (double)rand() / ((double)RAND_MAX + 1.0);
 return (low + (int)(_d * (high - low + 1)));
 }
 double GenerateRandomReal( double low, double high )
 {
 double _d;
 if( low > high )
 {
 cout << "GenerateRandomReal: Make sure low <= high.\n";
 exit( 2 );
 }
 _d = (double)rand() / (double)RAND_MAX;
 return (low + _d * (high - low));
 }


5  随机数库测试  

  • 单独测试库的所有函数 合法参数时返回结果是否正确 非法参数时返回结果是否正确,即容错功能是否正常

  • 联合测试 多次运行程序,查看生成的数据是否随机 测试整数与浮点数随机数是否均能正确工作  


三  作用域与生存期

1  量的作用域与可见性

  • 作用域与可见性 作用域:标识符的有效范围 可见性:程序中某个位置是否可以使用某个标识符 标识符仅在其作用域内可见 位于作用域内的标识符不一定可见

  • 局部数据对象 定义于函数或复合语句块内部的数据对象(包括变量、常量与函数形式参数等) 局部数据对象具有块作用域,仅在定义它的块内有效 有效性从定义处开始直到该块结束 多个函数定义同名的数据对象是允许的

  • 全局数据对象 定义于函数或复合语句块之外的数据对象 全局数据对象具有文件(全局)作用域,有效性从定义处开始直到 本文件结束,其后函数都可直接使用 若包含全局数据对象定义的文件被其他文件包含,则其作用域扩展 到宿主文件中, 这可能会导致问题 不要在头文件中定义全局数据对象

  • 函数原型作用域 定义在函数原型中的参数具有函数原型作用域,其有效性仅延续到 此函数原型结束 函数原型中参数名称可以与函数实现中的不同,也可以省略  

2  量的存储类与生存期

  • 生存期:量在程序中存在的时间范围 C/C++ 使用存储类表示生存期 作用域表达量的空间特性,存储类表达量的时间特性

  • 静态(全局)生存期 全局数据对象具有静态(全局)生存期 生死仅与程序是否执行有关

  • 自动(局部)生存期 局部数据对象具有自动(局部)生存期 生死仅与程序流程是否位于该块中有关 程序每次进入该块时就为该对象分配内存,退出该块时释放内存; 两次进入该块时使用的不是同一个数据  

  • static 关键字

    修饰局部变量:静态局部变量 使局部变量具有静态生存期 程序退出该块时局部变量仍存在,并且下次进入该块时使用上一次 的数据值 静态局部变量必须进行初始化 不改变量的作用域,仍具有块作用域,即只能在该块中访问, 其他 代码段不可见 修饰全局变量 使其作用域仅限定于本文件内部,其他文件不可见  

3  函数的作用域与生存期

  • 所有函数具有文件作用域与静态生存期 在程序每次执行时都存在,并且可以在函数原型或函数定义之后的 任意位置调用

  • 内部函数与外部函数 外部函数:可以被其他文件中的函数所调用 内部函数:不可以被其他文件中的函数所调用 函数缺省时均为外部函数 内部函数定义:使用 static 关键字 内部函数示例: static int Transform( int x ); 内部函数示例: static int Transform( int x ){ … }  

4  声明与定义  

  • 声明不是定义 定义在程序产生一个新实体 声明仅仅在程序中引入一个实体

  • 函数的声明与定义 声明是给出函数原型,定义是给出函数实现代码

  • 类型的声明与定义 产生新类型就是定义 类型定义示例: typedef enum __BOOL { FALSE, TRUE } BOOL; 不产生新类型就不是定义,而仅仅是声明 类型声明示例: enum BOOL;

5  全局变量的作用域扩展  

全局变量的定义不能出现在头文件中,只有其声明才可以出现 在头文件中 声明格式:使用 extern 关键字

 /* 库的头文件 */
 /* 此处仅引入变量 a,其定义位于对应源文件中 */
 extern int a; /* 变量 a 可导出,其他文件可用 */
 /* 库的源文件 */
 /* 定义变量 a */
 int a;


四  典型软件开发流程  


第六讲  复合数据类型

一  字 符

1  字符类型、字符文字与量

  • 定义格式char ch; const char cch = 'C';

  • 字符文字使用单引号对

  • 实际存储时字符类型量存储字符的对应 ASCII 值

  • 可使用 signed 与 unsigned 修饰字符类型

2  字符表示的等价性

char a = 'A'; char a = 65; char a = 0101; char a = 0x41;  

3  ASCII 码  

  • 回车与换行 Windows: \n\r Linux: \n Mac: \r


二  数 组

1  数组的意义与性质

  • 数组的定义 定义格式: 元素类型 数组名称[常数表达式]; 示例: int a[8]; /* 定义包含 8 个整数元素的数组 */

  • 特别说明 常数表达式必须是常数和常量,不允许为变量 错误示例: int count = 8; int c[count]; 数组元素编号从 0 开始计数,元素访问格式为 a[0]、 a[1]、 …… 不允许对数组进行整体赋值操作,只能使用循环逐一复制元素 错误示例三: int a[8], b[8]; a = b;

  • 意义与性质 将相同性质的数据元素组织成整体,构成单一维度上的数据序列  

2  数组的存储表示

  • 数组的地址 数组的基地址:数组开始存储的物理位置 数组首元素的基地址:数组首个元素开始存储的物理地址, 数值上总是与数组基地址相同 “&” 操作符:&a 获得数组的基地址;&a[0] 获得数组首元素的基地址

3  数组元素的访问

4  数组与函数

  • 数组元素作为函数实际参数 int Add( int x, int y ){ return( x + y ); } int a[2] = { 1, 2 }, sum; sum = Add( a[0], a[1] );

  • 数组整体作为函数形式参数 基本格式: 返回值类型 函数名称( 元素类型 数组名称[], 元素 个数类型 元素个数 ) 示例: void GenerateIntegers( int a[], unsigned int n ); 特别说明:作为函数形式参数时,数组名称后的中括号内不需 列写元素个数,必须使用单独的参数传递元素个数信息  

5  多维数组  

  • 多维数组的定义 定义格式: 元素类型 数组名称[常数表达式1] [常数表达式2]…; 示例一: int a[2][2]; /* 2×2 个整数元素的二维数组 */ 示例二: int b[2][3][4]; /* 2×3×4 个整数元素数组 */ 特别说明:同单维数组

  • 多维数组的初始化 与一维数组类似: int a[2][3] = {1, 2, 3, 4, 5, 6}; 单独初始化每一维: int a[2][3] = { {1, 2, 3}, {4, 5, 6} };  (建议用这种,调整格式写出矩阵形式)


三  结构体  

1  结构体的意义与性质

  • 结构体的意义 与数组的最大差别:不同类型数据对象构成的集合 当然也可以为相同类型的但具体意义或解释不同的数据对象集合

  • 结构体类型的定义 `struct 结构体名称 { 成员类型 1 成员名称 1; 成员类型 2 成员名称 2; …… 成员类型 n 成员名称 n; };`  

2  结构体的存储表示

3  结构体数据对象的访问

  • 结构体类型的变量与常量:按普通量格式定义 示例一: DATE date; 示例二: STUDENT zhang_san; 示例三: STUDENT students[8];

  • 结构体量的初始化 示例四: DATE date = { 2008, 8, 8 };

  • 结构体量的赋值 与数组不同,结构体量可直接赋值,拷贝过程为逐成员一一复制 示例五: DATE new_date; new_date = date;  

  • 结构体量成员的访问 使用点号操作符“.” 解析结构体量的某个特定成员 示例一: DATE date; date.year = 2008; date.month = 8; date.day = 8;

  • 嵌套结构体成员的访问 可以连续使用点号逐层解析 示例二: struct FRIEND{ int id; STRING name; DATE birthday; }; FRIEND friend; friend.birthday.year = 1988;

  • 复杂结构体成员的访问 严格按照语法规范进行


4  结构体与函数  

例:编写一函数,使用结构体类型存储日期,并返回该日在该年的第几天信息,具体天数从 1 开始计数,例如 2016 年 1 月 20 日返回 20,2 月 1 日返回 32

unsigned int GetDateCount( DATE date )

{

static unsigned int days_of_months[13] =

{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

unsigned int i, date_id = 0;

for( i = 1; i < date.month; i++ )

date_id += days_of_months[i];

date_id += date.day;

if( date.month > 2 && IsLeap(date.year) )

date_id++;

return date_id;

}  


第五、六讲的评论 (共 条)

分享到微博请遵守国家法律