C++ 入門指南 V2.00 - 單元 15 - 實作 set_code_array()




set_code_array() 的工作就是建立密碼表,我們需要的密碼表就是一個攪亂順序的英文字母表



先來溫習一下用來編碼的數學公式


y = a * x + b

m = y % n

r = m + diff


ab 預定是 09 之間的隨機整數,要取得隨機整數的話,標準程式庫 (standard library) 有程式可用,倒是現在先不用急著一次到位,我們先把 a 設定成 3b 設定成 5 測試看看好了,如此 set_code_array() 的實作如下


    // 設定 code_array 的 setter 成員函數
    void Encrypt::set_code_array() {
       // 設定 a 、 b 值 
       int a = 3;
       int b = 5;
   
       // 利用公式建立密碼表字串     
       int x, y, m;
       char c = 'a';
       string s;
       int i;
       for (i = 0; i < 26; i++) {
          x = c; 
          y = x * a + b;
          m = y % 26;
          s += m + 97; 
          c++; 
       }
   
       // 將建立好的密碼表直接設定給成員變數
       code_array = s;
    }

因為英文字母表的小寫字母共有 26 個,因此公式用迴圈 (loop) 跑了 26


    for (i = 0; i < 26; i++) {
       x = c;
       y = x * a + b;
       m = y % 26;
       s += m + 97;
       c++;
    }

我們多用了除了公式外的兩個變數 (variable) cs ,變數 c 為起始字元 (character) ,初值設定成英文字母表的第一個字母 'a's 則是宣告為字串 (string) ,這裡並沒有直接拿變數 c 進行計算,而是把變數 c 的值指派給整數型態的 x


    x = c;

會這樣做的原因很簡單,因為需要一個變數表示目前處理的字元,而字元型態的變數可以如同整數型態進行加減乘除,因此迴圈的最後利用遞增將變數 c 轉移到下一個字元,例如迴圈從 'a' 開始,第二個處理的字元為 'b' ,第三個為 'c' ,以此類推


    c++;

由於 C++ 的字元型態其實就是範圍較小的整數,因此也可以直接將迴圈的控制變數 i 設定為 97 ,讓 i 依次遞增到 97 + 26 為止。

迴圈跑完,最後就是把 s 設定給 code_array


    // 將建立好的密碼表直接設定給成員變數
    code_array = s;

建構函數 Encrypt() 就是呼叫 set_code_array() 設定 code_array ,另外 get_code_array() 也就是回傳 code_array ,目前的實作版本如下


001 // 引入 Encrypt 類別的標頭檔 
002 #include "encrypt01.h"
003
004 // Encrypt 的建構函數 
005 Encrypt::Encrypt() {
006    // 呼叫 setter 設定 code_array
007    set_code_array();    
008 }
009
010 // 設定 code_array 的 setter 成員函數
011 void Encrypt::set_code_array() {
012    // 設定 a 、 b 值 
013    int a = 3;
014    int b = 5;
015
016    // 利用公式建立密碼表字串     
017    int x, y, m;
018    char c = 'a';
019    string s;
020    int i;
021    for (i = 0; i < 26; i++) {
022       x = c; 
023       y = x * a + b;
024       m = y % 26;
025       s += m + 97; 
026       c++; 
027    }
028
029    // 將建立好的密碼表直接設定給成員變數
030    code_array = s;
031 }
032
033 // 回傳密碼表字串的 getter 成員函數     
034 string Encrypt::get_code_array() {
035    return code_array;
036 }
037
038 /* encrypt01.cpp 
039    Kaiching Chang 
040    2014-5 */

我們用另外一個程式來測試目前的版本吧!因為 ToEncode()ToDecode() 都還沒實作,所以就印出密碼表來看看就好了


001 // 引入標準程式庫中的 iostream
002 #include <iostream>
003 // 引入 Encrypt 類別的標頭檔
004 #include "encrypt01.h"
005
006 // 使用 std 中的兩個名稱
007 using std::cout// 標準輸出串流的物件
008 using std::endl// 新行符號,等於 '\n'
009
010 // 程式執行的 main() 函數 
011 int main() {
012    // 印出空白一行
013    cout << endl;
014
015    // 建立 Encrypt 物件
016    Encrypt encryptor; 
017    // 印出密碼表字串
018    cout << encryptor.get_code_array()
019         << endl << endl;
020
021    return 0;
022 }
023  
024 /* encrypt_demo01.cpp 
025    Kaiching Chang 
026    2014-5 */

編譯執行,結果如下



結果如預期,一個英文小寫字母恰恰好對應到另外一個英文小寫字母,這樣我們的公式就 ok 了嗎?a 等於 3b 等於 5 是沒問題的,可是我們希望 ab 可以是 09 之間的任意整數,這樣就有 100 種組合說,所以我們接下來要繼續測試,看看是不是每一種組合都 ok 囉!


中英文術語對照


標準程式庫 standard library
迴圈 loop
變數 variable
字元 character
字串 string

重點整理


  1. 實作 set_code_array() 是先將公式中的 a 設成 3b 設成 5 ,然後用迴圈利用兩個控制變數 ic 逐一計算每個字元。
  2. 字元型態就是範圍較小的整數,因此可直接進行算術運算。
  3. 計算完的整數直接與字串進行運算,加號在字串類別重載過,因此可把轉換成字元的整數附加到字串的最後。

問題與討論


  1. 為什麼不把建立對換表格直接寫在建構函數裡就好了?
  2. 為什麼字串變數用 += 可以把字元附加到字串物件的最後?

練習


  1. 承接上一個單元的猜數字遊戲,另寫一個程式 exercise1501.cpp ,接受使用者輸入,加入判斷使用者是否猜對的邏輯及提示訊息。
  2. 承上題,另寫一個程式 exercise1502.cpp ,將 answer 與使用者輸入都轉換成整數陣列,並將判斷的邏輯改成比較陣列元素。
  3. 重構是指不改變軟體功能,而將程式碼重新整理成易讀、好整理的概念。試著重構猜數字遊戲的 exercise1502.cpp ,將新程式寫在 exercise1503.cpp 中,把整數拆成陣列的部份改寫到函數 ArrayNumber() 中,小提醒,陣列識別字等同指標,因此可以直接傳遞陣列給函數,初始化陣列元素。

the end

沒有留言: