C++的cin/cout输入输出流概念及其与缓冲区关系

转自:https://blog.csdn.net/selina8921/article/details/79067941

其他链接:https://blog.csdn.net/selina8921/article/details/79067941

https://www.cnblogs.com/gujiayue/p/5536661.html (类比了送快递与cin缓冲)

https://blog.csdn.net/k346k346/article/details/48213811 cin详细用法

https://wenku.baidu.com/view/2484b9f4c8d376eeaeaa31bf.html cin用法

输入原理:

程序的输入都有一个缓冲区,即输入缓冲区。一次输入过程是这样的,当一次键盘输入结束时会将输入的数据存入输入缓冲区,而cin对象直接从输入缓冲区中取数据。正因为cin对象是直接从缓冲区取数据的,所以有时候当缓冲区中有残留数据时,cin对象会直接取得这些残留数据而不会请求键盘输入

一. cin>>

该操作符是根据后面变量的类型读取数据。

输入结束条件 :遇到Enter、Space、Tab键。

对结束符的处理 :详见下面注意(2)

注意: 

(1)cin>>等价于cin.operator>>(),即调用成员函数operator>>()进行读取数据。 
(2)当cin>>从缓冲区中读取数据时,若缓冲区中第一个字符是空格、tab或换行这些分隔符时,cin>>会将其忽略并清除,继续读取下一个字符,若缓冲区为空,则继续等待。但是如果读取成功,字符后面的分隔符是残留在缓冲区的,cin>>不做处理。 
(3)不想略过空白字符,那就使用 noskipws 流控制。比如cin>>noskipws>>input;

#include <string> 
#include <iostream>
using namespace std;
 
int main()
{
    char a;
    int b;
    float c;
    string str;
    cin>>a>>b>>c>>str;
    cout<<a<<" "<<b<<" "<<c<<" "<<str<<endl;
 
    string test;
    getline(cin,test);//不阻塞
    cout<<"test:"<<test<<endl;
    system("pause");
    return 0;
}
从键盘输入:[回车][回车][回车]a[回车]5[回车]2.33[回车]hello[回车],输出结果是: 

从结果可以看出,cin>>对缓冲区中的第一个换行符视而不见,采取的措施是忽略清除,继续阻塞等待缓冲区有效数据的到来。但是,getline()读取数据时,并非像cin>>那样忽略第一个换行符,getline()发现cin的缓冲区中有一个残留的换行符,不阻塞请求键盘输入,直接读取,送入目标字符串后,再将换行符替换为空字符’\0’,因此程序中的test为空串。

二.cin.get

读取字符的情况:

输入结束条件:Enter键

对结束符处理:不丢弃缓冲区中的Enter

若要读取单个字符,直接cin.get(char ch)或ch=cin.get()即可

cin.get()的返回值是int类型,成功:读取字符的ASCII码值,遇到文件结束符时,返回EOF,即-1,Windows下标准输入输入文件结束符为Ctrl+z,Linux为Ctrl+d。

cin.get(char var)如果成功返回的是cin对象,因此可以支持链式操作,如cin.get(b).get(c)。

#include <iostream>
using namespace std;
 
int main()
{
    char a;
    char b;
    a=cin.get();
    cin.get(b);
    cout<<a<<b<<endl;
    system("pause");
    return 0;
}
输入:e[回车],输出: 


注意: 
(1)从结果可以看出,cin.get()从输入缓冲区读取单个字符时不忽略分隔符(空白符),直接将其读取,就出现了如上情况,将换行符读入变量b,输出时打印两次。

(2)cin.get()的返回值是int类型,成功:读取字符的ASCII码值,遇到文件结束符时,返回EOF,即-1,Windows下标准输入输入文件结束符为Ctrl+z,Linux为Ctrl+d。

cin.get(char var)如果成功返回的是cin对象,因此可以支持链式操作,如cin.get(b).get(c)。

读取一行的情况:(会在读取的字符串后面自动加上'\0')

istream& get ( char* s, streamsize n, char delim )

cin.get(数组名,长度,结束符)

其中结束符为可选参数,读入的字符个数最多为(长度-1)个,结束符规定结束字符串读取的字符,默认为ENTER

读取一行可以使用istream& get ( char* s, streamsize n )或者istream& get ( char* s, size_t n, streamsize delim )。二者的区别是前者默认以换行符结束,后者可指定结束符。n表示目标空间的大小。

