一個 C 語言程式長得如下的範例:

/*
 * 註解
 */
#include <stdio.h>
int x;
int main() {
    int y; // main裡的y
    x = 1;
    y=foo(x); // 這裡的y是main裡的y
    printf("I have done\n");
    return 0;
}
int foo(int z) {
    int y; // foo裡的y
    return z;
}

C 語言是由一個以上的函數所組成的,函數的名稱只能宣告一次,其中有個特別的函數叫做 main,是 C 程式開始執行的地方。以 /* 註解 */ 括起來的部分,以及 // 後面直到行尾的部分是註解,所謂註解是指該部分只是給人看的,並不會影響 Compiler 的編譯結果。原始程式碼由 # 號開頭的部分,是交由前置處理器來處理;#include 這個前置處理器命令,是把 Source code file 和其後的 Header file 合成為另一個修改過的 Source code file。換言之,#include <stdio.h> 其功能就好比我們用文字處理器將系統目錄內的 stdio.h 檔案插入到 #include 的位置上。

C 語言並不要求一定要引入 stdio.h,此範例要寫 #include <stdio.h> 的原因在於程式內使用了 printf 函數,這個函數是存在於系統程式庫內,為了讓 Compiler 了解 printf 是在別的地方定義的,因此要將宣告 printf 長相的 stdio.h 包含進來。

有時候你會看到

#include "my.h"

#include 後面的檔名可用 <>""括起來,其差別在於 <> 表示系統的引入檔,在 UNIX 的 gcc 會去目錄 /usr/include 下面找,""則表示使用者的引入檔,preprocessor 會在和這個 .c 一樣的目錄下尋找。為甚麼要分 <>""這兩種呢?硬碟上的空間被分成很多樹狀的目錄,不同的目錄下可以存在同名的目錄,這就像每個系每個年級都有 26 號同學,要區分這些 26 號同學,我們得說 『資管大一 26 號』或『跟我在同一個房間內的 26 號』. #include <26 號> 就像說 『資管大一 26 號』,#include "26 號" 則像『跟我在同一個房間內的 26 號』。

第二行的

int x;

是宣告全域 (global) 變數 x 的型態為 int(整數)。合法的變數名稱是由英文字母或底線開頭,後面可加上不定長的文數字和底線,如 _x123。所謂變數宣告是要求 compiler 在某個記憶體上配置足夠容納該型態的空間,對 C 語言來說,int 型態比較複雜一點,其大小在不同的平台上可能不同,但以目前 32 bits 的機器而言,int 一般為 4 個 bytes 大小,因此 int x;這個指令,是要 compiler 在某塊記憶體上 (對程式設計師而言不用管實際上在哪裡) 分配 4 個 bytes 準備放資料,而這 4 個 bytes 的記憶體我們在程式內就以 x 這個符號來代表他。凡是宣告在函數之外的變數,都可稱為全域變數。

函數的宣告包含幾個部分:傳回值、函數名稱、() 內的參數列、以及 {} 內的程式碼。

int main() {}

表示 main 這個函數不需要參數,其傳回值的型態為 int

每一個函數寫作的開始和結束點,是由 {} 來表達。函數可以有多行的敘述 (statement)。每一個敘述由分號 ; 或右大括弧 } 結尾。敘述分成兩大類,第一類是變數宣告,第二類是運算指令,運算指令可以是運算式或流程控制敘述。敘述只能寫在函數裡面,不像變數可以宣告在函數外面成為全域變數。C 語言要求運算指令內所用到的變數必須在該運算指令前宣告。變數宣告的寫法為

型態名稱 變數名稱 ;

C 語言的合法型態名稱及意義請參見型別的詳細說明。

int y;

要 compiler 準備 4 個 bytes 的空間,以存放 int,並將該空間以 y 這個符號代表。

x = 1;

表示將整數 1 複製到 x 所代表的記憶體。此處的 x 指的是宣告在 main 函數之前的 x

y=foo(x);

表示將整數 x 的值複製到堆疊上,CALL foo,然後將傳回值 (可能是放在暫存器或某塊記憶體上面) 複製到整數 y。詳情見函數與遞迴

return 0;

表示將整數 0 回傳給呼叫 main 的函數。是誰呼叫 main 呢? 這就由作業系統負責了,此處不做詳述。

int foo(int z){}

宣告呼叫 foo 這個函數時,需要傳入一個 int 當參數 (事實上此 int 是放在稱為 Stack 的某塊記憶體上),這個在堆疊上的變數我們稱之為 z。

int y;

在堆疊上產生新的變數 y,此 ymain 裡面宣告的 y 是完全不同的變數。

return z;

表示將整數 z 記憶體的內容複製到暫存器上,然後以此數值當做 foo 函數的傳回值。

如果一個變數定義在函數的外面 (如範例裡的 x),則此變數稱為 global variable(全域變數)。全域變數的可見範圍 (意思是哪些函數) 是程式內的所有函數 (前面有 static, extern 等修飾字的情況於後面的章節再討論);其存在期間從該程式執行就存在,程式結束該變數才會消失。

