以前一直使用string::data()函数没发现什么问题,前天居然发现string::data不能用了,也就是data()返回没有结束符,导致拷贝崩溃,后来一查,这个data函数返回是不一定会包含结束符的。写本文专门写了个测试程序去复现,测试程序却又带\0结束符返回,编译器什么都没换过(指教)。
不过不管怎样,还是使用c_str()保险,对涉及中间带\0的string,使用data()时,注意结合len来进行安全限定。
一、string::data不带结束符、string::c_str带结束符
这是:
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()了。
二、勿通过string::data、string::c_str返回指针修改string内容
也就是说data()和c_str()只供引用使用。而且一旦string内容变动,则必须重新获取该指针。string对象的赋值,必须使用符合string类规则的处理方式,比如构造、append、erase等函数进行。
具体参考:http://www.cplusplus.com/reference/string/string/
三、中间带\0结束符的string对象
有多种方法可实现中间带结束符\0的string对象初始化。但是像:
string s="123 \0 123"; s5="abc\0"; s5+="def\0";
这样的初始化方法都是不行的,因为编译器或运行时默认都会截掉结束符后面的字符串。结果就是:
s="123 "
s5="abcdef"
1、构造法初始化
string s5= string("12345 \0 54321", 13);
这样的方式初始化,这时 s5="12345 \0 54321"
2、append函数添加
除了上面方法,还可以使用append函数,代码如下:
s5.append("abc\0",4); s5.append("def\0",4);