2018年5月30日 星期三

C 語言學習筆記 : 字串函數測試

C 語言的字串處理需匯入 string.h 函式庫, 其中常用的函式如下 :

 函數 說明
 strlen(str) 傳回字串 str 的長度 (字元個數)
 strrev(str) 將字串 str 反轉後傳回新字串之位址
 strupr(str) 將字串 str 轉成大寫後傳回新字串之位址
 strlwr(str) 將字串 str 轉成小後傳回新字串之位址
 strchr(str, ch) 從字串 str 頭開始尋找字元 ch, 傳回第一次出現的位址
 strrchr(str, ch) 從字串 str 尾開始尋找字元 ch, 傳回第一次出現的位址
 strspn(s1, s2) 比對兩個字串, 傳回第一次字元不同位置之索引
 strcspn(s1, s2) 比對兩個字串, 傳回第一次字元相同位置之索引
 strstr(heystack, needle) 從字串 needle 頭開始尋找字串 heystack, 傳回第一次出現的位址
 strcpy(dest, source) 將字串 source 的內容複製到字串 dest, 傳回目的字串 dest 位址
 strncpy(dest, source, n) 將字串 source 的內容複製 n 個字元到字串 dest, 傳回字串 dest 位址
 strcat(dest, source) 將字串 source 的內容串接到字串 dest 後面並傳回 dest 的位址
 strcmp(s1, s2) 比較字串 s1 與 s2 的內容, 相等傳回 0, s1 > s2 傳回正數, 否則負數
 strtok(str, delim) 將字串 str 以 delim 字串為分界符遞迴切割為子字串傳回 
 memset(str, ch, n) 以 n 個 ch 字元填入字串 str 中, 傳回 str 位址 

注意, 傳回值為位址的函數如 strrev() 等必須宣告一個 char 指標來儲存新字串之位址, 不可用 char 陣列. 參考 :

https://zh.wikipedia.org/wiki/String.h


測試 1 : strlen(str) 

此函數會傳回傳入字串 s1 的字元個數 (整數), 下列程式分別使用 scanf() 與 gets() 讀取輸入字串, scanf() 遇到空格就會停止讀取, 但 gets() 則不會, 會一直讀到跳行為止 (含); 除此之外 scanf() 不會讀入跳行字元 \n, 但 gets() 則會. 程式如下 :

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

int main(void) {
   char str[256];       
   printf("請輸入字串\n");                //輸入 "Hello World"
   scanf("%s", str);                            //用 scanf() 讀取會被空格中斷
   printf("讀入字串=%s\n", str);       //輸出 "Hello"
   printf("字串長度=%d 個字元\n", strlen(str));   //輸出 5
   gets(str);                                         //用 gets() 讀取不會被空格中斷
   printf("讀入字串=%s\n", str);       //輸出 " World"
   printf("字串長度=%d 個字元\n", strlen(str));    //輸出 6 (含前面一空格)
   return 0;
   }

執行結果如下 :

請輸入字串
Hello World
讀入字串=Hello
字串長度=5 個字元
讀入字串= World          (注意, W 前面有一個空格)
字串長度=6 個字元

--------------------------------
Process exited after 9.066 seconds with return value 0
請按任意鍵繼續 . . .


測試 2 : strrev(str) 

此函數會將傳入字串反轉, 並將反轉後之新字串開頭位址傳回, 故須定義一個 char 指標來儲存此位址. 程式如下 :

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

int main(void) {
   char str[256], *nstr;                     //分別儲存原始字串與反轉後之字串
   printf("請輸入字串\n");
   gets(str);   
   printf("讀入字串=%s\n", str);
   nstr=strrev(str);                           //須用 char 指標來儲存位址
   printf("反轉字串=%s\n", nstr);
   return 0;
   }

執行結果 :

請輸入字串
Hello World
讀入字串=Hello World
反轉字串=dlroW olleH 

--------------------------------
Process exited after 11.87 seconds with return value 0
請按任意鍵繼續 . . .


測試 3 : strupr(str)

此函數會將傳入字串之全部字元轉成大寫, 傳回此新字串之開頭位址, 因此必須定義一個 char 指標來儲存. 範例如下 :

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

int main(void) {
   char str[256], *nstr;                      //分別儲存原始字串與大寫後之字串
   printf("請輸入字串\n");
   gets(str);   
   printf("讀入字串=%s\n", str);
   nstr=strupr(str);                           //須用 char 指標來儲存位址
   printf("大寫字串=%s\n", nstr);
   return 0;
   }

執行結果 :

請輸入字串
hello world
讀入字串=hello world
大寫字串=HELLO WORLD

