C風格字串

來源:互聯網
上載者:User

標籤:style   color   使用   strong   檔案   資料   問題   ar   

儘管C++支援C風格字串,但在C++程式中最好還是不要使用它們。這是因為C風格字串不僅使用起來不太方便,而且極易引發程式漏洞,是諸多安全問題的根本原因。

字串字面值是一種通用結構的執行個體,這種結構即是C++由C繼承而來的C風格字串。C風格字串不是一種類型,而是為了表達和使用字串而形成的一種約定俗成的寫法。按此習慣書寫的字串存放在字元數組中並以Null 字元串結束。以Null 字元結束的意思是在字串最後一個字元後面跟著一個Null 字元(‘\0‘)。一般利用指標來操作這些字串。

C標準庫String函數

下表列出了C語言標準庫提供的一組函數,這些函數可用於操作C風格字串,它們定義在出string標頭檔中,出string是C語言標頭檔string.h的C++版本。

C風格字串的函數

strlen(p)      返回p的長度,Null 字元不計算在內

strcmp(p1,p2)         比較p1和p2的相等性。如果p1==p2,返回0;如果p1>p2,返回一個正值;如果p1<p2,則返回一個負值

strcat(p1,p2)     將p2附加到p1之後,返回p1

strcpy(p1,p2)     將p2拷貝給p1,返回p1

傳入此類函數的指標必須指向以Null 字元作為結束的數組

char ca[]={‘c‘,‘+‘,‘+‘};  //不以Null 字元結束

cout<<strlen(ca)<<endl;  //嚴重錯誤:ca沒有以Null 字元結束

此例中,ca雖然也是一個字元數組但他不是以Null 字元作為結束的,因此上述程式將產生未定義的結果。strlen函數將有可能沿著ca在記憶體中的位置不斷向前尋找,直到遇到Null 字元才停下來。

比較字串

比較兩個C風格字串的方法和之前學習過的比較標準庫string對象的方法大相徑庭。比較標準庫string對象的時候,用的是普通的關係運算子和相等性運算子:

string s1="A string example";

string s2="A different string";

if(s1<S2)  //false:s2小於s1

如果把這些運算子用著兩個C風格字串上,實際比較的將是指標而非字串本身:

const char ca1[]="A string example";

const char ca2[]="A different string";

if(ca1<ca2)   //未定義的:試圖比較兩個無關地址

謹記之前介紹過的,當使用數組的時候其實真正用的是指向數組首元素的指標。因此,上面的if條件實際上比較的是兩個const char*的值。這兩個指標指向的並非同一個對象,所以將得到未定義的結果。

要想比較兩個C風格字串需要調用strcmp函數,此時比較的就不再是指標了。如果兩個字串相等,strcmp返回0,如果前面的字串較大,返回正值;如果後面的字串較大,返回負值:

if(strcmp(ca1,ca2)<0)  //和兩個string對象的比較s1<s2效果一樣

目標字串的大小由調用者指定

串連或拷貝C風格字串也與標準庫string對象的同類操作差別很大。例如,要想把剛剛定義的那兩個string對象s1和s2串連起來,可以直接攜程下面的形式:

//將largeStr初始化成s1,一個空格和s2的串連

string largeStr=s1+“ ”+s2;

同樣的操作如果放到ca1和ca2這兩個數組身上就會產生錯誤了。運算式ca1+ca2試圖將兩個指標相加,顯然這樣的操作沒什麼意義,也肯定是非法的。

正確的方法是使用strcat函數和strcpy函數。不過要想使用這兩個函數,還必須提供一個用於存放結果字串的數組,該數組必須足夠大以便容納下結果字串及末尾的Null 字元。下面的代碼雖然很常見,但是充滿了安全風險,極易引發嚴重錯誤:

//如果我們計算錯了largeStr的大小將引發嚴重錯誤

strcpy(largeStr,ca1);  //把ca1拷貝給largeStr

strcat(largeStr," ");  //在largeStr的末尾加上一個空格

strcat(largeStr,ca2);  //把ca2串連到largeStr後面

 

混用string對象和C風格字串

允許使用字串字面值來初始化string對象:

string s("Hello World!");  //s的內容是Hello World

更一般的情況是,任何出現字串字面值的地方都可以用以Null 字元結束的字元數組來替代:

  •  允許使用以Null 字元結束的字元數組來初始化string對象或為string對象賦值。
  • 在string對象的加法運算中允許使用以Null 字元結束的字元數組作為其中一個運算對象(不是兩個運算對象都是):在string對象的複合賦值運算中允許使用以Null 字元數組作為右側的運算對象。

上述性質反過來就不成立了:如果程式的某處需要一個C風格字串,無法直接用string對象來代替它。例如,不能用string對象直接初始化指向字元的指標。為了完成該功能,string專門提供了一個名為c_str的成員函數:

char *str=s;//錯誤:不能用string對象初始化char*

const char *str=s.c_str();  //正確

顧名思義,c_str函數的傳回值是一個C 風格的字串。也就是說,函數的返回結果是一個指標,該指標指向一個以Null 字元結束的字元數組,而這個數組所存的資料恰好與那個string對象的一樣。結果指標的類型是const char*,從而確保我們不會改變字元數組的內容。

我們無法保證c_str函數返回的數組一直有效,事實上,如果後續的操作改變了s的值就可能讓之前返回的數組失去效用。

 

使用數組初始化vector對象

前面介紹過不允許使用一個數組為另一個內建類型的數組賦初始值,也不允許使用vector對象初始化數組。相反的,允許使用數組類初始化vector對象。要實現這一目的,只需指明要拷貝地區的首元素地址和尾後元素地址就可以了:

int int_arr[]={0,1,2,3,4,5};

//ivec有6個元素,分別是int_arr中對應元素的副本

vector<int> ivec(begin(int_arr),end(int_arr));

在上述代碼中,用於建立ivec的兩個指標實際上指明了用來初始化的值在數組int_arr中的位置,其中第二個指標應指向待拷貝地區尾元素的下一個位置。此例中,使用標準庫函數begin和end來分別計算int_arr的首指標和尾後指標,在最後的結果中,ivec將包含6個元素,它們的次序和值都與數組int_arr完全一樣。

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.