主题:[原创]<C++ Primer>翻译-chapter 1-1.2
1.2 第一次接触输入和输出
C++没有定义专门定义有关输入和输出操作的语句,相反程序的输入和输出是通过使用标准库来实现的,即使用其中的IO(Input/Output)类库。标准库提供了丰富的IO功能,但基于本书学习的需要,我们只需要了解其中的一些基本概念和相关操作。
本书的所有程序实例都是用了被称为iostream的库,这是一个处理输入和输出的IO类库。iostream库中的两个基础类型是istream 和ostream,他们分别表示输入和输出流。流是一个抽象出来的概念,这里表示连续的一串字符,流的概念体现出在时间上字符的产生和消耗的连续性。输入流中的字符来自于输入设备(键盘),输出流中的字符将流向输出设备(显示器)。
1.2.1 标准输入输出对象
iostream类库定义了4个对象。其中由类型istream定义的对象是cin(读作see-in),其他三个对象由类型ostream定义,分别是cout(读作see-out),cerr(读作see-err),clog(读作see-log)。
我们经常使用 cin来从标准设备读入数据,使用cout输出数据到标准输出设备。操作系统一般都提供程序重新定向的功能,例如程序的输入可定向到一个文件,即使cin不再从键盘(或者其它标准设备)得到数据,而是读取文件中的数据。操作系统重定向也同样影响cout,但不会影响cerr。cerr对象用于输出错误提示消息。因此,如果将程序重定向到文件,并发生了错误,则屏幕仍然会出现错误提示信息。若此时使用cout来输出错误提示信息,那么这个错误信息会写入(输出到)文件,我们将无法从屏幕看到错误提示信息。
译者注:在C语言中的,语句int var;表示定义了一个int型变量var,在 C++中这也可以称为类型int定义了一个对象var。这和上面提到的类型istream定义的对象cin在概念上是一致的。
1.2.2 使用标准IO库的程序实例
到现在为止,经过上节的介绍我们已经知道怎样编译一个程序,尽管那个程序什么也干不了。现在提出一个问题,假如我们知道了一个书号(ISBN)的几个分开销售记录,但我们要知道这个书号的总的销售记录,这意味着我们要把那几个销售记录加起来。
为了解决上面的问题,我们先来看看怎样用代码实现把两个数加起来。使用IO库,我们可以扩展那个什么也不能干的程序的main函数,增加的功能是要求用户输入两个数值,然后显示出它们的和。
#include <iostream>
int main()
{
std::cout << "Enter two numbers:" << std::endl;
int v1, v2;
std::cin >> v1 >> v2;
std::cout << "The sum of " << v1 << " and " << v2
<< " is " << v1 + v2 << std::endl;
return 0;
}
在程序开始计算之前会显示
Enter two numbers:
这是等待用户的输入,如果输入
3 7
则接着程序将输出
The sum of 3 and 7 is 10
程序的第一行是一个预处理器指令
#include <iostream>
它将告诉编译器我们要使用iostream库。一对尖括号内是头文件名,程序为了使用库的功能,则必须先包含其头文件。预处理器指令#include必须在单独的一行出现,而且一般都要出现源文件的起始处。一般来说,任何函数体内部不能使用#include指令。
写入一个流
主函数main的第一行语句执行了一个表达式。在C++中一个表达式由一个或多个的操作数和(经常)一个操作符组成。为了输出请求用户输入的提示信息,表达式使用了输出操作符“<<”把提示信息送到标准输出(显示器屏幕)。
std::cout << "Enter two numbers:" << std::endl;
这条语句两次使用了输出操作符“<<”。每个操作符使用了两个操作数,左边是一个ostream类型的对象(cout),右边是一个需要打印的数值。操作符把右边的操作数写入左边输出流对象。
在C++表达式中,由于操作符对操作数的作用,表达式会产生(返回)一个数值。对于含有输出操作符的表达式中,表达式产生的数值就是操作符左边的操作数。换句话说,输出操作产生的数值就是输出流本身。
译者注:在C语言中,我们可以连续使用使用赋值操作符a=b=c;这里“<<”的使用情况和赋值操作符“=”很相似。
这样的一个事实,说明了输出操作返回的数值是左边的操作数(cout),进而说明我们可以连续使用输出操作符来输出。括号内的表达式的返回值就是cout,下面的语句写法表明了这个观点,它和原来的代码是等价的。
(std::cout << "Enter two numbers:") << std::endl;
表达式(std::cout << "Enter two numbers:")返回左边的操作数,即std::cout。这个语句等价于:
std::cout << "Enter two numbers:";
std::cout << std::endl;
endl是一个特殊的数值,可以被写入输出流中并起到换行的作用。另一个作用是刷新输出设备的输出流缓冲区,刷新缓冲区后,用户可以马上看到输出流中的内容。
BEWARE:程序员在调试程序的时候,经常会插入一些输出语句,并根据其输出的内容来确定运行的程序在哪个位置出现了问题。但要注意,插入这样的语句时,同时要刷新输出流。因为如果忘记了这样作,在任何隐式或显示的刷新输出流的行为发生之前,那些输出内容会一直存放在缓冲区中,当程序出现错误而崩溃的时候,那些输出内容来不及在输出设备上显示,这样会让程序员得出关于错误出现位置的不正确结论。因为对于那些未显示的输出,我们无法确定是在哪个输出语句的位置上错现了错误。
使用标准库的名称空间
细心的读者会发现,我们的程序使用了std::cout 和 std::endl,而不是cout 和 endl。
使用前缀std::表明cout 和 endl作为标识符,他们的名字被定义在名字叫做std的名称空间中。名称空间避免了库内部命名的同名冲突。由于标准库使用了名称空间,我们的程序标识符的命名可以与标准库的相同。
一方面由于标准库库使用了名称空间,所以当我们使用库中的一个名字时,我们必须显式的说明我们使用了std名称空间中的名字。对于std::cout,其中的作用域操作符“::”意味着我们使用了std名称空间中定义的的一个名字cout。在第三章我们将介绍在程序中避免反复书写作用域操作符的方法。
从流输入中读取数据
现在讲到程序已经输出了提示输入的信息,下一步程序将读取用户输入的数据。我们已经定义了两个变量(对象)v1 和v2 来报存用户的输入。
int v1, v2;
这两个没有初始化的变量的类型为 int,int是一个C++语言内建的表示整数的类型。第一次使用这两个变量是保存用户输入的数据,所以我们没有必要为他们初始化进行赋值。
std::cin >> v1 >> v2;
输入操作符“>>”的行为与输出操作符很相似。它左边是一个istream类型对象,而右边的操作数是一个int类型变量,输入操作符把左边的输入流的数据传送到右边的变量保存。输入操作符和输出操作符一样,将其左操作数作为返回结果。因此我们也可以连续使用输入操作符“>>”。输入部分等价于下面的代码:
std::cin >> v1;
std::cin >> v2;
这里输入操作的目的是从标注输入读取两个数值,并用v1保存第一个数值,v2保存第二个。
读到程序的最后
剩下的代码将输出计算结果.
std::cout << "The sum of " << v1 << " and " << v2
<< " is " << v1 + v2 << std::endl;
这条输出语句和前面的有些不同。它右边的操作数的类型并不相同,一些操作数是字符串,比如:
"The sum of "
而其它的两个是整型,比如变量v1和v2,及其他们的算术相加表达式:
v1 + v2
iostream库定义了不同版本的输入和输出操作符,这使得他们能处理所有语言内建类型的数据。
NOTE:在写C++代码的时候,在空格可以出现的地方,我们也可以另起一行取而代之。
这条规则的例外是在字符串内部出现空格的地方,我们就不可以另起一行(有的编译器允许这样作)。还有一个例外是预处理指令内部出现的空格也不能用另起一行取而代之。比如对于
std::cout << "Enter two numbers:" << std::endl;
cout与“<<”之间有一个空格,字符串内部Enter和two之间也有一个空格。我们可以这样书写代码:
std::cout
<< "Enter two numbers:" << std::endl;
但不可以这样写:
std::cout << "Enter
two numbers:" << std::endl;
Key Concept:初始化变量
初始化是C++中的一个重要的概念。初始化的意思就是在定义变量时对其进行赋值。
int val1 = 0; //已经初始化
int val2; // 没有初始化
给每一个变量进行初始化总是正确的,但我们并不总是需要这样作。当我们可以确定变量在第一次使用时,即将被重新赋值,所以在定义变量时进行初始化没有什么意义。本节的实例程序也是这样做的。相反如果我们不能定变量在第一次使用时已被重新赋值,我们还是有必要对其进行初始化。
Exercises Section 1.2.2
Exercise 1.3: 写一个程序可以输出字符串"Hello, World"的程序 .
Exercise 1.4: 本节的程序使用了内建加法操作符“+”来进行求和。试使用内建乘法操作符“*”,来求出两个数的乘积。
Exercise 1.5:本节的程序的输出语句一般都连用“<<”,把输出在一条语句实现。现在把原来的输出内容分写在单独的语句中。
Exercise 1.6: 解释下面代码段的作用
std::cout << "The sum of " << v1;
<< " and " << v2 ;
<< " is " << v1 + v2
<< std::endl;
这个代码段的书写是合法的吗?为什么?
C++没有定义专门定义有关输入和输出操作的语句,相反程序的输入和输出是通过使用标准库来实现的,即使用其中的IO(Input/Output)类库。标准库提供了丰富的IO功能,但基于本书学习的需要,我们只需要了解其中的一些基本概念和相关操作。
本书的所有程序实例都是用了被称为iostream的库,这是一个处理输入和输出的IO类库。iostream库中的两个基础类型是istream 和ostream,他们分别表示输入和输出流。流是一个抽象出来的概念,这里表示连续的一串字符,流的概念体现出在时间上字符的产生和消耗的连续性。输入流中的字符来自于输入设备(键盘),输出流中的字符将流向输出设备(显示器)。
1.2.1 标准输入输出对象
iostream类库定义了4个对象。其中由类型istream定义的对象是cin(读作see-in),其他三个对象由类型ostream定义,分别是cout(读作see-out),cerr(读作see-err),clog(读作see-log)。
我们经常使用 cin来从标准设备读入数据,使用cout输出数据到标准输出设备。操作系统一般都提供程序重新定向的功能,例如程序的输入可定向到一个文件,即使cin不再从键盘(或者其它标准设备)得到数据,而是读取文件中的数据。操作系统重定向也同样影响cout,但不会影响cerr。cerr对象用于输出错误提示消息。因此,如果将程序重定向到文件,并发生了错误,则屏幕仍然会出现错误提示信息。若此时使用cout来输出错误提示信息,那么这个错误信息会写入(输出到)文件,我们将无法从屏幕看到错误提示信息。
译者注:在C语言中的,语句int var;表示定义了一个int型变量var,在 C++中这也可以称为类型int定义了一个对象var。这和上面提到的类型istream定义的对象cin在概念上是一致的。
1.2.2 使用标准IO库的程序实例
到现在为止,经过上节的介绍我们已经知道怎样编译一个程序,尽管那个程序什么也干不了。现在提出一个问题,假如我们知道了一个书号(ISBN)的几个分开销售记录,但我们要知道这个书号的总的销售记录,这意味着我们要把那几个销售记录加起来。
为了解决上面的问题,我们先来看看怎样用代码实现把两个数加起来。使用IO库,我们可以扩展那个什么也不能干的程序的main函数,增加的功能是要求用户输入两个数值,然后显示出它们的和。
#include <iostream>
int main()
{
std::cout << "Enter two numbers:" << std::endl;
int v1, v2;
std::cin >> v1 >> v2;
std::cout << "The sum of " << v1 << " and " << v2
<< " is " << v1 + v2 << std::endl;
return 0;
}
在程序开始计算之前会显示
Enter two numbers:
这是等待用户的输入,如果输入
3 7
则接着程序将输出
The sum of 3 and 7 is 10
程序的第一行是一个预处理器指令
#include <iostream>
它将告诉编译器我们要使用iostream库。一对尖括号内是头文件名,程序为了使用库的功能,则必须先包含其头文件。预处理器指令#include必须在单独的一行出现,而且一般都要出现源文件的起始处。一般来说,任何函数体内部不能使用#include指令。
写入一个流
主函数main的第一行语句执行了一个表达式。在C++中一个表达式由一个或多个的操作数和(经常)一个操作符组成。为了输出请求用户输入的提示信息,表达式使用了输出操作符“<<”把提示信息送到标准输出(显示器屏幕)。
std::cout << "Enter two numbers:" << std::endl;
这条语句两次使用了输出操作符“<<”。每个操作符使用了两个操作数,左边是一个ostream类型的对象(cout),右边是一个需要打印的数值。操作符把右边的操作数写入左边输出流对象。
在C++表达式中,由于操作符对操作数的作用,表达式会产生(返回)一个数值。对于含有输出操作符的表达式中,表达式产生的数值就是操作符左边的操作数。换句话说,输出操作产生的数值就是输出流本身。
译者注:在C语言中,我们可以连续使用使用赋值操作符a=b=c;这里“<<”的使用情况和赋值操作符“=”很相似。
这样的一个事实,说明了输出操作返回的数值是左边的操作数(cout),进而说明我们可以连续使用输出操作符来输出。括号内的表达式的返回值就是cout,下面的语句写法表明了这个观点,它和原来的代码是等价的。
(std::cout << "Enter two numbers:") << std::endl;
表达式(std::cout << "Enter two numbers:")返回左边的操作数,即std::cout。这个语句等价于:
std::cout << "Enter two numbers:";
std::cout << std::endl;
endl是一个特殊的数值,可以被写入输出流中并起到换行的作用。另一个作用是刷新输出设备的输出流缓冲区,刷新缓冲区后,用户可以马上看到输出流中的内容。
BEWARE:程序员在调试程序的时候,经常会插入一些输出语句,并根据其输出的内容来确定运行的程序在哪个位置出现了问题。但要注意,插入这样的语句时,同时要刷新输出流。因为如果忘记了这样作,在任何隐式或显示的刷新输出流的行为发生之前,那些输出内容会一直存放在缓冲区中,当程序出现错误而崩溃的时候,那些输出内容来不及在输出设备上显示,这样会让程序员得出关于错误出现位置的不正确结论。因为对于那些未显示的输出,我们无法确定是在哪个输出语句的位置上错现了错误。
使用标准库的名称空间
细心的读者会发现,我们的程序使用了std::cout 和 std::endl,而不是cout 和 endl。
使用前缀std::表明cout 和 endl作为标识符,他们的名字被定义在名字叫做std的名称空间中。名称空间避免了库内部命名的同名冲突。由于标准库使用了名称空间,我们的程序标识符的命名可以与标准库的相同。
一方面由于标准库库使用了名称空间,所以当我们使用库中的一个名字时,我们必须显式的说明我们使用了std名称空间中的名字。对于std::cout,其中的作用域操作符“::”意味着我们使用了std名称空间中定义的的一个名字cout。在第三章我们将介绍在程序中避免反复书写作用域操作符的方法。
从流输入中读取数据
现在讲到程序已经输出了提示输入的信息,下一步程序将读取用户输入的数据。我们已经定义了两个变量(对象)v1 和v2 来报存用户的输入。
int v1, v2;
这两个没有初始化的变量的类型为 int,int是一个C++语言内建的表示整数的类型。第一次使用这两个变量是保存用户输入的数据,所以我们没有必要为他们初始化进行赋值。
std::cin >> v1 >> v2;
输入操作符“>>”的行为与输出操作符很相似。它左边是一个istream类型对象,而右边的操作数是一个int类型变量,输入操作符把左边的输入流的数据传送到右边的变量保存。输入操作符和输出操作符一样,将其左操作数作为返回结果。因此我们也可以连续使用输入操作符“>>”。输入部分等价于下面的代码:
std::cin >> v1;
std::cin >> v2;
这里输入操作的目的是从标注输入读取两个数值,并用v1保存第一个数值,v2保存第二个。
读到程序的最后
剩下的代码将输出计算结果.
std::cout << "The sum of " << v1 << " and " << v2
<< " is " << v1 + v2 << std::endl;
这条输出语句和前面的有些不同。它右边的操作数的类型并不相同,一些操作数是字符串,比如:
"The sum of "
而其它的两个是整型,比如变量v1和v2,及其他们的算术相加表达式:
v1 + v2
iostream库定义了不同版本的输入和输出操作符,这使得他们能处理所有语言内建类型的数据。
NOTE:在写C++代码的时候,在空格可以出现的地方,我们也可以另起一行取而代之。
这条规则的例外是在字符串内部出现空格的地方,我们就不可以另起一行(有的编译器允许这样作)。还有一个例外是预处理指令内部出现的空格也不能用另起一行取而代之。比如对于
std::cout << "Enter two numbers:" << std::endl;
cout与“<<”之间有一个空格,字符串内部Enter和two之间也有一个空格。我们可以这样书写代码:
std::cout
<< "Enter two numbers:" << std::endl;
但不可以这样写:
std::cout << "Enter
two numbers:" << std::endl;
Key Concept:初始化变量
初始化是C++中的一个重要的概念。初始化的意思就是在定义变量时对其进行赋值。
int val1 = 0; //已经初始化
int val2; // 没有初始化
给每一个变量进行初始化总是正确的,但我们并不总是需要这样作。当我们可以确定变量在第一次使用时,即将被重新赋值,所以在定义变量时进行初始化没有什么意义。本节的实例程序也是这样做的。相反如果我们不能定变量在第一次使用时已被重新赋值,我们还是有必要对其进行初始化。
Exercises Section 1.2.2
Exercise 1.3: 写一个程序可以输出字符串"Hello, World"的程序 .
Exercise 1.4: 本节的程序使用了内建加法操作符“+”来进行求和。试使用内建乘法操作符“*”,来求出两个数的乘积。
Exercise 1.5:本节的程序的输出语句一般都连用“<<”,把输出在一条语句实现。现在把原来的输出内容分写在单独的语句中。
Exercise 1.6: 解释下面代码段的作用
std::cout << "The sum of " << v1;
<< " and " << v2 ;
<< " is " << v1 + v2
<< std::endl;
这个代码段的书写是合法的吗?为什么?