CS50 week 2 - Arrays 筆記
大家好,我是 Cindy,最近跟同事小夥伴相約一起看 CS50 的課程,CS50 (Introduction to Computer Science)是一堂美國哈佛大學知名的通識課程,完全免費,在 edx 或 youtube 或 CS50-Study-Group github 都可以非常容易地看到。
這系列的文章會是我的個人筆記,歡迎有興趣的人一定要自己去看看 CS50 的課程歐。
今天這篇是 CS50 week 2 筆記,想先看 week 0 和 week 1 筆記的各位觀眾可以點連結過去看看唷!
課程的一開始講師開始講解上週我們使用的指令 make
…
make hello
1 | // 此檔案為 hello.c |
上週我們使用 make 指令來做 compiling 的時候,輸入完指令後畫面會出現這些 clang -ggdb3 -O0 -std=c11 -Wall -Werror -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wshadow hello.c -lcrypt -lcs50 -lm -o hello
,實際上我們在使用的指令其實是 clang
呢!
而當我們直接使用 clang hello.c
這個指令時,我們編譯出的可執行檔案叫做 a.out
(多年前人類決定的預設名稱),而如果我們輸入的指令為 clang -o hello hello.c
時 (clang 後面的指令可以稱之為 command line arguments),這次指令的意思是編譯 hello.c 這個檔案且 output 的檔案要叫 hello。
1 | // 此檔案為 hello.c |
當我們引用了 cs50 的 library 時,我們用同樣的 clang -o hello hello.c
指令是會出現 undefined reference to ‘get_string’ 的錯誤,因為我們沒有告訴電腦我們有使用到 cs50 的 library,這時候指令可以改成 clang -o hello hello.c -lcs50
(l 表示 link),這樣就可以正常運作了,而 make
指令其實就是在幫我們自動做這些事情。
Compiling
上週我們簡單的知道從 source code 到 machine code 會經過 compiler,但 compiling 的過程其實可以細分成四個步驟:
Preprocess
這個步驟將 header 檔案裡 function 的 prototype(原型) 寫到我們的檔案裡,例如上面的程式碼會變成這樣:1
2
3
4
5
6
7
8
9
10...
string get_string(string prompt);
int printf(string format, ...);
...
int main(void)
{
string name = get_string("What's your name? ");
printf ("hello, %s\n", name);
}Compiling
將 source code(C) 轉變成另一種 source code 叫做 assembly code (對電腦的大腦(CPU)較友善的語言),看起來像這樣:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24...
main: # @main
.cfi_startproc
# BB#0:
pushq %rbp
.Ltmp0:
.cfi_def_cfa_offset 16
.Ltmp1:
.cfi_offset %rbp, -16
movq %rsp, %rbp
.Ltmp2:
.cfi_def_cfa_register %rbp
subq $16, %rsp
xorl %eax, %eax
movl %eax, %edi
movabsq $.L.str, %rsi
movb $0, %al
callq get_string
movabsq $.L.str.1, %rdi
movq %rax, -8(%rbp)
movq -8(%rbp), %rsi
movb $0, %al
callq printf
...Assembling
將 assembly code 轉換成最後的 machine code (0 和 1)。Linking
將我們寫的程式碼已經轉換的 0 和 1 們,以及有用到的 library 程式碼轉換的 0 和 1 們全部合併再一起。
debugging
- printf:將我們需要的資訊印出來看看問題在哪裡。
- debug50:CS50 提供給我們的工具,在 CS50 IDE 中可以直接使用,在執行指令前輸入 debug50,例如
debug50 ./hello
,但要先設定 breakpoint,程式才知道要停在哪裡。 - Duck Debugging:說出來就會發現問題,跟桌上的小鴨說說話吧:)
C data types
1 byte(位元組) = 8 bits(位元)
- bool(布林):1 byte
- char:1 byte
- double:8 bytes
- float:4 bytes
- int:4 bytes
- long:8 bytes
- string:? bytes (依據長度有所不同)
通常占多少空間依據電腦而有所不同。
memory
RAM(Random Access Memory):資料短暫儲存的記憶體(要插電才能運作),因為還沒有存到永久記憶體中而可能遺失,但速度快。
硬碟:資料永久儲存的地方。
當我們在執行程式的時候,變數會暫存在記憶體中,而佔用的空間可以參考上一段 C data types。
arrays
由左至右有序的排列,例如:int scores[3];
表示 3 個 integer 的 array,在電腦中慣例是從 0 開始數,所以 3 個數字會是 scores[0]、scores[1]、scores[2]。
在 function 中可以傳入 array 作為參數,範例如下:
1 | float average(int length, int array[]) |
型別轉換
我們都知道了字母或符號在 ASCII 都會有對應的數字,所以我們可以直接將 char 或符號轉換成 int,例如:
1 |
|
strings
我們將 char 放在 array 裡實現了 string (雙引號),所以我們可以 s[0] 取出 string 中的第一個字母,而電腦需要知道在記憶體中這個 string 是在哪裡結束(不會跟記憶體中的其他東西混在一起),string 會在最後多占一個 byte 存 00000000
,或用 \0
表示 byte 中全是 0,又稱為 NUL
,告訴電腦這裡是結束的位置,所以我們每次使用 string 都會多佔用一個 byte(00000000)。
- 注意:我們在 C 語言可以訪問記憶體中的任何位置。例如我只有存了叫做 HI! 的 string,
string s = "HI!";
卻可以透過 s[3] 得到 0,s[400] 得到記憶體中的某個東西。
我們可以透過 s[i] != '\0'
來判斷是不是最後一個字母,或著我們可以直接用 string.h
提供給我們的方法 strlen(s)
來知道 string 的長度。
英文大小寫轉換
再次觀察 ASCII 表,我們可以知道 s[i] >= 'a' && s[i] <= 'z'
表示是小寫英文字母,而大寫英文和小寫英文都差了 32,所以可以利用這個特性做到大小寫轉換,而 ctype.h
提供給我們 islower function。
Command-Line Arguments
1 | int main (int argc, string argv[]) |
- argc 表示 argument count,使用者輸入的所有字的數量(包含程式指令)。
- argv 表示 argument vector,使用者輸入的所有字(包含程式指令),以陣列中的 string 來表示。由於 string 本身也是 array,所以我們可以透過 array in array 的關係得到在 argv 中的每一個單字。
為什麼 main 回傳的是 integer?
執行指令後會回傳代碼,0 表示正常,1 或其他數字表示錯誤,當我們執行完程式後可利用 echo $?
來確認上一步驟執行的程式最後回傳的值是什麼,以利於發生錯誤時的檢測。
Cryptography
當我們在傳紙條的時候不會希望紙條的內容被其他人看懂,這時候我們可能會用類似暗號的方式,而暗號通常會有一個對照表找出暗號要表達的意思,這樣的話只要知道對照表的人就可以知道紙條的內容了,而這時候我們就會想要作加密這件事情,例如我們可能本來想要傳遞的訊息是 I LOVE YOU 而我們可以利用 ASCII 找到對應的數字 73 76 79 86 89 79 85,接著將每個值都 +1,內容會變成 74 77 80 87 90 80 86,接著再利用 ASCII 將數字轉換成英文,所以我們最終的結果會變成 J MPWF ZPV,其中 key 是 1,plaintext 是 I LOVE YOU,經過 cipher 加密後 ciphertext 為 J MPWF ZPV,如此的話只有知道如何加密且擁有 key 的人才會知道要怎麼解密。
過程示意如下:
key ->
plaintext -> cipher -> ciphertext
總結
這堂課針對前幾堂課的內容做更深入點的說明,讓我們認識 array,也讓我們了解 string 的運作是利用將單字放在 array 裡而達成的,並且了解了字母或符號是如何可以做型別轉換…等等,是內容豐富的一堂課,如果想知道更多的話可以參考官網唷!