電腦程式編寫

整同設計能夠執行得到嘅電腦程式嘅過程

編程粵拼pin1 cing4英文programming),全名程式編寫或者電腦程式編寫,係指整同設計能夠執行得到嘅電腦程式。編寫電腦程式嘅過程大致上涉及以下嘅工序[1][2]

  • 編程員要分析吓要解啲乜嘢問題,可以睇吓需求分析[3]
  • 佢需要度好要用邊啲演算法,中途要諗吓用啲演算法夠唔夠效率
  • 佢要揀返隻程式語言,用隻語言寫好程式嘅源碼
  • 打後編程員仲要做測試debug、保存程式嘅源碼同埋管理編程過程出嘅產物... 呀噉。
上圖段源碼係用高級程式語言寫嘅,但依然明顯唔似人日常傾偈講嘢。
一個人坐喺電腦前面寫程式;佢部電腦嘅熒光幕顯示一段段嘅源碼。

喺編程嘅過程當中,編程員要用程式語言向電腦俾命令電子電腦嘅原理係內部用微弱嘅電流嚟傳有電(1)同冇電(0)嘅訊號,而電腦內部用嘅機械語言就係用一串串 0 同 1 教部電腦做運算[4];而好似組合語言高級語言等高級啲嘅語言,就會將呢啲 0 同 1 轉化做對人類嚟講易睇易明符號(例如文字噉)[5];用家用呢啲高級語言寫好咗源碼之後,部電腦會用編譯器將段碼轉化做機械語言,等部電腦能夠行段命令[6]

喺廿一世紀初,編程係好多科技產品當中不可或缺嘅一部份,例如人工智能(AI)同視像遊戲等嘅技術都會用到編程-AI 簡單講就係用有技巧嘅編程方法嚟令機械做出類似有智能噉嘅行為[7],而視像遊戲就係以電腦程式形式存在嘅遊戲[8]。編程亦都因為呢啲廣泛嘅應用而成為咗一種相當有市場價值技能[9]

抽象概念

演算法

一個解決「盞燈唔着」呢個問題嘅演算法-演算法可以用流程圖表示。

一個電腦程式實會包含若干段演算法。喺數學電腦科學上,一個演算法係一串能夠完全唔含糊噉話俾人或者電腦聽要點樣解決某啲問題嘅命令[1][10]。好似係以下呢段嘢噉[11]

要解嘅問題:家吓俾若干個正數input)你,假設呢個列唔係一個空列,同我搵呢啲數入面最大嗰個出嚟

用嘅演算法嘅步驟:

  1. 設一個變數,叫佢做 max,並且將佢個數值設做 0;
  2. 將 input 嗰啲正數逐個逐個攞嚟同 max 比較吓;
  3. 如果撞到個數係大過 max 嘅(叫呢個數做 x)嘅話,將 max 嘅數值設做 x,並且繼續將 max 同下個正數比較吓;
  4. 將最後得出嗰個 max 嘅數值俾出嚟(output)。max 嘅數值會係拃數入面最大嗰個。

諗演算法嘅過程,係要將一份作業揼散做組成份作業嘅細部份,每個細部份都要係一啲電腦普遍都會識做嘅簡單運算,例如係「比較兩個,睇吓邊個大啲」噉-呢啲細部份可以話係組成演算法嘅元素,有咗呢啲細部份就有可能將任何「運算解得到嘅作業」砌到出嚟[11][12]

有關演算去要點分析同埋評估,可以睇吓運算理論運算複雜度等嘅課題。

資料類型

資料類型係一件資料會具有嘅一個屬性。

實際應用會用到嘅演算法,實要係噉將啲資料攞去做運算。一件資料會掕住個類型,個類型會話俾部編譯器知個程式打算點樣用呢件資料,等部編譯器識得適當噉將段碼變成電腦直接行到嘅機械碼[13]。常見-絕大多數程式語言都支援、而且多人用-嘅資料類型包括

  • 整數int),指件資料表示緊一個整數
  • 浮點數float),指件資料表示緊一個可以係小數實數
  • 字符char),指件資料表示緊一個文字等非數字嘅符號
  • 布林bool)指件資料表示緊一個真(1;True)假(0;False)值

