字符串是存储在内存的连续字节中的一系列字符。c++ 处理字符串的方式有两种,一种是来自 c 语言,被称为 C-风格字符串,另一种是基于 string 类库的方法。
1、字符串的构成
储存在连续字节中的一些列字符意味着可以将字符串储存在 char 数组中,其中每个字符都位于自己的数组元素中。即每一个元素代表一个字符。
比如:“i like you, how about you?”。这样的一个字符串里面有字母,标点符号和空格。而按照 ASCII 码将每一个符号进行编码得到其对应的数字,再将其储存在数组中。i 这个字符将被转换为 73,然后储存在这个元素所对应的字节中。
C-风格字符串具有一种特殊的性质:以空字符结尾,空字符被写成 \0,其 ASCII 码为 0,用来标记字符串的结尾。例如下来声明:
char a[10] = {'b','e','a','u','t','i','f','u','l'};
char b[10] = {'b','e','a','u','t','i','f','u','l','\0'};
这两个数组都是 char 数组,但只有第二个是字符串。如果使用 cout 显示 a,cout 将打印出 9 个字母,并接着将内存中随后的各个字节解释为要打印的字符,直到遇到空字符为止。如果打印 b,则将显示 9 个字母,发现空字符后停止。
注意:空字符也占数组的位数,即在声明时,所声明的数组长度应该大于或等于字符串长度+1。如上代码,beautiful 字符串只有九个字符,但是需要声明至少 10 个长度。当然也可以声明大于 10。
2、字符串初始化
使用引号括起字符串即可进行初始化,这种字符串被称为字符串常量或字符串字面值。
char a[10] = "Beautiful"
char b[] = "How beautifule a girl"
注意:用引号括起的字符串隐式地包括结尾的空字符,因此不需要显式地书写。
3、拼接字符串
任何两个由空白(空格、制表符和换行符)分隔的字符串常量都将自动拼接成一个。下列语句输出相同:
cout << "I like you" << endl;
cout << "I " "like " "you" << endl;
cout << "I "
"like "
"you" << endl;
4、字符串输入的问题
cin 使用空白(空格、制表符和换行符)来确定字符串的结束位置,意味着可能出现下列情况:
示例程序4.1:
#include <iostream>
int main()
{
using namespace std;
const int Size = 20;
char name [Size];
char dessert [Size];
cout << "Enter your name:\n";
cin >> name;
cout << "Enter your favorite dessert:\n";
cin >> dessert;
cout << "I have some " << dessert << " for you, " << name << endl;
return 0;
}
运行结果:
正常过程应该是我们输入名字 name 和甜点 dessert 之后,程序才会有输出,但是在我们输入名字后,程序直接进行了输出。实际上,cin 在处理这一段程序时的内部过程如下:
由于 cin 使用空白(空格、制表符和换行符)来确定字符串的结束位置,这意味着 cin 在获取字符数组时只能获得一个连续的单词,读取该单词后,cin 将该字符串放到数组中,并自动在结尾添加空字符。我们所输入的剩余的单词被留在了输入队列中,这里就是输入了第一个单词 wang,而 zhongxing 被留在了输入队列中。当 cin 在输入队列中搜索用户喜欢的甜点时,它发现了 zhongxing,并将它放在了 dessert 数组中。
5、读取一行字符串
因为 c++ 的 cin 具有的特性,我们想要读取整行时就不能单独使用 cin,c++ 给出了其它的方法,面向行的类成员函数:getline() 和 get()。两个函数都能读取一行输入,直到到达换行符。所不同的是,getline() 将丢弃换行符,ger() 将换行符保留在输入序列中。
5.1 getline()
使用 cin.getline()
的方法调用函数。该函数有两个参数,第一个参数用来存储输入行的数组的名称,第二个参数是要读取的字符数。
注意:如果这个参数是 20,那么函数最多读取 19 个字符,余下的一个空间用于存储自动添加的空字符。
用这样的方法替换上面程序的 cin:
cin.getline(name,20);
5.2 get()
由于 get() 不舍弃换行符,那么在连续两次调用 get() 时,将出现错误:第一次调用后,换行符将留在输入队列中,第二次调用时看到的第一个字符就是换行符,因此 get() 认为已经到达行尾,而没有发现任何可读取的内容。如果不借助其它帮助,get() 将不能跨过该换行符。
如果将示例程序 1.4.1 的所有 getline() 替换成 get(),就会出现这种情况
当 get() 不带任何参数时,cin.get() 可读取下一个字符,包括换行符,因此可以用它来处理换行符,为下一次的调用做准备。
在两个 get() 之间加一个
cin.get();
,将在输入队列的换行符取消,就可以解决这个问题。
注意:单独使用 cin() 时,cin 可以识别换行符并将其去掉,但是当先使用 cin(),接着使用 cin.getline() 时,该函数将得到一个换行符,因为 cin() 并未将换行符去掉,而是留在了输入队列。此时可以使用 cin.get() 将其去掉。