天天看點

使用字元串總結C風格字元串C++字元串

         在C語言中,字元串表示為字元的數組。字元串中的最後一個字元是空字元(’\0’),這樣,操作字元串的代碼就知道在哪裡結束,官方将這個空字元定義為NUL。C++包含一些來自C語言的字元串操作函數,它們在<cstring>頭檔案中定義。通常,這些函數直接操作記憶體配置設定。C++提供了一個得到極大改善的字元串概念,并作為标準庫的一部分提供了這個字元串的實作。在C++中,std::string是一個類(實際上是basic_string模闆類的一個執行個體),這個類支援<cstring>中提供的許多功能,還能自動管理記憶體配置設定。本篇博文就以使用字元串為話題展開,總結我們常用的字元串類型,希望對大家有一點幫助。

C風格字元串

         前面說過,C風格字元串就是以’\0’為結束标志的字元串,實際是以數組的形式來存儲的。下面我們用幾個C字元串函數舉幾個栗子吧!

#define_CRT_SECURE_NO_WARNINGS  //關閉安全性檢測

#include<iostream>

#include<string>

#include<cassert>

#include<cstring>

#include<cstdio>

usingnamespacestd;

//字元串拷貝函數的内部實作

char *Mystrcpy(char *strDest,const char *strSrc)

{

    //檢驗參數的合法性

    assert(NULL  !=  strDest &&  NULL  !=  strSrc);

    //儲存目标字元串的起始位置,以便最後傳回

    char *strAddr  =  strDest;

    //完成拷貝操作

    while( '\0'  !=  (*strDest++  =  *strSrc++) )

    {

        NULL;

    }

    //傳回目标字元串的起始位置

    return strAddr;

}

int main()

{

    const char *str  =  "C風格字元串";

    size_t size  =  strlen(str);

    //str[0]= 'K'; 

    //size大小為11,strlen計算的是實際字元串的大小,不包括字元串結束标志'\0'

    printf("The length of \"%s\" is %d\n", str,size);

    //為保證pStr能儲存str中内容,必須在size的基礎上加1,以便有位置來存儲字元串結束标志'\0'

    char *pStr  =  new char[size+ 1];

    //使用C字元串函數完成字元串拷貝

    strcpy(pStr,str);

    printf("The content of pStr is \"%s\"\n",pStr);

    //釋放動态申請記憶體

    delete[] pStr;

    //将指針變量置空,避免野指針

    pStr  = nullptr;

    pStr  = newchar[20];

    //使用自定義函數完成字元串拷貝操作

    Mystrcpy(pStr,"Hello ");

    //strcat字元串拼接,從pStr的結束标志'\0'處開始拼接str(包括str的'\0')

    strcat(pStr,str);

    printf("The content of pStr is \"%s\"\n",pStr);

    //釋放動态申請記憶體

    delete[] pStr;

    //将指針變量置空,避免野指針

    pStr  = nullptr;

    return 0;

}

程式運作結果:

使用字元串總結C風格字元串C++字元串

        注意到程式第一行的宏定義了嗎?相信大家在編寫程式時,使用到C庫函數時,在編譯時經常會報如下警告,這可能會令有“NO ERROR,NO WARNING”程式設計習慣的小夥伴很不爽。

