在 Xcode Playground 中,#include <stdio.h>
以導入 C 語言的框架,在 C 語言中是以 int main 做為開頭,此為一個帶有參數的函數,int argc
、const char * argv[]
即是參數的宣告,一個是 int 型別,另一個則是 char 型別,並且為 const。
int i, n, Max, Avg = 0;
為變數宣告及初始化,;
作為每段的結尾,與前後的程式碼區隔開來。
以迴圈來提示使用者輸入十個數字,for(i = 1; i ≤ 10; i++) { }
表示 i 從 1 開始,i++ 表示 i 遞增,i ≤ 10 表示迴圈從第 1 次開始跑到第 10 次,即是共進來此迴圈十次。中間一樣用 ;
隔開。
printf、scanf 表示每次印出都換行;每次輸入(Enter、Return)後都換行。printf(" 第 % 個 ", i)
這段程式碼表示印出第 i 個,由 %(precent sign)對應到未知數 i,若 i 為 2 則印出 第 2 個
。
而 scanf(" %d ", &n)
這段程式碼表示掃描/讀取
使用者的輸入,一樣由 % 對應到 &n,&n 的 &(Ampersand)為取址符號,表示使用者輸入時要給予這個變數 n 一個記憶體空間,而 d 更限定了使用者輸入的是整數。
兩段程式碼合一起看即為下面這個結果:
詢問使用者第一次到第十次,使用者輸入 20、30、40⋯⋯最後輸入 10,來取最大值與平均。
繼續閱讀|回目錄
最大值與平均數
在條件敘述句
中,if (i == 1 || n > Max) { Max = n }
表示前一段的迴圈,第一次進來時,便將 Max 令為 n,n 即是使用者輸入的變數,同樣地,我們在前一段給予它一個記憶體空去儲存(&n
),由於 n 是一次次輸入的數字,在第一次必須先將之令為 Max,才能在第二次輸入時去比較,即是第一次 Max 為 20,第二次的 n 為 30,但 n > Max,所以 Max = n(30
)。
在其後的是 Avg += n
表示每次輸入進來的 n 要相加,這種寫法在迴圈裡即是把所有的值相加,所以你常會看到 sum = sum + i 或 sum += i,因為我們不需要兩個變數來分別儲存 sum 與 Avg,所以這段用 Avg += n 即可。
而跳出迴圈後,Avg = Avg / 10,才得到真正的 Avg(平均數)。
再說說 if (n > Max) { Max = n }
這種條件敘述句,Max 已經是第一個使用者輸入的數字,若接著輸入的數字有比較大,Max 才令為這個數。
在程式語言中,可稱之為打擂台
,看到下方例子:
int a, b, c, d, e, f, g, h, i, j, Max = a;
if (b > Max) {
Max = b;
}if (c > Max) {
Max = c;
}⋯⋯
先是宣告了 a、b、c⋯⋯j 這些變數,並將 Max 令為 a,接著開始比較所有的變數的大小,由於他們的型別為 int
,所以當然可以比大小
。
若是 b > Max,Max = b;若是 c > Max,Max = c⋯⋯。
當然,這種方式寫出來的程式碼相當易讀,不過同樣的事情一直重複程式碼去做就相當不符合效益。
雖然我們用的是 if (i == 1 || n > Max) { Max = n }
來去做判斷,其實也只會在 i == 1,即第一次輸入的數字進到迴圈,但看到下面:
if (i == 1) {
Max = n;
} else if (n > Max) {
Max = n;
}
這段程式碼跟原先的程式碼並沒有什麼不同,但每次你都會判斷 i
是否等於 1
,這是不是也不符合效益呢?
然而更有趣的是,如果使用者第一次輸入的是大於 0 的數,那其實只需判斷 if (n > Max) { Max = n }
也同樣成立,就不用加入 if (i == 1)
了。
下面,我們來想想看有沒有將程式碼優化的方法。
繼續閱讀|回目錄
程式碼拆分
若將原先的函式抽離,改成如下:
先看到 int main 裡,int n[10]
表示宣告了整數陣列,n[10]
意思是說給 n[]
這個陣列有十個空位,所以 10 就是它的大小了。
可以用它來儲存 10 個數字。
迴圈沒有變,i 從 1 ~ 10,printf 一樣沒有變,但 n 已宣告,所以在 scanf 裡要設值進去需寫成 &n[i-1]
,為什麼呢?
陣列設值的方式為 &n[0]、&n[1]、&n[2]、&n[3]、&n[4]、&n[5]、&n[6]、&n[7]、&n[8]、&n[9],所以 0 ~ 9 用來表示陣列的位置,雖然它的大小是 10,但第一位是 n[0]
,最後一位是 n[9]
。
看到了嗎?迴圈裡並沒有計算最大值與平均值喔!因為我們將程式碼拆了出來。
函式宣告
C 語言中,如果要自己寫一個函式,我們會在 int main 的前面去寫上一個空的函式,如同前段的 int max(int n[10])
與 int avg(int n[10])
,這種宣告方式是不是很像 int main(int argc, const char * argv[])
呢?
是的。
然而,函式的撰寫我們會擺在 int main 的後面,如下:
max 為找十個數的最大值的函式,先令最大值為第一個數,即是 int Max = n[0]。
接著看到迴圈,這十次迴圈裡,若 n[i] > Max,注意看!迴圈寫錯了呢,因為 for (int i = 0; i < 10; i++) 同樣意思的迴圈為 for (int i = 1; i ≤ 10; i++) 才對,所以這邊其實是 i = 0。
若 n[0] > Max,Max = n[0],但 Max 已經令為 n[0] 了就不會再令一次。
最後 return 的是 Max。
我們再看到 int avg(int n[10])
裡,Avg 這個 int 型別的變數先令為 0,在這十次迴圈裡,同樣是累加所有的數,故 Avg += n[i],最後除以總數取平均,即是 Avg = Avg / 10。
調用此兩函式,是在 int main 裡如下操作:
這即是說,我把 n[10] 中最大的數值找出來,也把 n[10] 中所有數值加起來除以總數(取平均),代入時,只要將 n 傳遞至兩函式作為參數即可。
最終結果自然沒變,如下:
繼續閱讀|回目錄
物件導向的思考
我們想想物件導向的封裝(encapsulation),封裝常是讓你不知道內裡有什麼就能使用它,複雜的事在內裡已處理完成,工程師負責調用即可。
就像調用求最大值的函式,我們不需知道函式的內容,只需知道怎麼用;將麻煩的東西移出去,不要跟呈現給使用者的文字混在一起。
如此程式碼才會呈現易讀、好維護的姿態。
就像在 Xcode 中,我們將 Controller 的權責
分配出去,例如拆成 event trigger、API calling⋯⋯等。
不要把所有複雜的函式都寫在 Controller 裡,程式碼就會變得易讀
、好維護
,除此之外,代碼的複用
也很重要,在這次文章裡,我們總不會希望當整數陣列變大的時候,也要重寫一個函式。
因為目前的 int max、int avg 只滿足 n[10]
作為參數,所以我們會從 n[j]
開始去想,在你真正要使用這個函式時,j 才給定了 n 這個 int 矩陣大小,我們略過實際操作,是提供想法。
接著再往下推,也許我們希望變成 float、double 型別也能代入函式,甚至是特定的 string 型別,例如寫成數字的 string 也能通過使用同一個函式幫助我們找到 Max
與 Avg
。
講到這裡,是否令你想起 swift 的泛型
呢?是吧。
這次就分享到這,感謝您的閱讀。
繼續閱讀|回目錄