字串和 <string.h>

在一對雙引號 " 之內可以放任意長度的字元 (包括長度為 0, 也包括跳脫字串),成為一個常數字串。常數字串自動以 NUL 字元結束。 若在宣告 char 型態的序列時,順便以一個常數字串來定義它的值, 則 C 會自動計算那常數字串的字元數 (包括 NUL 字元),而決定該序列的維度。 使用標準外部函式 strlen() (string length) 可以計算字串長度 (不含 NUL 字元)。看以下原始碼:


#include <stdio.h>
#include <string.h>

/* 示範 strlen() 的用法 (test-strlen.c) */
main() {
    char s[] = "hello, world.\n";
    printf("%d:%s", strlen(s), s);
}

輸出的是
14:hello, world.
此時 s[] 的序列維度是 15 (包含 LF 和 NUL), 而字串長度則定義為 14 (包含 LF,不含 NUL)。

我們已經知道,C 不會代為看守序列的維度範圍。 所以您可以將 s[] 序列的編號寫到 15 以後。 例如以下程式,運氣好的時候會正確執行,輸出

19:hello, world! MORE
但是運氣不好意思的時候,會發生不可預期的結果。謹記不要犯這種錯。
#include <stdio.h>
#include <string.h>

/* 錯誤示範,請勿模倣 */
main() {
    char s[] = "hello, world.\n";
    s[12]='!';
    s[13]=' ';
    s[14]='M';
    s[15]='O';
    s[16]='R';
    s[17]='E';
    s[18]='\n';
    s[19]='\0';
    printf("%d:%s", strlen(s), s);
}

前面我們在檔頭部分,多寫了一個 #include <string.h>, 這個指令宣告了一些處理字串的標準外部函式。 前面我們已經看到 strlen() 的用法。 除此之外還有 19 個這類函式。以下再介紹 3 個,其他的函式會在以後陸續出現。

首先介紹 strcpy() (string copy): 它的用法是 strcpy(s, t),其中 st 都是字串, 但 s 必須是宣告了足夠維度的 char 序列變數, 而 t 可以是一個常數字串。 在 strcpy() 執行後,t 不會改變, 而 s 就變成了 t。 所以 strcpy(s,t) 就是將 t copy 到 s 的意思。

以前我們已經知道,下面這個語法是不正確的:

    char s[20];
    s = "hello, world.";
而前面說了,一個方便的例外是,在宣告的時候可以順便定義序列的值,例如
    char s[20]="hello, world.";
卻是可以的。以下程式示範如何用 strcpy() 改變字串的內容。 但要特別注意,s[] 的維度足夠 (還要留一個位置給 NUL)。
#include <stdio.h>
#include <string.h>

/* 示範 strcpy() 的用法 (test-strcpy.c) */
main() {
    char s[20]="hello, world.";
    printf("%s\n", s);
    strcpy(s, "this is a C.");
    printf("%s\n", s);
}

執行的結果應該是
hello, world.
this is a C.

其次介紹 strcat()。它的呼叫格式仍是 strcat(s, t), 其中 st 的意義與 strcpy() 相同, 但執行的結果是將 t 字串銜接到 s 的後面。

最後介紹 strcmp。它的呼叫格式是 strcmp(s, t), 但是此函式不會改變 st 的內容, 只會回應一個整數。若 st 是相同的兩個字串, 回應 0。否則,回應可能是正數,也可能是負數。 若回應正數,代表 s > t, 否則就是 s < t。 而字串的大小,就是按照一般英文字典裡面的排序法, 也就是 UNIX 的 sort 指令的排序法。 譬如 "abort" < "about" 而 "Schumann" > "Schubert"。

注意,因為當 st 相同的時候,回應的數是 0。 所以,若要用在 forwhileif 的條件語句內時, st 相同反而會成為 False。 因此要用 !strcmp(s,t) 來偵測 st 相同的。

習題

  1. 執行以下程式,觀察結果,並猜想為什麼會有這種結果?
    #include <stdio.h>
    #include <string.h>
    
    main() {
        char s[10]="abort", t[10]="about";
        printf("%d\n", strcmp(s,t));
        strcpy(s, "Schumann");
        strcpy(t, "Schubert");
        printf("%d\n", strcmp(s,t));
    }
    
  2. 解釋以下程式在做什麼?
    #include <stdio.h>
    #include <string.h>
    #define BUFSIZE 256 
    int getline(char[], int);
    
    main() {
        char buf[BUFSIZE];
        int n=0;
        while (getline(buf, BUFSIZE) > 0)
    	if(!strcmp(buf, "1234\n"))
    	    ++n;
        printf("%d\n", n);
    }
    
  3. 寫一個程式,將輸入文字做兩行 (two-column) 排列, 兩行之間以一個 HT 隔開。例如輸入是
    105633-36
    106437-03
    106522-03
    106569-01
    106592-03
    
    則輸出變成
    105633-36	106437-03
    106522-03	106569-01
    106592-03
    

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



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

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

shann@math.ncu.edu.tw