--------------------------------
Process exited after 9.636 seconds with return value 0
請按任意鍵繼續 . . .


測試 4 : strlwr(str)

此函數會將傳入字串之全部字元轉成小寫, 傳回此新字串之開頭位址, 因此必須定義一個 char 指標來儲存. 範例如下 :

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

int main(void) {
   char str[256], *nstr;                      //分別儲存原始字串與大寫後之字串
   printf("請輸入字串\n");
   gets(str);   
   printf("讀入字串=%s\n", str);
   nstr=strlwr(str);                           //須用 char 指標來儲存位址
   printf("小寫字串=%s\n", nstr);
   return 0;
   }

執行結果 :

請輸入字串
HELLO WORLD
讀入字串=HELLO WORLD
小寫字串=hello world 

--------------------------------
Process exited after 7.496 seconds with return value 0
請按任意鍵繼續 . . . 


測試 5 : strchr(str, ch)

此函數會從字串 str 頭開始尋找字元 ch, 找到的話傳回第一次出現的位址, 否則傳回 NULL. 將傳回位址減掉字串 str 之位址即為第一次出現的 ch 在 str 之索引, 例如 :

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

int main(void) {
   char str[]="Hello World";
   char *ptr;
   printf("字串內容 %s\n", str);
   for (int i=0; i<strlen(str); i++) {
    printf("字元 '%c' 位址=%p\n", str[i], &str[i]);
       }
   ptr=strchr(str, 'o');
   printf("第一個 o 出現位置之位址=%p\n", ptr);
   printf("第一個 o 出現位置之索引=%d\n", ptr-str);
   return 0;
   }

執行結果 :

字串內容 Hello World
字元 'H' 位址=000000000062FE20
字元 'e' 位址=000000000062FE21
字元 'l' 位址=000000000062FE22
字元 'l' 位址=000000000062FE23
字元 'o' 位址=000000000062FE24
字元 ' ' 位址=000000000062FE25
字元 'W' 位址=000000000062FE26
字元 'o' 位址=000000000062FE27
字元 'r' 位址=000000000062FE28
字元 'l' 位址=000000000062FE29
字元 'd' 位址=000000000062FE2A
第一個 o 出現位置之位址=000000000062FE24   
第一個 o 出現位置之索引=4   

--------------------------------
Process exited after 0.07511 seconds with return value 0
請按任意鍵繼續 . . .


測試 6 : strrchr(str, ch)

此函數會從字串 str 開始尋找字元 ch, 找到的話傳回第一次出現的位址, 否則傳回 NULL. 將傳回位址減掉字串 str 之位址即為第一次出現的 ch 在 str 之索引, 例如 : 

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

int main(void) {
   char str[]="Hello World";
   char *ptr;
   printf("字串內容 %s\n", str);
   for (int i=0; i<strlen(str); i++) {
    printf("字元 '%c' 位址=%p\n", str[i], &str[i]);
       }
   ptr=strrchr(str, 'o');
   printf("第一個 o 出現位置之位址=%p\n", ptr);
   printf("第一個 o 出現位置之索引=%d\n", ptr-str);
   return 0;
   }

執行結果 :

字串內容 Hello World
字元 'H' 位址=000000000062FE20
字元 'e' 位址=000000000062FE21
字元 'l' 位址=000000000062FE22
字元 'l' 位址=000000000062FE23
字元 'o' 位址=000000000062FE24
字元 ' ' 位址=000000000062FE25
字元 'W' 位址=000000000062FE26
字元 'o' 位址=000000000062FE27
字元 'r' 位址=000000000062FE28
字元 'l' 位址=000000000062FE29
字元 'd' 位址=000000000062FE2A
第一個 o 出現位置之位址=000000000062FE27
第一個 o 出現位置之索引=7

--------------------------------
Process exited after 0.08958 seconds with return value 0
請按任意鍵繼續 . . .


測試 7 : strspn(s1, s2) 

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

int main(void) {
   char str1[]="Hello World";
   char str2[]="Hello Tony";
   size_t loc=strspn(str1, str2);
   printf("第一個字元不同位置之索引=%d\n", loc); 
   return 0;
   }

執行結果 :

第一個字元不同位置之索引=6

--------------------------------
Process exited after 0.09996 seconds with return value 0
請按任意鍵繼續 . . .


測試 8 : strcspn(s1, s2) 

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

int main(void) {
   char str1[]="7777B333";
   char str2[]="6666B222";
   size_t loc=strcspn(str1, str2);
   printf("第一個字元相同位置之索引=%d\n", loc);
   return 0;
   }

