跳至內容

C語言語法

維基百科,自由的百科全書

C語言語法國際標準化組織所制定。[1]

複合語句

[編輯]

C語言中的複合語句(或稱語句塊)的格式為:

{
    語句;
    語句;
    /* ... */
}

[2] 複合語句可以使得幾個語句從文法上變成一個語句。

有時必須使用複合語句,否則會產生錯誤。例如,在運用循環語句的時候,如果循環體(即循環中執行部分)包含多個語句(以分號隔開),則必須使用花括號將他們合併成一個複合語句。如果不這麼做,系統僅把第一個分號前的內容看做循環體。

需要注意的是,部分C編譯器並不支持在任意位置使用複合語句。

條件語句

[編輯]

C語言有兩種條件語句形式,分別是ifswitch

If 的格式如下:

if (運算式) // 如果
    語句; 
// 有時還會有 else:
else      // 否則
    語句;

運算式的值非零表示條件為真;如果條件為假,程式將跳過if處的語句,直接執行if後面的語句。但是如果if後面有else,則當條件為假時,程式跳到else處執行。ifelse後面的語句可以是另個if語句,這種套疊式的結構,允許更複雜的邏輯控制流程得以實現。在一般情況下,else一定與最接近的if成對,因此常用括弧{}越過此限制。比較下面兩種情況:

if (邏輯表達)
    if (邏輯表達式)
        語句; 
    else
        語句;

下面是if的另一種格式if……else if……else……

if (逻辑表达式)
    语句;
else if (逻辑表达式)  //在下面可以加入多个“else if()”语句
    语句;
else
    语句;
if (邏輯表達式甲) {
    if (邏輯表達式乙)
        語句;
}
else 
    語句;

要注意這裡的縮進和換行只用於方便閱讀。編譯器並不會根據縮進層級猜測 if 和 else 的對應關係。

switch通常用於對幾種有明確值的條件進行控制。它要求的條件值通常是整數或字元。與switch搭配的條件轉移是case。使用case後面的標值,控制程式將跳到滿足條件的case處一直往下執行,直到語句結束或遇到break。通常可以使用default把其他例外的情況包含進去。如果switch語句中的條件不成立,控制程式將跳到default處執行;如果省略default子句,則直接執行下一語句。switch是可以嵌套的。

switch () {
  case :
  case :
    語句段1; // 甲乙都會執行
    // 更多語句…
    break;  // 跳轉到 switch 末尾處
  case :
    語句段2;
    break; 
  default:  // 無論如何都會匹配
    語句段3;
}

簡單的條件判斷也可用?:

運算式?值1:值2;
:
   a=b>c?b:c // 如果變數"b"的值大於變數"c" 把變數"b"的值賦予變數"a"

循環語句

[編輯]

C語言有三種形式的循環語句[2]

do 
    語句
while(判斷式);

和:

while(判斷式) 
    語句;

和:

for(起始化;判斷式;運算式)
    語句;

whilefor中,語句將執行到表達式的值為零時結束。在do...while語句中,循環將至少被執行一次。這三種循環結構可以互相轉化:

for(起始化;判斷式;運算式)
    語句;

如果語句中不使用continue語句的話,相當於

起始化;
while (判斷式) {
    語句;
    運算式;
}

當循環條件一直為真時,將產生無窮迴圈

跳轉語句

[編輯]

跳轉語句包括四種:goto,continue,break和return[2]

goto 標記;

goto語句是無條件轉移語句,且標記必須在當前函數中定義,使用「標記:」的格式定義。程式將跳到標記處繼續執行。由於goto(特別是向回 goto 和長距離的 goto)容易產生閱讀上的困難,所以對新手應該儘量少用。GCC 編譯器拓展支持對指針 goto和宏內 goto,一定程度上增強了 goto 的可讀性。


continue語句用在迴圈語句中,作用是結束當前一輪的迴圈,馬上開始下一輪迴圈。

break語句用在迴圈語句或switch中,作用是結束當前迴圈,跳到循環體外繼續執行。但是使用break只能跳出一層迴圈。在要跳出多重迴圈時,可以使用goto使得程式更為簡潔。

當一個函數執行結束後要返回一個值時,使用returnreturn可以跟一個運算式或變數。如果return後面沒有值,將執行不返回值。

在C語言中的運算符號

[編輯]

C和C++運算符

數據類型

[編輯]

數據類型 (C語言)

數組

[編輯]

如果一個變數名後面跟著一個有數字的中括弧,這個聲明就是陣列聲明。字串也是一種陣列,它們以ASCII的NUL作為陣列的結束。要特別注意的是,方括內的索引值是從0算起的。

例如:

int myvector [100]/* 從myvector[0]至[99]共100個元素 */
char mystring [80]
// 声明时初始化
float mymatrix [3] [2] = {2.0 , 10.0, 20.0, 123.0, 1.0, 1.0};
int notfull [3][3] = {{1},{1,2,3},{4,5}};
// 数组套数组
char lexicon [10000] [300]/* 共一萬個最大長度為300的字元陣列。*/
int a[3][4]

上面最後一個例子創建了一個陣列,但也可以把它看成是一個多維陣列。注意陣列的下標從0開始。這個陣列的結構如下:

a[0][0] a[0][1] a[0][2] a[0][3]
a[1][0] a[1][1] a[1][2] a[1][3]
a[2][0] a[2][1] a[2][2] a[2][3]

