String Topic 7 字串
Topic 7-1 字串簡介
什麼是String(字串)? 在C語言裡面,字串就是字元陣列(Character Array)[註] 例如下面這個例子: 就是利用一個長度為14的char array來把字串存起來。 [註] 在C++、Java等更高階的語言當中,有些有獨立的String資料形態,但在C語言當中 並沒有一種叫string的data type。
字串的結束符號 為什麼明明只有13個字元,但是卻用了14個char去存呢? 因為在每個字串的最後,都會有一個結束符號’\0’,表示這個字串結束了,否則在存取字串陣列的時候,很有可能會存取到其他無關的記憶體空間,會出現預期之外的程式行為,十分危險。
字串的結束符號 我們也可以使用字串的結束符號來把字串切短。例如下面這個程式: 範例7-1
先宣告了一個char array,存了”I am a string”,然後先印出string的內容與其長度 執行第8行的輸出結果為: 我們可以看到此字串的長度為13 Print string:I am a string, its len is 13
在第10行的時候,把string[5]的內容改寫為’\0’(字串的結束符號) 執行第12行的輸出結果為: 我們可以看到此字串的長度為5,內容也只剩下string[0]到string[4]的內容而已 由此我們可以看出\0是程式判定字串結尾的符號,也可透過插入\0的方式,來切斷字串、改變字串長度 Print string:I am , its len is 5
未直接寫定長度的字串宣告 除了剛才提到的字串宣告方式之外,還有其它幾種宣告方式,列舉於下: 宣告時未直接寫定長度的字串: 範例: 這種宣告方式在宣告時未先指定長度,但是會在宣告時直接指定字串初值,其字串長度即為字串初值的長度,在這個例子當中,就是”I am also a string”的長度,19個字原加一個結束符號,總長共20
未直接寫定長度的字串宣告 要小心的是,如果要用剛才未直接寫定長度的字串宣告,必須要在宣告時就指定字串初值 像下面的寫法是不行的 但我們確實會有未定長度字串宣告的需求,此部分待「Pointer Application」的主題再詳加討論,在這裡先不作論述
空字串宣告 如果是宣告時指定大小的char array,如同一般的陣列宣告一樣,可以在宣告時給定初值,亦可不給定初值,待後續程式再給定,如同下面的程式碼: 是先宣告一個空的Char array,然後再透過scanf把使用者輸入的東西寫到字串中
空字串宣告 亦可一個一個把Char填入Char array當中,如下面的程式碼: 其輸出為: string: string: hello
空字串宣告 但是如同一般的變數宣告,如果你一開始沒有指定初值,編譯器有可能會先幫你把初值填0,但初值也有可能是亂碼,故若要確保宣告的字串內容是完全空白的,可以像下面的方式宣告:
我們在課堂上不會將所有在string.h的函式都講過,只會講較常用者 接下來介紹幾個常用的字串處理函式,大部份的字串處理相關函式都在string.h當中,少部分如sprintf、scanf等是在stdio.h當中 我們在課堂上不會將所有在string.h的函式都講過,只會講較常用者 但如果對字串處理有興趣的同學,可以參考下列網址,自行研讀其他上課未提到的函式: http://pubs.opengroup.org/onlinepubs/7908799/xsh/string.h.html http://en.wikibooks.org/wiki/C_Programming/Strings
7-2 字串複製:strcpy
strcpy 目的: 參數: 須知: 針對把Source字串的內容複製到Target字串的函式 strcpy(Target字串,Source字串 ); 須知: 使用strcpy時,請注意strcpy只能完完整整的把Source字串的內容複製,我們不能透過傳參數的方式修改要寫入Target字串的內容,若要自由修改寫入Target字串的內容,須用後面講的sprintf
strcpy 範例 輸出結果 Before strcpy() First string: Hello world! Second string: After strcpy() Second string: Hello world! 範例7-2 未複製前是空的-> 複製後就把first_string的內容複製到second_string來了->
strncpy 目的: 參數: 針對把Source字串的內容前n個字元複製到Target字串的函式 strncpy(Target字串,Source字串 ,n);
strncpy範例 輸出結果 Before strncpy() First string: Hello world! Second string: After strncpy() Second string: Hello 範例7-3 未複製前是空的-> 複製後就把first_string的內容的前5項 複製到second_string來了 ->
7-3 字串輸出入:sprintf, sscanf
sprintf 目的: 參數: 所在函式庫: 目的與行為皆與printf相仿,只是輸出的結果不是到螢幕上,而是寫到字串 stdio.h(注意不是在string.h裡)
sprintf 範例 範例7-4 輸出結果 output= output=hello, I can type number 55. And I can also type variable 66
sscanf 目的: 參數: 須知: 所在函式庫: 與scanf相仿,只是不是從使用者輸入取得資料,而是從字串取得資料 讀進來的參數是用空白做切割不同variable,然後讀到\n時就會停止scan 所在函式庫: stdio.h(注意不是在string.h裡)
sscanf 範例 我們把本來的”Hello, we are 5566….”透過sscanf讀入後切割成 string_1 = Hello, string_2 = we string_3 = are string_4 = 5566 然後因為scanf只有要輸入四個參數,而5566後面的「…」又不是數字所以停止scan了 範例7-5 輸出結果 Hello, are we 5566?
事實上,sprintf和sscanf也都有snprintf等等,後面會提的strcmp也有strncmp,但是都是針對前n個做處理,觀念與strncpy之於strcpy一樣,故不再另外介紹,有興趣者可參考投影片一開始的參考網頁
7-4 字串長度:strlen
strlen 目的: 去看說這個字串長度多長 參數: strlen(字串); 回傳值格式: unsigned long
strlen範例 範例7-6 輸出結果 Print string:I am a string, its len is 13
7-5 字串進階處理
strstr 目的: 參數: 回傳值: 在source字串當中,找target字串出現的位置 回傳target字串在source字串第一次出現位置的指標
strstr範例 範例7-7 輸出結果 本來的字串:永和有永和路,中和也有永和路 第一次「中和」出現的位置:中和也有永和路
strtok 目的: 參數: 程式行為: 回傳值: 利用某關鍵字串去切割另外一個字串 strtok(source字串,target字串); 利用target字串的內容,去切割source字串 回傳值: 切好的部分字串
strtok使用方式 一開始先呼叫strtok(source, target) 但他回傳值只會把在遇到第一個token以前的東西切出來 那字串還有剩下的東西沒切完怎麼辦?要用後面的while loop來補完 再來重複呼叫strtok(NULL, target),直到沒有東西可以切出來為止 之所以使用方式如此特別的原因,在範例之後會有原理解釋
strtok範例 用空格當分界,把每個空格間的字串切出來 ----> 輸出結果 No.1 string:I No.2 string:saw No.3 string:a No.4 string:saw No.5 string:saw No.6 string:a No.7 string:saw No.8 string:(null) 範例7-8 用空格當分界,把每個空格間的字串切出來 ---->
strtok原理 之所以strtok的使用方式如此特別,是因為他在用token去切字串的時候,內部程式行為的緣故,我們將前面strtok的範例中,對字串切割處理的過程,整理成下面幾張圖,方便大家理解。 參考資料:http://support.microsoft.com/kb/51327/zh-tw
strtok原理 Step 0 Step 1 <- ---- - <- --- 第一次加\0來切斷程式碼 這是在還沒呼叫strtok之前source字串的狀況 I s a w \0 Step 1 呼叫第一次strtok,看到第一個空白,就把它補上\0,切出第一個字串 I \0 s a w <- ---- - <- --- 第一次加\0來切斷程式碼 --- 第一次strtok回傳的字串指標位置 所以第一次的str_tmp裡面只有I
Step 2 strtok原理 Step 1 <- <- - - --- 第二次加\0來切斷程式碼 I \0 s a w Step 2 呼叫第二次strtok,仍然用之前的source,所以source端填NULL 就把它補上\0,切出第一個字串 I \0 s a w <- - - <- --- 第二次加\0來切斷程式碼 第二次strtok回傳的字串指標位置 所以第二次的str_tmp裡面只有saw
strtok原理 Last Step -> <- - - 以此類推,直到最後一個Step為止 切到最後的時候,回傳的strtok的回傳值會是NULL -> I \0 s a w <- - - 切到最後strtok回傳的字串指標位置 --- 所以切到最後的str_tmp裡面只有NULL
7-6 記憶體應用
memcpy memcpy( targetStr, sourceStr, number of byte ) 範例7-9
memcpy原理 Step 0 Step 1 覆蓋原本的記憶體內容 呼叫memcpy,把destination字串複製到source字串 這是在還沒呼叫memcpy之前source字串的狀況 Step 1 呼叫memcpy,把destination字串複製到source字串 destination字串 source字串 覆蓋原本的記憶體內容
memcpy注意事項 1. 記得source字串的長度一定要夠長,才 不會附蓋到其他記憶體的內容。 2.複製的長度需為destinatio字串的長度+1, 千萬不要忘了“\0”
memcmp int memcmp(buffer1, buffer2, sizeofbuffer1)
memcmp 1. 此function會回傳一個integer值 2.如果兩個字串一模一樣,則會return 0 3.如果兩個字串不一樣,則會比較第一個不同字元的ASCII碼大小。 以上例而言,g的ASCII code = 103. G的ASCII = 71 所以回傳>0的值,固output為 ‘DWgaOtP12df0’ is greater than 'DWGAOTP12DF0'.