杨记

碎片化学习令人焦虑,系统化学习使人进步

0%

C++基本的输入输出

C++的输入输出

C++ 基本的输入输出

C++ 标准库提供了一组丰富的输入/输出功能,我们将在后续的章节进行介绍。本章将讨论 C++ 编程中最基本和最常见的 I/O 操作。

C++ 的 I/O 发生在流中,流是字节序列。如果字节流是从设备(如键盘、磁盘驱动器、网络连接等)流向内存,这叫做输入操作。如果字节流是从内存流向设备(如显示屏、打印机、磁盘驱动器、网络连接等),这叫做输出操作

I/O 库头文件

下列的头文件在 C++ 编程中很重要。

头文件 函数和描述
\ 该文件定义了 cin、cout、cerrclog 对象,分别对应于标准输入流、标准输出流、非缓冲标准错误流和缓冲标准错误流。
\ 该文件通过所谓的参数化的流操纵器(比如 setwsetprecision),来声明对执行标准化 I/O 有用的服务。
\ 该文件为用户控制的文件处理声明服务。

标准输出流(cout)

预定义的对象 coutiostream 类的一个实例。cout 对象”连接”到标准输出设备,通常是显示屏。cout 是与流插入运算符 << 结合使用的。

C++ 编译器根据要输出变量的数据类型,选择合适的流插入运算符来显示值。<< 运算符被重载来输出内置类型(整型、浮点型、double 型、字符串和指针)的数据项。

流插入运算符 << 在一个语句中可以多次使用,如上面实例中所示,endl 用于在行末添加一个换行符。

标准输入流(cin)

预定义的对象 ciniostream 类的一个实例。cin 对象附属到标准输入设备,通常是键盘。cin 是与流提取运算符 >> 结合使用的。

C++ 编译器根据要输入值的数据类型,选择合适的流提取运算符来提取值,并把它存储在给定的变量中。

流提取运算符 >> 在一个语句中可以多次使用。

标准错误流(cerr)

预定义的对象 cerriostream 类的一个实例。cerr 对象附属到标准错误设备,通常也是显示屏,但是 cerr 对象是非缓冲的,且每个流插入到 cerr 都会立即输出。

cerr 也是与流插入运算符 << 结合使用的,如下所示:

实例

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>

using namespace std;

int main( )
{
char str[] = "Unable to read....";

cerr << "Error message : " << str << endl;
}
// Error message : Unable to read....

标准日志流(clog)

预定义的对象 clogiostream 类的一个实例。clog 对象附属到标准错误设备,通常也是显示屏,但是 clog 对象是缓冲的。这意味着每个流插入到 clog 都会先存储在缓冲区,直到缓冲填满或者缓冲区刷新时才会输出。

clog 也是与流插入运算符 << 结合使用的,如下所示:

实例

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>

using namespace std;

int main( )
{
char str[] = "Unable to read....";

cerr << "Error message : " << str << endl;
}
// Error message : Unable to read....

通过这些小实例,我们无法区分 cout、cerr 和 clog 的差异,但在编写和执行大型程序时,它们之间的差异就变得非常明显。所以良好的编程实践告诉我们,使用 cerr 流来显示错误消息,而其他的日志消息则使用 clog 流来输出。


输出流中的函数

输入输出流中的函数示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
cout<<setiosflags(ios::left|ios::showpoint); // 设左对齐,以一般实数方式显示
cout.precision(5); // 设置除小数点外有五位有效数字
cout<<123.456789<<endl;
cout.width(10); // 设置显示域宽10
cout.fill('*'); // 在显示区域空白处用*填充
cout<<resetiosflags(ios::left); // 清除状态左对齐
cout<<setiosflags(ios::right); // 设置右对齐
cout<<123.456789<<endl;
cout<<setiosflags(ios::left|ios::fixed); // 设左对齐,以固定小数位显示
cout.precision(3); // 设置实数显示三位小数
cout<<999.123456<<endl;
cout<<resetiosflags(ios::left|ios::fixed); //清除状态左对齐和定点格式
cout<<setiosflags(ios::left|ios::scientific); //设置左对齐,以科学技术法显示
cout.precision(3); //设置保留三位小数
cout<<123.45678<<endl;
return 0;
}

