凡人視角C++之string(上)

來源:互聯網
上載者:User

標籤:調用   npos   應用   ascii   方式   comm   dev   term   not   

  好久沒有更新部落格了,這段時間一直在忙影像處理的項目,最近空了下來,也是時候整合C++的相關內容,靜心感受下程式設計語言的魅力,和大家共同探討學習。我將以標頭檔的形式展開學習,且只講述相關介面的應用,至於內部具體的實現,鑒於本人水平有限,不敢獻醜。經過考慮,決定先從和資料結構相關的標頭檔開始,因為這些標頭檔裡的內容在OJ裡經常要用到。今天要學習的是string標頭檔,這裡的string是C++裡的string,而C裡的string在C++裡仍然保留,標頭檔名為cstring,這裡不做展開。在此說明:以下的代碼都是在VS 2015編譯環境下運行。

Some Detailsbasic_string  

  實際上,string標頭檔裡並不只有string這個類型,這個標頭檔裡最主要的是一個叫basic_string的類模板,這個類模板的聲明如下:

template < class charT,           class traits = char_traits<charT>,           class Alloc = allocator<charT>           > class basic_string;

  上面的類模板構造有點複雜,我們沒有必要深究,只需要知道我們可以在basic_string這個類中自訂三種類型作為member type就行了。其中的charT (character type)是最重要的模板參數,它直接說明了字串中的元素類型,另外兩個類型均採用預設參數(以charT為參數構建的類)即可。

  為什麼要提basic_string這玩意兒呢,因為string類型正是basic_string的special type,在實際操作中,最常使用的是char類型(字元型),故只需將上面的charT轉換為char便是string類型了。string類型的構造如下:

typedef basic_string<char> string;      //元素為8bits字元類型

  類似的,在c++內建類型中,還有wstring、u16string和u32string(後兩個是在c++11標準下),我們可以根據實際需要選取字串類型,它們的構造如下:

typedef basic_string<wchar_t> wstring;      //16位或32位typedef basic_string<char16_t> u16string;   //16位typedef basic_string<char32_t> u32string;   //32位
String versus Character Array

  之前看到過一篇文章,講到了string和char*,我在此做個總結。

  1. string記憶體由系統進行管理,自動實現記憶體的申請和釋放;而char* 則需要自己管理。如果你要使用的記憶體較大,則string系統自動申請的記憶體可能不夠使用。因此,在使用記憶體大小知道的情況下,建議使用char* ,而當使用記憶體具體大小未知,但記憶體不大時可以使用string。
  2. string相比char* 有一個優點,c++標準庫對string類進行了封裝,裡面的各種成員函數處理字串相當方便,這也是我常用string的一個原因。

    至於string和char類型的vector有什麼區別,我倒還沒有深究過,大概是成員函數不同吧,知道的小夥伴可以在下面留言下。

ElaborationMember Functionsstring::string
string();       //(1)預設建構函式,構造一個Null 字元串,字串長度為0string(const string& str);      //(2)拷貝建構函式string(const string& str, size_t pos, size_t len = npos);//(3)複製str一部分,pos是起始位置,len是複製的字串長度(預設值是到字串底部)這裡要注意str的第一個字元pos=0string(const char* s);  //(4)複製C模式下s指標指向的字元數組(字串)string(const char* s, size_t n);    //(5)複製前n個字元數組元素string(size_t n,char c);        //(6)複製n個連續的字元ctemplate <class InputIterator>  string(InputIterator first, InputIterator last);//(7)利用iterator複製字元序列,範圍為[first,last),注意最後一個不包括string(initializer_list<char> il);  //(8)將初始化列表il轉換為stringstring(string&& str) noexcept; //(9)右值引用str,並且不拋出異常資訊。

  關於右值引用和move語義這塊內容,是C++11的新特性,我當時琢磨了很久也還是雲裡霧裡,估計是自己悟性不夠高,我覺得有兩篇文章寫得還不錯,貼在這裡。另外,不知右值和臨時變數有何不同,知道的小夥伴也可以在下面留言。

https://www.ibm.com/developerworks/cn/aix/library/1307_lisl_c11/

https://my.oschina.net/letiantian/blog/470921

