歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Linux C編程實戰之路

Linux C編程實戰之路

日期:2017/3/1 9:44:48   编辑:Linux編程

由於C語言是進入Linux開發,尤其是Linux底層開發的必備技能,因此掌握C語言也成為很多想從事Linux相關開發工作的朋友的一道坎,C語言較之其他編程語言,特點是簡潔高效,沒有過多冗余雞肋的概念,本博客打算用連載的方式,將Linux下的C語言編程所涉及的所有技術點一一剖析和展現,為了避免陷入教條式講解的歧途,我將采用各個擊破的方式,每一篇博客集中討論關鍵點問題,讓讀者一目了然。

打算用點時間將C語言梳理一下,分布在以下10個章節中:

  1. Linux-C成長之路(一):Linux下C編程概要 http://www.linuxidc.com/Linux/2014-05/101242.htm
  2. Linux-C成長之路(二):基本數據類型 http://www.linuxidc.com/Linux/2014-05/101242p2.htm
  3. Linux-C成長之路(三):基本IO函數操作 http://www.linuxidc.com/Linux/2014-05/101242p3.htm
  4. Linux-C成長之路(四):運算符 http://www.linuxidc.com/Linux/2014-05/101242p4.htm
  5. Linux-C成長之路(五):控制流 http://www.linuxidc.com/Linux/2014-05/101242p5.htm
  6. Linux-C成長之路(六):函數要義 http://www.linuxidc.com/Linux/2014-05/101242p6.htm
  7. Linux-C成長之路(七):數組與指針 http://www.linuxidc.com/Linux/2014-05/101242p7.htm
  8. Linux-C成長之路(八):存儲類,動態內存 http://www.linuxidc.com/Linux/2014-05/101242p8.htm
  9. Linux-C成長之路(九):復合數據類型 http://www.linuxidc.com/Linux/2014-05/101242p9.htm
  10. Linux-C成長之路(十):其他高級議題

C++ Primer Plus 第6版 中文版 清晰有書簽PDF+源代碼 http://www.linuxidc.com/Linux/2014-05/101227.htm

以下是C語言成長之路第一節:Linux下C編程概要

第一個問題,假設我是一個初學者,我需要學習的第一個知識並非C語言本身,而是可供我編輯、編譯、驗證乃至調試C語言程序的編程環境,如果你沒有一個合適的編程環境,那麼C語言的學習將是空中樓閣,無從談起。

因此我們的第一個任務便是搭建一個屬於自己的編程平台,由於針對Linux編程,我推薦大家直接使用Linux系統,Linux系統有許多發行版,選擇一個易用的就行了,比如我比較推薦Ubuntu,RedHat也是一款很成熟的Linux操作系統,但是redhat作為服務器Linux加載的服務太多,我們拿著這麼一台為服務器准備的系統當成PC來用不大合適,比如開關機時間就很長(服務器一般不會天天開關機)。

ubuntu操作系統的安裝ISO鏡像在網上到處都有,也可以通過ubuntu的官網下載:http://www.ubuntu.com/。下載下來之後可以安裝在虛擬機裡,也可以刻成光盤安裝在硬盤上,隨你喜好。

好了,下面來正式講解C編程技術。這裡,我們先不要著急去學習具體的語法點,而是來個統觀全局,看看一個C程序是長成什麼樣子的,有哪些要注意的地方,撇開語法細節,注重整體的程序編寫布局和規范,這是一個非常重要的步驟。就像廚師學廚藝,不是一來就馬上學習每一道菜怎麼做,而是先觀察師傅做出來的菜是什麼樣的,從大的方面加以學習和模仿,學習如何將菜做的好看,擺放惹眼,然後再考慮好吃,營養豐富等方面,如果一盤菜看起來就讓人倒胃口,即使再可口營養再豐富,也是大打折扣的。寫代碼也是一樣的,一開始要學會如何組織你的代碼,使人看起來舒服,樣式規范,風格一致,然後再來討論如何使得代碼的性能更好,算法更緊湊。搞清寫代碼的總體要求,這樣在後面的細節學習的時候,就有個總繩可以遵循。

