Can you summarize the following document?
        
  

  C語言最早由丹尼斯·裡奇(Dennis Ritchie)為了在PDP-11電腦上執行的Unix系統所設計出來的程式語言,第一次發展在1969年到1973年之間。  C源於BCPL語言,後者由馬丁·理察德(Martin Richards)於1967年左右設計實現。BCPL是一門"無型別"的程式語言:它僅能操作一種資料型別,即機器字(machine word)。1970年,肯·湯普遜為執行在PDP-7上的首個Unix系統設計了一個精簡版的BCPL,這個語言被稱為B語言,它也是無型別的。  Unix最早執行在PDP-7上,是以組合語言寫成。在PDP-11出現後,丹尼斯·裡奇與肯·湯普遜著手將Unix移植到PDP-11上,無型別的語言在PDP-11上愈發顯得不合適。PDP-11提供了多種不同規格大小的基本物件:一位元組長的字元,兩位元組長的整型數以及四位元組長的浮點數。B語言無法處理這些不同規格大小的物件,也沒有提供單獨的操作符去操作它們。  C語言最初嘗試通過向B語言中增加資料型別的想法來處理那些不同型別的資料。和大多數語言一樣,在C中,每個物件都有一個型別以及一個值;型別決定了可用於值的操作的含義,以及物件佔用的儲存空間大小。  1973年,Unix作業系統的核心正式用C語言改寫,這是C語言第一次應用在作業系統的核心編寫上。  1975年C語言開始移植到其他機器上使用。史蒂芬·強生實現了一套「可移植編譯器」,這套編譯器修改起來相對容易,並且可以為不同的機器生成程式碼。從那時起,C在大多數計算機上被使用,從最小的微型計算機到與CRAY-2超級計算機。C語言很規範,即使沒有一份正式的標準,你也可以寫出C程式,這些程式無須修改就可以執行在任何支援C語言和最小執行時環境的計算機上。  C最初在小型機器上實現,並且繼承了一系列小語種程式語言的特點;與功能相比,C的設計者更傾向於簡單和優雅。此外,從一開始,C語言就是為系統級程式設計而設計,程式的執行效率至關重要,因此,C語言與真實機器能力的良好匹配也就不足為奇。例如,C語言為典型硬體所直接支援的物件:字元,整數(也許有多種大小),以及浮點數(同樣可能有多種大小)提供了相應的基本資料型別。

  1978年,丹尼斯·裡奇和布萊恩·柯林漢合作出版了《C程式設計語言》的第一版。書中介紹的C語言標準也被C語言程式設計師稱作“K&R C”(柯里C),第二版的書中也包含了一些ANSI C的標準。  K&R C主要引入了以下語言特性:  即使在後來ANSI C標準被提出的許多年後,K&R C仍然是許多編譯器的最低標準要求,許多老舊的編譯仍然執行K&R C的標準。

  1989年,C語言被美國國家標準協會(ANSI)標準化,編號為ANSI X3.159-1989。這個版本又稱為C89。標準化的一個目的是擴充套件K&R C,增加了一些新特性。  1990年,國際標準化組織(ISO)成立 ISO/IEC JTC1/SC22/WG14 工作組,來規定國際標準的C語言,通過對ANSI標準的少量修改,最終制定了 ISO 9899:1990,又稱為C90。隨後,ANSI亦接受國際標準C,並不再發展新的C標準。  K&R C語言到ANSI/ISO標準C語言的改進包括:  WG14工作小組之後又於1994年,對1985年頒佈的標準做了兩處技術修訂(缺陷修復)和一個補充(擴充套件)。下面是 1994 年做出的所有修改:

  在ANSI的標準確立後,C語言的規範在一段時間內沒有大的變動,然而C++在自己的標準化建立過程中繼續發展壯大。《標準修正案一》在1994年為C語言建立了一個新標準,但是隻修正了一些C89標準中的細節和增加更多更廣的國際字符集支援。不過,這個標準引出了1999年的發表。它通常被稱為C99。C99被ANSI於2000年3月採用。  在C99中包括的特性有:  用於x86架構的GCC,Clang和其它一些商業編譯器(如IAR System,ICC)現支援C99的全部特性,而微軟和Borland支援C99的部分特性。

  2011年12月8日,ISO正式釋出了新的C語言的新標準C11,之前被稱為C1X,官方名稱為ISO/IEC 9899:2011。新的標準提高了對C++的相容性,並增加了一些新的特性。這些新特性包括泛型、多執行緒、帶邊界檢查的函式、匿名結構等。

  C18沒有引入新的語言特性,只對C11進行了補充和修正。

  C2x引入了一些新特性,但目前還沒有到凍結特性階段。目前可以確定的是,C2x標準將加入符合IEEE標準的十進位制浮點數,這使得計算機能夠精確地儲存浮點數。

  

  下面是一個在標準輸出裝置(stdout)上列印出 "Hello, world!" 字串的簡單程式。類似的程式,通常作為初學程式語言時的第一個程式:  int main(void)  其中只有int,main,return為C語言的關鍵字,而以"#"開頭的語句為前處理器所負責的部分,即預處理部分。printf為stdio.h所提供的函式。  printf函式中的"\n"是一個轉義字元,形式為"\"加上一個字元。所起的作用在ASCII碼中規定。  關於printf的更多細節,參見printf;  關於格式化字串的更多資訊,參見格式化字串

  C語言由函式和變數組成,C的函式就像是Fortran中的子程式和函式。  在C語言中,程式從 codice_12 開始執行。codice_12 函式通過呼叫和控制其他函式進行工作。例如上面的codice_14。程式設計師可以自己寫函式,或從庫中呼叫函式。在上面的codice_15 使得 codice_12 返回一個值給呼叫程式的殼層,表明程式是否成功執行。  一個C語言的函式由返回值、函式名、引數列表和函式體組成。函式體的語法和其它的複合的語句部分是一樣的。

  C語言中的複合語句(或稱語句塊)的格式為: 複合語句可以使得幾個語句從文法上變成一個語句。  有時必須使用複合語句,否則會產生錯誤。例如,在運用迴圈語句的時候,如果迴圈體(即迴圈中執行部分)包含多個語句(以分號隔開),則必須使用花括號將他們合併成一個複合語句。如果不這麼做,系統僅把第一個分號前的內容看做迴圈體。  需要注意的是,部分C編譯器並不支援在任意位置使用複合語句。

  C語言有兩種條件語句形式,分別是if和switch。  If 的格式如下: if(運算式) // 如果 // 有時還會有 else: else // 否則 運算式的值非零表示條件為真;如果條件為假,程式將跳過if處的語句,直接執行if後面的語句。但是如果if後面有else,則當條件為假時,程式跳到else處執行。if和else後面的語句可以是另個if語句,這種套疊式的結構,允許更復雜的邏輯控制流程得以實現。在一般情況下,else一定與最接近的if成對,因此常用括號{}越過此限制。比較下面兩種情況: if(邏輯表達) if(邏輯表示式甲) else  要注意這裡的縮排和換行只用於方便閱讀。編譯器並不會根據縮排層級猜測 if 和 else 的對應關係。  switch通常用於對幾種有明確值的條件進行控制。它要求的條件值通常是整數或字元。與switch搭配的條件轉移是case。使用case後面的標值,控制程式將跳到滿足條件的case處一直往下執行,直到語句結束或遇到break。通常可以使用default把其他例外的情況包含進去。如果switch語句中的條件不成立,控制程式將跳到default處執行;如果省略default子句,則直接執行下一語句。switch是可以巢狀的。 switch(值)  簡單的條件判斷也可用?: 運算式?值1:值2; 如:

  C語言有三種形式的迴圈語句:  do while(判斷式);  和:  while(判斷式)  和:  for(起始化;判斷式;運算式) 在while和for中,語句將執行到表示式的值為零時結束。在do...while語句中,迴圈將至少被執行一次。這三種迴圈結構可以互相轉化:  for(起始化;判斷式;運算式) 如果語句中不使用continue語句的話,相當於  起始化; while (判斷式) {  當迴圈條件一直為真時,將產生無窮迴圈。

  跳轉語句包括四種:goto,continue,break和return。 goto 標記; goto語句是無條件轉移語句,且標記必須在當前函式中定義,使用“標記:”的格式定義。程式將跳到標記處繼續執行。由於goto(特別是向回 goto 和長距離的 goto)容易產生閱讀上的困難,所以對新手應該儘量少用。GCC 編譯器拓展支援對指標 goto和巨集內 goto,一定程度上增強了 goto 的可讀性。 continue語句用在迴圈語句中,作用是結束當前一輪的迴圈,馬上開始下一輪迴圈。  break語句用在迴圈語句或switch中,作用是結束當前迴圈,跳到迴圈體外繼續執行。但是使用break只能跳出一層迴圈。在要跳出多重迴圈時,可以使用goto使得程式更為簡潔。  當一個函式執行結束後要返回一個值時,使用return。return可以跟一個運算式或變數。如果return後面沒有值,將執行不返回值。

  比較特別的是,位元右移(»)運運算元可以是"算術"(左端補最高有效位)或是"邏輯"(左端補 0)位移。例如,將 11100011 右移 3 位元,算術右移後成為 11111100,邏輯右移則為 00011100。因算術位元右移較適於處理帶負號整數,所以幾乎所有的編譯器都是算術位元右移。  運算子的優先順序從高到低大致是:單目運算子、算術運算子、關係運算子、邏輯運算子、條件運算子、賦值運算子(=)和逗號運算子。

  見資料型別 (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] = ; // 陣列套陣列 char lexicon [10000] [300];/* 共一萬個最大長度為300的字元陣列。*/ int a[3][4];  上面最後一個例子建立了一個陣列,但也可以把它看成是一個多維陣列。注意陣列的下標從0開始。這個陣列的結構如下:  例子中notfull建立了一個3*3的二維陣列,初始化時有些元素並未賦值。如下: 根據C標準的規定,在存在初始化列表時,如果初始化列表中未提供對所有元素的初始化,則剩餘元素會被預設初始化,並使用與靜態變數相同的初始化規則。

  如果一個變數宣告時在前面使用 * 號,表明這是個指標型變數。換句話說,該變數儲存一個地址,而 *(此處特指單目運算子 *,下同。C語言中另有雙目運算子 * 表示乘) 則是取內容操作符,意思是取這個記憶體地址裡儲存的內容。把這兩點結合在一起,可將 codice_17看作是 “*a 解得的內容型別為 int”,對更復雜的宣告也如此。指標是 C 語言區別於其他同時代高階語言的主要特徵之一。  指標不僅可以是變數的地址,還可以是陣列、陣列元素、函式的地址。通過指標作為形式引數可以在函式的呼叫過程得到一個以上的返回值(不同於codice_18這樣的僅能得到一個返回值。  指標是一把雙刃劍,許多操作可以通過指標自然的表達,但是不正確的或者過分的使用指標又會給程式帶來大量潛在的錯誤。  例如:  int *pi; // 指向整型資料的指標 pi int * api[3];// 由指向整型資料的指標構成的陣列,長度為 3 char ** argv;// 指向一個字元指標的指標 struct { int member; } stinst, // pst是一個指向一個匿名結構體的指標  儲存在指標中的地址所指向的數值在程式中可以由 * 讀取。例如,在第一個例子中, *pi 是一個整型資料。這叫做引用一個指標。  另一個運算子 &,叫做取地址運算子,它將返回一個變數、陣列或函式的儲存地址。因此,下面的例子:  int i, *pi; /* int and pointer to int */ pi = &i;  i 和 *pi 在程式中可以相互替換使用,直到 pi 被改變成指向另一個變數的地址。  當指標指向結構體時,可以使用運算子 -> 代替 *和. 的作用,如 (*p).m 與 p->m 等效。

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

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

  有三個標準輸入/輸出是標準I/O庫預先定義的:  下面的這個例子顯示了一個過濾程式(filter program)是怎樣構成的。  int main(int argc, const char * argv[])

  C語言的基本結構單位是函式。系統首先呼叫 main函式(主函式),通過函式的巢狀呼叫,再呼叫其他函式。函式可以是系統自帶的函式,也可以是使用者定義的函式。C語言中,不允許函式巢狀定義。

  C語言的特色之一是:程式設計師必須親自處理記憶體的分配細節。  大多數C語言實現使用棧(Stack)來儲存函式返回地址/棧幀基址、完成函式的引數傳遞和函式區域性變數的儲存。然而,在部分極特殊的平臺上,使用棧並不能獲得最大效率。此時的實現由編譯器決定。 如果程式需要在執行的過程中動態分配記憶體,可以利用堆(Heap)來實現。  基本上C程式的元素儲存在記憶體的時候有3種分配策略:  如果一個變數宣告為全域性變數或者是函式的靜態變數,這個變數的儲存將使用靜態分配方式。靜態分配的記憶體一般會被編譯器放在資料段或程式碼段來儲存,具體取決於實現。這樣做的前提是,在編譯時就必須確定變數的大小。 以IA32的x86平臺及gcc編譯器為例,全域性及靜態變數放在資料段的低端;全域性及靜態常量放在程式碼段的高階。  函式的自動區域性變數應該隨著函式的返回會自動釋放(失效),這個要求在一般的體系中都是利用棧(Stack)來滿足的。相比於靜態分配,這時候,就不必絕對要求這個變數在編譯時就必須確定變數的大小,執行時才決定也不遲,但是C89仍然要求在編譯時就要確定,而C99放鬆了這個限制。但無論是C89還是C99,都不允許一個已經分配的自動變數執行時改變大小。  所以說C函式永遠不應該返回一個區域性變數的地址。  要指出的是,自動分配也屬於動態分配,甚至可以用alloca函式來像分配堆(Heap)一樣進行分配,而且釋放是自動的。  還有一種更加特殊的情況,變數的大小在執行時有可能改變,或者雖然單個變數大小不變,變數的數目卻有很大彈性,不能靜態分配或者自動分配,這時候可以使用堆(Heap)來滿足要求。ANSI C定義的堆操作函式是malloc、calloc、realloc和free。  使用堆(Heap)記憶體將帶來額外的開銷和風險。

  C語言的特色之一是:語言不負責記憶體邊界檢查,這是因為在執行時進行記憶體邊界檢查會造成效能問題,與UNIX哲學不符。此特性容易導致緩衝區溢位問題。然而,部分編譯器會出於安全性的考量,提供方法以進行執行時記憶體邊界檢查。

  C語言的標準文件要求了一個平臺移植C語言的時候至少要實現的一些功能和封裝的集合,稱為“標準庫”,標準庫的宣告頭部通過前處理器命令#include進行引用。  在C89標準中:  在94年的修正版中 在C99中增加了六個函式庫 以上是C語言的標準。各個系統各自又對C庫函式進行的各種擴充,就浩如煙海了。如POSIX C、GNU C等。

  工具軟體可以幫助程式設計者避免一些程式中潛藏或容易出現的問題,例如常會造成程式未預期動作或是執行期錯誤的程式碼。  許多語言都有自動原始碼檢查及審計工具,C語言也有類似工具,像是Lint。可以在程式剛寫好時用Lint找出可能有問題的程式,通過Lint後再用C編譯器進行編譯,許多編譯器也可以設定是否要針對一些可能有問題的程式碼提出警告。MISRA C是一套針對嵌入式系統的法則,可主要也是避免一些可能有問題的程式碼。  也有一些編譯器、程式庫或作業系統可以處理一些非標準C語言的功能,例如邊界值檢查、快取溢位偵測、序列化及自動垃圾回收功能。  使用像Valgrind或IBM Rational Purify等軟體工具,或者連結有特別malloc函式的程式庫,有助於找出一些執行期記憶體使用的問題。

  以下是C語言的保留關鍵字:

  “void main()”的用法並不是任何標準制定的。 C語言標準語法是“int main()”,任何實現都必須支援codice_19和codice_20。 在 C++ 標準中,main的標準型態應是int,否則型別是由實現定義的。任何實現都必須支援codice_21和codice_20。
C是一種通用的程式語言,廣泛用於系統軟體與應用軟體的開發。於1969年至1973年間,為了移植與開發UNIX作業系統,由丹尼斯·裡奇與肯·湯普遜,以B語言為基礎,在貝爾實驗室設計、開發出來。