使用字元串總結C風格字元串C++字元串

         看到這張圖是不是有一種似曾相識的感覺呢!這主要是因為C庫函數關于字元串的操作函數都是不安全的,它們的安全性都有程式猿們來負責,這無疑是給程式猿增添了很多的麻煩,特别是處理一些記憶體溢出的問題。上面的警告是因為編譯器的安全檢查導緻的,這似乎是程式員們的福音。如果你習慣了使用C庫函數,又覺得這些WARNING令你很不爽,你可以嘗試部落客的做法(在源檔案的第一行加上”#define_CRT_SECURE_NO_WARNINGS”來關閉編譯器的安全性檢查)。如果你還是覺有點不舒服,那麼你可以嘗試在所有有警告的函數後面加上“_s”,如strcpy_s。 “s”是safe的簡寫,這些函數都是做過安全處理的,大家放心使用就可以了。這就是C風格字元串的内容,下面讓我們進入C++字元串吧!

C++字元串

         為了了解C++string類的必要性,我們先來看看C風格字元串的優勢和劣勢吧

優勢:

①很簡單,底層使用了基本的字元類型和數組結構

②量級輕,如果使用得當,隻會占用所需記憶體

③很低級,因為可以按操作原始記憶體的方式輕松操作和複制字元串

④能夠很好地被C程式猿所了解

劣勢:

①為了模拟字元串資料類型,需要付出很多努力

②使用難度大,而且很容易産生難以找到的記憶體bug

③沒有使用C++面向對象的特性

④要求程式猿了解底層的實作形式

         盡管string是一個類,但是可以把string當做内建類型來使用。事實上,把string想象成簡單類型更容易發揮string的作用。通過運算符的重載,C++的string使用起來比C風格字元串容易得多。下面我們就寫個簡單的程式用一下C++string吧!

#include<iostream>

#include<string>

using namespace std;

int main()

{

    string str1 = "C++string";

    //operator=完成拷貝功能,相當于C庫函數中的strcpy,操作是不是簡單多啦

    string str2 = str1;

    cout<<"The content of str2 is "<<"\""<< str2 << "\""<< endl;

    str1 = "Hello ";

    //operater+和operator+=都可以完成字元串拼接功能

    str1 += str2;//或str1 = str1 + str2;

    cout << "The content of str1 is " << "\"" <<  str1  <<  "\"" <<  endl;

    //為了達到相容的目的,還可以使用c_str()方法獲得一個表示C風格字元串的const字元指針

    const char *pStr  =  str1.c_str();

    cout << "The content of pStr is " << "\"" <<  pStr  <<  "\"" <<  endl;

    //将字元串轉換為數值

    string str3 = "100";

    int value = 0;

    value  = stoi(str3,NULL, 8);

    cout<<"value is "<< value << endl;

    //将數值轉換為字元串

    value = 12345;

    str3 = to_string(value);

    cout << "The content of str3 is " << "\"" <<  str3  <<  "\"" <<  endl;

    return0;

}

程式運作結果:

使用字元串總結C風格字元串C++字元串

        前面說過,在C++中,std::string是一個類(實際上是basic_string模闆類的一個執行個體),這個類支援<cstring>中提供的許多功能,還能自動管理記憶體配置設定。string類在std名稱空間的<string>頭檔案中定義。當string操作需要擴充string時,string類能夠自動處理記憶體需求,是以不再會出現記憶體溢出的情況了。string重載了“+”和“+=”運算符,友善字元串之間的拼接;重載了“==”、“!=”、“<”、“<=”、“>”、“>=”運算符,友善字元串之間的比較;重載了“=”運算符,友善字元串之間的拷貝;……

         為了達到相容的目的,還可以用于string類的c_str()方法獲得一個表示C風格字元串的const字元指針。不過,一旦string執行了任何記憶體重配置設定或string對象的銷毀操作,這個傳回的const指針就失效了。永遠不要從函數中傳回在基于堆棧的string上調用c_str()的結果。

std::string字面量

        源程式中的字元串字面量通常解釋為constchar*。在字元串後面加上“s”可以把字元串字面量解釋為std::string(這是C++14新特性)。如:

auto str = “std::string字面量”s;

         注意,有可能你的編譯器不支援上述操作,因為std::string字面量是C++14新特性,隻有支援C++14新特性的編譯器才支援上述定義哦。

原始字元串字面量

         原始字元串字面量(raw string literal)是可以橫跨多行代碼的字元串字面量,不需要轉義嵌入的雙引号,像“\t”“\n”等轉義序列不再按照轉義序列的方式來處理了,而是按照普通檔案的方式來處理。

#include<iostream>

#include<string>

using namespace std;

int main()

{

    //原始字元串字面量(raw string literal)是可以橫跨多行代碼的字元串字面量

    string str = R"( '\n \t

 "原始字元串字面量\v" ' )";

    //普通字元串字面量需要借助"\"來實作可以橫跨多行代碼的字元串字面量

    string str1 = "hello \

                  world\n";

    cout << "The content of str is " << "\"" <<  str  <<  "\"" <<  endl;

    cout << "The content of str1 is " << "\"" <<  str1  <<  "\"" <<  endl;

    //str= R"( "()" )"; 

    str = R"+( "()" )+";

    cout << "The content of str is " << "\"" <<  str  <<  "\"" <<  endl;

    return0;

}

程式運作結果:

使用字元串總結C風格字元串C++字元串

         注意,原始字元串字面量(rawstring literal)是可以橫跨多行代碼的字元串字面量,而普通字元串字面量需要借助“\”來實作可以橫跨多行代碼的字元串字面量。在原始字元串字面量中,不需要轉義嵌入的雙引号,像“\t”“\n”等轉義序列不再按照轉義序列的方式來處理了,而是按照普通檔案的方式來處理。

         如果需嵌入“"(”和“)"”,則需要使用擴充的原始字元串字面量文法,如下所示:

         R”d-char-sequence(r-char-sequence)d-char-sequence”

         r-char-sequence是實際的原始字元串。d-char-sequence是可選的分隔符序列,原始字元串首尾的分隔符序列應該一緻。分隔符序列最多能有16個字元。應該選擇未出現在原始字元串字面量中的序列作為分隔符序列。

         上面的程式中:

          str = R"("()" )";

改為:str = R"+("()" )+";// d-char-sequence為“ + ”,r-char-sequence為“ ”()” ”

      在操作資料庫查詢字元串和正規表達式等字元串時,原始字元串字面量可以令程式的編寫更加友善。

非标準字元串

         許多C++程式猿都不使用C++風格的字元串,有這麼幾個原因:一是一些程式猿不是不知道有C++string類型,而是因為它并不總是C++規範的一部分。二是一些程式猿發現,C++string沒有提供他們需要的行為,所有開發了自己的字元串類型。也許最常見的原因是,開發架構和作業系統有自己的表達字元串的方式。例如Microsoft MFC中的CString類,它常常用于相容或解決遺留的問題。在C++開始項目時,提前确定團隊如何表示字元串是非常重要的。

         如果你想進一步了解CString的用法,請查閱MSDN。