首頁>Club>
11
回覆列表
  • 1 # 校園小喇叭

    先要學會程式,再然後才能設計軟體,學會程式推薦從學習好C語言開始吧,不敢說自己很精通C語言,權當拋磚引玉吧。

    為什麼要學C語言?在你學習C語言之前,你必須明白C語言是用來幹什麼的。也許你看了書上的範例程式碼,渾渾噩噩,印象裡好像可以寫一個諸如華氏度轉攝氏度的東西,或者是給一堆數排個序之類的。總之,語言是用來寫程式的。那什麼是程式呢?我不知道你對計算機有多少了解,不過我猜想你應該知道,計算機的處理器能夠處理一條一條的指令,這些指令對應著不同的對資料的操作。計算機執行一個程式,就是把這些指令和資料載入到記憶體裡面,然後一條一條地執行。

    我相信你也知道計算機內部全都是用二進位制表示資訊。在機器中,每一條指令也是用二進位制數來表示的。我們很難記住這些數和指令的對應關係,它的表現也不夠直觀。所以計算機科學家們開始用助記符(比如mov、jmp等)來表示指令。這被稱作組合語言。

    儘管相比於徒手擼機器碼有進步,但是說到底組合語言也只是很淺的一層抽象。實現一個複雜的功能,也許要寫很長的一段程式碼。更可怕的是,許多彙編程式碼移植性不好,切換到另一個平臺上需要改很多程式碼。因此開發大型軟體很不方便。在C語言出現之前,已經有過許多在組合語言基礎上進一步抽象的高階語言,比如FORTRAN、COBOL等等,而且許多至今都還在某些領域有各自的一席之地。而C的抽象在它出生的那個年代做得恰到好處,既有高階語言的簡潔和表達力,又不失貼近底層系統的直接,再加上它與UNIX繫系統的密切關係,C在之後許多年裡成為了系統程式設計和軟體開發的首選語言。

    C的程式碼相比於之前的彙編,在可移植性上已經有了諸多進步,切換到另一個平臺的程式,只要那個平臺上有C的編譯器,不需要修改或者只需要修改少量的程式碼。我們可以看到在程式語言發展的過程中一個很明確的趨勢就是抽象層次愈來愈高,比如後來又出現了號稱“一次編寫,處處執行”的依靠虛擬機器的Java和眾多的指令碼語言,當然那是後話了。忘說了,在程式語言的發展之路上,還有另一條分叉,函式式語言,典型代表是lisp。它的思維方式同傳統的基於指令的語言截然不同,知乎上有大牛說過,函式式語言就是數學,只要數學不過時,函數語言程式設計語言就不會過時。不過在C誕生那個年代呢,由於機器條件所限,函數語言程式設計語言還沒有那麼得到人們的重視。

    好了,講歷史的部分到此打住,在今日軟體專案的實際開發中,C語言所佔的比重早已不能和八九十年代同日而語了。之所以還要學C語言呢,就是因為它跟底層有天生的親近感,C語言的許多特性和“坑”,深挖下去,其實也是計算機體系結構的問題。《C標準庫》的作者在書裡打趣說,C大概是少數能自我實現標準庫的語言了。所以,學C的時候,如果關注點僅僅是語法本身,那還不如python來得親切。(不過我想說國內大學裡有些教C語言的老師恐自己的python可能多數不太熟悉精通(獨立開發軟體)。

    Hello, world!大多數初學C語言的人寫的第一個程式都是所謂的“Hello, world!”。簡言之,就是一個能在螢幕上輸出這句話的程式。這句話的起源是C語言之父(可不是譚浩強哦)Dennis Ritchie和Brain Kernighan的名著《C程式設計語言》。

    從此以後成為了所有程式設計語言學習者的第一課。也許你也像多數人一樣,對所謂的“程式”或者說“軟體”,在之前並沒有一個明確的概念或者印象。也許你會認為軟體是像網易雲音樂一樣的,或者說是手機上的微信一樣的,有一個漂漂亮亮的視窗,還有按鈕,還有標籤什麼的東西。但當你費盡千辛萬苦,照著書上敲完這一段也許還不能一次敲對的程式碼,結果發現只有一個“黑漆漆”的螢幕的時候,你會不會略感失望呢?這就是我要的程式嗎,為什麼長這樣?如果你去問老師,說自己不想要這種程式。脾氣不好的老師也許會直接罵你一頓,有耐心點的老師可能會告訴你學會了這個才打好了基礎。

    可是我想你還是不明白這個黑漆漆的視窗到底代表著什麼。這也難怪,因為你用的是Windows,如果之前沒有弄過什麼bat指令碼的話,也許都從來沒有接觸過終端這個東西。不過我想你可以給家裡人打個電話聊聊。如果你爸媽在九十年代的時候學過計算機的話,他們應該對DOS的命令列介面還有印象。說不定小時候偷看過親戚玩電腦的你也有。事實上,在所謂的“圖形使用者介面”出現以前,一個程式的輸入和輸出基本只能依靠命令列中的鍵盤和螢幕。你在Windows的資源管理器裡對著a.txt右鍵點選刪除,和你在DOS的黑螢幕裡敲del a.txt然後回車是一個效果。

    只不過,前者可能對使用者而言更加友好。所以你明白了吧,由於早期計算機的顯示技術和設計理念的限制,輸入輸出採用的是命令列的方式。而你跑這個Hello, world!程式時候出現的黑視窗,實際上可以理解為是Windows對早期命令列系統的一種模擬。

    如果你還知曉有一種語言叫VB,它的Hello, world!可以用建立一個窗體,然後在上面畫一個Label的方式來實現。對比一下,可以發現,其實這兩者之間並無什麼本質區別。之所以我們喜用在命令列下輸出Hello, world!的程式來教授程式設計的第一課,原因首先是它簡單,不用考慮輸出的佈局、格式,僅僅是內容就可以了;然後是C語言的標準庫也並沒有給我們提供這樣一個圖形化的介面。事實上設計一個圖形介面的程式也沒有那麼簡單,你需要設定好佈局,要為每個元件編寫事件響應介面……作為初學者,你應當知曉的是,之所以用命令列,並不是因為C語言不能做圖形介面,而是因為那跟我在初學的時候需要挖掘的東西相隔太遠。不管是寫一個命令列的Hello, world!,還是點選按鈕彈出Hello, world!,甚至是用電腦的蜂鳴器bee一聲,本質都是一樣的。

    程式設計的意義事實上,寫程式和設計的目的是一樣的,都是為了解決問題。(儘管有些人喜歡欣賞所謂“純粹的技術”)國內高校教材最大的缺點之一,就是隻告訴你這個是什麼,卻從來不告訴你學了有什麼用。即使講了所謂的用途,給人的感覺也只是湊數用的。不信?可以拿我校數學系編的那本紫皮的《線性代數》和國外優秀的線代教材比,看看兩者差距有多大。

    儘管C語言相比python、Java等語言缺少許多必要的“輪子”,不過對於初學者來說,寫點能執行剪刀石頭布的程式碼,或者說能夠從某個文字檔案裡讀入生詞然後考查你背得如何的程式,都可以帶來巨大的成就感。上程式設計課和上高等數學不一樣,它不應該有什麼進度之分。在瞭解完基本的語法之後就可以動手實現了,期間遇到什麼問題再去網上查。寫完了再去跟別人寫得好的對比,看自己哪裡不足。初學程式設計,關鍵在練習。語法有什麼用?似乎譚浩強和其它諸多所謂國內“專家”編寫的教材,把C語言當做數學來講,按照不同的語法內容劃分成章節,有些學校說不定最後還會有筆試。有些學校甚至還叫學生上交手抄程式碼。我不太能夠理解和認同這種行為。作為初學程式設計的你,大概早就受夠了這種被動式的接受,在心裡反問自己:就算我都看完了,能寫出個什麼呢?確實寫不出什麼東西。因為在這種情況下,讀者很難理解到這些語法的含義。比如,你看到書上講分支語句和迴圈語句的時候,有想過它們有什麼用嗎?我不用分支行不行,不用迴圈行不行?試想我們有一個程式,讓我們在輸入的一堆數里面找出最大的那個。假設輸入是定死的,第三個數最大,那我完全可以接收到第三個輸入的時候直接輸出,結束程式了對不對?你可能覺得我這樣是在耍流氓,哪裡會有這樣的程式。

    事實上,這也是所謂條件語句存在的本質——程式需要接受不同的輸入(任何形式)。如果輸入是固定的,那麼理論上我可以改寫為沒有條件語句的程式碼。變數的概念,也是因為它所包含的值不是確定的。話說回來,只有用if語句才能實現分支結構嗎?你讓我求一年每個月多少天,我是不是可以開一個數組來儲存,然後單獨判斷閏年就可以了?你讓我輸出從1到100任意一個整數的平方,理論上我用switch...case語句或者if也能做,可直接輸出n*n,不是更好理解也更方便嗎?迴圈其實是類似的道理,只是它的目的在於重複執行某一段程式碼,而重複次數是不固定的。

    我們程式設計的目的是解決問題,不是讓你在寫程式碼的時候故意賣弄一些什麼東西上去把程式碼搞亂,像寫高中的語文作文一樣。每學到某個語法概念的時候,都要問一問自己,如果沒有這個東西,有沒有什麼程式是寫不出來的?或者說,如果沒有了這個語法,我寫程式的時候會增加多少麻煩?

    理論上,一門程式語言只需要非常簡單的語法,就可以寫出任何形式的程式。(可以搜一下“圖靈完備”)但是為什麼還有這麼多程式語言呢?為什麼有的程式語言適用於某個特定領域呢?為什麼人們會覺得用python寫點小程式比C要來得方便呢?C語言和現代高階的指令碼語言比,語法實在可以用“簡陋”來形容,標準庫提供的東西也不多,實際程式設計要用到的一些資料結構都要自己去實現。在自己“造輪子”的過程當中,你會自己去感受諸如記憶體分配這樣的事情,在這個基礎上理解其他語言一些高階資料結構的實現原理。比如說連結串列,比如說記憶體池。

    公式和程式碼的區別雖然說一開始學習程式設計的時候,許多同學都會把C語言當做一個計算器來用,比如說我輸入一個變數a,然後計算它的一個函式再輸出。在這個層面上,我們可以說,如果不考慮溢位的情況,數學公式(或者說理論上的演算法吧)和實際程式碼可能是對等的。這是非常簡單的情況。但是當我們的程式越來越大,步驟越來越複雜,寫起程式碼來可能就沒那麼簡單了。比方說,我們用C來寫高精度相乘,最簡單的情況是兩個陣列,每個元素代表一位。如果在腦子裡想,可能會很簡單:就是逐位乘然後相加嘛。可如果你真動手寫了,你會面臨這樣的問題:既然我的數佔不滿整個陣列,那到底是靠左還是靠右?乘法的過程不能一次結束,我需要一個臨時陣列來容納中間結果嗎?我怎麼知道這一輪乘的數是十位、百位,還是千位?相乘的函式應該有幾個引數?如果題目包含小數,我怎麼知道最終結果小數點後有多少位?我應該怎麼輸出?……儘管在搞競賽的人看來這簡直就是入門都算不上的題,但是還是有很多人不能一次寫對的(poj1001,比如我……)。

    數學上的演算法和公式是普適的,但是要實現成程式,就必須要落腳到具體語言的語法上。為什麼人們說要學好程式設計要多練習?因為練習就是一個踩坑的過程。我這一次踩到這個坑了,知道這裡容易出錯,我總結下來,以後也是如此。天下大事必作於細,所謂的程式碼能力就是這個。對程式設計的初學者來說,知道不等於會做。所以如果有什麼程式自己老是寫不對,不要一下子就灰心喪氣,但是要對它有個印象。比如說陣列不會自動初始化,比如if不加花括號就只執行後面一句。C語言與底層系統我們講,C語言在出生的時候,因為作了適當層次的抽象,才能抓住歷史潮流成為最流行的語言之一。

    這個所謂的“適當層次”,意思就是既避免了直接面向機器指令,又不完全將計算機執行的原理隱藏起來。於是你稍微學深入了,會產生許多疑問……為什麼printf("%u", -1);結果會輸出4294967295?為什麼陣列訪問a[-1]但程式沒有出錯?為什麼char str[]="abcd";我就可以修改str[0],而對於char *str="abcd";我這樣做程式就會出錯?為什麼我#define G 3+3而G*G的結果卻是15?為什麼scanf的引數名要加一個&號?為什麼printf和scanf的引數可以是不固定的?為什麼一個浮點數加了10次0.1之後結果卻是0.99999...?為什麼一個區域性陣列開太大了程式會爆掉?……多數問題,深挖下去都和計算機體系結構、計算機內部資料表示、可執行檔案格式、編譯原理等內容相關。

    知其然而不知其所以然,就很難說自己瞭解C語言。資料結構作為一個看見演算法就暈的非ACMer,我想我本來沒有什麼資格說資料結構。不過我想換個角度談談這個問題。資料結構和演算法的重要性自不必說,太多人都會像一個長者一樣叮囑你要想程式寫得好,資料結構最重要。資料結構的確重要。可是你有沒有想過,到底什麼是資料結構,資料結構的本質是什麼?有一大批講授資料結構的書籍一開始就把各種資料結構的概念灌輸給你,然後帶著你用實際的程式碼去實現這些結構(多半是C++或者Java的書吧)。

    不過我覺得這些作者仍然忽略了一個問題,即:這些東西有什麼用?事實上,每種資料結構都可以看作是對現實生活中物件的刻畫。為什麼會有棧?因為有很多場景需要先進後出。更本質地說,是在這些場景裡面,先進的需要包含後進的才能完成。比方說C語言函式的呼叫棧,逆序表示式的求值。或者在生活當中,假設我們要拆一臺電腦,我們得先開啟它的外殼,然後拆下大零件,最後弄下大零件裡包含的小零件。如果我們要裝配回去,我們要先裝上小的,再裝上大的,這裡有一個先後順序。我們就可以說,當我們拆機的時候,各個零件組成了一個棧,外面的殼在棧底,裡面的小部件在棧頂。當然,在修電腦的時候,我完全可以把所有的零件一通亂地扔在我的床上,要裝上去的時候再找,不用像陣列一樣有序排列。為什麼?因為當我完成步驟k的時候,我內心清楚k+1步需要哪個零件。而寫程式的時候,比如求逆序表示式的值,我就沒有辦法知道下一個“零件”是什麼,我只能猜測是棧頂元素。因此,在實際程式中,它必須有序。這就是棧這種資料結構的來源,它是一種抽象。本質上講,這也是個資訊的問題。其他的資料結構,比如佇列、樹、雜湊表等等,都一樣可以看作是對現實生活中事物運轉方式的刻畫。比如樹是一個極其典型的遞迴結構,想一想中世紀歐洲的封建制度,其原則是“我只需要對我下面一級的人發號施令就行了”。

    所謂二叉樹,它的特殊性在於它是樹的最簡形式,節點有兩個子節點的情況是生活中最常見的,比如我們的四則運算就可以用樹來表示。嗯,說到四則運算,我們可以把普通的中序表示式轉化為逆序表示式,本質上也就是把一棵二叉樹變成了棧,感受一下這個演算法。功利一點?其實如果僅就題主的問題本身,我想我沒有必要說那麼多。我個人感覺,我校軟院對大一新生的C語言考察要求還是不高的(可能是我校太渣?)。期末上機三道題,第一題無腦,第二題要考到C語言裡的許多語法內容,第三題會涉及到資料結構,不過不懂的人憑感覺寫估計也能過幾組資料。所以如果說你的目的僅僅是透過考試拿一個不錯的成績的話,大概沒有必要花這麼多時間去看這些“有的沒的”的東西。後面一些回答提到的東西大概是從從事C開發的專業人士的角度闡述的。作為大一新生,其實你就像我,不知道自己以後會從事哪方面的工作,也許去幹前端也說不定。

    我絕對不相信一個對作業系統沒什麼瞭解的大學生真能像某些人建議的一樣啃下APUE,更何況一個連C程式設計和Linux操作都不熟悉的呢,是吧?如果你所在的學校還沒有腦殘到要筆試學生C語言的程度,並且你們用的教材是譚浩強那本的話,我覺得你可以扔掉它了,真的。譚老對中國計算機普及作出的貢獻當然很大。但是都到2019年了,學校還在用這本書,我看這不是譚浩強之恥,是學校之恥!我沒有看過C Primer Plus這本書,寫作這個回答的時候到學校圖書館翻了翻,感覺還可以。學計算機的話,就不要畏懼這些大部頭了。厚不一定代表難讀。

    大學的課堂老師一學期也講不了多少內容,多數還得自己去看。一個好的老師,只能說給學生以最正面的引導,讓他們少走彎路。現在這個時代,大學生可以接觸到的專案很多,主要的型別無非是跟Web相關,其中的大多數也用不到C語言。不過不要因此就否定C/C++的價值,對此知乎上的大牛們講的很多了。還有,千萬記住,C和C++是兩種語言,C++也不完全相容C. 不信?在C和C++裡分別輸出sizeof("Z")試試。

    建議書目

    Code: The Hidden Language of Computer Hardware and SoftwareThe Information: A History, A Theory, A Flood

    Head First C

    C Programming: A Modern Approach

    The C Programming Language

    Computer Systems: A Programmer"s Perspective

    Expert C Programming: Deep C SecretsPointers on C

    C Traps and Pitfalls

  • 中秋節和大豐收的關聯?
  • 數學向量公式?