本章介绍程序中的数据存储和使用的基本知识。
"Hello, World!"程序只是打印到屏幕,它不从用户那里得到输入。实际的程序通常基于我们给它的输入产生结果,而不是每次执行都做相同的事。
为了读取数据,需要在计算机内存中的某个地方放置读取的内容,这样的“地方”称为对象。对象(object)是一个某种类型(type)的内存区域,类型指定了可以放置什么样的信息。有名字的对象称为变量(variable)。可以将对象看成一个“盒子”,在其中放置该对象类型的值。例如,下图表示一个名为age
的int
类型的变量,其中保存的是整数值42:
使用字符串(string
)变量可以从输入中读取一个字符串,然后将它打印出来:
main()
的第一行输出一个信息,鼓励用户输入一个名字,这个信息通常称为提示符(prompt)。
下一行string first_name;
定义了一个名为first_name
的string
变量,这将划分一个可以保存一个字符串的内存区域,并将它命名为first_name
,如下图所示:
下一行cin >> first_name;
将键盘输入的字符串读取到变量first_name
。
名字cin
是由标准库定义的标准输入流(读作"see-in",是"character input"的缩写)。操作符>>
右边的名字指定输入到哪里。因此,如果输入"Nicholas"并按回车,则first_name
的值将会变成字符串"Nicholas"
,如下图所示:
注:输出操作符>>
和输入操作符<<
可以看作是数据流动方向的箭头,cout << x
表示将变量x
的内容输出到cout
(屏幕),cin >> x
表示从cin
(键盘)读取内容到x
。
使用>>
运算符读取字符串时,计算机简单地收集输入的字符,直到遇到一个换行符(按下回车键),在按回车键之前可以删除或修改某些字符。这个换行符不会成为字符串的一部分。
最后一行cout << "Hello, " << first_name << "!\n";
使用first_name
变量输出欢迎词"Hello, Nicholas!"。该语句等价于以下三个语句:
cout << "Hello, ";
cout << first_name;
cout << "!\n";
注意,"Hello, "
使用了引号,是一个字符串常量,将原样输出;first_name
没有引号,是一个变量,输出的是变量中的值。
用来存储数据的内存区域称为对象(object),命名后的对象称为变量(variable),它有特定的类型(type)(例如int
或string
)。类型决定可以将什么赋给变量,以及可以使用的操作。赋给变量的数据项称为值(value)。用来定义变量的语句称为定义(definition),定义可以(通常应该)提供一个初始值。例如:
string name = "Annemarie";
int number_of_steps = 39;
可以像这样可视化这些变量:
不能将错误类型的值赋给变量:
string name = 39; // error: 39 is not a string
int number_of_steps = "Annemarie"; // error: "Annemarie" is not an int
否则会产生编译错误。编译器会记录每个变量的类型,并确认你对它的使用是否与它的类型一致。
C++提供了相当多的类型。但是只使用其中五种就完全可以写出好的程序:
int number_of_steps = 39; // int表示整数
double flying_time = 3.5; // double表示浮点数
char decimal_point = '.'; // char表示单个字符
string name = "Annemarie"; // string表示字符串
bool tap_on = true; // bool表示布尔值
每种类型的文字常量/字面值(literal)都有自己特殊的格式:一串数字表示一个整数(例如1234
、2
或976
);带小数点的一串数字表示一个浮点数(例如1.234
、0.12
或.98
);在单引号中的一个字符表示一个字符(例如'1'
、'@'
或'x'
);在双引号中的一串字符表示一个字符串(例如"1234"
、"Howdy!"
或"Annemarie"
);布尔值只有两个:true
或false
。
输入操作>>
(“get from”)是对类型敏感的,它读取的值与变量类型需要一致。例如:
如果输入"Carlos 22",>>
操作符将"Carlos"读入first_name
,将22读入age
,并输出"Hello, Carlos (age 22)"。
为什么它不将"Carlos 22"全部读入first_name
?这是有由于按照规定,字符串的读取会被空白符(whitespace)终止,包括空格、换行符和制表符(tab);对于数值类型的读取,空白符在默认情况下会被>>
忽略。例如,可以在读取的数字之前添加任意多的空格,>>
将会跳过它们并读取这个数字。
如果输入"22 Carlos",“22”将被读入first_name
,而"Carlos"并不是一个整数,因此age
的读取失败。这时的输出将是22和某个随机数(例如-96739或0)。这是因为没有给age
赋一个初始值,并且没能成功地读取一个值存入它,因此得到的是程序开始执行时碰巧在这块内存中的“垃圾值”。只要初始化age
,这样在输入错误时会得到一个可预测的值(初始值):
现在,输入"22 Carlos"将会输出"Hello, 22 (age 0)"。
注:书中说输出是"Hello, 22 (age -1)“,而实际得到的结果是"Hello, 22 (age 0)”。这是由于不同版本的C++标准的区别:当>>
读取失败时,C++11之前不改变变量的值,而C++11之后将变量置为0。对此cppreference有说明:
If extraction fails (e.g. if a letter was entered where a digit is expected), zero is written to value and failbit is set.
注意,可以在一个输入语句中读取多个值,就像可以在一个输出语句中写入多个值一样,因此cin >> first_name;
和cin >> age;
这两行等价于一行cin >> first_name >> age;
使用>>
读取字符串会被空白符终止,也就是说它只能读取一个单词。但是有时候需要读入多个单词,有多种方法来实现。例如,可以像这样读取由两个单词组成的名字:
输入时会忽略空白符,但输出时必须手动插入空格。