440 likes | 573 Views
第九章 字串. 從電腦外面提供給電腦的資料大部份都屬於文字或數字的字串。對於文字字串您必須有能力處理,包括字串長度、從字串抽取次字串( substring )、兩個字串的連結、從字串搜尋已知字串等等的操作。對於數字字串您必須有能力將它轉換成相對應的數值,包括轉換成整數或浮點數等等的操作。
E N D
第九章 字串 • 從電腦外面提供給電腦的資料大部份都屬於文字或數字的字串。對於文字字串您必須有能力處理,包括字串長度、從字串抽取次字串(substring)、兩個字串的連結、從字串搜尋已知字串等等的操作。對於數字字串您必須有能力將它轉換成相對應的數值,包括轉換成整數或浮點數等等的操作。 • C 語言提供很強的字串(string)的處理,透過 string.h 函式庫您可取得各種功能的函式。C 語言的字串其實是一個字元陣列,只不過必須擁有一個表示結束的空字元('\0')而已。C 語言提供許多有關字串操作的函式,本章只介紹幾個較常用的函式,其餘的請參閱「附錄C:ANSI C 函式」。 正修科技大學計算機中心
9.1 宣告字串 • 字串以字元陣列表示,但必須以空字元('\0')結束,且空字元算字串中的一個有效的字元,例如 "ANSI C" 雖然數一數只有六個字元,但隱含一個空字元,所以儲存字串為七個字元。空字元的 ASCII 碼,其值為 0,一般以逸出順序表示 '\0'。 • 字串的宣告格式如下: • 格式之一: • char 字串變數名稱 [ 字元個數 ] ; • 格式之二: • char *字串指標變數名稱 ; • 宣告時也可給予初值,格式如下: • char 字串變數名稱 [ 字元個數 ] = "字串常數" ; • char *字串指標變數名稱 = "字串常數" ; 正修科技大學計算機中心
char str[12]; /*宣告字串變數str,最多12個字元*/ char ansi[12]="ANSI C"; /*宣告字串變數ansi,最多12個字元*/ /*初值為字串常數"ANSI C"*/ 正修科技大學計算機中心
char *sp; /*宣告字串指標變數sp*/ char *thank="thank you"; /*宣告字串指標變數thank*/ /*初值為字串常數"thank you"*/ 正修科技大學計算機中心
【例題stringpointer】 以字元陣列 ansi 表示字串 "ANSI C",以字元指標變數 thank 表示字 串 "thank you",並輸出。 【說明】 當程式 stringpointer.c 執行 sp=thank 時,字串指標變數 sp 的內含 值為字串指標變數 thank 的內含值,也就是說 sp 與 thank 均指到同一 個字串 "thank you",因此以 printf() 函式使用 %s 字串格式輸 出 sp 時,顯示 "thank you"。 當執行程式 sp=ansi 時,字串指標變數 sp 的內含值為字串陣列變 數 ansi 的位址,也就是說 sp 與 ansi 均指到同一個字串陣 列 "ANSI C",因此以 %s 字串格式輸出 sp 時,顯示 "ANSI C"。 正修科技大學計算機中心
/*********************** stringpointer.c *******************/ #include <stdio.h> int main() { char ansi[12]="ANSI C", ansi2[12]; char *thank="thank you", *sp; int i; printf("字串ansi = \"%s\"\n", ansi); printf("指標變數thank所指的字串 = \"%s\"\n", thank); for (i=0; i<12; i++) ansi2[i]=ansi[i]; printf("將ansi拷貝至ansi2後,字串ansi2 = \"%s\"\n", ansi2); sp=ansi; printf("sp=ansi後,指標變數sp所指的字串 = \"%s\"\n", sp); sp=thank; printf("sp=thank後,指標變數sp所指的字串 = \"%s\"\n", sp); return 0; } 正修科技大學計算機中心
【執行結果】 字串ansi = "ANSI C" 指標變數thank所指的字串 = "thank you" 將ansi拷貝至ansi2後,字串ansi2 = "ANSI C" sp=ansi後,指標變數sp所指的字串 = "ANSI C" sp=thank後,指標變數sp所指的字串 = "thank you" 正修科技大學計算機中心
9.2 字串長度 • 有關字串的操作都有一個共同點,就是引入 string.h 的表頭檔,在這個表頭檔裡宣告並定義字串操作的函式,例如要取得字串的長度,可使用 strlen() 函式,它的呼叫格式如下: • #include <string.h> • size_t strlen(const char *s); • 傳回字串s之長度,不含結束字元 '\0'。 • 函式 strlen() 的傳回值型態為 size_t,是 int 整數型態的別名。關鍵字 const 表示 s 所指的字串是一個常數,不可任意更改,否則系統會發出錯誤訊息。參數 s 為字元指標變數或字元陣列。 正修科技大學計算機中心
【例題strlen】 以字元陣列 ansi 表示字串 "ANSI C",以字元指標變數 thank 表示字 串 "thank you",呼叫 strlen() 函式列出字串長度。 【說明】 程式 strlen.c 呼叫 strlen(),引數為 ansi 字串,即 "ANSI C" 雙引號內之字元,包含空白字元,共 6 個,因此將 6 傳回給變數 ansilength,故 ansilength 的值為 6。其餘類推。 正修科技大學計算機中心
/******************** strlen.c ********************/ #include <stdio.h> #include <string.h> int main() { int ansilength, thanklength, oklength; char ansi[12]="ANSI C"; char *thank="thank you"; ansilength=strlen(ansi); thanklength=strlen(thank); oklength=strlen("OK!"); printf("字串ansi=\"%s\" 長度=%d\n", ansi,ansilength); printf("字串thank=\"%s\" 長度=%d\n", thank,thanklength); printf("字串\"OK!\" 長度=%d\n", oklength); return 0; } 正修科技大學計算機中心
【執行結果】 字串ansi="ANSI C" 長度=6 字串thank="thank you" 長度=9 字串"OK!" 長度=3 正修科技大學計算機中心
9.3 字串連結 • 在 C 語言的函式庫中,有一個 strcat() 函式,用於將來源字串 scr 附加至目的字串 dest 後,並將 dest 之結合字串傳回。它的呼叫格式如下: • #include <string.h> • char *strcat(char *dest, const char *scr); • 傳回來源字串scr附加至目的字串dest後之結合字串。 正修科技大學計算機中心
【例題strcat】 以字元陣列 ansi 表示字串 "ANSI C",以字元陣列 thank 表示字串 "thank you",呼叫 strcat() 函式將 thank 字串附加至 ansi 後端,最後列印出附加後的字串。 【說明】 程式 strcat.c 執行時: sp=strcat(ansi,thank); 將 thank 字串附加至 ansi 字串後面並將附加後的結果傳回給 sp 指標變數。ansi 字串 "ANSI C",thank 字串 "thank you",附加後的字串 ansi 為 "ANSI Cthank you",字元指標變數 sp 指到 ansi。 正修科技大學計算機中心
/******************* strcat.c ******************/ #include <stdio.h> #include <string.h> int main() { char ansi[12]="ANSI C", thank[12]="thank you"; char *sp; printf("字串ansi=\"%s\"\n", ansi); printf("字串thank=\"%s\"\n", thank); sp=strcat(ansi,thank); printf("經過sp=strcat(ansi,thank)後\n"); printf("字串ansi=\"%s\"\n", ansi); printf("字串sp=\"%s\"\n", sp); return 0; } 正修科技大學計算機中心
【執行結果】 字串ansi="ANSI C" 字串thank="thank you" 經過sp=strcat(ansi,thank)後 字串ansi="ANSI Cthank you" 字串sp="ANSI Cthank you" 正修科技大學計算機中心
9.4 字串拷貝 • 在 C 語言的函式庫中,有一個 strcpy() 函式,用於將來源字串 scr 拷貝至目的字串 dest,並將 dest 字串傳回。它的呼叫格式如下: • #include <string.h> • char *strcpy(char *dest, const char *scr); • 由scr字串拷貝至dest。傳回dest。 正修科技大學計算機中心
【例題strcpy】 以字元陣列 ansi 表示字串 "ANSI C",以字元指標變數 thank 表示字 串 "thank you",呼叫 strcpy() 函式將 ansi 拷貝至 ansi2,將 ansi 位址指定給字元指標變數 thank2,最後列印出拷貝後的字串。 【說明】 程式 strcpy.c 呼叫 strcpy(),引數為 ansi2 及 ansi 字串,ansi 字串為 "ANSI C",將 ansi 字串拷貝至 ansi2,並將 ansi2 字串變數的位址傳回給 sp,因此 ansi2 和 sp 均表同一字串。 thank2=(char *)&ansi; 上面的敘述說明 thank2 指標指到 ansi 字串,因為 ansi 是一個字元陣 列,光取得位址並不曉的所指的資料型態,因此強迫轉型為字元型態。 正修科技大學計算機中心
/************************ strcpy.c **********************/ #include <stdio.h> #include <string.h> int main() { char ansi[12]="ANSI C", ansi2[12]; char *thank="thank you", *thank2, *sp; sp=strcpy(ansi2, ansi); printf("字串ansi=\"%s\"\n", ansi); printf("經過sp=strcpy(ansi2,ansi)後\n"); printf("字串ansi2=\"%s\" 字串sp=\"%s\"\n", ansi2,sp); printf("字串thank=\"%s\"\n", thank); thank2=(char *)&ansi; printf("經過thank2=&ansi後,字串thank2=\"%s\"\n",thank2); return 0; } 正修科技大學計算機中心
【執行結果】 字串ansi="ANSI C" 經過sp=strcpy(ansi2,ansi)後 字串ansi2="ANSI C" 字串sp="ANSI C" 字串thank="thank you" 經過thank2=&ansi後,字串thank2="ANSI C" 正修科技大學計算機中心
在 C 語言的函式庫中,另有一個 strncpy() 的函式,用於將來源字串 scr 最多拷貝 maxlen 個字元至目的字串 dest,並傳回 dest 字串。它的呼叫格式如下: #include <string.h> char *strncpy(char *dest, const char *scr, size_t maxlen); 由scr字串最多拷貝maxlen個字元至dest。若scr之長度超過或等於maxlen,則dest將不會以'\0'結束。傳回dest。 正修科技大學計算機中心
【例題strncpy】 以字元陣列 thank 表示字串 "thank you",呼叫 strncpy() 函式只拷貝最前面五個字元至 thank2,最後列印出拷貝後的字串。 【說明】 程式 strncpy.c 呼叫 strncpy(),引數為 thank2、thank 字串及符號常 數 N,其值為 5。thank 字串為 "thank you",將 thank 字串拷貝 5 個 字元至 thank2,並將 thank2 位址傳回給字元指標變數 sp,因此 thank2 和 sp 均表同一字串。 原來 thank2 字串並不含任何字元,如今從 thank 字串 "thank you" 拷 貝前五個字元,thankk2 原為十二個字元的陣列,並不含字串結束符號,因此這五個字元並不構成一個字串。 thank2[N]='\0'; 在第 N 個位置,即第五個位置(從0算起),填入字串結束符號 '\0', 經過上面的敘述執行過後,thank2 才算貨真價實的字串。 正修科技大學計算機中心
【程式strncpy.c】 /************************* strncpy.c **********************/ #include <stdio.h> #include <string.h> #define N 5 int main() { char thank[12]="thank you", thank2[12], *sp; printf("字串thank=\"%s\"\n", thank); sp=strncpy(thank2, thank, N); thank2[N]='\0'; printf("經過sp=strncpy(thank2,thank,N)後\n"); printf("字串thank2=\"%s\" 字串cp=\"%s\"\n", thank2,sp); return 0; } 【執行結果】 字串thank="thank you" 經過sp=strncpy(thank2,thank,N)後 字串thank2="thank" 字串cp="thank" 正修科技大學計算機中心
9.5 字串比較 • 在 C 語言的函式庫中,有一個 strcmp() 函式,用於比較兩個字串 s1 與 s2。若 s1<s2 則傳回負數(-1),若 s1==s2 則傳回 0 值,若 s1>s2 則傳回正數(+1)。s1 與 s2 字串以無符號字元逐字元比較,直到比完或分出大小為止。它的呼叫格式如下: • #include <string.h> • int strcmp(const char *s1, const char *s2); • 若 s1<s2 則傳回負數。若 s1=s2 則傳回 0 值。 • 若 s1>s2 則傳回正數。s1 與 s2 字串以無符號字元逐 • 字元比較,直到比完或分出大小為止。 正修科技大學計算機中心
【程式strcmp.c】 /********************** strcmp.c *********************/ #include <stdio.h> #include <string.h> int main() { char *s1="ABCDEFGH", *s2="ABC"; printf("字串s1=\"%s\"\n", s1); printf("字串s2=\"%s\"\n", s2); printf("strcmp(s1,s2)=%d\n", strcmp(s1,s2)); printf("strcmp(s2,\"ABB\")=%d\n", strcmp(s2,"ABB")); printf("strcmp(s2,\"ABC\")=%d\n", strcmp(s2,"ABC")); printf("strcmp(s2,\"ABD\")=%d\n", strcmp(s2,"ABD")); return 0; } 【執行結果】 字串s1="ABCDEFGH" 字串s2="ABC" strcmp(s1,s2)=1 strcmp(s2,"ABB")=1 strcmp(s2,"ABC")=0 strcmp(s2,"ABD")=-1 正修科技大學計算機中心
9.6 字串搜尋 • 在 C 語言的函式庫中,有兩個搜尋字元的函式,一個從前面搜尋 strchr(),一個從後面搜尋 strrchr()。它的呼叫格式如下: • #include <string.h> • char *strchr(const char *s, int c); • 傳回s字串中第一個出現c之指標。失敗時傳回NULL。 • #include <string.h> • char *strrchr(const char *s, int c); • 傳回s中最後出現c字元之指標,失敗時傳回NULL。 • 參數 c 為整數型態,如 'A' 表示整數 65,以十六進位表示為 0x41。參數 s 表示字串。傳回找到的字串指標變數。 正修科技大學計算機中心
#include <string.h> char *strstr(const char *s1, const char *s2); 傳回s1中第一次出現s2指標。如s1為"xyzab",s2為"ab",則傳回s1+3。 strstr() 函式提供在長字串中搜尋短字串的功能,其中 s2 為搜尋字串,s1 為被搜尋字串,在 s1 中找到 s2 時傳回字元指標,找不到時傳回 NULL 指標值。 正修科技大學計算機中心
【例題strsearch】 在長字串 longstr 中找尋短字串 shortstr 是否存在。 【說明】 程式 strsearch.c 中,長字串 longstr="Hi Taiwan Tainan Taipei", 共 23 個字元,從 0 算起至 22 為止。 字元變數 ch 之值為 'T',在 longstr 長字串中從頭找尋 'T' 字元,在第 3 個字元找到,並將第 3 個字元指標傳回,因此 sp 字串為 "Taiwan Tainan Taipei"。而 sp 與 longstr 指標值相差為 3,即是該字元的位置。 程式中短字串 shortstr 值為 'Tai',在 longstr 長字串中從頭找尋,在第 3 位置找到。 正修科技大學計算機中心
/********************* strsearch.c *******************/ #include <stdio.h> #include <string.h> int main() { int ch='T'; char *longstr="Hi Taiwan Tainan Taipei", *sp; char *shortstr="Tai", *s5; printf("字串longstr=\"%s\"\n", longstr); printf("字元ch=\'%c\'\n", ch); sp=strchr(longstr,ch); printf("sp=strchr(longstr,ch)後,字串sp=\"%s\"\n",sp); printf("找到的位置(從0算起)=%d\n", sp-longstr); printf("字串shortstr=\"%s\"\n", shortstr); sp=strstr(longstr,shortstr); printf("經過sp=strstr(longstr,shortstr)後\n"); printf("字串sp=\"%s\"\n", sp); printf("找到的位置(從0算起)=%d\n", sp-longstr); return 0; } 正修科技大學計算機中心
【執行結果】 字串longstr="Hi Taiwan Tainan Taipei" 字元ch='T' sp=strchr(longstr,ch)後,字串sp="Taiwan Tainan Taipei" 找到的位置(從0算起)=3 字串shortstr="Tai" 經過sp=strstr(longstr,shortstr)後 字串sp="Taiwan Tainan Taipei" 找到的位置(從0算起)=3 正修科技大學計算機中心
9.7 字串轉換數值 • 數字字串,例如 “19”、“365.25” 等,常為了計算而必須轉換為數值,將 “19” 轉換為整數的 19,將 “365.25” 轉換為浮點數的 365.25,以便計算。 • C 語言函式庫裡提供數個這種轉換的函式,說明如下: • #include <math.h> • double atof(const char *s); • 將s字串轉換並傳回倍精確浮點數。轉換不成功時傳回零值。 • #include <stdlib.h> • int atoi(const char *s); • 將s字串轉換並傳回整數值。轉換不成功時傳回零值。 • #include <stdlib.h> • double strtod(const char *s, char **endptr); • 傳回s字串轉換為浮點數之值,失敗時傳回HUGE_VAL。 • *endptr為傳回的s中終止字元之指標。 • **endptr為傳回的s中之終止字元。 正修科技大學計算機中心
【例題strtodec】 從鍵盤輸入一個字串 s,請在使用 atoi() 函式轉換為數值之前檢查一下所輸入的字串是否全部由數字組成,若是則呼叫 atoi() 轉換,若否則輸出錯誤訊息。 【說明】 程式 strtodec.c 執行時輸入 "1234567890" 至字串 s,然後逐一字元透過 isdigit(s[i]) 函式檢查 s 字串的第 i 個字元是否為數字,程式碼如下: for (i=0; i<strlen(s); i++) { if (isdigit(s[i])==0) { errflag=1; break; } } 若非數字則 isdigit() 函式傳回 0 值,則設 errflag 為 1 後跳出迴圈。最後檢查 errflag 是否為 1,若是則印出錯誤訊息,否則執行下列敘述 i=atoi(s); 並列印出轉換後的整數值。 正修科技大學計算機中心
/****************** strtodec.c *****************/ #include <stdio.h> #include <stdlib.h> int main() { int i, errflag=0; char s[16]; printf("請輸入一個數值字串: "); scanf("%s", &s); for (i=0; i<strlen(s); i++) { if (isdigit(s[i])==0) { errflag=1; break; } } if (errflag==1) printf("所轉換的\"%s\"字串非整數\n", s); else { i=atoi(s); printf("\"%s\" 轉換成 %d\n", s,i); } return 0; } 正修科技大學計算機中心
【執行結果】 請輸入一個數值字串: 1234567890 <Enter> "1234567890" 轉換成 1234567890 請輸入一個數值字串: abc123 <Enter> 所轉換的"abc123" 字串非整數 正修科技大學計算機中心
9.8 從命令列輸入字串 • 在程式測試或應用程式執行時,常常必須從命令列輸入一些資料到程式中,例如必須輸入檔名、日期、或其他的引數(argument),這些輸入的資料均屬於字串,在 main() 函式的參數列加於規範,最常見的情況如下: • main(int argc, char *argv[]) • 主函式 main() 提供兩個參數,一個為整數型態的 argc,表示從命令列輸入的引數個數,第一個引數為執行程式的名稱,如 command。第二個參數為字元指標陣列 argv[],用於儲存從命令列輸入的引數字串,包括執行程式的名稱及實際輸入的引數,都以字串方式儲存。 正修科技大學計算機中心
【例題command】 設計一個程式從命令列輸入年月日為 2006 9 28,將引數的個數及字串輸出。 【程式command.c】 /************* command.c ***************/ #include <stdio.h> int main(int argc, char *argv[]) { int i; printf("argc=%d\n", argc); for (i=0; i<argc; i++) printf("argv[%d]=%s\n", i,argv[i]); return 0; } 正修科技大學計算機中心
【執行】 ch09> command 2006 9 28 <Enter> argc=4 argv[0]=command argv[1]=2006 argv[2]=9 argv[3]=28 正修科技大學計算機中心
9.9 字串應用程式 • 從電腦外部傳到電腦裡頭的資料都是字串,而電腦所處理的很多資料也都屬於字串型態的,後面章節要討論的檔案也經常是本文檔案,本文是字串的別名,由此可見字串對於應用程式的重要性。 正修科技大學計算機中心
【例題quicksort】 某學校主辦考試,準考證號碼及序號如下表。 準考證號碼 序號 ---------------- ------ "23010001" 1 "23030005" 2 "23020007" 3 "23010003" 4 "23020002" 5 "23030004" 6 "23010002" 7 "23020008" 8 請使用 C 系統所提供的 qsort() 函式依準考證號碼字串由小至大排序,請列印排序後的準考證號碼。 正修科技大學計算機中心
【分析】 C 系統所提供的 qsort() 函式定義如下: void qsort(void *array, size_t number, size_t size, int (*comp)(const void *arg1, const void *arg2)); 使用快速排序法排序。array 欲排序陣列第0個元素之位址(指標)。number 欲排序陣列之元素個數。size 欲排序陣列之每一元素所佔記憶體位元組數。*comp 比較大小所使用之函式,其傳回值為整數指標。 有兩個引數 arg1、arg2 分別指到欲排序陣列之元素,依比較結果傳回小於、等於、或大於 0。 程式中定義了兩個整數比較的方法 int comp(),傳回比較的結果,若 引數 *arg1<*arg2 傳回 -1,若相等則傳回 0,若 *arg1>*arg2 則傳 回 +1。 呼叫快速排序 qsort(id,N,10,comp),其中 id 為準考證號碼整數陣列 ,N 為元素個數,其值為 8,每一個元素均為字串,佔 10 個位元組,函式 comp() 為兩個整數比較的方法。排序後仍存回 id 陣列。 正修科技大學計算機中心
【程式quicksort.c】 /********************** quicksort.c **************/ #include <stdio.h> #define N 8 int comp(char *arg1, char *arg2) { return strcmp(arg1, arg2); } int main() { char id[N][10]= {"23010001","23030005", "23020007","23010003", "23020002", "23030004", "23010002","23020008"}; int i; qsort(id,N,10,comp); for (i=0; i<N; i++) printf("\"%s\"\n", id[i]); return 0; } 【執行結果】 "23010001" "23010002" "23010003" "23020002" "23020007" "23020008" "23030004" "23030005" 正修科技大學計算機中心
【例題binarysearch】 下列為英文字與中文名稱的對照表。 英文字 中文名稱 -------------- -------- keyboard 鍵盤 mouse 滑鼠 computer 電腦 display 螢幕 printer 列表機 請呼叫 C 系統提供的 qsort() 函式依英文字排序後輸出,並輸入搜尋英文字 item 後呼叫 C 系統提供的 bsearch() 函式,看看該英文字是否在對照表裡。 正修科技大學計算機中心
【分析】 C 系統提供的 bsearch() 函式如下: #include <stdlib.h> void *bsearch(void *item, void *array, size_t number, size_t size, int (*comp)(void *arg1, void *arg2) ) 在有 number 個元素,每個元素為 size 位元組之陣列 array,以搜尋鍵 item 執行分元搜尋。 找到時傳回首先找到元素之位址,找不到時傳回 NULL 值。 array 陣列必須已經排序過。 comp() 函式傳回值如下: 若 *arg1 < *arg2 傳回負數。 若 *arg1 == *arg2 傳回0。 若 *arg1 > *arg2 傳回正數。 程式 binarysearch.c 中建立一個 N 個字串的陣列 word,每一個字串最 長 LENGTH 個字元,本例題 N 值 5、LENGTH 值 10,元素值如下: "keyboard","mouse","computer","display","printer" 您可以看出它並沒有依照英文字母順序排列,但要呼叫 bsearch() 函式 其先決條件必須陣列裡的元素已經完成排序,因此先呼叫 qsort() 函式 排序後再行呼叫 bsearch() 函式,如本程式作法。 正修科技大學計算機中心
/******************* binarysearch.c *******************/ #include <stdio.h> #include <stdlib.h> #define N 5 #define LENGTH 10 int comp(char *arg1, char *arg2) { return strcmp(arg1,arg2); } int main() { char word[N][LENGTH]={"keyboard","mouse","computer", "display","printer"}; char sk[LENGTH]; int i; qsort(word,N,10,comp); for (i=0; i<N; i++) printf("\"%s\"\n", word[i]); printf("請輸入一個英文字\n(computer,display," "keyboard,mouse,printer):"); scanf("%s", sk); char *cp=(char *)bsearch(sk,word,N,10,comp); if (cp==NULL) printf("\n%s 找不到\n", sk); else printf("\n%s 找到\n", sk); return 0; } 正修科技大學計算機中心
【執行結果】 "computer" "display" "keyboard" "mouse" "printer" 請輸入一個英文字 (computer,display,keyboard,mouse,printer): mouse <Enter> mouse 找到 正修科技大學計算機中心