Demonstration:      //為簡略,今後代碼將省略cout,自己操作時應加上#include<iostream>#include<string>        //調用string標頭檔#include<initializer_list>  //(8)中要用到using namespace std;string test(const string& x)    //(9)的測試函數,產生右值{    return x;}int main(){    string s4("string now");    //(4)    string s1;      //(1)    string s2(s4);  //(2)    string s3a(s4, 7, 3);   //(3)設定長度    string s3b(s4, 7);  //(3)預設長度,也就是到底部    string s5("string now", 6); //(5)    string s6(3, ‘6‘);  //(6)    string s7(s4.begin(), s4.begin() + 6);    //(7)begin函數後面會提到,可以產生iterator    initializer_list<char> s0 = {‘s‘, ‘t‘, ‘r‘, ‘i‘, ‘n‘, ‘g‘};    //產生initializer_list    string s8(s0);  //(8)    string s9(test(s4));    //(9)}//自行將注釋中的序號與上面的序號對照進行學習

  結果如下,看看是不是和你們想象中的一樣呢。

string::operator=
string& operator= (const string& str);  //(1)賦值string類型變數string& operator= (const char* s);      //(2)賦值c風格字串string& operator= (char c);             //(3)賦值一個字元,字串長度為1string& operator= (initializer_list<char> il); //(4)賦值初始化列表ilstring& operator= (string&& str) noexcept;  //(5)利用右值引用賦值
Demonstration:#include<iostream>#include<string>        //調用string標頭檔#include<initializer_list>  //(4)中要用到using namespace std;string test(const string& x)    //(5)的測試函數,產生右值{    return x;}int main(){    string s1, s2, s3, s4, s5;      //為把operator=和建構函式分開,使用預設建構函式    s2 = "string now";      //(2)    s1 = s2;                //(1)    s3 = ‘6‘;               //(3)    initializer_list<char> s0 = {‘s‘, ‘t‘, ‘r‘, ‘i‘, ‘n‘, ‘g‘};    s4 = s0;                //(4)    s5 = test(s2);          //(5)}

Some More Detailsstring類型對象是以’\0’結尾的嘛?

  估計很多人跟我一樣都想過這個問題,因為在C語言中,系統預設字串都是以’\0’截尾的。我們不妨今天來編個小程式驗證一下。

#include<iostream>#include<string>using namespace std;int main(){    string s0 = "string now";   //初始化s0    if (s0[10] == ‘\0‘)        cout << "Yes." << endl; //如果末尾是‘\0‘,則輸出Yes.    else cout << "No." << endl; //如果末尾不是‘\0‘,則輸出No.    return 0;}

  在這裡,我們得到了一個令人滿意的答案,說明C++風格的string仍然是以’\0’結尾的,通常情況下,末尾的’\0’我們可以忽略不計。

編碼類別型對string的影響

  提到這個問題,是因為我注意到了這麼一句話,我在這裡引用一下。

Note that this class handles bytes independently of the encoding used: If used to handle sequences of multi-byte or variable-length characters (such as UTF-8), all members of this class (such as length or size), as well as its iterators, will still operate in terms of bytes (not actual encoded characters).

  這句話的意思概括起來就是說,不管你使用哪種類型的編碼,string類型的操作都將按一個位元組的方式來處理。我們不禁想到了中文,因為中文是在GB2312中編碼的,而且一個中文字元佔用兩個位元組,這樣會引起什麼問題呢?我們也來測試一下。

#include<iostream>#include<string>using namespace std;int main(){    string s0 = "測試";   //用中文初始化s0    cout << s0 << endl << endl; //查看能否輸出中文    for (int i = 0; i < 2; ++i) //輸出前2個位元組,看看是否會輸出測試兩個字        cout << s0[i] << endl;    return 0;}

  剛開始,我們將整個字串輸出,看看是否會顯示“測試”這兩個字,結果是這兩個字顯示了,說明c++是可以識別GB2312編碼的。而當我們嘗試將字串按單個位元組輸出的時候,就發現了問題,因為輸出台輸出的是空白,這就說明string類型並不能直接辨別這個是什麼編碼,它只能按單個位元組進行讀取,這就會導致該位元組沒有預設的ASCII編碼可以對應,因此也就不會有內容輸出了。

  string的內容實在有點多,為了保持頁面的精簡,方便瀏覽,我將把下半部分內容放到下篇博文中。如有錯誤,歡迎指正!

凡人視角C++之string(上)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.