【C語言入門】C語言的組成結構(基礎完整篇)!

C是一種具備模塊化設計的命令式編程語言,具備簡約、直觀的設計風格,與相對清晰、簡單的語言結構。編程

在談C的語言結構以前,須要先解釋一些基本元素的含義。編程語言

1、表達式

表達式是一個或多個變量、常量、函數與運算符按照特定規則的組合,表達式根據特定的優先級與運算符進行計算並返回一個值。模塊化

注意:單個變量、常量或函數名也是一個表達式。函數

如下面表達式爲例:學習

var = fn(1) + 5優化

其中var、fn、一、5都是表達式,其返回值爲自身的值;fn(1)也是一個表達式,返回函數調用的返回值;fn(1) + 5也是一個表達式,返回算術運算的結果;var = fn(1) + 5也是一個表達式,返回賦值號左邊的值,此例中此值被丟棄。spa

特別地,調用返回值爲void類型的函數將返回一個void類型的值,但此值沒法被使用,只能丟棄。設計

一、完整表達式

若是一個表達式不是其餘表達式的子表達式,則稱這個表達式爲「完整表達式」。3d

如下面幾個語句爲例:指針

var = 1 + 2;

fn(var + 1);

if (var + 1) ;

    ✪ 表達式語句中的整個表達式爲完整表達式,如上面的var = 1 + 2和fn(var + 1),但第二行的var + 1不屬於完整表達式。(函數調用其實是運算符()對函數指針和參數進行運算)

    ✪ if、while、switch括號中的表達式以及for括號中的每一個份量都是完整表達式,因此第三行的var + 1是完整表達式。

 

2、反作用

除了返回值之外對程序形成的其餘影響稱爲反作用。好比修改變量的值,執行I/O操做等。

對於以下表達式:

var = 5

表達式的返回值爲5,反作用爲將5賦值給變量var。

而對於如下表達式:

1 + 2

表達式返回3,沒有反作用。

一般提及「反作用」,老是以爲可有可無或儘可能避免,但對於命令式編程語言來講,反作用纔是程序執行的主要目的。

好比咱們調用printf函數,咱們一般並不關心它的返回值,而是須要它把特定的字符輸出到屏幕,而標準輸出正是這個函數的反作用。

 

3、語句

語句是C的基本執行單元,語句不返回結果,僅執行反作用。語句可分爲簡單語句和複合語句。

在C語言中,「;」 不是分隔符(for語句中的 「;」 除外),而是大部分語句的結尾。

申明不屬於語句,由於申明一般不產生反作用,即便有時候會產生反作用(如初始化),但仍不將其視爲語句,申明也以「;」結尾。

C有5種語句:

    ✪ 表達式語句

    ✪ 跳轉語句

    ✪ 選擇語句

    ✪ 循環語句

    ✪ 標籤語句

 

一、簡單語句和複合語句

簡單語句指內部不包含其餘語句的語句。如表達式語句和跳轉語句。最簡單的語句是隻有一個 「;」 的空語句。

複合語句的定義與簡單語句相反,即其內部有其餘語句。

將幾個語句用 {} 括起來就造成了複合語句「塊」,最簡單的複合語句是空塊 {}。

複合語句能夠進行屢次複合,好比塊能夠嵌套,複合語句的子語句能夠是其餘複合語句。

C語言沒有else if關鍵字,這種語法結構只是將上一個if語句的else部分複合了另外一個if語句,將他們寫在一塊兒是爲了使代碼更簡潔。

二、表達式語句

表達式語句爲一個完整表達式後跟一個分號構成的語句。若表達式爲空,就構成了空語句。

表達式語句是最簡單也是最多見的語句。如下語句都是表達式語句:

;

1 + 2;

var = 5;

printf("hello, world\n");

三、跳轉語句

跳轉語句用於改變代碼的執行順序。跳轉語句包括continue、break、return、goto語句。

四、選擇語句

選擇語句是複合語句,其做用是根據特定表達式的值對程序執行進行跳轉。如if、if else、switch語句。

五、循環語句

循環語句是複合語句,其做用是根據特定表達式的值讓一部分代碼反覆執行屢次,如while、dowhile、for語句。循環語句也能夠經過選擇語句和跳轉語句實現。

六、標籤語句

在其餘語句前加上標籤便是標籤語句。標籤語句是複合語句,能夠在任何語句(包括標籤語句)前添加標籤。

由於申明不是語句,因此不能在申明前添加標籤。對於下面的代碼,gcc給出以下錯誤提示:

lable:

    int var = 0;

error: a label can only be part of a statement and a declaration is not a statement

case 標籤是一種特殊的標籤,其標誌是在標籤前的case關鍵字。case標籤只能在switch語句中使用,case標籤容許且只容許標籤名使用整數,而且把標籤的做用域限定在當前的switch語句中。

標籤是語句的一部分,而不僅是個記號,因此塊末尾不能是標籤。

好比下面語句:

switch (var) {

case 1:

case 2:

case 3:

    ;

}

最後的分號是不能夠省略的,空語句複合case 3標籤造成標籤語句,而後又複合case 1和case 2,因此這個塊內只有一條完整的複合語句。

 

4、C語言結構