测试输出结果:

1
2
3
4
123.46
****123.46
999.123
1.235e+02

其中 cout.setfsetiosflags 一样,cout.precisionsetprecision 一样,cout.unsetfresetiosflags 一样。

1
2
3
4
5
6
7
8
9
setiosflags(ios::fixed) 固定的浮点显示 
setiosflags(ios::scientific) 指数表示
setiosflags(ios::left) 左对齐
setiosflags(ios::right) 右对齐
setiosflags(ios::skipws) 忽略前导空白
setiosflags(ios::uppercase) 16进制数大写输出
setiosflags(ios::lowercase) 16进制小写输出
setiosflags(ios::showpoint) 强制显示小数点
setiosflags(ios::showpos) 强制显示符号

cout.setf 常见的标志

标志 功能
boolalpha 可以使用单词”true”和”false”进行输入/输出的布尔值.
oct 用八进制格式显示数值.
dec 用十进制格式显示数值.
hex 用十六进制格式显示数值.
left 输出调整为左对齐.
right 输出调整为右对齐.
scientific 用科学记数法显示浮点数.
fixed 用正常的记数方法显示浮点数(与科学计数法相对应).
showbase 输出时显示所有数值的基数.
showpoint 显示小数点和额外的零,即使不需要.
showpos 在非负数值前面显示”+(正号)”.
skipws 当从一个流进行读取时,跳过空白字符(spaces, tabs, newlines).
unitbuf 在每次插入以后,清空缓冲区.
internal 将填充字符回到符号和数值之间.
uppercase 以大写的形式显示科学记数法中的”e”和十六进制格式的”x”.

iostream 中定义的操作符:

操作符 描述 输入 输出
boolalpha 启用boolalpha标志
dec 启用dec标志
endl 输出换行标示,并清空缓冲区
ends 输出空字符
fixed 启用fixed标志
flush 清空流
hex 启用 hex 标志
internal 启用 internal 标志
left 启用 left 标志
noboolalpha 关闭boolalpha 标志
noshowbase 关闭showbase 标志
noshowpoint 关闭showpoint 标志
noshowpos 关闭showpos 标志
noskipws 关闭skipws 标志
nounitbuf 关闭unitbuf 标志
nouppercase 关闭uppercase 标志
oct 启用 oct 标志
right 启用 right 标志
scientific 启用 scientific 标志
showbase 启用 showbase 标志
showpoint 启用 showpoint 标志
showpos 启用 showpos 标志
skipws 启用 skipws 标志
unitbuf 启用 unitbuf 标志
uppercase 启用 uppercase 标志
ws 跳过所有前导空白字符

iomanip 中定义的操作符

操作符 描述 输入 输出
resetiosflags(long f) 关闭被指定为f的标志
setbase(int base) 设置数值的基本数为base
setfill(int ch) 设置填充字符为ch
setiosflags(long f) 启用指定为f的标志
setprecision(int p) 设置数值的精度(四舍五入)
setw(int w) 设置域宽度为w

C++输入多个字符,中间用一个字符隔开

1
2
3
4
cin>>a;cin.get();
cin>>b;cin.get();
cin>>c;
输入 1,2,3 或者 1a2b3都可以
1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
#include <iomanip>
using namespace std;

int main()
{
double d;
cin>>d;
cout << setprecision(4) << setiosflags(ios::fixed) << d << endl; //设置小数点后输出位数
return 0;
}

来自 C++ 基本的输入输出 | 菜鸟教程 (runoob.com)

cin详细介绍

在理解cin功能时,不得不提标准输入缓冲区。当我们从键盘输入字符串的时候需要敲一下回车键才能够将这个字符串送入到缓冲区中,那么敲入的这个回车键(\r)会被转换为一个换行符\n,这个换行符\n也会被存储在cin的缓冲区中并且被当成一个字符来计算!比如我们在键盘上敲下了123456这个字符串,然后敲一下回车键(\r)将这个字符串送入了缓冲区中,那么此时缓冲区中的字节个数是7 ,而不是6。

cin读取数据也是从缓冲区中获取数据,缓冲区为空时,cin的成员函数会阻塞等待数据的到来,一旦缓冲区中有数据,就触发cin的成员函数去读取数据。

