c 系列文章(10) C風格字串

2021-10-03 06:10:44 字數 3188 閱讀 6426

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

字串字面值是一種通用結構的例項,這種結構就是c風格字串。c風格字串不是一種型別,而是為了表達和使用字串而形成的一種約定俗成的寫法。按此習慣書寫的字串存放在字元陣列中並以空字元結束。以空字元結束的意思是在字串最後乙個字元後面跟著乙個空字元(』\0』),一般用指標來操作這些字串。

c語言標準庫提供了一組函式用於操作c風格字串,它們定義在cstring標頭檔案中。

strlen

(p);

//返回p的長度,空字元不計算在內

strcmp

(p1,p2)

;//比較p1和p2的相等性,如果p1==p2,返回0;p1>p2,返回正值;p1strcat

(p1,p2)

;//將p2附加到p1之後,返回p1

strcpy

(p1,p2)

;//將p2拷貝給p1,返回p1

這些函式不負責驗證其字串引數,傳入此類函式的指標必須指向以空字元作為結束的陣列

char ca=

;//不以空字元結束

cout <<

strlen

(ca)

<< endl;

//嚴重錯誤:ca沒有以空字元結束,strlen函式可能沿著ca在內的位置不斷向前尋找,直到遇到空字元才停止。

比較標準庫string物件時,用普通的關係運算子和相等性運算子就行,但如果用在c風格字串上,實際比較的將是指標而非字串本身。要想比較兩個c風格字串需要呼叫strcmp函式

const

char ca1=

"a string example"

;const

char ca2=

"a different string";if

(ca1 < ca2)

//未定義,實際上比較的是兩個const char*的值,這兩個指標指向的並非同乙個物件,所以將得到未定義的結果

連線或拷貝c風格字串也與標準庫string物件的同類操作差別很大。正確的方法是使用strcat和strcpy函式,不過要想使用這兩個函式,還必須提供乙個用於存放結果字串的陣列,該陣列必須足夠大以便容納下結果字串及末尾的空字元

string largestr = s1 +

" "+ s2;

//標準庫string物件可以直接進行相加

ca1 + ca2;

//錯誤,試圖將兩個指標相加

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

strcpy

(largestr,ca1)

;//把ca1拷貝給largerstr

strcat

(largestr,

" ")

;//在largestr的末尾新增乙個空格

strcat

(largestr,ca2)

;//把ca2連線到largestr後面

乙個潛在的問題是,我們在估算largestr所需的空間時不容易估準,而且largestr所存的內容一旦改變,就必須重新檢查其空間是否足夠。這類**充滿了風險而且經常導致嚴重的安全漏洞,對於大多數應用來說,使用標準庫string要比使用c風格字串更安全、更高效。

很多c++程式在標準庫出現之前就已經完成了,它們肯定沒有用到vector和string,而且有一些c++程式實際上就是與c語言或其他語言的介面程式,當然也無法使用c++標準庫。因此現代c++程式必須提供一組功能,將vector和string與陣列和c風格字串進行銜接。

任何出現字串字面值的地方都可以用空字元結束的字元陣列來替代

允許使用以空字元結束的字元陣列來初始化string物件或為sting物件賦值

在string物件的加法運算子中允許其中乙個運算物件是以空字元結束的字元陣列;

在string物件的復合運算中允許使用以空字元結束的字元陣列作為右側的運算物件;

但上述性質反過來就不成立:如果程式的某處需要乙個c風格字串,無法直接用string物件來代替它。例如不能用string物件直接初始化指向字元的指標,而需要借助c_str函式。c_str函式的返回值是乙個c風格的字串,也就是說該函式的返回結果是乙個指標,該指標指向乙個以空字元結束的字元陣列,而這個陣列所存的資料恰好與那個string物件的一樣。結果指標的型別是const char*,從而確保我們不會改變字元陣列的內容。我們無法保證c_str函式返回的陣列一直有效,如果後續的操作改變了s的值就可能讓之前返回的陣列失去效用

char

*str = s;

//錯誤,不能用string物件初始化char*

const

char

*str = s.

c_str()

;//正確

前面介紹過,不允許使用乙個陣列為另乙個內建型別的陣列賦初值,也不允許使用vector物件初始化陣列。相反,允許使用陣列初始化vector物件,要實現這一目的,只需指明拷貝區域的首元素位址和尾後位址就可以

int int_arr=

;vector<

int>

ivec

(begin

(int_arr)

,end

(int_arr));

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

vector<

int>

subver

(int_arr+

1,it_arr+4)

;//subver有3個拷貝元素:int_arr[1],int_arr[2],int_arr[3]

用於建立ivec的兩個指標實際上指明了用來初始化的值在陣列int_arr中的位置,其中第二個指標應指向待拷貝區域尾元素的下一位置。

現代的c++程式應當盡量使用vector和迭代器,避免使用內建陣列和指標;應該盡量使用string,避免使用c風格的基於陣列的字串

C風格字串與C 風格字串

c風格字串 對字串進行操作的 c 函式定義在標頭檔案中 1.字串定義 char result 2.字串的最後乙個字元是null字元 0 可以通過這個字元確定字串的結尾。3.strlen 返回的是字串的大小 因此,分配空間的時候,需要比字串的實際空間大1.e.g.char copystring con...

C風格字串與C 風格字串

c風格字串 對字串進行操作的 c 函式定義在標頭檔案中 1.字串定義 char result 2.字串的最後乙個字元是null字元 0 可以通過這個字元確定字串的結尾。3.strlen 返回的是字串的大小 因此,分配空間的時候,需要比字串的實際空間大1.e.g.char copystring con...

c風格字串與c風格字串陣列

include includeusing namespace std int main 輸出結果 0034ff10 0034ff10 0034ff04 013bdc80 char str abcd 先在文字常量區為 abcd 常量分配5b,接著在棧裡為指標str分配4b,並接收 abcd 字串的首位...