输入和输出格式
到现在为止,程序里的值都是写死的。std::cin 是输入流:它等用户输入,再把读到的值放进变量。点运行,输入一个数试试;页面上显示的是有人输入 25 时的样子(输入的内容本身不显示)。
1#include <iostream>2 3int main() {4 int age = 0;5 std::cout << "你多大了?\n";6 std::cin >> age;7 std::cout << "你今年 " << age << " 岁\n";8 return 0;9}
你多大了? 你今年 25 岁
std::cin >> age 的箭头朝着变量:值从 cin 流进 age。cout 用 <<,箭头朝着 cout,值流出去。>> 会看变量的类型:age 是 int,它就读一个整数。
一次读几个
和 cout 一样,>> 可以连着写,按顺序放进几个变量。类型不同也没关系:
1#include <iostream>2 3int main() {4 int count = 0;5 double price = 0;6 std::cout << "买几件?单价多少?\n";7 std::cin >> count >> price;8 std::cout << "一共 " << count * price << " 元\n";9 return 0;10}
买几件?单价多少? 一共 59.7 元
用户可以输入 3 19.9 再回车,也可以 3 回车、19.9 回车:>> 会先跳过空格和换行,再去读下一个值。
读到空格就停
>> 也能读 std::string。但它只读一个「词」:跳过前面的空格,读到下一个空格或换行就停。假设用户输入的是 林 小明:
1#include <iostream>2#include <string>3 4int main() {5 std::string name;6 std::cout << "你叫什么名字?\n";7 std::cin >> name;8 std::cout << "你好," << name << "!\n";9 return 0;10}
你叫什么名字? 你好,林!
只读到了 林。空格后面的 小明 还留在输入里,等下一次读。
getline 读一整行
要连空格一起读,用 std::getline(std::cin, s):它把这一行剩下的内容全放进 s,到换行为止(换行本身不要)。
1#include <iostream>2#include <string>3 4int main() {5 std::string name;6 std::cout << "你叫什么名字?\n";7 std::getline(std::cin, name);8 std::cout << "你好," << name << "!\n";9 return 0;10}
你叫什么名字? 你好,林 小明!
getline 也在 <string> 里。读名字、地址、一句话,用它;读数字,用 >>。
cin >> 后面接 getline
先用 >> 读一个数,再用 getline 读一行,会出一个有名的问题。用户输入 30 回车,再输入 林 小明 回车:
1#include <iostream>2#include <string>3 4int main() {5 int age = 0;6 std::string name;7 std::cin >> age;8 std::getline(std::cin, name);9 std::cout << "年龄:" << age << '\n';10 std::cout << "名字:" << name << '\n';11 return 0;12}
年龄:30 名字:
名字是空的。>> 读完 30 就停了,30 后面的那个换行还留在输入里。getline 一上来就碰到它,以为这一行已经结束,读到一个空行。
改法:在 getline 之前加一句 std::cin.ignore();(ignore 是 cin 自己会做的一件事,所以写在 std::cin. 后面),丢掉一个字符,也就是那个换行:
1#include <iostream>2#include <string>3 4int main() {5 int age = 0;6 std::string name;7 std::cin >> age;8 std::cin.ignore();9 std::getline(std::cin, name);10 std::cout << "年龄:" << age << '\n';11 std::cout << "名字:" << name << '\n';12 return 0;13}
年龄:30 名字:林 小明
注意: ignore() 只丢一个字符。用户在 30 后面多打了空格,就丢不干净了。现在记住这个坑在哪儿就够了。
控制小数位
输出的样子也可以控制,工具在 <iomanip> 里。std::setprecision(n) 单独用时,管的是一共显示几位数字;前面加上 std::fixed,它才是「小数点后面几位」:
1#include <iostream>2#include <iomanip>3 4int main() {5 double average = 86.4567;6 std::cout << average << '\n';7 std::cout << std::setprecision(2) << average << '\n';8 std::cout << std::fixed << average << '\n';9 std::cout << 5.0 << '\n';10 return 0;11}
86.4567 86 86.46 5.00
第二行只有两位数字:86。第三行有了 std::fixed,是两位小数 86.46(会四舍五入)。最后一行说明:这两个设置一直有效,后面的 double 都显示两位小数,连 5.0 也成了 5.00。显示价格、平均分,通常就写一次 std::fixed << std::setprecision(2)。
setw 对齐
std::setw(n) 让下一个值至少占 n 格,不够的在左边补空格,数字就能右对齐:
1#include <iostream>2#include <iomanip>3 4int main() {5 std::cout << "苹果" << std::setw(6) << 3 << '\n';6 std::cout << "香蕉" << std::setw(6) << 12 << '\n';7 std::cout << "西瓜" << std::setw(6) << 120 << '\n';8 return 0;9}
苹果 3 香蕉 12 西瓜 120
和 fixed 不同,setw 只管紧跟在它后面的那一个值,每个要对齐的值前面都要写一次。它按字节数算宽度,一个汉字在这里算 3 个,所以别拿它去对齐汉字。
[ 和 42 之间有几个空格?
1#include <iostream>2#include <iomanip>3 4int main() {5 std::cout << "[" << std::setw(5) << 42 << "]\n";6 return 0;7}
setw(5) 让 42 一共占 5 格。42 自己占 2 格,左边补 3 个空格:[ 42]。
练一练
写好代码,点检查。提示随便看,实在想不出来再看答案。练习里没人输入,要「输入」的值已经写在变量里了。
两位小数的价格
✓让程序显示 价格:3.50。
价格:3.50
1#include <iostream>2#include <iomanip>3 4int main() {5 double price = 3.5;6 std::cout << "价格:" << price << '\n';7 return 0;8}
对齐的分数
✓用 std::setw(5) 让三个分数右对齐,显示成下面的样子(每个分数占 5 格)。
数学 95 化学 8 美术 100
1#include <iostream>2#include <iomanip>3 4int main() {5 int math = 95;6 int chem = 8;7 int art = 100;8 9 return 0;10}
修好它:少了两位小数
✓程序本来想显示 总价:12.00,却显示了 总价:12。改好它。
总价:12.00
1#include <iostream>2#include <iomanip>3 4int main() {5 double total = 4 * 3.0;6 std::cout << std::setprecision(2);7 std::cout << "总价:" << total << '\n';8 return 0;9}
这一课学会了
std::cin >> x从输入读一个值放进x,按x的类型来读;>>可以连着读几个。>>会跳过空格和换行;读std::string时只读一个词,碰到空格就停。std::getline(std::cin, s)读一整行,空格也算。cin >>后面接getline,会读到剩下的换行;先std::cin.ignore();把它丢掉。<iomanip>:std::fixed << std::setprecision(2)显示两位小数,之后一直有效。std::setw(n)让下一个值至少占n格,右对齐,只管一个值。