C 語言初學教材 - 第三章 處理字串的迴圈

while 迴圈的一個常見的應用,就是進行字元陣列(字串)的處理。如果我們宣告固定大小的字元陣列接受使用者輸入文字,由於我們無法預期使用者實際輸入多少字元,例如可以鍵入一條句子,如 Boys will be boys. 一共有 18 個字元,或是一個單字 hi 兩個字元。所以我們所宣告的字元陣列,大小必須有相當的空間。



這會是一個不確定次數迴圈的應用,我們另以英文句子的結尾句點 '.' 當成停止輸入的警示值。我們提供的範例如下
#include <stdio.h>

int main(void)
{
    char ch;
    char saying[100];
    char *s = saying;
    int i = 0;
    
    printf("請輸入文字,結束請按 . \n");
    while ((ch = getchar()) != '.') { 
        saying[i] = ch;
        i++;
    }
    
    printf("\n\n剛剛輸入的句子是 ");
    while (*s != '\0') {
        putchar(*s);
        s++;
    }
    printf("\n");    
    
    return 0;
}

/* 《程式語言教學誌》的範例程式
    http://pydoing.blogspot.com/
    檔名:we.c
    功能:示範 while 迴圈的典型應用
    作者:張凱慶
    時間:西元2010年7月 */


編譯執行,結果如下



這個例子很簡單,就是要求使用者輸入一段文字,而且是以字元的方式輸入,第 11 行
while ((ch = getchar()) != '.') { 


函數 getchar() 標準函數庫 stdio.h 用來取得輸入字元的函數,這個函數不需要用到參數,回傳值就是得到的字元。因此在這個 while 迴圈的結束條件就是用小括弧圍起來的 ch = getchar() 先被執行,得到的字元被儲存在變數 ch 後, ch 再跟字元 '.' 進行相等性測試,若是不相等, while 迴圈就會繼續執行。


我們用字元 '.' 作為迴圈結束的警示值,一旦發現使用者輸入英文句點,也就代表這個句子結束了。由於我們不知道使用者何時輸入結束,可是通常句點為句子的結束,所以我們將句點當作迴圈結束的警示值。


利用指標操作字元陣列(字串)是很常見的寫法,第 17 行到第 20 行
while (*s != '\0') {
    putchar(*s);
    s++;
}


陣列宣告後,沒有被給值的元素會被塞進字元 '\0' ,這個字元在 ASCII 表示空字元,就是什麼都沒有的意思。因此我們可以用 '\0' 當成有儲存資料的字元陣列,內容結束的警示值。注意,這裡的變數 s 為第 7 行宣告的指標,同時被指派字元陣列 saying ,意思就是把 saying 指向的位址給 s
char *s = saying;


會這麼做是因為陣列名稱等同指標沒錯,就把陣列名稱當作是指標來看也沒關係,但是陣列名稱不能如指標變數一樣做算術運算。因此我們要用指標的方式操作陣列元素的話,就必須另外宣告一個指標變數來進行處理。


第 7 行的星號是宣告指標用的運算子,第 17 行的星號則是取值運算子,或稱反參考運算子,因為指標儲存的是某個變數的記憶體位址,若要由該變數的記憶體位址反參考該變數的值,就必須用取值運算子。下圖說明這個關係



用取值運算子才能取得指標指向變數的值,所以接下來在 stdio.h 的輸出字元函數 putchar() ,也須以 *s 當作參數。


問題與討論
  1. 我們用 '.' 作為結束輸入的警示值,如果我們在句子結束仍是希望加入 '.' ,這該怎麼做呢?
  2. 函數 scanf() 不是也可以輸入字元嗎?為什麼要有另外一個專門輸入字元的函數 getchar() ?
  3. 函數 printff() 不是也可以印出字元嗎?為什麼要有另外一個專門輸出字元的函數 putchar() ?
  4. 說明取值運算子的運作方式。
  5. 為什麼要另外宣告指標變數操作字元陣列?
  6. 有哪些運算子都用到星號,想一想,為什麼可以用相同符號當不同功能的運算子?




沒有留言: