C++裡的字串型別是比較二的,因為有太多表示方法:char*、string、字串陣列、wchar_t*、wstring,今天就來縷一縷這些玩意。
1. char*char* 貌似是C++字串最基礎最核心的。
看以下四個字串宣告及輸出結果:
先說說核心,C裡面的字串就是一連串記憶體,以記憶體為0的位元組作為結尾。
來分析一下程式碼,其中str1、str3、str4是一個東西(str3區別只是記憶體在堆上),str2是字面值常量,str5是單純的字元陣列。
1.1. 常規字串對於str1、str3、str4這種正常的字串,就可以隨意拿字串函式和下標訪問,進行各種操作。
在windows下,char*的字串編碼是多位元組,用的本地編碼,就是我們的GBK。linux下char*直接就是utf8,所以兩個平臺char*字串直接交流是不行的。。。
1.2. 字元陣列對於str5這種字元陣列,因為末尾沒有0,所以把他當作字串直接輸出就會有記憶體裡其他資料,就出現了“燙”。。
當我們把字元數組裡的某個位置改成0,就可以截斷出一個字串。比如以下程式碼,把第三個位置設定為0,然後就是字串“ab”。
1.3. 字面值對於str2這種在寫程式碼的時候就是一個常量,當你對這個資料的記憶體操作的時候就會報錯。
比如直接修改str2的元素,ide環境就可以給你報錯:
如果我們來硬的,執行的時候就會錯誤:
2. wchar_t*首先我們再敲一下重點:C裡面的字串就是一連串記憶體,以記憶體為0的位元組作為結尾。
記住,這非常重要!!!
wchar_t*與char*字串主要不同,那就是字元的編碼而已。
先看下以下程式碼和輸出:
“吃飯”這個字串,用GBK編碼後一共佔了5個位元組,其中4個位元組是用來存放字串內容的,最後末尾為0。
strlen這個函式,他是一個位元組統計一次,出現0就停止,所以gbkstrlen就是4。
對於純字母來說這沒毛病,但對於中文來說,顯然“吃飯”這是兩個字元。
utf16是用unicode編碼(全世界所有字元都有唯一一個數字表示),每個字元都用兩個位元組來儲存unicode編碼數字。
C++裡utf16字串需要用L開頭,所以得寫成 L"吃飯" 這種。
這時,我們用wcslen函式就可以計算出"吃飯"的長度是2。
哎,其實這也真的挺二的。。。因為簡單來說utf16一定是每個字元2個位元組,所以用strlen計算到末尾長度一定是2的倍數。除以2就肯定是實際長度了。
所以當我們用char* buf = (char*)utf16str;強轉成char*然後用strlen計算出的utf16memlen就是4。
看一下記憶體裡的情況,兩個字串都是佔用4個位元組,但是每個位元組裡儲存的內容是不一樣的。
其實C++裡的wchar_t*挺雞肋的感覺,現在utf8比較普遍。因為一刀切地用2個位元組表示,對於純英文字元那直接是浪費一倍的空間。所以utf8這種變長編碼就比較合適。
utf8也是Unicode編碼數字,就是根據每個位元組前面的二進位制位決定後面使用幾個位元組來表示一個unicode編碼。
比如對於0到127,因為第一個位元組第一個位是0,所以後面不使用任何位元組,就一個位元組表示Unicode編碼。
對於128-2047,因為第一個位元組0之前出現2個1,所以後面再使用兩個位元組(每個位元組最前面都是10)。
我們用windowsAPI將wchar_t*字串轉utf8看下:
可以看出來用WideCharToMultiByte得出的記憶體佔用大小和強制按照char*算出的utf8字串的一樣長。
對比看下,記憶體中和gbk與utf16的都不一樣:
可惜的是VC++中沒法顯示utf8字串,不過在linux下就用char*就夠了,直接utf8。
3. string和wstring這倆就是char*和wchar_t*的封裝,變成了類物件管理字串。