如果變數是定義在函數裡面 (如範例裡的 y),則此變數稱為 local variable(區域變數) 或 auto variable(自動變數)。區域變數的可見範圍僅侷限於定義該變數的函數;其存在期間則是開始於該函數被呼叫時,結束於該函數 return 時。換言之,如果 foo() 被呼叫了兩次,則 foo 裡宣告的 y 就會產生兩次。在 C 語言的執行環境下,區域變數會存放在堆疊上。

寫作程式時,需注意以下風格:

  • 程式開頭應加註解,說明用途,建立時間,修改時間與內容,作者,使用工具
  • 函數的開頭也應對此函數註解說明
  • 見到 {應內縮四個空格,以讓程式容易閱讀
  • 每一敘述應獨立一行,也就是說看到;{應該換行

以下是寫作的範例

/* 
 * Program Name: h2.c
 * Subject: "Introduction to Programming" Homework for practice of loop and I/O.
 * Since 1997/10/27
 * 2004/03/03, add more comment
 * 2008/09/28, correct comments typing error
 * ToolKit: gcc
 * Author: Shiuh-Sheng Yu
 *         Dept. of Information Management
 *         National ChiNan University
 */
#include <stdio.h>

/**
 * print out rectangle
 * @param size length of the rectangle
 */
void print_rectangle(int size) {
    int i, j;
    for (i = 1; i <= size; i++) {
        for (j = 1;  j <=  size; j++) {
            printf("*");
        }
        printf("\n");
    }
}

/**
 * Read size from keyboard as long as the size is between 1 and 40,
 * then call print_rectangel to print on screen
 */
int main() {
    int size = 0;
    while (scanf("%d",&size) > 0 && size > 0 && size < =  40) {
        print_rectangle(size);
    }
}

常用的 IO 函數

C 語言沒有定義標準函數庫 (Library), 但因為 IO 是撰寫程式幾乎一定要用到的功能, 因此我們在此說明不同平台上都會提供的 printfscanf 函數, 以方便讀者寫作程式。這兩個函數或許在不同平台上的某些特殊用法會有點小出入, 但大致上是相同的。

最簡單的 printf 用法如下:

printf("Hello World.\n");

這會在標準輸出裝置 (內定是螢幕) 上印出 Hello World。然後換行 '\n' 表示換行字元。如果我們要印出變數的內容,可以使用如下的形式

#include <stdio.h>
int main() {
    int varInt = 0;
    long varLong = 0;
    float varFloat = 2;
    double varDouble = 0;
    char varChar = 'A';
    char *varString = "Hello";
    printf("varInt=%d, varLong=%ld, varFloat=%f, varDouble=%lf, varChar=%c, varString=%s\n",varInt, varLong, varFloat, varDouble, varChar, varString);
}

printf 的第一個參數是一個字串,字串內以 % 開頭的符號有特別意義,表示此部份要用後面的參數取代。%d%i 以十進位數字表示 int, %x 以十六進位表示 int,%f 表示浮點數 (float or double),%c 表示字元,%s 表示字串,%% 表示 %%3d 表示最少 3 個數字靠右不足 3 個填空白,%-3d 表示最少 3 個數字靠左不足 3 個填空白,%03d 表示最少 3 個數字靠右不足 3 個填 0。如果要印出 % 號的話怎麼辦,那就用 %% 來代表了。printf 相關參數如下

  • %d %i 十進位整數
  • %u unsigned 十進位整數
  • %x unsigned 16 進位整數,小寫表示 (a-f)
  • %X unsigned 16 進位整數,大寫表示 (A-F)
  • %o unsigned 8 進位整數
  • 以上加 - 和數字表示左對齊最少幾位,如 %-9d 表示左切齊最少印 9 位
  • 以上加 + 和數字表示右對齊最少幾位,如 %+9d 表示右切齊最少印 9 位,不足處補空白
  • 以上加 + 和 0 開頭的數字表示右對齊最少幾位,不足補 0,如 %+09d 表示右切齊最少印 9 位,不足處補 0
  • %ld 以十進位印出 long
  • %lld 以十進位印出 long long
  • %f 浮點數 float
  • %e %E 科學表示法浮點數 double, %e 小寫 %E 大寫
  • %g %G 依照 double 的數值自動選擇以 %f 或 %e 格式印出
  • 以上加 - 和具有小數點的數字表示左對齊最少幾位,如 %-9.2f 表示左切齊最少印 9 位,其中小數點以下 2 位
  • 以上加 + 和具有小數點的數字表示右對齊最少幾位,如 %=9.2f 表示右切齊最少印 9 位,其中小數點以下 2 位
  • %c unsigned char
  • %s string(array of char terminated by 0)
  • %p pointer to void
  • %% 印出 %

printf() 傳回整數,代表輸出的字元數

scanf 用來做輸入,其參數和 printf 很類似,但要記得

  • int 用 %i%d
  • unsigned 用 %u
  • float 用 %f
  • double 用 %lf
  • long 用 %ld
  • long long 用 %lld
  • short 用 %hd

scanf() 傳回整數,代表有幾個成功讀入。

#include <stdio.h>
int main() {
    int varInt;
    long varLong;
    float varFloat;
    double varDouble;
    scanf("%d%l%f%lf", &varInt, &varLong, &varFloat, &varDouble);
}

results matching ""

    No results matching ""