输入结束条件:默认Enter键(因此可接受空格,Tab键),可在第三个参数上自定义结束符

对结束符处理:不丢弃缓冲区中的Enter(自定义结束符时同样不丢弃缓冲区中的结束符)

#include<iostream>
using namespace std;
int main(void){
  char ch='a',a[20];
  cin.get(a,5);
  cin.get(ch);
  cout<<a<<"--"<<(int)ch<<endl;
return 0;
}
输入:1[空格]23[回车],输出: 

遇到换行符时结束读取,但是不对换行符进行处理,换行符仍然残留在输入缓冲区。第二次由cin.get()将换行符读入变量ch,打印输入换行符的ASCII码值为10。
三.cin.getline(会在读取的字符串后面自动加上'\0')

getline()的原型istream& getline(char* s, streamsize count, char delim);
cin.getline(数组名,长度,结束符) 大体与 cin.get(数组名,长度,结束符)类似

另外,getline()的原型是istream& getline ( istream &is , string &str , char delim );
因此可采用string test; getline(cin,test);输入字符串
其中 istream &is 表示一个输入流,譬如cin;
string&str表示把从输入流读入的字符串存放在这个字符串中(可以自己随便命名,str什么的都可以);
char delim表示遇到这个字符停止读入,在不设置的情况下系统默认该字符为'\n',也就是回车换行符(遇到回车停止读入)。

区别:

1.cin.get()当输入的字符串超过规定长度时,不会引起cin函数的错误,后面的cin操作会继续执行,只是直接从缓冲区中取数据。

但是cin.getline()当输入超过规定长度时,会引起cin函数的错误,后面的cin操作将不再执行。

当输入的字符数大于count时,则get函数只读取count-1个字符,而其余的字符仍然保存在缓冲区中,还可再对其进行读取;
但是函数getline则不然,getline()会设置失效位(faibit),并且关闭后面的输入,这个时候再用ch=cin.get()是读取不到留在输入队列中的字符的。
可以用下面的命令来恢复输入:
cin.clear();//因为clear()会重置失效位,打开输入。这个时候ch=cin.get();就可以读取留在输入队列中的字符。
2.cin.get读取一行时,遇到换行符(自定义结束符)时结束读取,但是不对换行符(自定义结束符)进行处理,换行符(自定义结束符)仍然残留在输入缓冲区。

getline读取一行字符时,默认遇到’\n’(自定义结束符)时终止,并且将’\n’(自定义结束符)直接从输入缓冲区中删除掉,不会影响下面的输入处理。

两者都会在读取的字符串后面自动加上'\0'

3.cin.get(str,size);读取一行时,只能将字符串读入C风格的字符串中,即char*,但是C++的getline函数还可以将字符串读入C++风格的字符串中,即string类型。(string test; getline(cin,test);)

鉴于getline较cin.get()的优点,建议使用getline进行行的读取。

输入缓冲区清除方法

通常大家会用sync()函数来清除输入缓冲区的内容。个人感觉还是用ignore更好。

cin.clear()是用来更改cin的状态标示符的,cin在接收到错误的输入的时候,会设置状态位good。如果good位不为1,则cin不接受输入,直接跳过。如果下次输入前状态位没有改变那么即使清除了缓冲区数据流也无法输入。所以清除缓冲区之前必须要cin.clear()。

  sync()的作用就是清除输入缓冲区。成功时返回0,失败时badbit会置位,函数返回-1. 
  另外,对于绑定了输出的输入流,调用sync(),还会刷新输出缓冲区。 

  但由于程序运行时并不总是知道外部输入的进度,很难控制是不是全部清除输入缓冲区的内容。通常我们有可能只是希望放弃输入缓冲区中的一部分,而不是全部。

  比如清除掉当前行、或者清除掉行尾的换行符等等。但要是缓冲区中已经有了下一行的内容,这部分可能是我们想保留的。这个时候最好不要用sync()。可以考虑用ignore函数代替。 

   cin.ignore(numeric_limits<std::streamsize>::max(),’\n’);//清除输入缓冲区的当前行 
   cin.ignore(numeric_limits<std::streamsize>::max()); //清除输入缓冲区里所有内容 
   cin.ignore()//清除一个字符

       可采用cin.get(str,5).get();//清除后面的换行符       


  不要被长长的名字吓倒,numeric_limits<std::streamsize>::max()不过是climits头文件定义的流使用的最大值,你也可以用一个足够大的整数代替它。
 ———————————————— 
