以前一直使用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);