... 等等。

舉個簡化例子,想像家陣部電腦收到一件數據 0001,如果呢件數據標明咗係 int 類型,噉部電腦就知呢件數據代表緊 1 呢個整數,但如果件數據標明咗係 bool 類型,噉呢件數據所代表嘅係先至啱。寫程式嗰陣,每個變數常數都會有返個資料類型[註 1];而如果用家嘗試將一個類型唔啱嘅數值加落一件資料嗰度-例如個程式嘅開頭講明咗 max 呢個變數屬一個整數,但程式半路出現

max = 0.005(將 max 呢件數據設做 0.005)

部電腦就會彈件信息出嚟,同個用家講話段碼有錯[14][15]

(真)、 (假)
整數浮點數字符布林

程式語言

程式語言係人向電腦俾命令嘅媒介。最原始嘅電腦唔會識得聽自然語言(簡單講,即係好似廣東話同客家話等日常講嘢會用嘅語言),所以就噉將頭先嗰段「搵一個數列入面嘅最大數值」嘅演算法打落去部電腦度,係唔會有任何結果出到嘅。一個編程員決定咗個程式做要邊啲運算用咩演算法,就需要搵返隻啱用嘅程式語言,用隻語言將啲演算法寫做一串串電腦會聽得明嘅陳述式。頭先嗰段「搵拃數入面最大嗰個數值」嘅演算法用 Python 呢隻程式語言寫出嚟嘅話,會係噉嘅[11]

# Input:一列冧巴 L。# Output:L 入面最大嘅冧巴。def wan2_max (L):  # 定義乜嘢係 "wan2_max"。   max = 0         # 設 max 做 0。   for x in L:     # 同每個喺 L 入面嘅 x,做...      if x > max:       # 如果 x 大過 max,         max = x         # 設 max 做 x。   return max      # 俾返 max 個值出嚟。

唔同程式語言喺「支持啲咩編程範式」等多方面都可能有異。搞清楚要用乜演算法解問題之後,編程員需要諗吓用邊一隻程式語言,而揀用邊隻語言取決於好多因素,例如係隻語言有幾啱用、公司政策、有冇啱用嘅編譯器同埋係個編程員自己嘅習慣呀噉。

雖然話唔同程式語言有頗大嘅差異,不過都有唔少功能係主流程式語言冚唪唥都有嘅。美國電腦科學家亞倫·當尼喺佢本著作《How To Think Like A Computer Scientist》(粵譯:點樣好似電腦科學家噉思考)入面指出,所有程式語言都有以下呢啲功能[16]

高級低級

呢個熒幕顯示緊用機械語言寫成嘅碼;呢種語言完全唔似自然語言,冇返咁上下專業知識唔會睇得明。

程式語言可以分做高級低級兩大類。呢種分級唔係話唔同程式語言「有啲勁啲有啲渣啲」,而且基於一隻程式語言有幾似自然語言:

  • 低級嘅語言(好似係機械語言噉)差唔多完全係由 1 同 0 等嘅數字組成嘅,一般人冇乜可能會睇得明,但電腦就係基於呢啲語言嚟行嘅-機械語言冇將電腦嘅運算抽象化
  • 高級啲嘅語言(好似係頭先提過嘅 Python 噉)就係電腦科學家為咗令寫程式呢家嘢容易啲而設計出嚟嘅,呢啲語言比較似自然語言,例如上面嗰串 Python 碼就有 if 等嘅英文字,所以對於一般人嚟講比較易明,但就同電腦實際處理緊嘅訊號(有電冇電)好唔同,所以用高級語言寫程式嗰陣,吓吓寫完段源碼之後都要搵編譯器將段源碼轉化成機械語言,或者搵直譯器將段源碼實時處理;但係即使係用編譯器,編出嚟嘅機械碼行起上嚟可能會慢少少[17]

