本文特记录C++中string类(注意string是一个类)的一些值得注意的地方。
string类的实例是以‘\0'结束的吗?
这个问题有时还真容易混淆,因为我们可能会将 C++ 语言中的string类的实例跟 C 语言的字符串相混淆。在 C 语言中,字符串是以’\0'结束的字符数组。但C++还提供了string类,跟 C 语言字符串是完全不一样的东西,但却容易相互混淆。
我们先来看一下,对于string类而言,'\0'跟其他字符是否有不一样的意义。
实际上,‘\0’在string类之中并不具有特殊意义,它跟其他字符的地位完全相同。为了证明这个说法,我们来看一个例子:
1 #include <iostream> 2 #include <string> 3 using namespace std; 4 5 int main() 6 { 7 string in{"abc"}; 8 in.push_back('\0'); 9 in.append("def"); 10 cout << in << endl; 11 12 return 0; 13 }
我们将断点设定在第10行,可以发现有如此结果:
另外,程序输出如下:
从上述结果可以看出,'\0'在string类中确跟其他字符的地位一样。
同时,我们也可以知道string类的实例并不以'\0'结束。不过,我们再看看下边例子,我们可能会动摇这个结论:
1 #include <iostream> 2 #include <string> 3 using namespace std; 4 5 int main() 6 { 7 string in{"abcdef"}; 8 int i = 0; 9 while (in[i] != '\0') 10 { 11 cout << in[i] << " "; 12 i++; 13 } 14 cout << endl; 15 16 return 0; 17 }
程序运行结果如下:
从这个程序来看,string类的实例好像又是以'\0'结束的。实际上,是操作符'[]'捣的鬼。对于string类而言,操作符’[]‘并不检查索引是否有效,所以当索引越界时,操作符'[]'的访问行为是不明确的。不过对于string类而言,用操作符'[]'访问第length()个字符时会返回'\0',而对第length()+1以上的访问会使得程序崩溃。这个可以通过上边程序的 in 变量的原始视图来验证到:
但是这并不能证明string类的实例就以'\0'结束。如果我们用string类提供的会进行类型检查的成员函数 at 来访问实例中的字符,就会发现上一程序会发生越界错误:
1 #include <iostream> 2 #include <string> 3 using namespace std; 4 5 int main() 6 { 7 string in{"abcdef"}; 8 int i = 0; 9 while (in.at(i) != '\0') 10 { 11 cout << in[i] << " "; 12 i++; 13 } 14 cout << endl; 15 16 return 0; 17 }
程序运行时错误:
综上所述,‘\0’在string类之中并不具有特殊意义,它跟其他字符的地位完全相同,而且string类的实例也并不以'\0'结束。
string类实例与 C 语言字符串转换
将string类实例转换为 C 语言字符串是比较常见的,一般利用的是c_str()函数,如下例:
1 #include <iostream> 2 #include <string> 3 using namespace std; 4 5 int main() 6 { 7 string in{"1234"}; 8 9 char *cstr = const_cast<char *>(in.c_str()); 10 printf("%s\n", cstr); 11 12 int str2Int = atoi(cstr); 13 printf("%d\n", str2Int); 14 15 return 0; 16 }
string::npos
npos是string类的一个公有静态成员变量,定义如下:
static const size_t npos = -1;
它主要有两个用处:
1. 当作为成员函数参数 len 的默认数值时,表示“until the end of the string”。
如str.substr(pos)表示截取从pos到str最末尾的字符串。
2. 作为成员函数返回值表示没有匹配。
如str.substr("test")若返回string::npos则表示在str中找不到test子串。