
一个标准的 C++ 程序,基本上都会涉及到数据的输入和输出,可以把我们要写的程序想像成一个黑盒子,一端输入数据,经过程序的各种魔法处理,再输出处理后的数据。
前面的程序中,我们已经有使用 cin 来读入数据,使用 cout 来输出数据,而且我们也知道了它们是属于标准输入输出流中的一部分。
标准输入输出
cin 与 cout
要使用 cin 与 cout,需要引入 iostream 头文件。iostream 是 input / output stream 的缩写,它是 C++ 中用于数据输入与输出的标准头文件,属于 C++ 标准函数库的一部分。
#include <iostream>
using namespace std;
int main() {
int a, b, c;
cin >> a >> b >> c;
cout << "三数之和为 " << a + b + c << endl;
}endl 代表 end line,简单说就是换行,也可以换成 \n,是同样的效果。
按行读入字符串
假设有下面一段代码去读入字符串:
#include <iostream>
using namespace std;
int main() {
string s;
cin >> s;
cout << s << endl;
return 0;
}输入数据
hello world!运行程序,得到
hello可以发现,后面的 world! 没有读进来,这是因为在默认情况下,无论使用 cin 还是 scanf() 来读入数据,在遇到空格或换行后都会停止读入。
如果要读入完整一行内容(包括空格),可以使用getline()。
#include <iostream>
using namespace std;
int main() {
string s;
getline(cin, s); // 按行读入(包括当前行的所有内容)
cout << s << endl;
return 0;
}运行程序,输出结果正确。
hello world!空行读入的问题
偶尔我们还会同时使用 cin 和 getline() 去读入数据,这里就很容易遇到读入空行的问题。
比如说,我们希望读入下面这样的数据,一行是年龄,一行是姓名:
18
Jordan Chan我们很容易写出下面这段代码:
#include <iostream>
using namespace std;
int main() {
int age;
cin >> age;
string name;
getline(cin, name);
cout << age << endl;
cout << name << endl;
return 0;
}运行程序,与期待的结果不一样,发现第二行字符串 Jordan Chan 没有读入进来。
这是因为,当我们使用 cin 读完 18 就停下来了(停在 18 与换行符之间),当使用 getline() 读入时,会首先读入 18 后面的换行符,然后就停下来,因此多读入了一个空行,反而真正想读的下一行数据没有读入进来。
解决办法,在 cin 后添加语句 cin.ignore(),忽略掉 cin 后面的换行符。
#include <iostream>
using namespace std;
int main() {
int age;
cin >> age;
cin.ignore(); // 忽略 cin 后面的换行符
string name;
getline(cin, name);
cout << age << endl;
cout << name << endl;
return 0;
}scanf() 与printf()
要使用scanf() 与printf() ,需要引入 cstdio 头文件。cstdio 是将 C 中的 stdio.h 内容以 C++ 头文件的形式表示出来的写法,stdio.h 是 C 标准函数库中的头文件,是 standard buffered input & ouput 的缩写。
下面的代码我们使用了 scanf() 来读入数据,使用 printf() 来输出数据。
#include <cstdio>
using namespace std;
int main() {
int a, b, c;
scanf("%d %d %d", &a, &b, &c);
printf("三数之和为 %d\n", a + b + c);
}这里双引号中的百分号 %,代表后面紧跟的是格式化指令,不同的变量类型,对应不同的格式指令,下面是几组常见的格式化类型指令。
%d,这里的d代表 decimal,表示以整数输出%f,这里的f代表 float,表示以浮点数输出%lf,这里的lf代表 double,表示以双精度浮点数输出%s,这里的s代表 string,表示以字符串输出%c,这里的c代表 character,表示以字符输出
格式化指令当然不止这些,记住一些常用的就行了,在实际使用中,那些不常见的指令可以去查阅相应的文档。
下面两种情况,建议使用 scanf() / printf() :
- 一些带复杂的格式化输出,使用
printf()更为方便 - 需要读取的数据很大时,使用
scanf()读入,效率会更高一些
一般来说,在使用
cin或cout的地方,一定可以替换为scanf或printf,反过来就不行!
格式化输出
当我们在输入数据时,很多时候都会涉及到结果的格式化输出。
来看一个简单的例子。
#include <iostream>
using namespace std;
int main() {
float a, b;
cin >> a >> b;
cout << a / b << endl;
return 0;
}下面是几组输入输出数据。
输入数据 1
2 3输出数据 1
0.666667输入数据 2
20 3输出数据 2
6.66667输入数据 3
200 3输出数据 3
66.6667如果将程序改为 scanf 和 printf 输入输出,代码如下所示:
#include <iostream>
using namespace std;
int main() {
float a, b;
scanf("%f %f", &a, &b);
printf("%f", a / b);
return 0;
}同样的上面三组输入数据,结果如下。
输入数据 1
2 3输出数据 1
0.666667输入数据 2
20 3输出数据 2
6.666667输入数据 3
200 3输出数据 3
66.666664可以发现它们之间的区别。
- 当我们用
cout输出时,结果默认保留 6 位数字(除开小数点后的所有数字) - 当我们用
printf输出时,结果默认保留小数点后 6 位数字
在实际应用中,我们如何去控制输出数据的格式呢,比如,如果想结果保留小数点后两位,该怎么做?
cout 进行格式化输出
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
const float PI = 3.1415926; // 定义为常量
cout << fixed << setprecision(2) << PI << endl;
return 0;
}这里有两点需要注意:
- 要进行格式化输出,需要引入
<iomanip>头文件,或者使用万能头文件 setprecision用于设置精度,但精度所代表的具体含义是由fixed来确定的,加上fixed,表示保留小数点后两位,如果没有fixed,表示除开小数点后保留两位数。
printf 格式化输出
用 printf() 实现同样的保留小数点后两位输出,代码如下:
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
const float PI = 3.1415926; // 定义为常量
printf("%.2f", PI);
return 0;
}这里的 .2f 表示结果以浮点数(float)输出,并且小数点后保留两位,相比 cout 的格式化输出更加简洁、直观。
更复杂的格式化输出
对于一些比较复杂的格式化输出,使用 printf() 可能会更方便一些。
例如,我们想希望输入两个整数 a 和 b,按下面的指定格式输出。
输入:
5 3输出:
a + b = 8, a - b = 2如果使用 cout 输出,代码如下:
#include <iostream>
#include <cstdio>
using namespace std;
int main() {
int a, b;
cin >> a >> b;
cout << "a + b = " << a + b << ", " << "a - b = " << a - b << endl;
return 0;
}使用 printf() 输出,代码如下:
#include <iostream>
#include <cstdio>
using namespace std;
int main() {
int a, b;
cin >> a >> b;
printf("a + b = %d, a - b = %d\n", a + b, a - b);
return 0;
}可以直观看到,使用 printf() 的格式化输出同样会更简洁一些。
小结
在本章节中,我们快速梳理了一下 C++ 中与输入输出相关的基本知识点,在实际应用中,关于输入输出的内容还有很多,比如更多的格式化输出、说文件读入与输出等高级主题,对于初学者和刚入门的竞赛选手来说,掌握上面的这些知识点基本上够用了。