基本输入/输出
前面几节的示例程序几乎没有提供与用户的交互,如果有的话。它们只是在屏幕上打印简单的值,
但标准库提供了许多额外的方式来通过其输入/输出功能与用户交互。
本节将简要介绍一些最有用的内容。
C++ 使用称为流(streams)的便捷抽象在屏幕、键盘或文件等媒体中执行输入和输出操作。
流是一个程序可以在其中读写字符的抽象实体。
我们无需了解与流相关联的媒体或其任何内部规范的详细信息。
我们需要知道的是,流是字符的源/目的地,并且这些字符是按顺序读出/写入的(即一个接一个)。
标准库定义了一些流对象,可用于访问程序运行平台认为是标准字符源/目标的内容:
stream |
说明 |
cin |
标准输入流 |
cout |
标准输出流 |
cerr |
标准错误(输出)流 |
clog |
标准日志记录(输出)流 |
我们将详细地了解cout和cin(标准输出和输入流);cerr和clog也是输出流,
因此它们的工作方式本质上与cout类似,
唯一的区别是它们为特定目标的流:错误消息和日志记录;在大多数环境设置中,
它们实际上做完全相同的事情:在屏幕上打印,
尽管它们也可以单独重定向。
☞ 标准输出(cout)
在大多数程序环境中,默认的标准输出是屏幕,而定义用来访问它的 C++ 流对象是cout.
对于格式化输出操作,cout与输出运算符一起使用,它被写为 <<(即两个“小于”符号)。
cout << "Output sentence"; // 打印 Output sentence 到屏幕
cout << 120; // 打印 120 到屏幕
cout << x; // 打印 x 的值到屏幕 |
操作符<<将它后面的数据输出到它前面目标。
在上面的示例中,它将字符串Output sentence、数字 120 和变量值 x 输出到标准输出流cout中。
请注意,第一个语句中的句子用双引号 ( ")括起来,因为它是字符串文字,而在最后一个语句中x则不是。
加或不加双引号是有区别的。当文本在双引号之间时,文本按字面打印;
如果不加,则文本被解释为变量的标识符,并打印其值。
例如,这两个句子有不同的结果:
cout << "Hello"; // 打印 Hello
cout << Hello; // 打印变量 Hello 的值 |
在一个语句中,多个输出操作(<<)可以是链式的:
cout << "This " << " is a " << "single C++ statement"; |
这条语句最后将打印 This is a single C++ statement.
链式输出操作对于包含字符和变量的一条语句进行操作是很有用的:
cout << "I am " << age << " years old and my zipcode is " << zipcode; |
假如 age 的值是 24,zipcode 的值是 90064,这条语句最后将打印:
I am 24 years old and my zipcode is 90064
cout 不会自动结束换行.例如,下面这两个句子:
cout << "This is a sentence.";
cout << "This is another sentence.";
因为没有任何结束标志,他们将输出在一行.
This is a sentence.This is another sentence.
要结束一行,我们需要在合适的地方插入换行符.
c++使用 \n 作为换行符,(一个反斜杠加一个字符 n).例如:
cout << "First sentence.\n";
cout << "Second sentence.\nThird sentence."; |
输出结果:
First sentence.
Second sentence.
Third sentence.
endl也可以结束一行.例如:
cout << "First sentence." << endl;
cout << "Second sentence." << endl; |
输出结果:
First sentence.
Second sentence.
endl和
\n做同样的操作,但是它有一个额外的操作:如果流有缓冲区,那么将被刷新.
这意味着如果缓冲区数据尚未被写入物理设备,则该操作会将缓冲区数据写入设备
这主要影响完全缓冲流,cout(通常)不是完全缓冲流。
不过,通常只在需要刷新流时才使用endl,而在不需要刷新流时使用'\n'是一个好主意。
请记住,刷新流操作会产生一定的开销,在某些设备上可能会产生延迟。
☞ 标准输入 (cin)
在大多数程序环境中,默认的标准输入是键盘,而定义用来访问它的 C++ 流对象是cin.
对于格式化输入操作,cin与输入运算符一起使用,它被写为 >>(即两个“大于”符号)。
该运算符之后是存储输入数据的变量。例如:
第一条语句声明了一个名为 age 的 int 变量,第二条语句从 cin 中提取要存储到其中的值。
此操作使程序等待输入;通常,这意味着程序将等待用户用键盘输入一些数据。
在这种情况下,请注意,使用键盘输入的字符仅在按下 ENTER(或 RETURN) 键时才会输入到程序。
一旦程序运行到cin,程序将等待输入。
上面的操作 cin 使用 >> 运算符后变量的类型来确定它如何解释从输入中读取的字符;
如果是整数,则输入的格式是一系列数字,如果是字符串,则是字符序列等。
// i/o example
#include <iostream>
using namespace std;
int main ()
{
int i;
cout << "Please enter an integer value: ";
cin >> i;
cout << "The value you entered is " << i;
cout << " and its double is " << i*2 << ".\n";
return 0;
} |
Please enter an integer value: 702
The value you entered is 702 and its double is 1404. |
使用cin标准输入使输入数据变得非常简单和直接。但是这种方法也有一个很大的缺点。
如果用户输入了非整数的内容,在上面的示例中会发生什么呢?
在这种情况下,输入操作失败。默认情况下,程序将继续运行而不为变量 i 赋值,
如果稍后使用 i 的值,则会产生不确定的结果。
这是非常糟糕的行为。无论用户键入什么,程序都应该恰当地处理无效值,并且以预期的方式运行。
只有非常简单的程序才依赖直接从 cin 中输入的值,而无需进一步检查。
稍后我们将看到如何使用stringstreams用于更好地控制用户输入。
在单个语句中, cin 也可以链式输入多个数据:
这相当于:
在这种情况下,用户应该输入两个值,一个用于变量 a,另一个用于变量 b。
可以使用空格、制表符或换行符用于分隔两个连续的输入操作;
☞ cin 和 字符串
输入运算符可以让 cin 使用与基本数据类型相同的方式获取字符串:
string mystring;
cin >> mystring; |
但是,cin输入总是将空格(空格、制表符、换行符...)视为正在输入的值的终止,
因此输入字符串意味着始终输入单个单词,而不是短语或整个句子。
要从 cin 获取整行,有一个名为 getline 的函数,
它将流 ( cin) 作为第一个参数,将字符串变量作为第二个参数。例如:
// cin with strings
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string mystr;
cout << "What's your name? ";
getline (cin, mystr);
cout << "Hello " << mystr << ".\n";
cout << "What is your favorite team? ";
getline (cin, mystr);
cout << "I like " << mystr << " too!\n";
return 0;
} |
What's your name? Homer Simpson
Hello Homer Simpson.
What is your favorite team? The Isotopes
I like The Isotopes too! |
请注意,在对 getline 的两次调用中,我们如何使用相同的字符串标识符 ( mystr)。
程序在第二次调用中所做的只是用输入的新内容替换之前的内容。
大多数用户期望控制台程序的标准行为是:
每次程序向用户请求输入时,用户输入一段,然后按ENTER(或RETURN)。
也就是说,输入一般都是在控制台程序中以行的形式出现的,
这可以通过使用getline获取用户的输入来实现。
因此,除非您有充分的理由,否则您应该始终使用getline获取控制台程序中的输入,而不是cin.
☞ 字符串流(stringstream)
标准库头文件
<sstream>
定义了一种称为 stringstream 的类,它允许将字符串视为流,
从而以与 cin 和cout 相同的方式读写字符串。
此功能最适用于将字符串转换为数值,反之亦然。
例如,为了从字符串中提取一个整数,我们可以这样写:
string mystr ("1204");
int myint;
stringstream(mystr) >> myint; |
这声明了一个string类型变量, 初始化的值为 "1204" ,以及一个类型为 int 的变量。
然后,第三行使用 stringstream 从字符串 mystr 中提取。
这段代码将数值 1204 存储在名为 myint 的变量中。
// stringstreams
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main ()
{
string mystr;
float price=0;
int quantity=0;
cout << "Enter price: ";
getline (cin,mystr);
stringstream(mystr) >> price;
cout << "Enter quantity: ";
getline (cin,mystr);
stringstream(mystr) >> quantity;
cout << "Total price: " << price*quantity << endl;
return 0;
} |
Enter price: 22.25
Enter quantity: 7
Total price: 155.75 |
在这个例子中,我们间接地从标准输入(standard input)中获取数值:我们不是直接从 cin 中提取数值,
而是从它输入的一个字符串对象 ( mystr) 中获取一行.
我们将这个字符串中的值提取到变量 price 和 quantity中。
如果这些是数值,就可以对它们进行算术运算,例如将它们相乘以获得总价。
通过这种获取整行并提取其内容的方法,我们将获取用户输入的过程,与将其作为数据的运算分开,
这是符合用户期望的输入操作,同时,增强了通过程序对其内容转换为有用数据的控制。