zoukankan      html  css  js  c++  java
  • 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;

    典型软件开发流程

    软件工程的思想

  • 相关阅读:
    我的周记8——"因为相信,所以看见"
    我的周记7——“阳光开朗,自信表达一切”
    一些做设计挺不错的网站
    我的周记6——"不破楼兰誓不还“
    版本管理工具 Git
    我的周记5——"侵略如火,不动如山"
    SQLite-FMDatabase用法
    UIImage与Base64相互转换
    百度地图--地图标注的重复单击
    百度地图的单例模式
  • 原文地址:https://www.cnblogs.com/bear-Zhao/p/13647022.html
Copyright © 2011-2022 走看看