C與C 風格的字串辨析

2022-09-07 04:48:07 字數 3125 閱讀 4083

c++中實際上存在兩類字串,一類是常說的標準庫中的string,另一類是c風格的字串。

正如c++ primer中所述:

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

確實c風格的字串及其難用,而且非常容易發生問題。

但是,我們不能完全不了解c風格的字串,因為很多程式和相關的api在標準庫出現前就已經完成。而且其中很多涉及重要的系統呼叫,例如網路程式設計中就有大量的c風格字串的使用。我們可以嫌棄它,但是掌握它也是必須的。

下面就c與c++風格的字串中一些使用上極易混淆的地方做一些辨析。

c風格的字串是string.h

cstring是c風格的string.h在c++下的對應標頭檔案。

c++風格的字串是string(stl標準庫)。

實際是c++是相容上述三個標頭檔案的。

他們是完全不一樣的,如需詳細了解,可以查閱cppreference.com文件。

c風格的字串有兩大類初始化方式:

// 第一類:字元陣列形式

// 指定大小

char c[6] = "abcde";

// 由編譯器計算大小

char c = "abcde";

// 第二類:字元指標形式

char *c = "abcde";

第一類方法用來指定大小時,必須至少比初始化的內容多1個空間,用來存放null-terminated,即'\0'。否則會有undefined錯誤發生。

必須要明確知道,這兩類初始化完全不同。使用字元陣列所建立的字串是可讀可寫的,儲存位置為棧區。而用字元指標所得到的字串是唯讀的,因為儲存位置位於常量區。這是使用前必須明確的。

由於上述兩種關係,我們常常會覺得,字元陣列的名字和字元指標是一樣的。實際上在很多使用到陣列名字的地方,確實編譯器會幫我們自動將其替換成「乙個指向陣列首元素的指標」。這句話的另一層意思就是,二者其實是不一樣的,只是「好像在一些操作中一樣」。有兩個點需要注意:

即:

char c = "abcde";

auto auto_c = c;

decltype(c) decl_c = "abc";

觀察其型別:

注意:decltype連大小都繼承下來了,因此不注意的話非常容易出現錯誤(不過大部分ide能檢測到)。

在知道了字元陣列和字元指標的區別後,必須要指出,不建議使用2.1中所述的字元指標方法構建字串(即第二類)。這並不是一種標準的用法,而且十分危險。它的記憶體存放在文字常量區,可讀不可寫。如果試圖寫入,程式會直接崩潰,甚至編譯器不會警告(gcc應該會)。因此,乙個常規的做法是用第一類方法初始化,而字元指標可以用來指向已經初始化好的字串。接下來討論賦值的時候,都是儲存在棧中的字串。

當我們以為辨清了儲存問題就可以隨意賦值,那就大錯特錯了,因為在c風格的字串中,不能將陣列的內容拷貝給其他陣列作為其初始值

也就是說,不能進行賦值操作。具體來說是不能使用「等號」進行賦值。我們應該是用cstring或string.h中提供的字串拷貝函式來進行操作:

char* strcpy( char* dest, const char* src );

char *strncpy( char *dest, const char *src, std::size_t count );

這裡通常就會出現及其危險的操作了,必須足夠注意:

乙個常用的方法時把dest開得大一些,然後用0作為初始值,這樣能以一種相對優雅的方式防止大多數問題,但是使用起來仍需注意。

char src = "abcde";

char dest[100] = ;

// 拷貝下標2開始的總共2個字元

strncpy(dest, src + 2, 2);

cout << dest << endl;

// 結果輸出:cd

前面也提到了,我們無法拋棄c風格的字串。當我們使用stl的string時,難免遇到c風格與stl容器類混用的問題。幸運的是stl已經為我們考慮了足夠多,二者的轉換可以非常方便。

stl對於c風格是非常寬容的,我們可以直接使用建構函式將c風格轉換成容器類。

char cs = "unix";

string s(cs);

cout << s << endl;

//輸出:unix

也可以直接用c風格給stl string賦值。

string s2;

s2 = cs;

cout << s2 << endl;

//輸出:unix

進行stl string的加法運算時,c風格的字串可以作為其中乙個物件。

string scs = s + cs;

cout << scs << endl;

//輸出:unixunix

需要再次警告:我們必須保證c風格的字串是正確的,如果它沒有爭取地以'\0'結尾,那結果也是undefined。當我們的一些api只能接收c風格的字串時,就必須考慮stl string向c風格轉換。這裡stl再一次為我們考慮了,提供了對應的轉換函式:

它的使用方法非常簡單,如下:

string s = "unix";

// 以c格式的字元指標傳進去

func(s.c_str());

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 字串的首位...