跳轉到內容

C 語言入門/C 語言入門程式

來自華夏公益教科書,自由的教學讀物

這是一個簡單的 C 程式,用於計算球體的體積

/* sphere.c */

#include <stdio.h>                  /* Include header file for printf. */

#define PI 3.141592654f             /* Define a constant. */

static float sphere(float);         /* Function prototype. sphere is given internal linkage with the keyword
                                        'static' since it isn't used outside of this translation unit. */

int main(void)                      /* Main function. */
{
	float volume;               /* Define a float variable. */
	float radius = 3;           /* Define and initialize variable. */
	
	volume = sphere(radius);    /* Call sphere and copy the return value into volume. */
	printf( "Volume: %f\n", volume );  /* Print the result. */
	return 0;
}

static float sphere(float rad)             /* Definition of a volume calculating function. */
{ 
	float result;               /* "result" is defined with an automatic storage duration and block scope. */
	
	result = rad * rad * rad;
	result = 4 * PI * result / 3;
	return result;              /* "result" is returned to the function which called sphere. */
}

在這個程式中可以觀察到的第一個特點是註釋用 "/*" 和 "*/" 括起來。註釋幾乎可以放在任何地方,因為編譯器會忽略它們。另一個明顯的特徵是程式中的單個語句以 ";" 結束。忘記 ";" 或在不需要的地方新增 ";" 是常見的 C 程式設計錯誤。程式碼行透過使用花括號 ("{ }") 分組為塊。

C 語言區分大小寫。所有 C 語言關鍵字都小寫。程式變數和函式名稱可以使用任何大小寫,但按照慣例應使用小寫。"常量"(稍後會討論)按照慣例使用大寫。

並非 C 程式中的所有行都是可執行語句。上面顯示的一些語句是 "預處理指令"。

C 語言編譯是一個多階段過程。為了建立一個程式,C 語言編譯器系統會執行以下步驟

  • 它將原始檔文字透過 "C 預處理器"。它所做的只是對原始檔執行各種文字操作,例如 "宏擴充套件"、"常量擴充套件"、"檔案包含" 和 "條件編譯",這些內容將在後面解釋。預處理器的輸出是用於實際編譯的二級原始檔。您可以將 C 預處理器視為一種特殊的自動 "文字編輯器"。
  • 接下來,它將二級原始檔透過編譯器本身,編譯器實際上將原始碼語句轉換為它們的二進位制等價物。也就是說,它從原始檔建立一個 "目標檔案"。
  • 但是,目標檔案仍然無法執行。如果它使用 C 庫函式,例如上面的示例中的 "printf()",則庫函式的二進位制程式碼必須與程式目標檔案合併或 "連結"。此外,需要將一些定址資訊連結到目標檔案,以便它可以在目標系統上載入和執行。

這些連結任務由 "連結器" 執行,連結器將一個或多個目標檔案連結到二進位制庫檔案,以建立一個可以實際執行的 "可執行" 檔案。

C 語言有大量的庫和庫函式。C 語言本身只有很少的語句,因此它的許多功能都是透過庫呼叫實現的。

意圖用於 C 預處理器而不是 C 編譯器本身的命令以 "#" 開頭,被稱為 "預處理指令" 或 "元命令"。上面的示例程式中有兩個這樣的元命令

  #include <stdio.h>

  #define PI 3.14

第一條語句 "#include <stdio.h>" 只是在編譯之前將檔案 "stdio.h" 的內容合併到當前程式檔案中。"stdio.h" 檔案包含使用標準 I/O 庫所需的宣告,該庫提供 "printf()" 函式。

順便說一句,"stdio.h" 檔案或 "標頭檔案" 只包含宣告。庫的實際程式碼包含在單獨的庫檔案中,這些庫檔案在連結時新增。如果需要,可以建立使用自定義宣告載入的自定義標頭檔案,然後如下包含在程式中

   #include "mydefs.h"

尖括號 ("< >") 不用於自定義標頭檔案。它們只用於定義與 C 編譯器一起提供的預設標頭檔案(在 Unix/Linux 系統上,這些檔案位於目錄 "/usr/include" 中)。

C 程式由一個或多個函式組成。上面的程式包含兩個使用者定義的函式 "main()" 和 "sphere()",以及 "printf()" 庫函式。

在編寫獨立程式時,"main()" 函式是必需的。它定義了程式執行時自動執行的函式。所有其他函式將直接或間接由 "main()" 呼叫。

