逗點指令

若干個可以獨立成為指令的語句,可以用逗點相銜接,而形成一個新的指令。 C 會先做左邊的語句,再做右邊的語句。 例如以下這個簡單的程式,會交換 a, b 兩變數的值。


#include <stdio.h>
main() {
    int a=2, b=3;
    a += b, b = a-b, a -= b;
    printf("%d\t%d\n", a, b);
}

以上三句指令之中,
    a += b, b = a-b, a -= b;
等同於三個獨立指令,依序寫開,如下
    a += b;
    b = a-b;
    a -= b;
在這種情形,我們稱那個逗點 , 為逗點指令。

要注意的是,前面那個指令的第一句和第三句裡面的逗點,都不是逗點指令。 因為,在這些逗點的兩邊,不是可以獨立執行的指令。 譬如說,第一句

    int a=2, b=3;
不能寫成
    int a=2;
    b=3;
而第三句裡面的兩個逗點,只是分隔一個函式的參數 (arguments seperation) 而已, 不能被視為逗點指令。

利用這種算法來交換整數值的時候,要注意 a+b 的值不能超過資料型態所能接受的範圍。

逗點指令經常用在 for 迴圈的前置或後置作業裡面。 在此,我們介紹一個程式:reverse()。 一方面,我們練習逗點 , 的用處,另方面,我們欣賞這個程式的寫法。 它的規格是

    void reverse(char[]);
假設呼叫了 reverse(s),則 s 必需是一個字串變數, 而函式結束之後,s 完全反過來排列。 例如,若 s 原來是 "hello, world." 則呼叫 reverse(s) 之後, s 就成了 ".dlrow ,olleh"。
void reverse(char s[]) {
    int i,j,c;

    for (j=0; s[j] != '\0'; ++j) ;
    for (i=0, --j; i<j; ++i, --j) {
	c = s[i];
	s[i] = s[j];
	s[j] = c;
    }
}

此程式中的第一個 for 迴圈,目的在找到這個字串的結尾處。 以
    char s[]="hello, world.";
為例,s[13] 就是 NUL,所以我們要將 s[0]s[12] 之間的字元前後對調,而 s[13] 保留不變。 對調的方法,就是用兩個足標,i 從頭開始 (0)、 j 從尾開始 (12),將 s[i]s[j] 的字元對調, 然後 i 加一、j 減一。 如此一直重複地做,直到 i==ji>j 為止。

如果您想要將逗點指令寫得更淋漓盡致,則可以將 reverse() 的第二個 for 迴圈改寫成一列:

    for (i=0, --j ; i<j ; c=s[i], s[i++]=s[j], s[j--]=c) ;

每當我們寫一個程式,要特別注意它的強軔性。 也就是說,要事先設想可能出錯的狀況。 做這種設想的技巧之一,就是找出輸入資料的極端狀況。 通常一個程式遇到正常的輸入資料時,都沒問題, 因為您就是根據那些資料的假設來設計程式的。 但是遇到極端奇怪、但是卻符合定義、的輸入資料時,就可能出錯。 要找到哪些是極端狀況?並沒有一定的方法。 這時候可能經驗是很重要的。 例如,reverse() 的一種極端狀況,應該是輸入空字串的時候。 也就是說,s[0] == '\0' 的時候。 我們可以檢查,此時

    for (j=0; s[j] != '\0'; ++j) ;
第一次執行 s[j] != '\0' 就得到 False,所以 j 就是 0。因此,
    for (i=0, --j; i<j; ++i, --j) {
的前置語句會使得 j 成為 -1, 因此第一次執行 i<j 就得到 False, 所以根本沒有任何字元被調換。 而 s[] 也就沒有被改變,它還是個空字串。

注意,若 s[] 當中缺少了 NUL, 則 reverse() 當然也可能出錯。 但是,這種輸入資料並不被考慮為極端狀況, 它根本是個錯誤

習題

  1. 以下程式錯在哪裡?
    void reverse(char[]);
    main() {
        char s[] = "hello, world";
        printf("%s\n", reverse(s));
    }
    
  2. 寫一個程式,使得輸入文字檔案的每一列都反過來輸出。 假設輸入文字的每一列都不會超過 256 個字元。 例如輸入是
    This is a book.
    That is a pen.
    
    輸出是
    .koob a si sihT
    .nep a si tahT
    
    在電影「阿瑪迪斯」中,莫札特曾經玩這個遊戲來挑逗一個女生。 注意,不能多輸出、或少輸出一個 LF 符號。
  3. 寫一個函式,規格如下
        void ireverse(int[], int)
    
    使得若 v[] 是一個 int 型態的序列, 則 ireverse(v, 13> 會將 v[] 的前 13 個元素 (v[0]v[12]) 順序反過來。

[ 前一節 ]‧[ 後一節 ]‧[ 回目錄 ]



注意:此處所有文件均為原著,個別的版權宣告日後會一一公布, 整體版面設計亦尚未完成。但仍請勿抄襲文字與圖片,以免觸犯著作權法。

Created: May 14, 2000
Last Revised: May 16, 2000
© Copyright 2000 Wei-Chang Shann 單維彰

shann@math.ncu.edu.tw