第五、六講
第五講 ?程序組織與軟件開(kāi)發(fā)方法 ?
一 ?庫(kù)與接口
1 ?庫(kù)與程序文件
程序文件:源文件(.cpp)、頭文件(.h、 *.hpp、 *)
庫(kù):源文件與頭文件
2 ?接 口
通過(guò)接口使用庫(kù):包括指定庫(kù)的頭文件與源文件
優(yōu)勢(shì):不需了解庫(kù)的實(shí)現(xiàn)細(xì)節(jié),只需了解庫(kù)的使用方法 ?
3 ?標(biāo)準(zhǔn)庫(kù)
C標(biāo)準(zhǔn)庫(kù) 標(biāo)準(zhǔn)輸入輸出庫(kù)、工具與輔助函數(shù)庫(kù)、字符串庫(kù)
C++標(biāo)準(zhǔn)庫(kù) 輸入輸出流庫(kù)、字符串庫(kù)、標(biāo)準(zhǔn)模板庫(kù) ?
4 ?數(shù)學(xué)庫(kù)
數(shù)學(xué)庫(kù) 頭文件:
math.h/cmath
庫(kù)文件:
libm
鏈接方式:g++ -lm main.cpp ?(linux系統(tǒng)下)
5 ?標(biāo)準(zhǔn)輔助函數(shù)庫(kù)
工具與輔助函數(shù) 頭文件:
stdlib.h/cstdlib
常用函數(shù)
void exit( int status );
void free( void * p );
void * malloc( size_t size );
int rand();
void srand( unsigned int seed );
二 ?隨機(jī)數(shù)庫(kù)
1 ?隨機(jī)數(shù)的生成
?#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 ?庫(kù)的設(shè)計(jì)原則
用途一致 接口中所有函數(shù)都屬于同一類(lèi)問(wèn)題
操作簡(jiǎn)單 函數(shù)調(diào)用方便,最大限度隱藏操作細(xì)節(jié)
功能充足 滿足不同潛在用戶的需要
性能穩(wěn)定 經(jīng)過(guò)嚴(yán)格測(cè)試,不存在程序缺陷 ?
3 ?隨機(jī)數(shù)庫(kù)接口
?void Randomize();
?int GenerateRandomNumber( int low, int high );
?double GenerateRandomReal( double low, double high );
4 ?隨機(jī)數(shù)庫(kù)實(shí)現(xiàn)
?#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 ?隨機(jī)數(shù)庫(kù)測(cè)試 ?
單獨(dú)測(cè)試庫(kù)的所有函數(shù) 合法參數(shù)時(shí)返回結(jié)果是否正確 非法參數(shù)時(shí)返回結(jié)果是否正確,即容錯(cuò)功能是否正常
聯(lián)合測(cè)試 多次運(yùn)行程序,查看生成的數(shù)據(jù)是否隨機(jī) 測(cè)試整數(shù)與浮點(diǎn)數(shù)隨機(jī)數(shù)是否均能正確工作 ?
三 ?作用域與生存期
1 ?量的作用域與可見(jiàn)性
作用域與可見(jiàn)性 作用域:標(biāo)識(shí)符的有效范圍 可見(jiàn)性:程序中某個(gè)位置是否可以使用某個(gè)標(biāo)識(shí)符 標(biāo)識(shí)符僅在其作用域內(nèi)可見(jiàn) 位于作用域內(nèi)的標(biāo)識(shí)符不一定可見(jiàn)
局部數(shù)據(jù)對(duì)象 定義于函數(shù)或復(fù)合語(yǔ)句塊內(nèi)部的數(shù)據(jù)對(duì)象(包括變量、常量與函數(shù)形式參數(shù)等) 局部數(shù)據(jù)對(duì)象具有塊作用域,僅在定義它的塊內(nèi)有效 有效性從定義處開(kāi)始直到該塊結(jié)束 多個(gè)函數(shù)定義同名的數(shù)據(jù)對(duì)象是允許的
全局?jǐn)?shù)據(jù)對(duì)象 定義于函數(shù)或復(fù)合語(yǔ)句塊之外的數(shù)據(jù)對(duì)象 全局?jǐn)?shù)據(jù)對(duì)象具有文件(全局)作用域,有效性從定義處開(kāi)始直到 本文件結(jié)束,其后函數(shù)都可直接使用 若包含全局?jǐn)?shù)據(jù)對(duì)象定義的文件被其他文件包含,則其作用域擴(kuò)展 到宿主文件中, 這可能會(huì)導(dǎo)致問(wèn)題 不要在頭文件中定義全局?jǐn)?shù)據(jù)對(duì)象
函數(shù)原型作用域 定義在函數(shù)原型中的參數(shù)具有函數(shù)原型作用域,其有效性?xún)H延續(xù)到 此函數(shù)原型結(jié)束 函數(shù)原型中參數(shù)名稱(chēng)可以與函數(shù)實(shí)現(xiàn)中的不同,也可以省略 ?
2 ?量的存儲(chǔ)類(lèi)與生存期
生存期:量在程序中存在的時(shí)間范圍 C/C++ 使用存儲(chǔ)類(lèi)表示生存期 作用域表達(dá)量的空間特性,存儲(chǔ)類(lèi)表達(dá)量的時(shí)間特性
靜態(tài)(全局)生存期 全局?jǐn)?shù)據(jù)對(duì)象具有靜態(tài)(全局)生存期 生死僅與程序是否執(zhí)行有關(guān)
自動(dòng)(局部)生存期 局部數(shù)據(jù)對(duì)象具有自動(dòng)(局部)生存期 生死僅與程序流程是否位于該塊中有關(guān) 程序每次進(jìn)入該塊時(shí)就為該對(duì)象分配內(nèi)存,退出該塊時(shí)釋放內(nèi)存; 兩次進(jìn)入該塊時(shí)使用的不是同一個(gè)數(shù)據(jù) ?
static 關(guān)鍵字
修飾局部變量:靜態(tài)局部變量 使局部變量具有靜態(tài)生存期 程序退出該塊時(shí)局部變量仍存在,并且下次進(jìn)入該塊時(shí)使用上一次 的數(shù)據(jù)值 靜態(tài)局部變量必須進(jìn)行初始化 不改變量的作用域,仍具有塊作用域,即只能在該塊中訪問(wèn), 其他 代碼段不可見(jiàn) 修飾全局變量 使其作用域僅限定于本文件內(nèi)部,其他文件不可見(jiàn) ?
3 ?函數(shù)的作用域與生存期
所有函數(shù)具有文件作用域與靜態(tài)生存期 在程序每次執(zhí)行時(shí)都存在,并且可以在函數(shù)原型或函數(shù)定義之后的 任意位置調(diào)用
內(nèi)部函數(shù)與外部函數(shù) 外部函數(shù):可以被其他文件中的函數(shù)所調(diào)用 內(nèi)部函數(shù):不可以被其他文件中的函數(shù)所調(diào)用 函數(shù)缺省時(shí)均為外部函數(shù) 內(nèi)部函數(shù)定義:使用 static 關(guān)鍵字 內(nèi)部函數(shù)示例: static int Transform( int x ); 內(nèi)部函數(shù)示例: static int Transform( int x ){ … } ?
4 ?聲明與定義 ?
聲明不是定義 定義在程序產(chǎn)生一個(gè)新實(shí)體 聲明僅僅在程序中引入一個(gè)實(shí)體
函數(shù)的聲明與定義 聲明是給出函數(shù)原型,定義是給出函數(shù)實(shí)現(xiàn)代碼
類(lèi)型的聲明與定義 產(chǎn)生新類(lèi)型就是定義 類(lèi)型定義示例:
typedef enum __BOOL { FALSE, TRUE } BOOL;
不產(chǎn)生新類(lèi)型就不是定義,而僅僅是聲明 類(lèi)型聲明示例:enum BOOL;
5 ?全局變量的作用域擴(kuò)展 ?
全局變量的定義不能出現(xiàn)在頭文件中,只有其聲明才可以出現(xiàn) 在頭文件中 聲明格式:使用 extern 關(guān)鍵字
?/* 庫(kù)的頭文件 */
?/* 此處僅引入變量 a,其定義位于對(duì)應(yīng)源文件中 */
?extern int a; /* 變量 a 可導(dǎo)出,其他文件可用 */
?/* 庫(kù)的源文件 */
?/* 定義變量 a */
?int a;
四 ?典型軟件開(kāi)發(fā)流程 ?
略
第六講 ?復(fù)合數(shù)據(jù)類(lèi)型
一 ?字 符
1 ?字符類(lèi)型、字符文字與量
定義格式:
char ch; const char cch = 'C';
字符文字使用單引號(hào)對(duì)
實(shí)際存儲(chǔ)時(shí)字符類(lèi)型量存儲(chǔ)字符的對(duì)應(yīng) ASCII 值
可使用 signed 與 unsigned 修飾字符類(lèi)型
2 ?字符表示的等價(jià)性
char a = 'A'; char a = 65; char a = 0101; char a = 0x41; ?
3 ?ASCII 碼 ?
回車(chē)與換行
Windows: \n\r
Linux: \n
Mac: \r