C 函式的呼叫方法是簡單地指定它的名稱,並在後面的括號中包含任何引數,引數之間用逗號分隔。在上面的程式中,"printf()" 函式的呼叫方法如下

   printf( "Volume: %f\n", volume );

此呼叫提供了兩個引數。第一個—"Volume: %f\n"——提供文字和一些格式化資訊。第二個—"volume"——提供一個數值。

函式可以返回也可以不返回值。"sphere()" 函式返回一個值,因此它的呼叫方法如下

   volume = sphere( radius );

函式使用 "return" 關鍵字返回值。在 "sphere" 的情況下,它使用以下語句返回球體的體積

   return result;

C 程式中的所有變數都必須 "宣告",方法是指定它們的名稱和型別。示例程式為 "main" 例程聲明瞭兩個變數

   float volume;
   float radius = 3;

——以及 "sphere" 例程中的一個變數

   float result;

"volume"、"radius" 和 "result" 的宣告指定了一個浮點變數。該宣告允許在需要時在宣告時初始化變數,在本例中,宣告 "radius" 併為其賦值 "3"。

所有這三個宣告都定義了塊級作用域的變數。具有塊級作用域的變數只存在於宣告它們的塊中。可以在不同的塊中宣告同名的變數,而不會相互干擾。還可以宣告具有檔案級作用域的變數,這些變數可以由所有函式共享,方法是在翻譯單元的所有塊之外宣告它們。預設情況下,所有具有檔案級作用域的識別符號都被賦予外部連結。只有使用關鍵字 "static" 才能將識別符號賦予內部連結。像這樣的宣告

extern int a;

將 "a" 識別為一個 int,其儲存在其他地方定義;最好是在另一個翻譯單元中。

   /* global.c */

   #include <stdio.h>

   void somefunc( void );
   int globalvar;

   void main()
   {
     extern int globalvar;
     globalvar = 42;
     somefunc();
     printf( "%d\n", globalvar );
   }

   void somefunc( void )
   {
     extern int globalvar;
     printf( "%d\n", globalvar );
     globalvar = 13;
   }

除了變數宣告之外,上面的示例程式還包含函式宣告或 "函式原型",它允許 C 編譯器對程式中對函式的呼叫進行檢查,並在呼叫不正確時發出錯誤

   float sphere(float);

函式原型宣告函式返回的值的型別(如果它不返回值,則型別將為 "void"),以及要為函式提供的引數。

最後,"printf()" 庫函式為程式提供文字輸出功能。可以使用 "printf()" 函式列印簡單的訊息,如下所示

   printf( "Hello, world!" );

——顯示文字

   Hello, world!

請記住,"printf()" 不會自動新增 "換行符",以允許後續 "printf()" 在下一行顯示中列印。例如

   printf( "Twas bryllig " );
   printf( "and the slithy toves" );

——列印文字

   Twas bryllig and the slithy toves

必須新增換行符 ("\n") 以強制換行。例如

   printf( "Hello,\nworld!" );

——給出

   Hello,
   world!

這些示例只打印預定義的文字常量。可以在字串中包含 "格式程式碼",然後在字串後面加上一個或多個變數,以列印它們包含的值

   printf( " Result = %f\n", result );

這將列印類似的內容

   Result = 0.5

"%f" 是格式程式碼,它告訴 "printf" 列印一個浮點數。舉另一個例子

   printf( "%d times %d = %d\n", a, b, a * b );

——將列印類似的內容

   4 times 10 = 40

"%d" 列印一個整型數量。可以在引數列表中包含數學或字串表示式和函式。

為了簡單地列印一段文字,有一個更簡單的函式 "puts()",它顯示指定的文字並自動追加一個換行符

   puts( "Hello, world!" );

僅僅為了好玩,讓我們看看在 ANSI 之前的 C 語言版本中,我們的示例程式會是什麼樣子

   /* oldspher.c */

   #include <stdio.h>
   #define PI 3.141592654

   float sphere();        /* Parameters not defined in function prototype. */

   main()
   {
     float volume;
     int radius = 3;

     volume = sphere( radius );
     printf( "Volume: %f\n", volume );
   }

   float sphere( rad )
   int rad;               /* Parameter type not specified in function header. */
   { 
     float result;

     result = rad * rad * rad;
     result = 4 * PI * result / 3;
     return result;
   }

以下部分詳細闡述了本節概述的原理。

華夏公益教科書