C++字符串输入的使用及混合数字读取可能出现的问题
2023-12-18 21:58:32 # 技术

0x00 字符串输入

cin使用空白来确定字符串的结束位置,这意味着cin在获取字符数组输入时只读取一个单词。读取该单词后,cin将该字符串放到数组中,并自动在结尾添加空字符\0

注:C风格字符串以空字符结尾,空字符被写作\0,其ASCII码为0,用来标记字符串的结尾。

0x10 每次读取一行字符串输入

大多时候,每次读取一个单词不是最好的选择。

头文件istream中的类(如cin)提供了一些面向「行」的类成员函数:getline()get()。这两个函数都读取一行输入,直至到达换行符。然而,随后getline()丢弃换行符,而get()将换行符保留在输入序列中。

0x11 面向行的输入:getline()

getline()函数读取整行,它使用通过回车键输入的换行符来确定输入结尾。要调用这个函数,可以使用cin.getline()

该函数有两个参数:

  • 第一个参数是用来存储输入行的数组的名称;
  • 第二个参数是要读取的字符数;

getline()成员函数在读取指定数目的字符或遇到换行符时停止读取。

例如,在使用该函数将姓名读取到一个包含20个元素的name数组时,可以这样使用: cin.getline(name, 20);

0x12 面向行的输入:get()

cin类还有一个名为get()的成员函数,该函数有几种变体。

其中有一种变体的工作方式与getline()类似,它们接受的参数相同,解释参数的方式也一样,并且都读到行尾。但get并不再读取并丢弃换行符,而是将其留在输入队列中。假设我们连续两次使用get():

1
2
cin.get(name1, len);
cin.get(name2, len); // 出现问题,上一个get将换行符留在了输入队列,导致此get看到的第一个字符就是换行符,不能继续读取想要读取的内容

由于第一次调用后,将换行符留在了输入队列中,因此第二次调用时看到的第一个字符便是换行符,此时,因为get(name2,len)并不能读取换行符,所以它会认为已经到达行尾了,并没有发现任何可以读取的内容。因此,如果不借助其他帮助,第二次调用将无法跨过换行符来读取内容。

而get()函数的另一种变体,使用不带任何参数的cin.get()调用可以读取下一字符(可以是换行符)。因此可以使用它来处理换行符。例如:

1
2
3
cin.get(name1, len);
cin.get(); // 读取换行符
cin.get(name2, len);

另一种方式是将两个类成员函数变体拼接起来,如下所示:

1
2
cin.get(name1, len).cin.get(); // 读取字符串后继续读取掉换行符
cin.get(name2, len);

之所以可以这样使用是因为cin.get(name1, len)返回一个cin对象,该对象可以用来继续调用get()函数。

0x20 混合输入字符串和数字所带来的问题

C++中混合输入面向行的字符串数字会导致问题。例如:

1
2
3
4
int age;
char name[30];
cin>>age;
cin.getline(name, 30);

这样使用会导致cin.getline()读取到一个空字符串,原因在于当cin在读取age时会将回车键生成的换行符留在了输入队列,而后面的cin.getline()在看到换行符后,将认为这是一个空行,并将一个空字符串数组赋给name数组。

解决方法是:在使用cin.getline(name, 30)读取整行字符串之前,先使用cin.get()读取并丢弃换行符。