二 ?數(shù) 組
1 ?數(shù)組的意義與性質(zhì)
數(shù)組的定義 定義格式: 元素類(lèi)型 數(shù)組名稱(chēng)[常數(shù)表達(dá)式]; 示例:
int a[8]; /* 定義包含 8 個(gè)整數(shù)元素的數(shù)組 */
特別說(shuō)明 常數(shù)表達(dá)式必須是常數(shù)和常量,不允許為變量 錯(cuò)誤示例: int count = 8; int c[count]; 數(shù)組元素編號(hào)從 0 開(kāi)始計(jì)數(shù),元素訪問(wèn)格式為 a[0]、 a[1]、 …… 不允許對(duì)數(shù)組進(jìn)行整體賦值操作,只能使用循環(huán)逐一復(fù)制元素 錯(cuò)誤示例三: int a[8], b[8]; a = b;
意義與性質(zhì) 將相同性質(zhì)的數(shù)據(jù)元素組織成整體,構(gòu)成單一維度上的數(shù)據(jù)序列 ?
2 ?數(shù)組的存儲(chǔ)表示
數(shù)組的地址 數(shù)組的基地址:數(shù)組開(kāi)始存儲(chǔ)的物理位置 數(shù)組首元素的基地址:數(shù)組首個(gè)元素開(kāi)始存儲(chǔ)的物理地址, 數(shù)值上總是與數(shù)組基地址相同 “&” 操作符:&a 獲得數(shù)組的基地址;&a[0] 獲得數(shù)組首元素的基地址
3 ?數(shù)組元素的訪問(wèn)
4 ?數(shù)組與函數(shù)
數(shù)組元素作為函數(shù)實(shí)際參數(shù) int Add( int x, int y ){ return( x + y ); } int a[2] = { 1, 2 }, sum; sum = Add( a[0], a[1] );
數(shù)組整體作為函數(shù)形式參數(shù) 基本格式: 返回值類(lèi)型 函數(shù)名稱(chēng)( 元素類(lèi)型 數(shù)組名稱(chēng)[], 元素 個(gè)數(shù)類(lèi)型 元素個(gè)數(shù) ) 示例:
void GenerateIntegers( int a[], unsigned int n );
特別說(shuō)明:作為函數(shù)形式參數(shù)時(shí),數(shù)組名稱(chēng)后的中括號(hào)內(nèi)不需 列寫(xiě)元素個(gè)數(shù),必須使用單獨(dú)的參數(shù)傳遞元素個(gè)數(shù)信息 ?
5 ?多維數(shù)組 ?
多維數(shù)組的定義 定義格式: 元素類(lèi)型 數(shù)組名稱(chēng)[常數(shù)表達(dá)式1] [常數(shù)表達(dá)式2]…; 示例一:
int a[2][2]; /* 2×2 個(gè)整數(shù)元素的二維數(shù)組 */
示例二:int b[2][3][4]; /* 2×3×4 個(gè)整數(shù)元素?cái)?shù)組 */
特別說(shuō)明:同單維數(shù)組多維數(shù)組的初始化 與一維數(shù)組類(lèi)似:
int a[2][3] = {1, 2, 3, 4, 5, 6};
單獨(dú)初始化每一維:int a[2][3] = { {1, 2, 3}, {4, 5, 6} };
?(建議用這種,調(diào)整格式寫(xiě)出矩陣形式)
三 ?結(jié)構(gòu)體 ?
1 ?結(jié)構(gòu)體的意義與性質(zhì)
結(jié)構(gòu)體的意義 與數(shù)組的最大差別:不同類(lèi)型數(shù)據(jù)對(duì)象構(gòu)成的集合 當(dāng)然也可以為相同類(lèi)型的但具體意義或解釋不同的數(shù)據(jù)對(duì)象集合
結(jié)構(gòu)體類(lèi)型的定義
`struct 結(jié)構(gòu)體名稱(chēng)
{
成員類(lèi)型 1 成員名稱(chēng) 1;
成員類(lèi)型 2 成員名稱(chēng) 2;
……
成員類(lèi)型 n 成員名稱(chēng) n;
};` ?
2 ?結(jié)構(gòu)體的存儲(chǔ)表示
3 ?結(jié)構(gòu)體數(shù)據(jù)對(duì)象的訪問(wèn)
結(jié)構(gòu)體類(lèi)型的變量與常量:按普通量格式定義 示例一: DATE date; 示例二: STUDENT zhang_san; 示例三: STUDENT students[8];
結(jié)構(gòu)體量的初始化 示例四: DATE date = { 2008, 8, 8 };
結(jié)構(gòu)體量的賦值 與數(shù)組不同,結(jié)構(gòu)體量可直接賦值,拷貝過(guò)程為逐成員一一復(fù)制 示例五: DATE new_date; new_date = date; ?
結(jié)構(gòu)體量成員的訪問(wèn) 使用點(diǎn)號(hào)操作符“.” 解析結(jié)構(gòu)體量的某個(gè)特定成員 示例一:
DATE date; date.year = 2008; date.month = 8; date.day = 8;
嵌套結(jié)構(gòu)體成員的訪問(wèn) 可以連續(xù)使用點(diǎn)號(hào)逐層解析 示例二:
struct FRIEND{ int id; STRING name; DATE birthday; };
FRIEND friend;
friend.birthday.year = 1988;
復(fù)雜結(jié)構(gòu)體成員的訪問(wèn) 嚴(yán)格按照語(yǔ)法規(guī)范進(jìn)行
4 ?結(jié)構(gòu)體與函數(shù) ?
例:編寫(xiě)一函數(shù),使用結(jié)構(gòu)體類(lèi)型存儲(chǔ)日期,并返回該日在該年的第幾天信息,具體天數(shù)從 1 開(kāi)始計(jì)數(shù),例如 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;
}??