版权声明:本文为CSDN博主「selina3578」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/selina8921/article/details/79067941

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要降低 coutcin 的输出速度,可以采取以下方法: 1. 减少输出频率:可以通过适当减少使用 cout 输出语句的次数来降低输出速度。避免在循环中使用 cout 输出大量信息,可以将输出集中到一个语句中,减少频繁的输出操作。 2. 提高缓冲区大小:可以通过设置缓冲区的大小来提高输出速度。使用 cout.rdbuf()->pubsetbuf() 函数可以设置输出的缓冲区大小。增加缓冲区的大小可以减少输出的次数,从而提高输出速度。 3. 禁用同步:可以通过将同步设置为 false 来禁用缓冲区的同步。使用 cout.sync_with_stdio(false) 函数可以关闭与 C 标准库的同步,从而提高输出速度。 4. 使用快速输入输出函数:可以使用更快速的输入输出函数如 printf 和 scanf 来代替 coutcin。这些函数在处理大量数据时比 iostream 库中的函数更快速。 5. 使用文件输出和输入:如果输出的数据量较大,可以将结果输出到文件中,然后再使用文件输入读取数据。使用文件输入输出可以避免频繁的控制台输出,从而提高速度。 需要注意的是,在降低输出速度的同时,也要注意保证程序的可读性和可维护性。有时候,牺牲一些速度换取代码的可读性和可维护性可能更为重要。 ### 回答2: 要降低cout/cin输出/输入的速度,可以考虑以下几个方面: 1. 减少输出/输入的信息量:只输出/输入必要的信息,避免不必要的输出/输入操作。例如,只输出/输入关键结果或用户必要的输入,避免冗余输出/输入。 2. 使用缓冲区:使用缓冲区可以减少每次输出/输入的系统调用次数,提高效率。可以使用endl来刷新缓冲区,但要注意过多的刷新会影响性能。 3. 使用格式化输出/输入:使用适当的格式化方法可以提高输出/输入速度。例如,使用setw来设置输出字段宽度,使用setprecision来控制浮点数的精度等。 4. 使用快速的IO流:可以使用更快的IO流,如iostream代替cstdio,来提高输出/输入的速度。 5. 使用多线程或异步IO:使用多线程或异步IO可以实现并行输出/输入操作,提高效率。但要注意多线程/异步IO的正确使用,避免出现竞态条件或不安全的操作。 6. 尽量避免频繁的输出/输入操作:尽量将多个输出/输入操作合并为一个,减少系统调用次数,提高效率。 总而言之,降低cout/cin输出/输入的速度可以通过减少信息量、使用缓冲区、使用格式化输出/输入、使用快速的IO流、使用多线程或异步IO以及减少频繁的输出/输入操作等方法来实现。这样可以提高程序的运行效率和用户体验。 ### 回答3: 要降低`c++`中`std::cout`和`std::cin`的速度,可以使用以下几种方法: 1. 使用`std::ios_base::sync_with_stdio(false)`函数:这个函数可以用来取消`std::cout`和`std::cin`与`stdio`的同步,默认情况下`sync_with_stdio`为`true`,即`cout`和`cin`与`stdio`同步,取消同步可以提高输入输出的速度。 ```c++ #include <iostream> int main() { std::ios_base::sync_with_stdio(false); // 取消同步 int x; std::cin >> x; std::cout << x << std::endl; return 0; } ``` 2. 使用`std::endl`替代`\n`:`std::endl`会刷新输出流缓冲区,以确保输出的内容立即显示在控制台上,但这样也会降低输出速度。相比之下,使用`\n`只是插入一个换行符,不会刷新缓冲区。 ```c++ #include <iostream> int main() { int x; std::cin >> x; std::cout << x << '\n'; // 使用'\n'而不是std::endl return 0; } ``` 3. 减少使用`std::endl`:如果不是必要的情况下,可以选择性地使用`std::endl`,在输出大量数据时可以通过将所有数据输出完后再刷新一次缓冲区。 ```c++ #include <iostream> int main() { int x; for (int i = 0; i < 1000; ++i) { std::cout << i << ' '; // 输出1000个数字 } std::cout << std::endl; // 输出完毕后再刷新缓冲区 std::cin >> x; return 0; } ``` 这些方法可以在一定程度上降低`std::cout`和`std::cin`的速度,提高程序的执行效率。但需要注意的是,在某些情况下,优化可能无法显著提高代码的运行速度,所以要根据具体情况选择合适的优化方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值