例子中notfull創建了一個3*3的二維陣列,初始化時有些元素並未賦值。如下:

1  ?  ?
1  2  3
4  5  ?

根據C標準的規定,在存在初始化列表時,如果初始化列表中未提供對所有元素的初始化,則剩餘元素會被默認初始化,並使用與靜態變量相同的初始化規則[3]

指針

[編輯]

如果一個變量聲明時在前面使用 * 號,表明這是個指針型變量[2]。換句話說,該變量存儲一個地址,而 *(此處特指單目運算符 *,下同。C語言中另有雙目運算符 * 表示乘) 則是取內容操作符,意思是取這個內存地址里存儲的內容。把這兩點結合在一起,可將 int *a;看作是 「*a 解得的內容類型為 int」,對更複雜的聲明也如此[註 1]。指針是 C 語言區別於其他同時代高級語言的主要特徵之一。

指針不僅可以是變量的地址,還可以是數組、數組元素、函數的地址。通過指針作為形式參數可以在函數的調用過程得到一個以上的返回值(不同於return z這樣的僅能得到一個返回值。

指針是一把雙刃劍,許多操作可以通過指針自然的表達,但是不正確的或者過分的使用指針又會給程序帶來大量潛在的錯誤。

例如:

int *pi;     // 指向整型数据的指针 pi
int * api[3];// 由指向整型数据的指针构成的数组,长度为 3
char ** argv;// 指向一个字符指针的指针
struct { int member; } stinst,
  * pst = & stinst;
// pst是一个指向一个匿名结构体的指针

儲存在指針中的地址所指向的數值在程序中可以由 * 讀取。例如,在第一個例子中, *pi 是一個整型數據。這叫做引用一個指針。

另一個運算符 &,叫做取地址運算符,它將返回一個變量、數組或函數的存儲地址。因此,下面的例子:

int i, *pi; /* int and pointer to int */
pi = &i;

i*pi 在程序中可以相互替換使用,直到 pi 被改變成指向另一個變量的地址。

當指針指向結構體時,可以使用運算符 -> 代替 *和. 的作用,如 (*p).mp->m 等效。

字符串

[編輯]

C語言的字符串其實就是char型數組,所以使用字符串並不需要引用庫。然而C標準庫確實包含了用於對字符串進行操作的函數,使得它們看起來就像字符串而不是陣列。使用這些函數需要引用標頭檔string.h

文件輸入/輸出

[編輯]

在C語言中,輸入和輸出是經由標準函式庫中的一組函數來實現的。在ANSI/ISO C中,這些函數被定義在標頭檔stdio.h中。

標準輸入/輸出

[編輯]

有三個標準輸入/輸出是標準I/O庫預先定義的:

  • stdin:標準輸入
  • stdout:標準輸出
  • stderr:標準錯誤輸出

下面的這個例子顯示了一個過濾程式(filter program)是怎樣構成的。

#include <stdio.h>

int main(int argc, const char * argv[])
{
    char c;
    while ((c=getchar())!=EOF)
        putchar(c);
    perror("getchar() got EOF");
    return -1;
}

函數

[編輯]

C語言的基本結構單位是函數[2],就像是Fortran中的子程序和函數[4][2]。C語言的一個函數由返回值、函數名、參數列表和函數體組成。函數體的語法和其它的複合的語句部分是一樣的。C函數可以是庫中自帶的函數,也可以是用戶定義的函數,且不允許函數嵌套定義。

在一個C語言編寫的程序開始運行時,系統首先調用 main函數(主函數),從此處開始執行。通過函數的嵌套調用,再調用其他函數。函數通常會返回一個值給調用程序的殼層,表明程序是否成功運行。

保留關鍵字

[編輯]

以下是ANSI/ISO C標準中定義的C語言的保留關鍵字:[5]

char short int unsigned
long float double struct
union void enum signed
const volatile typedef auto
register static extern break
case continue default do
else for goto if
return switch while sizeof

C99標準新增了以下關鍵字:

_Bool _Complex _Imaginary inline restrict

C11標準新增了以下關鍵字:

_Alignas _Alignof _Atomic _Generic _Noreturn
_Static_assert _Thread_local

注釋

[編輯]
  1. ^ C 的聲明使用這種「解方程」的形式,於是便出現了多種複雜的聲明。https://cdecl.org 是一個基於網頁的實用「翻譯工具」。

參考文獻

[編輯]
  1. ^ ISO/IEC JTC1/SC22/WG14 - C. [2022-04-02]. (原始內容存檔於2018-02-12) (英語). 
  2. ^ 2.0 2.1 2.2 2.3 2.4 2.5 ISO/IEC 9899:2018 (PDF). [2020-06-10]. (原始內容存檔 (PDF)於2020-07-22). 
  3. ^ ISO/IEC 9899:2011. International Organization for Standardization. [2020-03-08]. (原始內容存檔於2020-03-28) (英語). §6.7.9 Initialization 21 If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, or fewer characters in a string literal used to initialize an array of known size than there are elements in the array, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration. 
  4. ^ Dennis M. Ritchie,Brian W. Kernighan. C程序设计语言. 北京: 機械工業出版社. 2004年1月 [2020-06-10]. ISBN 9787111128069 (中文). 
  5. ^ ISO/IEC 9899:2011. International Organization for Standardization. [2020-03-08]. (原始內容存檔於2020-03-28) (英語).