String类
要使用string类,必须在程序中包含头文件string。string类位于名称空间std中,因此必须提供一条using编译指令,或者使用std::string。string类定义隐藏了字符串的数组性质,能够像处理普通变量那样处理字符串。
程序4.7
//strtype1.cpp ——使用C++string类
#include<iostream>
#include<string>
int main()
{
using namespace std;
char charr1[20]; //创建一个空数组
char charr2[20] = "jaguar"; //创建一个初始化数组
string str1; //创建一个空string对象
string str2 = "panther"; //创建一个初始化对象
cout << "Enter a kind of feline: ";
cin >> charr1;
cout << "Enter another kind of feline: ";
cin >> str1; //使用cin进行输入
cout << "Here are some felines:\n";
cout << charr1 << " " << charr2 << " "
<< str1 << " " << str2 //使用cout进行输出
<< endl;
cout << "The third letter in " << charr2 << " is "
<< charr2[2] << endl;
cout << "The third letter in " << str2 << " is "
<< str2[2] << endl; //使用数组表示法
cin.get();
cin.get();
cin.get();
return 0;
}
运行结果:
在很多方面,使用string对象的方式与使用字符数组相同。
- 可以使用C-风格字符串来初始化string对象;
- 可以使用cin来将键盘输入存储到string对象中;
- 可以使用cout来显示string对象;
- 可以使用数组表示法来访问存储在string对象中的字符。
string对象和字符数组之间的主要区别是,可以将string对象声明为简单对象,而不是数组。
类设计让程序能够自动处理string的大小,例如,str1的声明创建一个长度为0的string对象,但程序将输入读取到str1中时,将自动调整str1的长度。
这使得与使用数组相比,使用string对象更方便安全。可以将char数组视为一组用于存储一个字符串的char存储单元,而string类变量是一个表示字符串的实体。
1. C++11字符串初始化
C++11允许将列表初始化用于C-风格字符串和string对象:
char first_date[] = {"Le Chapon Dodu"};
char second_date[] {"The Blegant Plate"};
string third_date = {"The Bread Bowl"};
string fourth_date {"Hank's Fine Eats"};
2. 赋值、拼接和附加
不能将一个数组赋给另一个数组,但可以将一个string对象赋给另一个string对象:
char charr1[20];
char charr2[20] = "jaguar";
string str1;
string str2 = "panther";
charr1 = charr2; //invalid
str1 = str2; //valid
string类简化了字符串合并操作。可以使用运算符+将两个string对象合并起来,还可以使用使用运算符+=将字符串附加到string对象的末尾:
string str3;
str3 = str1+str2; //将str1和str2合并并赋给str3
str1 += str2; //将str2附加到str1末尾
程序4.8
// strtype2.cpp 赋值、附加、拼接
#include<iostream>
#include<string>
int main()
{
using namespace std;
string s1 = "penguin";
string s2, s3;
cout << "You can assign one string object to another: s2 = s1\n";
s2 = s1;
cout << "s1: " << s1 << ", s2: " << s2 << endl;
cout << "You can assign a C-style string to a string object.\n";
cout << "s2 = \"buzzard\"\n";
s2 = "buzzard";
cout << "s2: " << s2 << endl;
cout << "You can concatenate strings: s3 = s1 + s2\n";
s3 = s1 + s2;
cout << "s3: " << s3 << endl;
cout << "You can append strings.\n";
s1 += s2;
cout << "s1 += s2 yields s1 = " << s1 << endl;
s2 += " for a day";
cout << "s2 += \" for a day\" yields s2 = " << s2 << endl;
cin.get();
return 0;
}
运行结果:
3. string类的其他操作
头文件cstring(string.h)提供了一些函数:
strcpy(charr1, charr2); //将charr2复制给charr1
strcat(charr1, charr2); //将charr2附加到charr1末尾
在VS2015中进行编译时,使用strcpy和strcat会报错,并建议使用strcpy_s和strcat_s。
报错信息:
error C4996: ‘strcpy’: This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
报错解决办法:
- 按alt+F7打开属性管理器
- 配置选择所有配置
- 在C/C++下选择预处理器
- 在右侧预处理器定义点击编辑
- 在打开的窗口添加_CRT_SECURE_NO_WARNINGS
程序4.9
//strtype3.cpp
#include<iostream>
#include<string>
#include<cstring>
int main()
{
using namespace std;
char charr1[20]; //创建一个空数组
char charr2[20] = "jaguar"; //创建一个初始化数组
string str1; //创建一个空string对象
string str2 = "panther"; //创建一个初始化对象
//string对象和字符数组的赋值
str1 = str2;
strcpy(charr1, charr2); //这里在使用strcpy时发出警告,无法生成,使用上述解决方法
//string对象和字符数组的附加
str1 += " paste";
strcat(charr1, " juice"); //这里在使用strcat时发出警告,无法生成
//获取string对象和C-风格字符串的长度
int len1 = str1.size();
int len2 = strlen(charr1);
cout << "The string " << str1 << " contains "
<< len1 << " characters.\n";
cout << "The string " << charr1 << " contains "
<< len2 << " characters.\n";
cin.get();
return 0;
}
运行结果:
处理string对象的语法通常比使用C字符串函数简单,尤其是进行较为复杂的操作时,比如:
str3 = str1 +str2;
使用C-风格字符串则需:
strcpy(charr3,charr1);
strcat(charr3,charr2);
另外,在使用字符数组时,总是存在目标数组过小,无法存储指定信息的危险,如:
char site[10] = "house";
strcat(site, " of pancakes"); //memory problem
4. string类I/O
使用cin>>来将输入存储到string对象中和使用cout<<来显示string对象的用法,与C-风格字符串相同。但在读取一行时,二者有所不同。
程序4.10
//strtype4.cpp
#include<iostream>
#include<string>
#include<cstring>
int main()
{
using namespace std;
char charr[20];
string str;
cout << "Length of string in charr before input: "
<< strlen(charr) << endl;
cout << "Length of string in str before input: "
<< str.size() << endl;
cout << "Enter a line of text: \n";
cin.getline(charr, 20); //指出最大长度
cout << "You entered: " << charr << endl;
cout << "Enter another line of text:\n";
getline(cin, str); //此时cin是一个参数,不需指定长度
cout << "You entered: " << str << endl;
cout<< "Length of string in charr after input: "
<< strlen(charr) << endl;
cout << "Length of string in str after input: "
<< str.size() << endl;
cin.get();
cin.get();
cin.get();
return 0;
}
运行结果:
在用户输入之前,该程序指出数组charr的长度为31,这比该数组的长度要大:首先,未初始化的数组的内容是未定义的;其次,函数strlen()从数组的第一个元素开始计算字节数,直到遇到空字符。对未初始化的数据,第一个空字符出现的位置是随机的,因此运行该程序时,得到的数组长度很可能不同。
在用户输入之前,str的字符串长度为0,这是因为未初始化的string对象长度被自动设置为0。
程序4.10也指出了在输入一行时,数组和string类对象的不同。
cin.getline(charr,20);
getline(cin, str);
5. 其他形式的字符串字面值
对类型wchar_t、char16_t、char32_t,C++分别使用前缀L、u和U表示:
wchar_t title[] = L"Chief Astrogator"; //wchar_t字符串
char16_t name[] = u"Felonia Ripova"; //char16_t字符串
char32_t car[] = U"Humber Super Snipe"; //char32_t字符串
对UTF-8编码方案,使用前缀u8。
C++11新增了原始字符串(raw)。在原始字符串中,字符表示的就是自己。比如\n表示反斜杠\和n两个字符,而不是换行符。在原始字符串中,可以直接使用双引号(”),而不必繁琐的使用\。
原始字符串使用”( )”来作为界定符,而不是” “。并使用前缀R:
cout<< R"(Jim "King" Tutt uses "\n" instead of endl.)"<<'\n';
上述代码将输出:Jim “King” Tutt uses “\n” instead of endl.
如果不使用原始字符串,将需要输入以下代码:
cout << "Jim \"King\" Tutt uses \"\\n\" instead of endl."<<'\n';
在输入原始字符串时,按回车键不仅会移到下一行,还会在原始字符串中添加回车字符。
如果要在原始字符串中包含)”,便一起在见到第一个)”时,将会认为字符串到此结束。但原始字符串允许在表示字符串开头的”(之间添加其他字符,同时在表示字符串结尾的)”之间也添加相同的字符,比如使用 “+* ( )+*”
cout << R"+*("(Who wouldn't?)", she whispered.)+*"<<endl;
将输出”(Who wouldn’t?)”, she whispered.
注意两边添加的字符不是对称关系,而是顺序相同。
自定义界定符是,可在默认界定符之间添加任意数量的基本字符,但空格、左括号、右括号、斜杠和控制字符(制表符和换行符)除外。
可将前缀R和其他字符串前缀结合使用,以标识wchar_t等其他类型的原始字符串。可将R放在前面,也可放在后面,如Ru或uR。