喺廿一世紀頭,比較多人用嘅高級程式語言包括咗[18]

... 等等。

編程範式

編程範式係一種按功能而對程式語言作出嘅分類。唔同程式語言有唔同嘅功能[註 4],唔同嘅功能會支援唔同嘅編程「處理方法」。一隻程式語言有可能可以屬多過一隻編程範式[19]

舉個例說明,物件導向編程(OOP)係一種常用嘅編程範式,指建構程式嗰陣用物件嚟去做基本單元:個程式會有[20][21]

  • 一個個嘅類別class),每個類別會有若干個實例instance),
  • 每個物件都係一個實例,會有若干份資料,
  • 每件同類別嘅物件,有嘅變數都一樣。

例如以下呢段 C++ 碼噉:

class Car { // "Car" 係一個類別。  public: // Car 嘅每一個實例(每件屬於 Car 嘅物件)都會有以下呢啲變數...    string brand; // 牌子    string model; // 型號    int year; // 年份};

呢種做法喺好多應用上都好能夠令個程式更加易打理,例子:想像有位遊戲製作師喺度編寫佢隻新遊戲遊戲程式,佢想創造一個遊戲世界俾玩家喺裏面移動;佢想個虛擬世界設計成好似一座現實嘅城市噉,喺度諗緊座城市其中一條街要點設計,佢想條街有幾架車泊咗喺度做背景,佢可以設定一個class,個 class 每個 instance 都有色水位置等嘅變數,然後叫個程式將「建構一個車嘅 instance」呢樣嘢做三次-就唔使吓吓都重新打過「建構一個車嘅 instance」嘅碼[22]

因為 OOP 咁好使好用,有好多常見嘅程式語言都支援 OOP,會為用家提供一啲專做 OOP 嘅陳述式,包括咗 C++、JavaScript 同埋好多遊戲引擎都支援嘅 C#... 等等[23]

OOP 嘅例子;如果家陣用家想部電腦顯示四個外形上有少少唔同嘅星形物體,個程式可以將嗰四件物體當成喺「顏色」呢個變數上唔同、但屬同一個 class 嘅物件。

Debug

1947 年嗰個 bug;當時電腦科學家喺電腦入面搵到隻飛蛾,從此程式出錯就有咗個花名叫

Debug粵拼di6 bak1)係寫好程式之後要做嘅工序。Debug 指檢查吓個程式,搵吓佢有冇 bug粵拼bak1-嚟自英文名詞嘅意思),有嘅話就將啲 bug 清除咗佢。

Debug 嘅一種常見方法係俾個程式行幾次,睇吓佢 output 嗰啲結果有冇異常。呢個過程可能會嘥好多時間,複雜嘅程式要行嗮一次,可能要用成幾日咁耐嘅時間。不過 debug 好緊要-將一個有錯嘅程式放出嚟俾人用後果可以好嚴重,例如一隻負責用嚟分析科研數據嘅軟件如果有錯,可能會連累用隻軟件嚟做研究嘅科學家啲研究結果跟住出錯。對 debug 嘅思考會影響程式語言嘅選擇-某啲程式語言零舍容易有某啲類型嘅問題,好多時係因為呢啲語言喺編譯嘅過程當中冇其他語言檢查得咁嚴密[24][25]

Bug 種類