C語言代碼文件包括源文件和頭文件,源文件能夠進行編譯和連接,頭文件通常經過預處理指令包含到源文件中使用。

源文件由預處理指令、申明、類型定義、函數定義和註釋組成。

預處理指令和註釋能夠出如今源文件的任何位置而不影響其功能,而申明和類型定義的位置決定了其做用域。

申明有時會伴隨定義,定義必定會包含申明。

函數定義由返回值類型、函數名、參數列表和語句塊組成。語句只能出如今函數定義內部。

C源文件必須有且只能有一個main函數,C89規定,main函數的返回值必須爲int類型,若是程序正常終止,應返回0。

標準的main函數應寫爲 int main(void); 或 int main(int argc, char const *argv[]); 。

 

5、序列點

C語言經過序列點控制反作用的執行。在該點處以前的求值的全部的反作用已經發生,在它以後的求值的全部反作用仍未開始。

序列點的存在必定程度上保證了程序按照預期執行,但仍存在一些未定義的行爲。

C中的序列點不多,由於C追求效率,更少的序列點能夠給編譯器更多優化的空間。

注意:C中有不少符號同時承擔多種功能,在不一樣語境下扮演不一樣的身份。

 

C的序列點包括:

一、&& 與 || 運算符

&& 與 || 運算符會先對左邊的表達式求值並執行反作用。

對 && 運算符來講,只有當左邊表達式的值爲1時纔對右邊的表達式求值並執行反作用。

這是對程序的一種優化,由於根據「與」邏輯,若是左邊表達式的值爲0,則總表達式的值定爲0,無需對右邊表達式進行計算。根據這一特性,能夠寫出更加符合人類邏輯的代碼。

if (var != 0 && 3 == 100 / var) {}

若是沒有此序列點,則可能會出現0作除數的錯誤。

|| 運算符同理,只有當左邊表達式的值爲0時纔對右邊的表達式求值並執行反作用。

二、逗號運算符

「,」 在C語言中有不少用途,在某些地方它是分隔符,在某些地方它是運算符。好比如下表達式:

var = 1, var = 2

這裏的 「,」 不是分隔符,而是運算符。此逗號運算符的兩邊是兩個賦值表達式,逗號表達式先對左邊的表達式求值並執行反作用,此時var的值被修改成1,以後對右邊的表達式求值並執行反作用,var的值被修改成2,最後,逗號表達式返回右邊表達式的值,即2。

逗號表達式的特性可使兩個表達式像兩個表達式語句那樣執行,適合用在須要用表達式代替語句塊的地方,如 for 語句的括號內。

三、三元運算符 ? : 中的 ?

在 ? 前的表達式求值並執行反作用後,才判斷返回其後哪一個表達式的值。而且,若是肯定返回某個表達式的值,則不會對另外一個表達式求值或執行反作用。

? : 表達式的這個特性使其行爲與if else表現一致。

四、完整表達式的末尾

完整表達式的末尾也是一個序列點,這保證了表達式語句的反作用按照其書寫順序執行。

同時,根據前面對完整表達式的定義,if、while、switch括號中的表達式以及for括號中的每一個份量都是完整表達式,這些表達式的反作用也都會在語句其餘部分開始前執行。

五、函數調用與返回

函數調用時參數列表中的逗號不是表達式,而是分隔符。

參數列表的求值順序是未定義的,好比 fn(a++, b--),a++和b--的求值順序是未知的,取決於編譯器。

此處的序列點表現爲在進入函數前,全部表達式的反作用都已經完成;函數返回時,返回值已經拷貝到調用處。

六、初始化末尾

由於初始化是申明的一部分,不屬於語句或表達式,因此不能套用表達式的說法,但其表現是相似的。

以下申明:

int var = 5;

在分號前已經完成反作用,即把var初始化爲5。

七、初始化列表中的逗號分隔符

初始化列表中的逗號是分隔符而不是運算符。

初始化列表中的表達式按照從左到右的順序求值並執行反作用。

以下代碼:

int var = 0;

int array[] = { var++, var++, var++ };

八、申明中的逗號分隔符

申明中的逗號是分隔符而不是運算符。

以下代碼:

int a = 0;

int b = a++, c = a++;

b、c分別被初始化爲0、1。

並且,在逗號前的變量已經申明完成,逗號後的則否則。

以下代碼:

int a = 0, b = a; //Correct

int c = d, d = 0;  //Error

在申明b前,a已經申明並初始化完成,因此能夠用a初始化b。而在申明c時尚未申明d,因此初始化會報錯。

由於缺乏序列點,C會產生不少未定義的行爲。最典型的例子是:

int var = 0;

var = var++;

根據優先級,表達式var = var++的值是肯定的,然而賦值和自增反作用的執行順序是未定義的,因此var的值是未知的。若是用gcc編譯這段代碼,var的值爲0,比較符合預期;但在VC++中,var的值爲1。

因此咱們應避免在表達式中同時使用某一變量和它的自增表達式。


 

最後,無論你是轉行也好,初學也罷,進階也可,若是你想學編程~

【值得關注】個人 C/C++編程學習交流俱樂部!【點擊進入】

問題答疑,學習交流,技術探討,還有超多編程資源大全,零基礎的視頻也超棒~

相關文章
相關標籤/搜索