執行結果 :

第一個字元相同位置之索引=4

--------------------------------
Process exited after 0.08926 seconds with return value 0
請按任意鍵繼續 . . .


測試 9 : strstr(heystack, needle)

此函數會在 heystack 字串中從頭尋找第一個符合之子字串 needle, 找到的話將此起始位址傳回, 否則傳回 NULL. 顯示傳回位址所指內容即是此起始位置之後之子字串. 將傳回位址減掉 heystack 字串開頭位址即是符合字串在 heystack 中之索引.

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

int main(void) {
   char str[]="Hello World";
   char *ptr;
   printf("字串內容 %s\n", str);
   for (int i=0; i<strlen(str); i++) {    //顯示字串中各字元位址
       printf("字元 '%c' 位址=%p\n", str[i], &str[i]);
       }
   ptr=strstr(str, "o");
   printf("字串開頭位址=%p\n", str);
   printf("第一個 o 出現位置之子字串=%s\n", ptr);
   printf("第一個 o 出現位置之子字串位址=%p\n", ptr);
   printf("第一個 o 出現位置之索引=%d\n", ptr-str);
   return 0;
   }

執行結果 :

字串內容 Hello World
字元 'H' 位址=000000000062FE20
字元 'e' 位址=000000000062FE21
字元 'l' 位址=000000000062FE22
字元 'l' 位址=000000000062FE23
字元 'o' 位址=000000000062FE24
字元 ' ' 位址=000000000062FE25
字元 'W' 位址=000000000062FE26
字元 'o' 位址=000000000062FE27
字元 'r' 位址=000000000062FE28
字元 'l' 位址=000000000062FE29
字元 'd' 位址=000000000062FE2A
字串開頭位址=000000000062FE20
第一個 o 出現位置之子字串=o World
第一個 o 出現位置之子字串位址=000000000062FE24
第一個 o 出現位置之索引=4

--------------------------------
Process exited after 0.1082 seconds with return value 0
請按任意鍵繼續 . . .


測試 10 : strcpy(dest, source) 

此函數會將第二參數來源字串 source 的內容複製到第一參數目的字串 dest, 並傳回目的字串的位址.

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

int main(void) {
   char source[]="Hello World"; 
   char dest[20]={};   
   printf("來源字串 '%s'\n", source);
   printf("目的地字串 '%s'\n", dest);
   printf("來源字串位址 %p\n", source);   //顯示來源字串位址
   printf("目的地字串位址 %p\n", dest);   //顯示目的地字串位址
   strcpy(dest, source);     //傳回 dest 字串之位址
   printf("目的字串 '%s'\n", dest); 
   printf("目的地字串位址 %p\n", strcpy(dest, source));  //顯示目的地字串位址
   return 0;
   }

執行結果 :

來源字串 'Hello World'
目的地字串 ''
來源字串位址 000000000022FE40
目的地字串位址 000000000022FE20
目的字串 'Hello World'
目的地字串位址 000000000022FE20

--------------------------------
Process exited with return value 0
Press any key to continue . . .


測試 11 : strncpy(dest, source, n)

此函數會將第二參數來源字串 source 的內容複製 n 個字元到第一參數目的字串 dest, 並傳回目的字串 dest 的位址.

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

int main(void) {
   char source[]="Hello World";
   char dest[20]={}; 
   printf("來源字串 '%s'\n", source);
   printf("目的地字串 '%s'\n", dest);
   printf("來源字串位址 %p\n", source);   //顯示來源字串位址
   printf("目的地字串位址 %p\n", dest);   //顯示目的地字串位址
   strncpy(dest, source, 7);     //傳回 dest 字串之位址 (複製 7 個字元)
   printf("目的字串 '%s'\n", dest);
   printf("目的地字串位址 %p\n", strcpy(dest, source, n));  //顯示目的地字串位址
   return 0;
   }

執行結果 :

來源字串 'Hello World'
目的地字串 ''
來源字串位址 000000000062FE40
目的地字串位址 000000000062FE20
目的字串 'Hello W'
目的地字串位址 000000000062FE20

--------------------------------
Process exited after 0.09536 seconds with return value 0
請按任意鍵繼續 . . .


測試 12 : strcat(dest, source)

此函數會將字串 source 的內容串接到字串 dest 後面並傳回 dest 的位址 (指標), 例如 :

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