Bug 主要有以下嘅種類:

  • 句法錯誤句法係指一隻程式語言有嘅一啲法則,負責指定「邊啲符號(包括數字字母)嘅組合算係有意思」,例如喺 C 程式語言入面,printf("xxx"); 呢行碼會教部電腦顯示出 xxx 噉嘅字,因為 C 語言嘅句法指明咗 printf陳述式係教部電腦做「顯示段字或者變數嘅數值出嚟」嘅作業,而如果一個編程員打錯字,將段碼打咗做(例如)prinf("xxx");(少噉咗個 t),就會搞到個程式因為句法問題而出錯。句法上嘅錯誤係咁多種錯誤當中最易搵到嘅:喺編譯器將段源碼轉換成機械碼嗰陣,實會捉到句法上嘅錯誤[26]
  • 算術上嘅錯誤:就算一個程式句法冇錯、而且亦冇打錯字,個程式都有可能喺算術上出錯,好似係除以 0 就會搞到個程式行行吓出錯(行吓行吓,段碼叫部電腦將個變數嘅數值除 0,跟手部電腦就出錯),亦都反映個編程員寫個程式嗰陣考慮得唔夠周詳,冇諗到個程式行到呢個位有可能會出現個噉嘅數值。要應付呢種錯誤,編程界嘅一種常見做法係叫個程式定時定候將啲變數嘅數值顯示出嚟(可以睇返 C 程式語言嘅 printf),等編程員可以一路睇到個程式行嗰陣每個變數嘅數值點樣變,即係個程式會出好似以下噉嘅輸出[27]
    t=0:    wai_zi = 0      cuk_dou = 0 // 喺時間點(t)0 嗰陣,wai_zi 嘅值係 0,cuk_dou 嘅值係 0 t=1:    wai_zi = 0      cuk_dou = 10 // 喺時間點(t)1 嗰陣,wai_zi 嘅值係 0,cuk_dou 嘅值係 10 t=2:    wai_zi= 10      cuk_dou = 20 // ... 如此類推。t=3:    wai_zi = 30     cuk_dou = 30t=4:    wai_zi = 60     cuk_dou = 40t=5:    wai_zi = 100    cuk_dou = 50
  • 迴圈遞歸上嘅錯誤迴圈係一種好常用嘅編程技術;一個迴圈會掕住若干句陳述式同埋重複條件,個程式會按住條重複條件,重複噉行掕住嗰柞陳述式若干次,直至重複條件達到為止,例子有 while 迴圈for 迴圈都係噉。有陣時,編程員可能打錯字,搞到個程式出現無限迴圈或者無限遞歸等嘅問題,令到個程式係噉行同一段碼永遠都唔停[28][29]
  • 資源上嘅錯誤:有返咁上下複雜嘅程式基本上實會用到多件資源,包括用部電腦嘅記憶體記住處理緊嗰啲變數嘅數值;呢個過程可以引起好多錯誤,例如係編程員喺初始化嗰陣唔記得咗要設定某個變數嘅數值,然後個程式要攞個變數做運算,跟住搞到部電腦因為個變數冇數值而出錯[30]

... 等等。

質素要求

一位軟件工程師喺度試軟件

一般嚟講,無論一個程式係用嚟做乜嘅都好,啲人都會希望個程式具有以下呢啲特性:

  • 可靠度:指個程式有幾常會俾到啱嘅結果,一個完美可靠嘅程式每次行嗰陣都會成功俾到正確輸出;可靠度取決於啲演算法喺概念上係咪正確同埋寫程式嘅過程當中有冇出錯,靠唔住嘅程式成日會有競爭危害(指個程式嘅最終輸出會受一啲唔受控制嘅時間差影響)或者緩衝區溢位等嘅問題-如果有呢類問題出現,噉通常表示個程式寫得唔好[31]
  • 頑健度:指個程式有幾能夠預測同應對一啲佢自身以外嘅差錯,包括輸入嘅資料唔啱款(例如係輸入需要係浮點數但用家俾咗個字符)、要用嘅資源(好似係記憶體)唔夠用以及係用家方面嘅出錯... 呀噉。一個頑健嘅程式能夠喺佢自己以外嘅嘢出錯嗰陣有方法應對-簡單講可以想像成
    if 有問題,then 用噉噉噉嘅步驟嚟應對」,
  • 可移植度:指個程式嘅源碼可以喺幾廣泛嘅電腦硬件作業系統上面行,一個有完美可移植度嘅程式能夠喺任何電腦(無論係個人電腦定係手機等)上面行。可移植度由好多因素話事,例如係有啲程式可能用咗一啲比較專業嘅指令,而呢啲指令專業得滯,未必部部電腦都有裝呢啲指令-噉就會搞到個程式喺某啲電腦上面行唔到[33]
  • 可維護度:指嗰個程式有幾易可以俾現時或者將來嘅編程員攞去改良、執錯或者調較。高嘅可維護度對於普通嘅用家嚟講重要性唔係咁明顯,但就對一個程式長遠嘅命運同價值嚟講就好緊要-具有高可維護度嘅程式往往會俾人攞去改完又改,因而有一個更活躍嘅用家群[34][35]

