basics

這堂課David講解了一些很接近電腦底層的知識,例如因為ASCII編碼的轉換,在C語言裡面,char的本質其實是int,透過減去'0'就可以將char轉換成他本身int的模樣,還蠻有趣的!

char c = 'A';
printf("%i\n", c) // 65

他也解釋了如下的4 steps of compiling,過去自學的過程中其實很難觸碰到如此底層的東西,雖然也沒有100%聽懂我們下compile指令之後電腦裡面到底在幹嘛,但概念上大致理解。

  • preprocessing
  • compiling
  • assembling
  • linking


lab2/srcabble

lab2 scrabble的任務是從user方取得兩組字,並由指定編碼自算這兩組字分別的加總分數,分數比較大的player即獲勝此回合遊戲。比較簡單的main function就先不提,這邊只附上compute_score()的function程式碼。

int compute_score(string word)
{
    // compute and return score for string
    int score = 0;
    for (int i = 0, len = strlen(word); i < len; i++)
    {
        if (islower(word[i]))
        {
            score += POINTS[word[i] - 'a'];
        }
        else if (isupper(word[i]))
        {
            score += POINTS[word[i] - 'A'];
        }
        else
        {
            score += 0;
        }
    }
    return score;
}

需要注意的是字的分數不分大小寫,除了alphabetic letters之外的符號都視為零分(或是說不列入計算)。例如以下輸入會得到平手的結果。

$ ./scrabble
Player 1: Question?
Player 2: Question!
Tie!


pset2/readability

readability的任務是透過一組算式計算出user輸入的這組文字適合幾年級的學生閱讀。算式裡面包含:

  • L: average number of letters per 100 words in the text
  • S: average number of sentences per 100 words in the text

這份作業可能會出錯的眉眉角角比較多,submit50會包含各式各樣可能找到你program bug的範例text來阻止你交作業(?)要把letters, words, sentences, spaces跟punctuations的出現會帶來的結果都想清楚再寫。


pset2/caesar

caesar作業其實就是最初階的寫一個program做凱薩密碼的加密。概念很簡單,就是指定一個數字作為key,而輸入的plaintext都會照那個數量base on alphabet往後偏移,轉換為ciphertext。因為這份作業不像之前都是在program裡面去跟userget_string()、而是使用command-line argument,因此還要處理如果輸入的argument不是數字必須exit程式並提醒user輸入數字的狀況。

我不確定這樣是不是最有效率的方法,不過取得key之後我把plaintext轉換成ciphertext的步驟有三。轉換過程中還必須考慮英文字母大小寫的問題,寫成兩種狀況討論,不過想清楚之後其實蠻簡單的:)

1. convert ascii to alphabetical index 
// 0~26 instead of 65~90 (uppercase) or 97~122 (lowercase)
2. shift by key
3. convert back to ascii


pset2/substitution

subsitution又是前面caesar作業的困難版,前面我們只要取得一個key的數字並將所有字母都按數量偏移,但subsitution的任務是在command-line argument輸入一組長度26個英文字母的key(不分大小寫、字母不可重複)用來指定A~Z分別被替換成哪些字母,而輸入跟輸出的text會呈現大寫換大寫、小寫換小寫、特殊符號不變的情況。

因為command-line argument的輸入有限制,如果user輸入的key不符合當作key的資格就必須exit program,所以必須先驗證以下三個問題,全部通過才視為valid的key

  1. key是否全部為英文字母
  2. key是否全部不重複
  3. key的輸入是否過剛好長度為26

拿到key之後我的做法是計算出alphabetical orderABCDEFGHIJKLMNOPQRSTUVWXYZkey之間的距離(int差)當作mapping的依據。要小心製造這個diffarray的時候,因為user有可能輸入的時大小寫混雜的key,取得diff的時候必須先將所有chartoupper()統一變成uppercase(當然全部換成lowercase也可以),之後才有辦法統一處理。

int diff[26] = {};
    int base = 65;
    for (int i = 0; i < 26; i++)
    {
        diff[i] = toupper(argv[1][i]) - base;
        base++;
    }

接下來處理字母轉換,方法跟caesar大同小異,也是分為大小寫情況處理,以下以大寫情況作為提示,也要注意如果plaintext裡面有包含非英文字母的符號,就原形輸出不需要做任何事。最後取得ciphertext之後簡單printf出來就可以了!

for (int i = 0; i < len; i++)
    {
        if (isupper(plaintext[i]))
        {
            int alpha_index = plaintext[i] - 65;
            plaintext[i] = (alpha_index + diff[alpha_index]) + 65;
        }


【課後心得】

因為不確定自己的程度到底在哪裡、也希望儘可能多練習跟多寫,所以打算把less comfortable跟more comfortable的作業都完成。一方面也由於上週發現先寫完less comfortable再寫more comfortable對於我對邏輯跟語法的掌握度都有幫助,所以就算工作量暴增也要努力寫完!另外,雖然課才跟到week 2,我已經可以深刻地體會為什麼有人說cs50看完影片只能學到10%,剩下90%知識都在作業裡了,真的要自己動手寫才可以感受到所有困難並自己練習解決!然後上個月因為開始準備GRE,寫程式的時間被壓縮了不少(作業寫完之後這篇筆記拖了三週才痛苦不已地生出來…)希望自己可以不要本末倒置,每天都要努力工作努力讀書努力玩耍!