cin连续读入数据时,以==空格(32),tab(9),或换行符(10)==作为分隔符。

  • cin>>等价于cin.operator>>()
  • cin.get()
  • cin.getline()

noskipws不忽略空白符

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
using namespace std;

int main()
{
char a, b;
cin>>noskipws>>a>>b;
cout<<"a:"<<a<<endl;
cout<<"b:"<<b<<endl;
return 0;
}
1
2
3
4
5
6
7
8
9
10
输入"a b"+回车
输出b的值为空格,而不是'b'
a:a
b:

输入a+回车
输出b为回车
a:a
b:

cin.get的用法

函数原型:

1
2
3
4
int cin.get();
istream& cin.get(char& var);
istream& get ( char* s, streamsize n); // 默认换行符结束,n 表示目标空间大小
istream& get ( char* s, streamsize n, char delim); // 指定结束符

其中streamsize在VC++中被定义为long long

1
2
istream& get ( streambuf& sb);
istream& get ( streambuf& sb, char delim );

cin.get读取一个字符

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
using namespace std;

int main()
{
char a, b;
a=cin.get();
cin.get(b);
cout<<"a:"<<a<<endl;
cout<<"b:"<<b<<endl;
return 0;
}

cin.get()的返回值是int类型,成功:读取字符的ASCII码值,遇到文件结束符时,返回EOF,即-1,Windows下标准输入输入文件结束符为Ctrl+z,Linux为Ctrl+d。cin.get(char var)如果成功返回的是cin对象,因此可以支持链式操作,如cin.get(b).get(c)。

cin.get读取一行

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
using namespace std;

int main()
{
char a;
char array[20]={NULL};
cin.get(array,20);
cin.get(a);
cout<<array<<" "<<(int)a<<endl;
return 0;
}

注意:只能读入C风格的字符串char *,不能是C++风格字符串string。

cin.getline读取一行

函数原型

1
2
istream& getline(char* s, streamsize count); //默认以换行符结束
istream& getline(char* s, streamsize count, char delim); // 指定结束符

示例

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
#include <string>
using namespace std;
int main()
{
//C风格
char array[20]={NULL};
cin.getline(array,20); //或者指定结束符,使用下面一行
//cin.getline(array,20,'\n');
cout<<array<<endl;
}

注意:cin.getline与cin.get的区别是,cin.getline不会将结束符或者换行符残留在输入缓冲区中。

cin的条件状态

使用cin读取键盘输入时,难免发生错误,一旦出错,cin将设置条件状态(condition state)。条件状态标识符号为:
goodbit:无错误
eofbit:已到达文件尾
failbit:非致命的输入/输出错误,可挽回
badbit:致命的输入/输出错误,无法挽回
若在输入输出类里.需要加ios::标识符号。与这些条件状态对应的就是设置、读取和判断条件状态的流对象的成员函数。他们主要有:
s.eof():若流s的eofbit置位,则返回true;
s.fail():若流s的failbit置位,则返回true;
s.bad():若流s的badbit置位,则返回true;
s.good():若流s的goodbit置位,则返回true;
s.clear(flags):清空状态标志位,并将给定的标志位flags置为1,返回void。
s.setstate(flags):根据给定的flags条件状态标志位,将流s中对应的条件状态位置为1,返回void。
s.rdstate():返回流s的当前条件状态,返回值类型为strm::iostate。strm::iostate 机器相关的整形名,由各个iostream类定义,用于定义条件状态。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
using namespace std;

int main()
{
char ch, str[20];
cin.getline(str, 5);
cout<<"flag1:"<<cin.good()<<endl; // 查看goodbit状态,即是否有异常
cin.clear(); // 清除错误标志
cout<<"flag1:"<<cin.good()<<endl; // 清除标志后再查看异常状态
cin>>ch;
cout<<"str:"<<str<<endl;
cout<<"ch :"<<ch<<endl;

system("pause");
return 0;
}
1
2
3
4
5
6
7
8
9
E:\C++projects\命令行>基本输入输出测试.exe
12345
flag1:0
flag1:1
str:1234
ch :5
请按任意键继续. . .

E:\C++projects\命令行>

