C++ 入門指南 4.01
單元 23 - 認識標準程式庫
標準程式庫 (standard library) 是依據 C++ 標準,隨編譯器 (compiler) 提供的程式庫 (library)
我們已經用過不少標準程式庫中的例子,例如於命令列印出字串 (string)
cout << endl << m << endl << endl << endl;
完整程式請參考單元 1 - 認識 C++ 語言。
或是產生擬隨機整數
int a = rand() % 10;
完整程式請參考單元 16 - 繼續測試。
當然還有上一個單元重構版本的 Encrypt 類別 (class) ,其中攪亂密碼表字串順序
// 初始化密碼表字串 code_array = "abcdefghijklmnopqrstuvwxyz"; // 獲取時鐘週期個數 unsigned int seed = system_clock::now().time_since_epoch().count(); // 攪亂字串中的元素順序 shuffle(code_array.begin(), code_array.end(), mt19937(seed));
到編碼與解碼
r += code_array.at(alphabet_array.find(c));
以上都是利用標準程式庫的例子,標準程式庫涵蓋的應用相當廣泛。
標準程式庫隨新標準也不斷推出新的擴充內容,我們從單元 14 到單元 24 的練習一路來介紹不少標準程式庫中的功能,如下表
單元 | 類型 |
---|---|
14 | 陣列、資料型態 |
15 | 陣列、型態轉換 |
16 | vector 、擬隨機數 |
17 | vector 、 shuffle |
18 | map 、時間相關 |
19 | map 、格式化輸出 |
20 | set 、數學相關 |
21 | 集合體型態、數學相關 |
22 | 命令列參數、系統指令 |
23 | 輸入與檔案處理 |
24 | 字串相關 |
以上散落在各單元的練習是以舉例示範為主的小程式 (program) ,實際上開發程式是要按照目標進行開發,標準程式庫的好處是已經有極其大量已經寫好,具有效率並且測試無誤的程式,這些程式都可以直接拿來使用,我們寫程式就不需要什麼都從頭自己開發。
進行軟體開發要避免重新發明輪子,這裡所謂輪子也就是開發好的程式,為什麼要避免重新發明輪子呢?原因很簡單,這樣我們就可以專注開發我們想要的功能,例如要開發圖形介面的應用程式,如果不使用其他第三方程式庫 (third party library) ,全部自己從頭開發的話,等於差不多要自己開發一套作業系統,那工程極其浩大,除了要精熟一門程式語言以外,更要熟悉各種硬體基礎知識。
如果要好好、詳細的介紹標準程式庫,那可能就是一本大部頭的書了說,本書中只挑選些常用功能介紹。
學會程式語言會基本語法後,接下來就是搭配學習程式庫的內容,通常會先以標準程式庫開始,然後繼續延伸就是學習第三方程式庫,第三方程式庫或者可稱為應用程式介面 (application programming interface) 、軟體開發套件 (software development kit) 、軟體框架 (software framework) 、遊戲引擎 (game engine) 等等的名稱,之所以有這些名稱差異,不外是應用領域不同或是程式語言不同。
基本上寫程式常見的是在程式中混用標準程式庫的各種功能,除了我們重構版的 Encrypt 是典型的例子外,以下再看到一個利用標準程式庫的例子
// 引入標準程式庫中時間日期的相關程式 #include <ctime> // 引入標準程式庫中相關的輸入、輸出程式 #include <iostream> // 引入標準程式庫中的 array #include <array> // 引入標準程式庫中的 vector #include <vector> // cout 為 std 中的輸出物件 using std::cout; // endl 為 std 中的斷行符號 using std::endl; // array 為 std 中的陣列型態 using std::array; // vector 為 std 中的集合體型態 using std::vector; int main() { // 計算陣列處理時間 time_t t1 = time(NULL); long i = 0; array<long, 1000000> a; for (int j: a) { j = i++; cout << j << ", "; } cout << endl; time_t t2 = time(NULL); // 計算 vector 處理時間 time_t t3 = time(NULL); vector<long> v; for (int k = 0; k < 1000000; k++) { v.insert(v.end(), k); cout << v[k] << ", "; } cout << endl; time_t t4 = time(NULL); // 顯示處理時間 cout << endl << endl; cout << "array: " << t2 - t1 << endl; cout << "vector: " << t4 - t2 << endl; return 0; } /* 《程式語言教學誌》的範例程式 http://kaiching.org/ 檔名:time_test.cxx 功能:示範利用標準程式庫比較 array 與 vector 執行時間 作者:張凱慶 */
這個程式比較建立 array 與 vector 各 1000000 個相同整數元素的處理時間,
// 顯示處理時間 cout << endl << endl; cout << "array: " << t2 - t1 << endl; cout << "vector: " << t4 - t2 << endl;
其中時間是利用 time(NULL) 取得現在的系統時間,單位是秒
time_t t1 = time(NULL);
一共分別取得四次時間,分別是 array 處理前的 t1 ,處理後的 t2 , vector 處理前的 t3 ,處理後的 t4 ,利用 Windows 11 下的 Ubuntu 子系統,編譯執行結果如下
因為利用 Windows PowerShell 編譯 C++11 程式會出現問題,因此改用 Ubuntu 子系統進行編譯。
以上只是粗略地以「秒」為單位計算,可以大概知道 vector 比 array 耗時,但相對 vector 的功能也較多。
現在寫程式通常會混用大量程式庫內容,因為很多程式功能都已經開發好,放在程式中,我們就不需要重新開發已經有的程式功能,而能專注開發新的程式功能,依據程式語言標準隨附的是標準程式庫,編譯器也通常都會直接實作標準程式庫的功能。
然而雖然 C++ 的標準程式庫提供非常豐富的資源,可是使用者介面 (user interface) 仍是沿襲 C 語言命令列 (command line) 的風格,因此我們要替 Encrypt 設計一個圖形使用者介面 (graphical user interface, GUI) 就得借助第三方程式庫。所以接下來就讓我們繼續認識一下第三方程式庫 - Qt 吧!
中英文術語對照 | |
---|---|
應用程式介面 | application programming interface |
類別 | class |
命令列 | command line |
編譯器 | compiler |
遊戲引擎 | game engine |
圖形使用者介面 | graphical user interface, GUI |
程式庫 | library |
程式 | program |
軟體開發套件 | software development kit |
軟體框架 | software framework |
標準程式庫 | standard library |
字串 | string |
第三方程式庫 | third party library |
使用者介面 | user interface |
重點整理 |
---|
1. 標準程式庫是依 C++ 標準隨編譯器提供的程式庫,第三方程式庫則是其他開發商提供程式庫。 |
2. 標準程式庫提供眾多的應用,包括容器、工具、地方資訊、字串、串流及輸出入、語言、執行緒、數學等應用。 |
3. 學習程式設計不應該重新發明輪子,實際寫程式往往會混用程式庫的內容。 |
問題與討論 |
---|
1. 為什麼要有標準程式庫?不能程式的所有功能都自己開發嗎? |
2. 什麼是命名空間?為什麼要用命名空間? |
3. 為什麼要有第三方程式庫?除了 Qt 外還有其他的第三方程式庫嗎? |
練習 |
---|
1. 標準程式庫 iostream 的 cin 物件用來接收使用者輸入,連帶須使用 >> 運算子,將儲存輸入的變數放在 >> 之後,寫一個程式 exercise2301.cxx ,宣告字元變數 c ,然後用 cin 接收使用者輸入,最後印出字元變數 c 。 參考程式碼 |
2. 承上題,寫一個程式 exercise2302.cxx ,改成使用 cin 接收使用者輸入兩個整數,然後印出相加值。 參考程式碼 |
3. 承上題,寫一個程式 exercise2303.cxx ,利用 while (true) 迴圈接收使用者輸入,直到使用者輸入 'q' 之後就結束程式。 參考程式碼 |
4. 標準程式庫中的 fstream 可以用來進行檔案處理,寫一個程式 exercise2304.cxx ,宣告 fstream 的檔案物件,然後利用 open() 開啟指定的檔案, open() 的第一個參數為檔名字串,第二個參數可以用 std::ios_base::app ,接下來用 is_open() 判斷檔案是否開啟,開啟成功寫入自訂字串,開啟失敗印出失敗訊息。 參考程式碼 |
5. 承上題,將 open() 的第二個參數改成 std::ios::in 讀取檔案內容,實際讀取要用 read() , read() 的第一個參數用字元陣列,第二參數則是字元陣列的長度,寫一個程式 exercise2305.cxx ,讀取並印出上題存檔的文字內容。 參考程式碼 |
6. 承上題,寫一個程式 exercise2306.cxx ,利用 cin 的 getline() 取得使用者輸入的字元陣列,然後儲存到檔案中,再從檔案讀取印出來。 參考程式碼 |
7. 標準程式庫 filesystem 中的 exists() 可以判斷檔案是否存在,寫一個程式 exercise2307.cxx ,利用 exists() 判斷指定的檔案例如 demo.cxx 是否存在。 參考程式碼 |
8. 承上題, file_size() 回傳指定檔案的位元組數,寫一個程式 exercise2308.cxx ,利用 file_size() 印出指定的檔案例如 demo.cxx 的位元組數。 參考程式碼 |
9. 承上題, is_directory() 可以判斷指定路徑是否為目錄,寫一個程式 exercise2309.cxx ,利用 is_directory() 判斷指定的檔案例如 demo 是否為目錄。 參考程式碼 |
10. 承上題, is_empty() 可以判斷指定檔案是否沒有內容,寫一個程式 exercise2310.cxx ,利用 is_empty() 判斷指定的檔案例如 demo.cxx 是否沒有內容。 參考程式碼 |
相關教學影片