... 等等。

可讀度

喺程式編寫上,可讀度指一個程式嘅源碼對人嚟講有幾易睇得明。

有啲程式好簡潔,令人一睇就知段源碼係點運作同用嚟做乜;但又有啲程式可能會(例如)有一大柞唔等使嘅陳述式,搞到一個冇份幫手寫段碼嘅人望落就俾佢搞到一頭霧水。可讀度對於一段源碼嚟講相當緊要:首先,可讀度會影響到個程式有幾易用可移植可維護-源碼可讀嘅程式會令到其他人一睇就明佢搞緊乜,所以亦都

  • 令人容易攞去用、
  • 將段碼用落去喺第啲機上(可移植)同埋
  • 執呢段碼(可維護);

另一方面,專業嘅編程員會揼好多時間心機去讀同研究彼此寫嘅程式,嘗試理解其他編程員寫嘅程式,以及係將其他編程員嘅程式改少少攞嚟用,而可讀度高會令呢個過程更加容易。事實上有研究指,好多時用一啲簡單方法令段源碼變可讀啲,就能夠幫其他編程員慳好多時間[36]

要提高一段源碼嘅可讀度,常見嘅方法有[37]

  • 用一貫嘅程式碼風格
  • 用好嘅縮排風格(喺每行陳述式前面加適量嘅空格);
  • 注釋comment;一啲會俾個程式忽略嘅文字碼,可以用嚟向睇嘅人講解每行陳述式用嚟做乜);
  • 分解,指將一件複雜嘅工作分做好多件細啲嘅工作,等想改段源碼嗰個人能夠直接飛去佢想改嗰部份[38],例如係喺編寫遊戲程式嗰陣,啲編程員好興俾唔同嘅人物關卡各有自己嘅檔案,等啲人玩起改檔上嚟易搞啲;

... 等等[36]。例如之前提到嗰個「搵出數列入面最大嘅數值」嘅 Python 程式噉:

冇縮排冇注釋:有縮排有注釋:
def wan2_max (L):                                   max = 0for x in L:if x > max:max = xreturn max
# Input:一列冧巴 L。# Output:L 入面最大嘅冧巴。def wan2_max (L):  # 定義乜嘢係 "wan2_max"。   max = 0         # 設 max 做 0。   for x in L:     # 同每個喺 L 入面嘅 x,做...      if x > max:       # 如果 x 大過 max,         max = x         # 設 max 做 x。   return max      # 俾返 max 個值出嚟。

簡史

英格蘭數學家勒芙蕾絲嘅畫像

中世紀(5 至 15 世紀)經已有數學家喺度寫類似電腦程式嘅嘢,不過歷史學家一般認為,史上第一個電腦程式係由英格蘭數學家勒芙蕾絲喺 1840 年寫嘅,當時佢為由運算機械之父巴貝治設計嘅分析機寫咗一段演算法,用嚟計白努利數。但係喺 19 世紀至廿世紀初期間,程式編寫一路都係一樣高度專業化嘅嘢,平民好少可會參與[39]