下面是一個完整的C程序:

//example1.c
#include <stdio.h>
#include <string.h>
#include <strings.h>

int main(void)
{
char buf[100];
bzero(buf, 100);

fgets(buf, 100, stdin);

printf("you have input %d letters\n", strlen(buf));

return 0;
}

//example1.c
#include <stdio.h>
#include <string.h>
#include <strings.h>

int main(void)
{
char buf[100];
bzero(buf, 100);

fgets(buf, 100, stdin);

printf("you have input %d letters\n", strlen(buf));

return 0;
}

注意觀察上面的程序,有這麼幾個要點需要謹記:

1, 寫程序的時候,代碼塊內部的代碼,一定要有縮進,注意到在main函數中,左花括號和右花括號分別各自獨占一行,而裡面的代碼統統縮進8個空格。注意,一定要縮進而且最好統一縮進8個空格,這樣做的好處是使得代碼塊邏輯清晰,結構分明。

2,注意適當的地方要有空格,就像英文文檔的普遍書寫習慣一樣,一般在標點符號的右邊都空一下。另外,如果程序中有賦值號“=”也最好在左右兩邊空格一下,不要讓你的代碼統統擠在一起。

3,要注意在適當的地方有空行,比如在不同的邏輯塊之間,在上面的例子中,寫完最開頭的三行#include語句之後,是main函數,它們之間沒有緊密的邏輯關系,可以空行一下。另外在程序代碼中,也要適當空行,不然你的代碼將會很快使人疲乏,適當的空行會使生活更美好,而且空行空格是免費的,不要吝啬它們。

上面幾點是編程規范,下面再來看看example1.c中具體的代碼:

1,最開始的一行是//example1.c 這是一個注釋語句,因為它以兩個正斜槓開頭。凡是以兩個正斜槓//開頭的語句,在C語言中都將被視為注釋語句,所謂的注釋語句就是在編譯的時候會被丟棄的語句,這樣的語句用於開發者在程序中書寫自然語言,來對復雜的代碼加以解釋,方便閱讀。

另外,C語言中的注釋還可以是這樣的形式:

/* 這是一行注釋,對代碼的運行不起任何作用 */

/*
這樣的注釋是C語言的傳統風格
可以同時注釋多行,但是不能嵌套
這些注釋語句在編譯時都將被丟棄
*/

上面的注釋語句是用/* ... ... */ 包含起來的。寫注釋是對閱讀代碼的人負責的表現,如果一個程序的實現邏輯非常復雜,並不能一眼能看懂,那麼不加注釋對於程序的閱讀者和維護者而言將會是一場噩夢。那麼注釋寫什麼呢?答案是:寫代碼的功能,而不是寫原理。比如你寫了一個函數,這個函數用了高深的數學原理實現了求解某范圍內的所有素數,那麼你的注釋寫的就是它的功能:尋找素數。而不是寫它是如何運用數學原理找到的。我們都是實用主義者,我們知道怎麼用就行了,其他的不關心。

2,接下來的三行是預處理指令#include .... 所謂的預處理指令就是以#開頭的語句。(除了黏貼符##之外,我們以後在講解復雜宏的時候會講解)預處理指令其實不是C語言的一部分,這些指令由專門的稱之為預處理器的軟件cpp來完成,而且#include <xxxxxx.h> 語句的作用就是將所指定的文件直接拷貝到當前行。這些文件的後綴是.h,h的意思就是head的意思,因此這些文件也被稱為頭文件,它們在哪兒呢?答案是系統的標准頭文件路徑中,一般是在/usr/include裡面。

為什麼要包含這三個頭文件呢?我們就這個具體的例子而言,第一,我們用了庫函數printf(),所以我們要包含stdio.h這個頭文件,因為函數printf()的聲明在stdio.h裡面。同理,函數bzero()和函數strlen()的聲明分別放在了strings.h和string.h裡面,因此它們都需要被包含。關於函數的聲明和使用,在後面詳細講解。

3,接下來是一個main函數:

int main(void)
{
.... ....
}

請注意,C程序中,必須包含這麼一個東西。這個叫做main函數的東西是整個程序的入口,換句話講,不管你的這個函數寫在哪裡,你的程序執行的時候,都是從這個函數開始的,所以它叫主函數。注意這個主函數的書寫規范:int main(void) 前面的int表示這個函數的返回值類型是整型,不可寫成void也不可不寫,有些書籍上面介紹C語言的時候,主函數的返回值類型不是int,那不是因為書寫錯了,而是因為那些書所介紹的C語言不是LINUX下的C語言,LINUX是遵循GNU-C語法的,因此我們現在學習的其實是GNU-C,所謂的GNU-C其實是一套在標准C語言的基礎上帶增強功能的C規范,那些增強的功能需要編譯器額外的支持,所以我們用的編譯器是gcc,在gcc編譯器下的主函數返回值類型必須是int類型。

另外,main函數的參數是void,這表示此程序不需要任何命令行參數。main函數的參數還可以寫成這樣:main(int argc, char **argv) 這個我們留到後面再講。

在函數體中,首先是定義了一個數組buf,然後用bzero()將它清零,然後用fgets()函數等待用戶的輸入,並將用戶輸入的字符串放置到數組buf中,然後用strlen()函數計算用戶剛剛輸入了幾個字符,然後再用printf()將結果打印到屏幕上。

再來觀察一下,程序的最後一行是一個return語句:return 0; 首先,這個return關鍵字有兩個作用,第一:出現在普通函數中的時候,代表返回調用者。第二,出現在主函數中的時候,代表退出整個進程。這裡是第二種情況。一旦程序執行到這個return語句,我們的這個程序就game over了! 那麼後面的那個0是神馬呢?可不可以是1呢? 2呢? 答案是這樣的:後面的那個數字就是main函數的退出值,這個退出值將會被傳遞給我們這個進程的“父進程”! 是的,這個進程是有爸爸的,就像每個人都有父母一樣。我們的進程在退出的時候將會把自己的情況報告給它的父進程,一般規則是:正常退出返回0,非正常退出返回非0. 我們的進程壽終而寢,屬於正常退出,因此返回了一個0,否則如果是碰到了權限不足、內存不夠、參數有誤等等異常情況,導致程序無法執行下去,這時可以返回一個非0值來告訴它的老爸。

好了,這就是example1.c 你學到了多少呢? 這個程序分析完了,我們想要來運行它,怎麼運行呢? 很簡單,我們使用一款名為gcc的編譯器,來對它進行編譯,編譯的命令如下:

www.linuxidc.com@ubuntu:~$ gcc example1.c -o example1 -Wall

上面的命令,表示使用gcc編譯器,將example1.c 編譯生成一個叫 example1 的文件,-Wall的意思是將所有的Warning打開,也就是說如果我們寫的代碼有任何語法問題,都歡迎gcc幫我們顯示出來,我們不會怪罪它啰嗦,因為我們要學習嘛。(有時gcc是很羅嗦的,會爆出很多無關痛癢的警告)

這樣,你就擁有了一個可執行文件 example1 了,執行它:

上面的命令,表示使用gcc編譯器,將example1.c 編譯生成一個叫 example1 的文件,-Wall的意思是將所有的Warning打開,也就是說如果我們寫的代碼有任何語法問題,都歡迎gcc幫我們顯示出來,我們不會怪罪它啰嗦,因為我們要學習嘛。(有時gcc是很羅嗦的,會爆出很多無關痛癢的警告)

這樣,你就擁有了一個可執行文件 example1 了,執行它:

www.linuxidc.com@ubuntu:~$ ./example
hello
you have input 5 letters
www.linuxidc.com@ubuntu:~$

你輸入了一個字符串 hello,程序幫你計算出來,你剛剛輸入了 5 個字符。有趣吧? 如果這是你第一次編寫程序,能跟你的程序進行交互將會是一個極好的開端,下一節我們繼續征戰LINUX下C語言編程。

Copyright © Linux教程網 All Rights Reserved