int main(void) {
   char str1[20]="Hello";
   char str2[20]=" World";
   printf("'Hello' 位址=%p\n", str1);       //顯示第一個字串位址
   printf("' World' 位址=%p\n", str2);     //顯示第二個字串位址
   printf("strcat('Hello', ' World')=%s\n", strcat(str1, str2));     //串接後以第一個字串為結果
   printf("strcat('Hello', ' World') 位址=%p\n", strcat(str1, str2));   //顯示第一個字串位址
   return 0;
   }

此程式中先顯示兩個串接字串在記憶體中之位址, strcat(dest, source) 函數以第一個字串作為結果字串, 因此傳回值為第一個字串之位址.

執行結果 :

'Hello' 位址=000000000062FE30 
' World' 位址=000000000062FE10
strcat('Hello', ' World')=Hello World 
strcat('Hello', ' World') 位址=000000000062FE30     //串接後傳回第一個字串位址

--------------------------------
Process exited after 0.08643 seconds with return value 0
請按任意鍵繼續 . . .


測試 13 : strcmp(s1, s2)

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

int main(void) {
   char str1[20]="Hello";
   char str2[20]="hello";
   printf("strcmp('Hello', 'Hello')=%d\n", strcmp(str1, str1));
   printf("strcmp('Hello', 'hello')=%d\n", strcmp(str1, str2));
   printf("strcmp('hello', 'Hello')=%d\n", strcmp(str2, str1));
   return 0;
   }

執行結果 :

strcmp('Hello', 'Hello')=0
strcmp('Hello', 'hello')=-1
strcmp('hello', 'Hello')=1

--------------------------------
Process exited after 0.09408 seconds with return value 0
請按任意鍵繼續 . . .

可見由於 H 的 ASCII 編碼數值 (72) 小於 h 的編碼 (104), 因此 strcmp('Hello', 'hello') 傳回 -1.


測試 14 : strtok(str, delim)

此函數會以字串 delim 為分界符號拆解字串 str, 傳回值為分界符前面之子字串, 若要全部拆解須用遞迴方式, 但遞迴時第一參數必須傳入 NULL, 例如 :

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

int main(void) {
   char str[]="11:22:33:44:55:66";      //待拆解字串
   char delim[]=":";      //分界符
   char *tok;                 //儲存分界符前之子字串
   printf("待拆解字串 %s\n", str);
   printf("分界字串 %s\n", delim);
   tok=strtok(str, delim);      //第一次拆解
   while (tok != NULL) {     //遞迴拆解
       printf("%s\n", tok);       //輸出分界符前之子字串
       tok=strtok(NULL, delim);    //第二次拆解傳入 NULL
       }
   return 0;
   }

執行結果 :

待拆解字串 11:22:33:44:55:66
分界字串 :
11
22
33
44
55
66

--------------------------------
Process exited with return value 0
Press any key to continue . . .

遞迴迴圈內的 strtok() 第一參數若傳入待拆解字串 str 會不斷地拆解第一個子字串而形成無窮迴圈, 務必要傳入 NULL, 參考 :

 # 切割字串函數:strtok, Network mac address 分割


測試 15 : memset(str, ch, n)

此函數會以 n 個 ch 字元填入 str 字串中, 傳回值為 str 字串之位址 (指標). 在宣告字元陣列時可用字串 literal 例如 "0000000000" 或 {'0', '0', .... '0'} 初始化, 但是如果陣列很大的話就必須用 memset() 了. 例如 :

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

int main(void) {
   char str[11];
   memset(str, '0', 10);     //填入 10 個 '0' 
   str[10]='\0';                  //字串結尾字元
   printf("%s\n", str);
   for (int i=0; i<strlen(str); i++) {
       printf("字元 '%c' 位址=%p\n", str[i], &str[i]);
       } 
   return 0;
   }

執行結果 :

0000000000
字元 '0' 位址=000000000022FE30
字元 '0' 位址=000000000022FE31
字元 '0' 位址=000000000022FE32
字元 '0' 位址=000000000022FE33
字元 '0' 位址=000000000022FE34
字元 '0' 位址=000000000022FE35
字元 '0' 位址=000000000022FE36
字元 '0' 位址=000000000022FE37
字元 '0' 位址=000000000022FE38
字元 '0' 位址=000000000022FE39

--------------------------------
Process exited with return value 0
Press any key to continue . . .

參考 :

http://www.cplusplus.com/reference/cstring/memset/
字串比較、搜尋
C語言字符串函數大全
[C&++] 字串整數轉換
C++字符串格式化 sprintf、printf
[C/C++] cstring (string.h) 搜尋函式:strstr, strchr
[C/C++] 切割字串函數:strtok, Network mac address 分割
C語言編譯器哪個好?6款好用的C語言編譯器推薦


沒有留言:

張貼留言