程式編寫普及化係喺廿世紀中開始嘅:廿世紀初嘅電腦程式編寫用嘅基本上淨係得機械語言組合語言,而喺 1953 年,美國電腦科學家莊·巴吉斯提出咗「想要有比起組合語言更加易讀嘅程式語言」嘅諗頭,並且喺 1957 年開發咗世上第一隻廣泛俾人使用嘅高級程式語言 Fortran [40]。高級程式語言呢一樣發明令程式編寫更加易做,所以助長咗「冇乜受過專業訓練嘅人自己學程式編寫」嘅風氣。而到咗廿一世紀初,編程經已成為咗好多技術-例如係人工智能遊戲編程等-嘅重要一環,呢點令編程成為咗一種有相當市場價值技能[9]

睇埋

詞彙

以下係篇文用咗嘅詞彙嘅粵英對照,啲拼音用嘅係粵拼

註釋

引咗

文獻

  • A. K. Hartmann, Practical Guide to Computer Simulations, Singapore: World Scientific (2009).
  • A. Hunt, D. Thomas, and W. Cunningham, The Pragmatic Programmer. From Journeyman to Master, Amsterdam: Addison-Wesley Longman (1999).
  • Brian W. Kernighan, The Practice of Programming, Pearson (1999).
  • Weinberg, Gerald M., The Psychology of Computer Programming, New York: Van Nostrand Reinhold (1971).
  • Edsger W. Dijkstra, A Discipline of Programming, Prentice-Hall (1976).
  • O.-J. Dahl, E.W. Dijkstra, C.A.R. Hoare, Structured Pogramming, Academic Press (1972).
  • David Gries, The Science of Programming, Springer-Verlag (1981).
  • Donald Knuth. The Art of Computer Programming, Volumes 1-4A Boxed Set. Third Edition (Reading, Massachusetts: Addison-Wesley, 2011), 3168pp. ISBN 978-0-321-75104-1, 0-321-75104-3
    • Volume 1: Fundamental Algorithms. Third Edition (Reading, Massachusetts: Addison-Wesley, 1997), xx+650pp. ISBN 978-0-201-89683-1, 0-201-89683-4. Errata: [1] (2011-01-08), [2] (2017-09-18, 27th printing). Addenda: [3] (2011).
    • Volume 2: Seminumerical Algorithms. Third Edition (Reading, Massachusetts: Addison-Wesley, 1997), xiv+762pp. ISBN 978-0-201-89684-8, 0-201-89684-2. Errata: [4] (2011-01-08), [5] (2017-09-18, 26th printing). Addenda: [6] (2011).
    • Volume 3: Sorting and Searching. Second Edition (Reading, Massachusetts: Addison-Wesley, 1998), xiv+780pp.+foldout. ISBN 978-0-201-89685-5, 0-201-89685-0. Errata: [7] (2011-01-08), [8] (2017-09-18, 27th printing). Addenda: [9] (2011).
    • Volume 4A: Combinatorial Algorithms, Part 1. First Edition (Reading, Massachusetts: Addison-Wesley, 2011), xv+883pp. ISBN 978-0-201-03804-0, 0-201-03804-8. Errata: [10] (2017-09-18, ? printing).
    • Volume 1, Fascicle 1: MMIX – A RISC Computer for the New Millennium. (Addison-Wesley, 2005-02-14) ISBN 0-201-85392-2 (will be in the fourth edition of volume 1). Errata: [11] (2016-08-02).
    • Volume 4, Fascicle 5: Mathematical Preliminaries Redux; Backtracking; Dancing Links. (Addison-Wesley, 2018-10-18) 320pp, ISBN 978-0-13-467179-6 (will become part of volume 4B).
    • Volume 4, Fascicle 6: Satisfiability. (Addison-Wesley, 2015-12-08) xiii+310pp, ISBN 978-0-13-439760-3. Errata: [12] (2017-06-01) (will become part of volume 4B).

外拎

  • (英文) GitHub,程式設計者常用嘅協作網站
  • (英文) StackExchange,程式設計者成日用嘅網上討論區
  • (英文) CodeForces,程式設計比試網站
  • (英文) TopCoder,都係程式設計比試網站
  • (英文) Leetcode,都係程式設計比試網站