目录
一、使用原始的 cin 进行输入
二、使用 cin.get(char) 进行补救
三、文件尾条件
四、另一个 cin.get() 版本
? ? ? ? 在通过 cin 和 cout 对象进行标准输入/输出时,C++系统经常会使用循环语句重复读写数据。在重复读写数据的过程中需要注意 cin 对象会忽略空白字符(空格、换行符和制表符)。产生这个问题的主要原因是系统的 I/O 缓冲区和字符数据的转换。因此文本输入中需要 cin 对象的 get() 函数对空白字符进行特殊处理,或使用 cin 对象的 getline() 函数读取一行数据输入。?
一、使用原始的 cin 进行输入
? ? ? ? 如果程序要使用循环来读取来自键盘的文本输入,则必须有办法知道何时停止读取。有一种方法是选择某个特殊字符——有时被称为哨兵字符(sentinel character),将其作为停止标记。如下面的示例程序在遇到 # 字符时停止读取输入,该程序计算读取的字符数并回显这些字符。
//textin1.cpp -- reading chars with a while loop
#include <iostream>
int main()
{
using namespace std;
char ch;
int count = 0;
cout << "Enter characters; enter # to quit:\n";
cin >> ch;
while (ch != '#')
{
cout << ch;
++count;
cin >> ch;
}
cout << endl << count << " characters read\n";
return 0;
}
? ? ? ? ?上面的示例程序中,在循环开始之前进行了一次输入读取,保证循环的测试表达式可以正常执行。在循环前声明整型变量并初始化为 0 ,保证了第一个字符就是停止字符 # 时,最后显示的 count 值的准确性。 ? ? ? ? 另外,在循环内最后一步读取字符的语句很重要,如果没有这一步,循环将反复处理第一个输入字符,一直进行下去。 ? ? ? ? 最后,因为程序使用原始的 cin 进行输入的读取,而 cin 将忽略空白字符,所以输入中的空格没有被回显,也没有被包括在计数内。
二、使用 cin.get(char) 进行补救
? ? ? ? 通常,逐个字符读取输入的程序需要检查每个字符,包括空格、换行符和制表符。?cin 所属的 istream 类(在 iostream 中定义)中包含一个能够满足这种要求的成员函数——cin.get(ch),它读取输入中的下一个字符(即使是空格),并将其赋给变量 ch。如下面示例程序,使用 cin.get(ch) 函数替换 cin >> ch,可以解决空格没有被回显以及不被包括在计数内的问题。
//textin2.cpp -- using cin.get(char)
#include <iostream>
int main()
{
using namespace std;
char ch;
int count = 0;
cout << "Enter characters; enter # to quit:\n";
cin.get(ch);
while (ch != '#')
{
cout << ch;
++count;
cin.get(ch);
}
cout << endl << count << " characters read\n";
return 0;
}
? ? ? ? 在《C++学习笔记14:字符串》中,我们使用了这样的代码: ????????cin.get(name,ArSize); ????????cin.get(); ? ? ? ? 至此,我们使用过 cin.get() 函数的三个版本:没有参数、一个参数和两个参数。在C++中,基于函数重载的 OOP 特性,允许创建多个同名函数,条件是它们的参数列表不同。例如,如果在C++中使用?cin.get(name,ArSize),则编译器将找到使用 char* 和 int 作为参数的 cin.get() 版本;如果使用 cin.get(ch),则编译器将使用接受一个 char 参数的版本;如果没有提供参数,则编译器将使用不接受任何参数的版本。
三、文件尾条件
? ? ? ? 使用诸如 # 等符号来表示输入结束很难满足所有需求,因为这样的符号可能就是合法输入的组成部分。如果输入来自文件,则可使用一种功能更强大的技术——检测文件尾(EOF)。?如果输入来自键盘,可通过键盘模拟文件尾条件。例如,在 Unix 中,可以在行首按下 Ctrl+D 来实现;在 Windows 命令提示符模式下,可以在任意位置按 Ctrl+Z 和 Enter。 ? ? ? ? 检测到 EOF 后,cin 将两位(eofbit 和 failbit)都设置为 1。可以通过成员函数 eof() 或 fail() 来查看是否被设置:如果检测到 EOF,cin.eof() 和 cin.fail() 将返回 bool 值 true,否则返回 false。注意,eof() 和 fail() 方法报告最近读取的结果,也就是说它们是事后报告,而不是预先报告,因此应将 cin.eof() 或 cin.fail() 测试放在读取后。下面的示例程序体现了这一点,它使用的是 fail(),而不是 eof(),因为前者可用于更多的实现中。
//textin3.cpp -- reading chars to end of file
#include <iostream>
int main()
{
using namespace std;
char ch;
int count = 0;
cout << "Enter characters; enter # to quit:\n";
cin.get(ch);
while (cin.fail() == false)
{
cout << ch;
++count;
cin.get(ch);
}
cout << endl << count << " characters read\n";
return 0;
}
//在键盘上敲击 Ctrl+Z 和回车键,结束读取输入
? ? ? ? 前面指出过,cin 方法检测到 EOF 时,将设置 cin 对象中一个指示 EOF 条件的标记。设置这个标记后,cin 将不再读取输入,再次调用 cin 也不管用。对于文件输入,这是有道理的,因为程序不应读取超出文件尾的内容。然而,对于键盘输入,有可能使用模拟 EOF 来结束循环,但稍后要读取其他输入。cin.clear() 方法可以清除 EOF 标记,使输入继续进行。不过要记住的是,在有些系统中,按 Ctrl+Z 实际上将结束输入和输出,而 cin.clear() 将无法恢复输入和输出。
四、另一个 cin.get() 版本
? ? ? ? 不接受任何参数的 cin.get() 成员函数返回输入中的下一个字符,也就是说,可以这样使用它:? ? ? ? ? ch = cin.get(); ? ? ? ? 该函数的工作方式与C语言中的 getchar() 相似,将字符编码作为 int 值返回;而 cin.get(ch) 返回一个对象,而不是读取的字符。同样,可以使用 cout.put() 函数来显示字符: ? ? ? ? cout.put(ch); ? ? ? ? 该函数的工作方式类似C语言中的 putchar(),只不过其参数类型为 char,而不是 int。 ? ? ? ? 当 cin.get() 到达 EOF 时,将没有可返回的字符,它将返回一个用符号常量 EOF 表示的特殊值(该常量是在头文件 iostream 中定义的)。EOF 值必须不同于任何有效的字符值,通常被定义为-1。下面的示例程序使用 cin.get() 方法修改了前面的示例程序。
//textin4.cpp -- reading chars with cin.get()
#include <iostream>
int main()
{
using namespace std;
int ch;
int count = 0;
cout << "Enter characters; enter # to quit:\n";
//cin.get(ch);
while ((ch = cin.get()) != EOF)
{
cout.put(char(ch));
++count;
//cin.get(ch);
}
cout << endl << count << " characters read\n";
return 0;
}
? ? ? ? 在上面示例程序中,由于 EOF 表示的不是有效字符编码,因此可能不与 char 类型兼容,所以使用 cin.get()(没有参数)并测试 EOF 时,必须将返回值赋给 int 变量,而不是 char 变量。另外,如果将 ch 声明为 int,而不是 char,则必须在显示 ch 时将其强制转换为 char 类型。 ? ? ? ? cin.get(ch) 和 cin.get() 之间的差别如下表所示:
属性 | cin.get(ch) | ch = cin.get() | 传递输入字符的方式 | 赋给参数 ch | 将函数返回值赋给 ch | 用于字符输入时函数的返回值 | istream 对象(执行 bool 转换后为 true) | int 类型的字符编码 | 到达 EOF 时函数的返回值 | istream 对象(执行 bool 转换后为 false) | EOF |
|