跳转到内容

数据输入与输出

一个标准的 C++ 程序,基本上都会涉及到数据的输入和输出,可以把我们要写的程序想像成一个黑盒子,一端输入数据,经过程序的各种魔法处理,再输出处理后的数据。

前面的程序中,我们已经有使用 cin 来读入数据,使用 cout 来输出数据,而且我们也知道了它们是属于标准输入输出流中的一部分。

标准输入输出

cincout

要使用 cincout,需要引入 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!

空行读入的问题

偶尔我们还会同时使用 cingetline() 去读入数据,这里就很容易遇到读入空行的问题。

比如说,我们希望读入下面这样的数据,一行是年龄,一行是姓名:

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() 读入,效率会更高一些

一般来说,在使用 cincout 的地方,一定可以替换为 scanfprintf,反过来就不行!

格式化输出

当我们在输入数据时,很多时候都会涉及到结果的格式化输出。

来看一个简单的例子。

#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

如果将程序改为 scanfprintf 输入输出,代码如下所示:

#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;
}

这里有两点需要注意:

  1. 要进行格式化输出,需要引入 <iomanip> 头文件,或者使用万能头文件
  2. 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() 可能会更方便一些。

例如,我们想希望输入两个整数 aabb,按下面的指定格式输出。

输入:

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++ 中与输入输出相关的基本知识点,在实际应用中,关于输入输出的内容还有很多,比如更多的格式化输出、说文件读入与输出等高级主题,对于初学者和刚入门的竞赛选手来说,掌握上面的这些知识点基本上够用了。