1. 程式人生 > 實用技巧 >05.程式組織與開發方法

05.程式組織與開發方法

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 <<".\n";
    cout<<"Five numbers the rand function generates as follows:\n";
    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 <<".\n";
    cout<<"Input the seed: ";
    cin>>seed;
    cout<<"Five numbers the rand function generates as follows:\n";
    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 <<".\n";
    cout<<"Five numbers the rand function generates as follows:\n";
    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. \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);
}

隨機數庫測試

單獨測試庫的所有函式:合法引數時返回結果是否正確;非法引數時返回結果是否正確,即容錯功能是否正常。

聯合測試:多次執行程式,檢視生成的資料是否隨機;測試整數與浮點數隨機數是否均能正確工作。

例項

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;

典型軟體開發流程

軟體工程的思想