以前一直使用string::data()函數沒發現什麼問題,前天居然發現string::data不能用了,也就是data()返回沒有結束符,導致拷貝崩潰,後來一查,這個data函數返回是不一定會包含結束符的。寫本文專門寫了個測試程序去復現,測試程序卻又帶\0結束符返回,編譯器什麼都沒換過(指教)。
不過不管怎樣,還是使用c_str()保險,對涉及中間帶\0的string,使用data()時,注意結合len來進行安全限定。
這是:
http://www.cplusplus.com/reference/string/string/data/
http://www.cplusplus.com/reference/string/string/c_str/
說法,而天緣實際測試,這個data函數還是有\0添加返回的。測試程序如下:
#include <iostream> #include <string> using namespace std; bool fun(string x) { const char* p=x.data(); return true; } void main() { string s1 = "98765432109876543210A"; char* s2 = "12345"; char s3[] = "12345"; char res[255]; int len1 = s1.length(); //=21, no(or not including) '\0'(terminating null character) int len2 = strlen(s2); //=5, no(or not including) '\0' int len3 = strlen(s3); //=5, no(or not including) '\0' const char* abuf = s1.c_str(); //append '\0' strcpy(res,abuf); //ok, find '\0' const char* bbuf = s1.data(); //find '\0' (maybe no) strcpy(res,s1.data()); //Do not use this string s4 = "12345 \0 54321"; //s4="12345 " size_t len=s4.length(); //=6 size_t size=s4.size(); //=6 const char*ps=s4.c_str(); string s5= string("12345 \0 54321", 13);//s5=12345 \0 54321 //const char*pd=s5.data(); fun(s5); }
但確實也遇到過沒有結束符返回的情況,好像內容很長時(函數引用?...),當時就因為沒有結束符導致拷貝崩潰。後來全部換成c_str()了。
也就是說data()和c_str()只供引用使用。而且一旦string內容變動,則必須重新獲取該指針。string對象的賦值,必須使用符合string類規則的處理方式,比如構造、append、erase等函數進行。
具體參考:http://www.cplusplus.com/reference/string/string/
有多種方法可實現中間帶結束符\0的string對象初始化。但是像:
string s="123 \0 123"; s5="abc\0"; s5+="def\0";
這樣的初始化方法都是不行的,因為編譯器或運行時默認都會截掉結束符後面的字符串。結果就是:
s="123 "
s5="abcdef"
string s5= string("12345 \0 54321", 13);
這樣的方式初始化,這時 s5="12345 \0 54321"
除了上面方法,還可以使用append函數,代碼如下:
s5.append("abc\0",4); s5.append("def\0",4);