C++ 入門指南 4.01

單元 15 - 實作 set_code_array()

-unit15-

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

setCode()
⇓
012345678910111213141516171819202122232425
qzirajsbktcludmvenwfoxgpyh

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

y = a * x + b
m = y % n
r = m + diff

a 與 b 預定是 0 到 9 之間的隨機整數,要取得隨機整數的話,標準程式庫 (standard library) 有程式可用,倒是現在先不用急著一次到位,我們先把 a 設定成 3 , b 設定成 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) c 與 s ,變數 c 為起始字元 (character) ,初值設定成英文字母表的第一個字母 'a' , s 則是宣告為字串 (string) ,這裡並沒有直接拿變數 c 進行計算,而是把變數 c 的值指派 (assign) 給整數型態的 x

    x = c;

會這樣做的原因很簡單,因為需要一個變數表示目前處理的字元,而字元型態的變數可以如同整數 (integer) 型態進行加減乘除,因此迴圈的最後利用遞增將變數 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 ,目前的實作版本如下

// 引入 Encrypt 類別的標頭檔
#include "encrypt01.h"

// Encrypt 的建構函數
Encrypt::Encrypt() {
    // 呼叫 setter 設定 code_array
    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;
}

// 回傳密碼表字串的 getter 成員函數
string Encrypt::get_code_array() {
    return code_array;
}

/* 程式語言教學誌》的範例程式
   http://kaiching.org/
   檔名:encrypt01.cxx
   功能:實作發展中版本的 Encrypt 類別
   作者:張凱慶 */

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

// 引入標準程式庫中的 iostream
#include <iostream>
// 引入 Encrypt 類別的標頭檔
#include "encrypt01.h"

// 使用 std 中的兩個名稱
using std::cout; // 標準輸出串流的物件
using std::endl; // 新行符號,等於 '\n'

// 程式執行的 main() 函數
int main() {
    // 印出空白一行
    cout << endl;

    // 建立 Encrypt 物件
    Encrypt encryptor;
    // 印出密碼表字串
    cout << encryptor.get_code_array() << endl << endl;

    return 0;
}

/* 《程式語言教學誌》的範例程式
   http://kaiching.org/
   檔名:encrypt_demo01.cxx
   功能:實作發展中版本 Encrypt 類別的測試程式
   作者:張凱慶 */

編譯執行,結果如下

-encrypt_demo01-

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

中英文術語對照
指派assign
字元character
整數integer
迴圈loop
程式program
標準程式庫standard library
字串string
變數variable
重點整理
1. 實作 set_code_array() 是先將公式中的 a 設成 3 , b 設成 5 ,然後用迴圈利用兩個控制變數 i 與 c 逐一計算每個字元。
2. 字元型態就是範圍較小的整數,因此可直接進行算術運算。
3. 計算完的整數直接與字串進行運算,加號在字串類別重載過,因此可把轉換成字元的整數附加到字串的最後。
問題與討論
1. 為什麼不把建立對換表格直接寫在建構函數裡就好了?
2. 為什麼字串變數用 += 可以把字元附加到字串物件的最後?
練習
1. 字元陣列的最後一個元素如果是 '\0' 就可以跟字串進行比較,寫一個程式 exercise1501.cxx ,宣告相同內容的字元陣列及字串,例如 "hello" ,在字元陣列的結尾加上 '\0' ,然後利用比較相等運算子 == 測試兩者內容是否相等,如果相等就印出 "equal" ,不相等印出 "not equal" 。 參考程式碼
2. 陣列識別字就是指標,寫一個程式 exercise1502.cxx ,宣告建立一個整數陣列,然後將整數陣列的識別字指派給整數指標變數,利用這個指標變數印出陣列的所有元素值。 參考程式碼
3. 標準程式庫中的 array 是物件形式的陣列,可以利用角括弧宣告陣列的型態及元素個數,例如 array<int, 5> 是含有五個元素的整數陣列,寫一個程式 exercise1503.cxx ,分別宣告整數陣列 int a1[] 及 array<int, 5> a2 ,利用字面常數指派陣列內容,然後逐次比較兩個陣列, array 可用 at() 取得索引值的內容,如果比較結果相同就印出元素值,不相同就印出 "n" 。 參考程式碼
4. 標準程式庫中的 array 同樣可以用中括弧及索引值存取與修改元素內容,另外 empty() 可判斷是否為空陣列, size() 回傳陣列元素總數,寫一個程式 exercise1504.cxx ,先利用字面常數設定陣列內容,再利用中括弧及索引值修改任意兩個元素內容,然後判斷陣列是否為空,如果不為空就印出全部的元素。 參考程式碼
5. 標準程式庫中的 array 還有其他好用的成員函數,寫一個程式 exercise1505.cxx ,宣告建立一個整數陣列,然後利用 front() 印出第一個元素, back() 印出最後一個元素。 參考程式碼
6. 基本內建型態利用小括弧,例如 (char) 97 ,就可以把整數 97 轉換成字元 'a' ,另外也可用關鍵字 static_cast 加上角括弧轉換成角括弧中指定的型態, static_cast 會在編譯期間做型態是否相容的檢查,寫一個程式 exercise1506.cxx ,宣告 int 變數 a 為 97 ,然後利用 (char) 及 static_cast<char> 轉換變出 a 為字元,並且印出轉換後的結果。 參考程式碼
7. 承上題,同樣的方式可以用在 int 轉換成 short ,但是 short 的範圍較小,因此如果 int 型態的變數數值超出 short 的範圍就會發生溢位,寫一個程式 exercise1507.cxx ,宣告 int 變數 a 為 32768 ,然後印出轉換成 short 的結果。 參考程式碼
8. 承上題,同樣在 long 轉換成 int 也會有溢位問題,寫一個程式 exercise1508.cxx ,宣告 long 變數 a 為 2147483648 ,然後印出轉換成 int 的結果。 參考程式碼
9. 承上題,同樣的方式可以用在浮點數轉換成整數,例如 float 轉換成 int ,寫一個程式 exercise1509.cxx ,宣告 float 變數 a 為 10.51 ,然後印出轉換成 int 的結果。 參考程式碼
10. 承上題,如果是字串要轉換成整數或浮點數,例如 "99.99" 轉換成 int 或 float ,需要用到標準程式庫中 string 的 stoi() 或 stof() ,寫一個程式 exercise1510.cxx ,宣告 string 變數 a 為 "99.99" ,然後印出轉換成 int 及 float 的結果。 參考程式碼

相關教學影片

上一頁 單元 14 - Encrypt 類別
回 C++ 入門指南 4.01 目錄
下一頁 單元 15 - 實作 set_code_array()
回 C++ 教材
回程式語言教材首頁