84669 orang belajar
152542 orang belajar
20005 orang belajar
5487 orang belajar
7821 orang belajar
359900 orang belajar
3350 orang belajar
180660 orang belajar
48569 orang belajar
18603 orang belajar
40936 orang belajar
1549 orang belajar
1183 orang belajar
32909 orang belajar
c++ 自带string类 的对象 字符串结尾带不带‘0’?
人生最曼妙的风景,竟是内心的淡定与从容!
先上图
string 类型把' 0'当做普通字符处理,长度加一,可见' 0'不是结束字符,不含有特殊功能,string末尾不需加' 0'
C语言中没有string类型,而是用字符数组代替,一般字符数组可以不确定长度char * string = " ABCD" ,编译器靠什么知道字符串结束,一般在后面加 ' 0'
C++ 中的std::string和 C-style string 是两种不同的字符串,前者是标准库中定义的一个类,后者是字符数组的别名。
std::string
C-style string:通常都以\0作为结尾。
\0
std::string:标准中未规定需要\0作为字符串结尾。编译器在实现时既可以在结尾加\0,也可以不加。但是,当通过c_str()或data()(二者在 C++11 及以后是等价的)来把std::string转换为const char *时,会发现最后一个字符是\0(原因见文末附录)。
c_str()
data()
const char *
C-style string 中一般不能包含\0字符(因为这个字符被当作表示字符串结束的特殊字符处理了),如果包含这个字符,那么其后的字符将会被忽略。即:
char s[] = "ab\0c"; cout << s << endl; // 输出 ab
而std::string没有这个限制。即:
std::string s{'a', 'b', '\0', 'c'}; //std::string s = "ab\0c"; // 这里由于是从 C-style string 构造 std::string,所以仍然会忽略 \0 之后的字符 cout << s << endl; // 输出 ab c
通过c_str()或data()(二者在 C++11 及以后是等价的)来把std::string转换为const char *时,会发现最后一个字符是\0。想理解这个问题需要一点背景知识:
一,std::string 是 std::basic_string<CharT, Traits, Allocator>这个模板的特例std::basic_string<char>。即模板:
std::basic_string<CharT, Traits, Allocator>
std::basic_string<char>
template< class CharT, class Traits = std::char_traits<CharT>, class Allocator = std::allocator<CharT> > class basic_string;
中的参数CharT为char时的特例。
CharT
char
二,s.size()会返回std::string中字符的个数,即:
s.size()
string s{'a', 'b', '\0', 'c'}; cout << s.size() << endl; // 输出 4 s += '\0'; s += 'd'; cout << s.size() << endl; // 输出 6
三,使用[]运算符(即std::basic_string::reference std::basic_string::operator[](size_type pos);)获取std::string中的字符时,其字符的范围pos是从0到size()。其中0到size()-1是所存储的字符,而对于pos == size()有如下规定:
[]
std::basic_string::reference std::basic_string::operator[](size_type pos);
pos
0
size()
size()-1
pos == size()
If pos == size(), a reference to the character with value CharT() (the null character) is returned. For the first (non-const) version, the behavior is undefined if this character is modified.
CharT()
意思是当访问s[s.size()]时,会返回CharT()的返回值的引用,而CharT对于std::string是char,且char()返回的是\000,所以s[s.size()]会返回\0。
s[s.size()]
char()
\000
四,通过c_str()或data()(const CharT* c_str() const;)返回的指针访问字符串时,其效果为:
const CharT* c_str() const;
Returns: A pointer p such that p + i == &operator[](i) for each i in [0,size()].
p
p + i == &operator[](i)
i
即p[s.size()]等价于p + s.size()等价于&s.operator[](s.size())等价于s[s.size()],所以会发现返回值是\0。
p[s.size()]
p + s.size()
&s.operator[](s.size())
0是C语言中的的字符数组作为结束标记用的,C++字符串没有这个需要
何不创建一个string对象,打印看看他的size?
c语言用char*指针作为字符串时,在读取字符串时需要一个特殊字符0来标记指针的结束位置,也就是通常认为的字符串结束标记。而c++语言则是面向对象的,长度信息直接被存储在了对象的成员中,读取字符串可以直接根据这个长度来读取,所以就没必要需要结束标记了。而且结束标记也不利于读取字符串中夹杂0字符的字符串。
参照std::string的实现 bits/basic_string.h
String本身是封装过的,会把'\0'在调用的时候给去掉,但实际上存储的时候还是有'\0'的不管是用data()还是c_str()获取到的字符串都是一样的
#include <iostream> #include <stdio.h> #include <string> using std::string; using namespace std; void test1(){ string s1 = "Hello"; const char * v1 = s1.data(); printf("0x%.2x\n", v1[s1.size()]); string *s2 = new string("Hello"); const char * v2 = s2->data(); printf("0x%.2x\n", v2[s2->size()]); } void test2(){ string s1 = "Hello"; const char * v1 = s1.c_str(); printf("0x%.2x\n", v1[s1.size()]); string *s2 = new string("Hello"); const char * v2 = s2->c_str(); printf("0x%.2x\n", v2[s2->size()]);; } int main() { test1(); test2(); return 0; }
输出都是0x00
先上图
string 类型把' 0'当做普通字符处理,长度加一,可见' 0'不是结束字符,不含有特殊功能,string末尾不需加' 0'
C语言中没有string类型,而是用字符数组代替,一般字符数组可以不确定长度
char * string = " ABCD" ,编译器靠什么知道字符串结束,一般在后面加 ' 0'
C++ 中的
std::string
和 C-style string 是两种不同的字符串,前者是标准库中定义的一个类,后者是字符数组的别名。C-style string:通常都以
\0
作为结尾。std::string
:标准中未规定需要\0
作为字符串结尾。编译器在实现时既可以在结尾加\0
,也可以不加。但是,当通过c_str()
或data()
(二者在 C++11 及以后是等价的)来把std::string
转换为const char *
时,会发现最后一个字符是\0
(原因见文末附录)。C-style string 中一般不能包含
\0
字符(因为这个字符被当作表示字符串结束的特殊字符处理了),如果包含这个字符,那么其后的字符将会被忽略。即:而
std::string
没有这个限制。即:附录
通过
c_str()
或data()
(二者在 C++11 及以后是等价的)来把std::string
转换为const char *
时,会发现最后一个字符是\0
。想理解这个问题需要一点背景知识:一,
std::string
是std::basic_string<CharT, Traits, Allocator>
这个模板的特例std::basic_string<char>
。即模板:中的参数
CharT
为char
时的特例。二,
s.size()
会返回std::string
中字符的个数,即:三,使用
[]
运算符(即std::basic_string::reference std::basic_string::operator[](size_type pos);
)获取std::string
中的字符时,其字符的范围pos
是从0
到size()
。其中0
到size()-1
是所存储的字符,而对于pos == size()
有如下规定:意思是当访问
s[s.size()]
时,会返回CharT()
的返回值的引用,而CharT
对于std::string
是char
,且char()
返回的是\000
,所以s[s.size()]
会返回\0
。四,通过
c_str()
或data()
(const CharT* c_str() const;
)返回的指针访问字符串时,其效果为:即
p[s.size()]
等价于p + s.size()
等价于&s.operator[](s.size())
等价于s[s.size()]
,所以会发现返回值是\0
。0是C语言中的的字符数组作为结束标记用的,C++字符串没有这个需要
何不创建一个string对象,打印看看他的size?
c语言用char*指针作为字符串时,在读取字符串时需要一个特殊字符0来标记指针的结束位置,也就是通常认为的字符串结束标记。
而c++语言则是面向对象的,长度信息直接被存储在了对象的成员中,读取字符串可以直接根据这个长度来读取,所以就没必要需要结束标记了。而且结束标记也不利于读取字符串中夹杂0字符的字符串。
String本身是封装过的,会把'\0'在调用的时候给去掉,但实际上存储的时候还是有'\0'的
不管是用data()还是c_str()获取到的字符串都是一样的
输出都是0x00