05.程序组织与开发方法

库与接口

库与程序文件

程序文件:源文件(*.cpp)、头文件(*.h、*.hpp、*),必须包含main()作为程序的入口

库:源文件与头文件,因为库文件不会单独执行,所以无需包含main()。源文件提供库的具体实现,头文件提供库的接口。

接口

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

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

随机数库

随机数的生成

编写程序,调用rand()函数生成五个随机数

第一版

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

程序运行结果:

PS E:C++Random> .Random        //第一次执行
On this computer, the RAND_MAX is 32767.
Five numbers the rand function generates as follows:
41;18467;6334;26500;19169;
PS E:C++Random> .Random        //第二次执行
On this computer, the RAND_MAX is 32767.
Five numbers the rand function generates as follows:
41;18467;6334;26500;19169;
PS E:C++Random> .Random        //第三次执行
On this computer, the RAND_MAX is 32767.
Five numbers the rand function generates as follows:
41;18467;6334;26500;19169;

每次产生的随机数相同。C++ 库有一个名为 rand() 的函数,每次调用该函数都将返回一个非负整数。要使用 rand() 函数,必须在程序中包含 <cstdlib> 头文件。但是,该函数返回的数字其实是伪随机数。这意味着它们具有随机数的表现和属性,但实际上并不是随机的,它们实际上是用算法生成的。该算法需要一个起始值,称为种子,以生成数字。如果没有给出一个种子,那么它将在每次运行时产生相同的数字流

要在每次运行程序时获得不同额随机数字流,则必须为随机数生成器提供一个种子以开始。在C++中,这是通过srand()完成的。在rand()被调用之前,srand()要先被调用,并且srand()在整个程序中仅被调用一次。如下随机数生成第二版所示:

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

程序运行结果:

PS E:C++Random> ./Randomv2		//第一次运行
On this computer, the RAND_MAX is 32767.
Input the seed: 3
Five numbers the rand function generates as follows:
48;7196;9294;9091;7031;
PS E:C++Random> ./Randomv2		//第二次运行
On this computer, the RAND_MAX is 32767.
Input the seed: 2
Five numbers the rand function generates as follows:
45;29216;24198;17795;29484;
PS E:C++Random> ./Randomv2		//第三次运行
On this computer, the RAND_MAX is 32767.
Input the seed: 3
Five numbers the rand function generates as follows:
48;7196;9294;9091;7031;

srand(seed),seed只接受非负整数。当种子seed相同时,产生的随机数相同。

获取种子值的常见做法是调用time(),它是C++标准库的函数。

time()返回从1970年1月1日午夜到现在逝去的秒数,因此每次运行程序,它都将提供不同的种子值。如下所示:

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

限制随机数的范围

要将随机数的范围限制在1和某个最大值max之间的整数,则可使用如下公式:

number = rand() % max + 1;

例如生成1~9的随机数:

number = rand() % 9 + 1;

余数范围为08,加1即为19的随机数

可以扩展到任意范围内的随机数,通用公式如下:

number = (rand() % (maxValue - minValue + 1)) + minValue;

库的设计原则

习惯把自定义的库的头文件保存为*.h,源文件保存为*.cpp。

例如:要使用自定义的随机数库产生符合要求的随机数,需定义三个文件,CustomRandom.h,CustomRandom.cpp,main.cpp

随机数库接口

接口设计原则

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

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

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

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

实例

CustomRandom.h包含自定随机数库的接口

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

随机数库实现

实例

CustomRandom.cpp包含自定随机数库的具体实现

#include <iostream>
#include <cstdlib>  //包含srand()
#include <ctime>    //包含time()
using namespace std;

void Randomize()
{
    srand((int) time(0));
}
int GenerateRandomNumber(int low, int high)
{
    double _d;
    if(low > high)
    {
        cout<<"GenerateRandomNumber:make sure low <= high. 
 ";
    	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. 
 ";
    	exit(2);
    }
    _d = (double)rand()/((double)RAND_MAX);
    return low + _d * (high - low);
}

随机数库测试

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

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

实例

main.cpp来调用自定随机数库

#include <iostream>
#include "CustomRandom.h"   //标准库用<>,自定的库需要用""
using namespace std;

int main()
{
    int i;
    Randomize();
    for(i = 0; i < 8; i++)
    {
        int t = GenerateRandomNumber(10,99);
        cout<<t<<";";
    }
    cout<<endl;
    for(i = 0; i < 8; i++)
    {
        int t = GenerateRandomReal(10.0,99.0);
        cout<<t<<";";
    }
    cout<<endl;
}

作用域与生存期

量的作用域与可见性

作用域与可见性

作用域:标识符的有效范围

可见性:程序中某个位置是否可以使用某个标识符

标识符仅在其作用域内可见,位于作用域内的标识符不一定可见

局部数据对象

定义于函数或复合语句块内部的数据对象(包括变量、常量于函数形式参数等)

局部数据对象具有块作用域,仅在定义它的块内有效

有效性从定义出开始知道该块结束

多个函数定义同名的数据对象是允许的

全局数据对象

定义于函数或复合语句块之外的数据对象

全局数据对象具有文件(全局)作用域,有效性从定义处开始直到本文件结束,其后函数都可直接使用

若包含全局数据对象定义的文件被其他文件包含,则其作用域扩展到宿主文件中,这可能会导致问题,所以一般不要在头文件中定义全局数据对象

函数原型作用域

定义在函数原型中的参数具有函数原型作用域,其有效性仅延续到此函数原型结束

函数原型中参数名称可以与函数实现中的不同,也可以省略

量的存储类与生存期

生存期:量在程序中存在的时间范围

C/C++使用存储类表示生存期

作用域表达量的空间特性,存储类表达量的时间特性

静态(全局)生存期

全局数据对象具有静态(全局)生存期

生死仅与程序是否执行有关

自动(局部)生存期

局部数据对象具有自动(局部)生存期

生死仅与程序流程是否位于该块中有关

程序每次进入该块时就为该对象分配内存,退出该块时释放内存

两次进入该块时使用的不是同一个数据对象

static关键字

修饰局部变量:静态局部变量

使局部变量具有静态生存期

程序退出该块时局部变量仍存在,并且下次进入该块时使用上一次的数据值

静态局部变量必须进行初始化

不改变量的作用域,仍具有块作用域,即只能在该块中访问,其他代码段不可见

修饰全局变量

使其作用域仅限定于本文件内部,其他文件不可见

函数的作用域与生存期

所有函数都具有文件作用域与静态生存期

在程序每次执行时都存在,并且可以在函数原型或函数定义之后的任意位置调用

内部函数与外部函数

外部函数:可以被其他文件中的函数所调用

内部函数:不可以被其他文件中的函数所调用

函数缺省时均为外部函数

内部函数定义:使用static关键字

内部函数示例:static int Transform(int x);

内部函数示例:static int Transform(int x){...}

声明与定义

声明不是定义

定义是在程序产生一个新实体

声明仅仅在程序中引入一个实体

函数的生命与定义

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

类型的声明与定义

产生新类型就是定义

类型定义示例:typedef enum _BOOL{FALSE,TRUE} BOOL;

不产生新类型就不是定义,而仅仅是声明

类型声明示例:enum _BOOL;

典型软件开发流程

软件工程的思想

原文地址:https://www.cnblogs.com/bear-Zhao/p/13647022.html