可以看出,因输入缓冲区未读取完造成输入异常,通过clear()可以清除输入流对象cin的异常状态。,不影响后面的cin>>ch从输入缓冲区读取数据。因为cin.getline读取之后,输入缓冲区中残留的字符串是:5[换行],所以cin>>ch将5读取并存入ch,打印输入并输出5。

如果将clear()注释,cin>>ch;将读取失败,ch为空。

cin.clear()等同于cin.clear(ios::goodbit);因为cin.clear()的默认参数是ios::goodbit,所以不需显示传递,故而你最常看到的就是:cin.clear()。

cin清空输入缓冲区

从上文中可以看出,上一次的输入操作很有可能是输入缓冲区中残留数据,影响下一次的输入。那么如何解决这个问题呢?自然而然,我们想到了在进行输入时,对输入缓冲区进行清空和状态条件的复位。条件状态的复位使用clear(),清空输入缓冲区应该使用:

函数原型:istream &ignore( streamsize num=1, int delim=EOF );

函数作用:跳过输入流中n个字符,或在遇到指定的终止字符时提前结束(此时跳过包括终止字符在内的若干字符)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
using namespace std;

int main()
{
char str1[20]={NULL},str2[20]={NULL};
cin.getline(str1,5);
cin.clear(); // 清除错误标志
cin.ignore(numeric_limits<std::streamsize>::max(),'\n'); //清除缓冲区的当前行
cin.getline(str2,20);
cout<<"str1:"<<str1<<endl;
cout<<"str2:"<<str2<<endl;
system("pause");
return 0;
}
1
2
3
4
5
6
E:\C++projects\命令行>基本输入输出测试.exe
12345
sgjeij
str1:1234
str2:sgjeij
请按任意键继续. . .

注意:

程序中使用cin.ignore清空了输入缓冲区的当前行,使上次的输入残留下的数据没有影响到下一次的输入,这就是ignore()函数的主要作用。其中,numeric_limits::max()不过是头文件定义的流使用的最大值,你也可以用一个足够大的整数代替它。

如果想清空输入缓冲区,去掉换行符,使用:cin.ignore(numeric_limits< std::streamsize>::max()); 清除cin里所有内容。

cin.ignore(); 当输入缓冲区没有数据时,也会阻塞等待数据的到来。

其它标准输入读取一行

getline读取一行

C++中定义了一个在std名字空间的全局函数getline,因为这个getline函数的参数使用了string字符串,所以声明在了\头文件中了。

getline利用cin可以从标准输入设备键盘读取一行,当遇到如下三种情况会结束读操作:1)到文件结束,2)遇到函数的定界符,3)输入达到最大限度。

函数原型

1
2
istream& getline ( istream& is, string& str);//默认以换行符结束
istream& getline ( istream& is, string& str, char delim); // 指定结束符

示例

1
2
3
4
5
6
7
8
9
10
11
12
#include <string> 
#include <iostream>
using namespace std;

int main()
{
string str;
getline(cin, str);
cout<<str<<endl;
system("pause");
return 0;
}
1
2
3
4
E:\C++projects\命令行>基本输入输出测试.exe
hello world
hello world
请按任意键继续. . .

注意

getline遇到结束符时,会将结束符一并读入指定的string中,再将结束符替换为空字符。因此,进行从键盘读取一行字符时,建议使用getline,较为安全。但是,最好还是要进行标准输入的安全检查,提高程序容错能力。

getline不会忽略分隔符,若键盘缓冲区存在分隔符,会读入,字符串为空。

cin.getline()类似,但是cin.getline()属于istream流,而getline()属于string流,是不一样的两个函数。

gets读取一行

gets是C中的库函数,在\声明,C++是\库,从标准输入设备读字符串,可以无限读取,不会判断上限,以回车结束或者EOF时停止读取,所以程序员应该确保buffer的空间足够大,以便在执行读操作时不发生溢出。
函数原型:char *gets( char *buffer );

1
2
3
4
5
6
7
8
9
10
#include <iostream>
using namespace std;
int main()
{
char array[20]={NULL};
gets(array);
cout<<array<<endl;
system("pause");
return 0;
}

来自 : (14条消息) C++中cin的详细用法_独行Freedom的博客-CSDN博客_cin的用法

欢迎关注我的其它发布渠道