轉載https://blog.csdn.net/qq_31930499/article/details/80374310
之前在某篇文章中看到,C語言字符串是以’\0’結尾的,但是C++string類型的字符串並不是以’\0’結尾。話不多說,直接放代碼(Cygwin64環境g++編譯器):
string b("abc");
cout << b.capacity() << endl;
cout << b.size() << endl;
if(b[3] == '\0')
cout << "yes" << endl;
else
cout << "no" << endl;
運行結果:
3
3
yes
可以看到,字符串b大小和容量都是3,但是卻可以使用b[3]越界訪問,並且字符串的結尾就是’\0’。此刻,我心里想"abc"是C語言風格的字符串給b構造,肯定會把"abc"后面影藏的’\0’給構造進去。至於size和capacity是3,是因為這些方法進行了結尾處理,不計算最后一個’\0’,所以都是3。
然后我再試了如下代碼:
string a("abcd",3);
cout << a.capacity() << endl;
cout << a.size() << endl;
if(a[3] == '\0')
cout << "yes" << endl;
else
cout << "no" << endl;
結果跟上面一模一樣。此刻我又想,構造函數會在末尾自動添加一個’\0’,並且size和capacity函數都不計算’\0’的。
所以此刻,我肯定是矛盾的。因為最開始說string字符串是不以’\0’結尾的,但是測試下來,確實是以’\0’結尾的。
經過一番查找,得出:
std::string:標准中未規定需要\0作為字符串結尾。編譯器在實現時既可以在結尾加\0,也可以不加。(因編譯器不同)
但是,當通過c_str()或data()(二者在 C++11 及以后是等價的)來把std::string轉換為const char
*時,會發現最后一個字符是\0。但是C++11,string字符串都是以’\0’結尾。
最后說一下,為什么C語言風格的字符串要以’\0’結尾,C++可以不要:
c語言用char*指針作為字符串時,在讀取字符串時需要一個特殊字符0來標記指針的結束位置,也就是通常認為的字符串結束標記。
而c++語言則是面向對象的,長度信息直接被存儲在了對象的成員中,讀取字符串可以直接根據這個長度來讀取,所以就沒必要需要結束標記了。而且結束標記也不利於讀取字符串中夾雜0字符的字符串。
進一步來看string字符串,代碼如下:
string a("abcd",3);
printf("%p\n",&a);
printf("%p\n",&a[0]);
a[1] = 'X';
cout << a << endl;
printf("%p\n",&a);
printf("%p\n",&a[0]);
string b("abc");
printf("%p\n",&b);
printf("%p\n",&b[0]);
運行結果:
0xffffcbe0
0x6000003e8
aXc
0xffffcbe0
0x6000003e8
0xffffcbd8
0x600000418
由0xffffcbe0、0xffffcbd8可以看出,a,b類似於指針,他們所指的對象地址分別在0x6000003e8,0x600000418。所以a,b是棧變量,而所指的對象非棧變量。假設是文字常量,那么第四行執行會段錯誤,顯然沒有,排除。那么就是堆變量,地址也是向下增加的,符合要求。所以,string在構造函數的時候,會在堆上開辟一塊內存存放字符串,並且指向這塊字符串。
