c++笔记2——cin原理及其用法
第一部分是介绍cout的原理
第二部分是介绍插入运算符
第三部分是对语法的介绍
1首先是cout的原理(cin近似)
先来看一个小例子
cout << "What are you doing?"
这里双括号引起的是字符串
<<符号表示该语句把字符串发送给cout,理解成该符号指出了信息流动的路径
而cout到底是什么呢?
它是一个预定义的对象,知道如何显示字符串,数字和单个字符等
目前只需要知道如何使用它,而不需要知道这个特定实例的内部情况,这也体现了对象的长处,无需得知内部情况就可以直接使用
可以看出cout有一个简单的接口,如果string是一个字符串,内容就是What are you doing?,那上述程序也可以写为
cout << string
这里不需要像C一样指定输出类型
这里需要理解一下输出过程
输出是一个流,cout对象表示这个流,其对象属性包括插入运算符(<<),它可以将右侧信息插入流中
因此我们与其说程序显示了字符串,不如说它将一个字符串插入到了输出流
理解了输出流就更容易理解cin了
2.再看cout的printf()的区别(插入运算符<<的妙用)
输出字符串已经说明,现在说整数
int carrots=25;cout << carrots;
这里会输出25,而不是字符串carrots,也不是字符串25,这两个与25D都有天壤之别
因为cout很聪明——它可以识别数据类型,从而改动显示的字符,即将carrots变量转化成整形数25(二进制存储),随后转化成字符2和5
这源于C++的面向对象特性。实际上,C++插入运算符(<<)将根据其后的数据类型相应调整行为,这是一个运算符重载的例子,具体的日后再学
习惯了printf之后感觉cout难以控制
但了解了之后发现cout与 printf相比十分便捷
一是cout可以识别类型,不用像printf用%s/%d等进行选择输出,变量是什么它就输出什么类型
当然你也可以通过强制类型转换来指定输出类型
二是它可以拓展的,即可以重新定义插入运算符,使得cout能识别更多更新的类型
三是cout也可以做到printf类似于域宽修饰的细致控制,这里日后再学
3.接下来学习cout和cin的语法知识
3.1cin>>的用法
cin可以连续从键盘读取数据(其实是从缓冲区读取),
语法格式:
//a可以是整型、实型、字符型、字符串型int a;float b;char str[8];string buf;cin >> a; // 单个输入cin >> a >> b ; // 多个不同类型输入cin >> str; // 以数组首地址为对象的输入buf = str; //数组首地址和字符串变量赋值cout << buf << str << a << b; //进行多个变量的打印
注意事项
3.1.1读入的数据和所需数据类型要相同
由于插入运算符<<是会识别对象的,因此cin读入的数据类型不同会导致一些问题
先说结论:读入数据与变量不匹配可能会导致cin返回FALSE,尤其是将字符型赋给整型
下面举一个个特殊的例子来说明
#include <iostream>using namespace std;int main() {int a;char b;cin >> a >> b;cout << a << " " << int(b) << endl;}
正常情况如下
但如果我们给char数组一个4,它会字符理解为4,并且输出4的ASCII码
但是char变量毕竟能对应所有的字符(包括回车换行,当然cin无法输入回车换行,原因参见本文3.1.4),而如果给a一个字符会怎么样呢?
那么这个情况为何会发生呢?原因如下:
cin 解析了变量a的类型,a的变量类型是int,因此cin只有接受到数字输入才是正确的
当你输入整型数值时,cin返回TRUE;输入字母时,cin返回值是FALSE,因此a变量被赋值默认值0.
因此cout<< a当然会打印出0啦
并且b显示-52,也说明cin发生了未知的错误,所以这样做是十分危险的
3.1.2.cin对分隔符的处理
先介绍一下标准输入缓冲区:
当我们从键盘输入字符串的时候需要敲一下回车键才能够将这个字符串送入到缓冲区中,那么敲入的这个回车键(\r)会被转换为一个换行符\n,这个换行符\n也会被存储在cin的缓冲区中并且被当成一个字符来计算!比如我们在键盘上敲下了123456这个字符串,然后敲一下回车键(\r)将这个字符串送入了缓冲区中,那么此时缓冲区中的字节个数是7 ,而不是6。
再说结论,cin会略过第一个分隔符
还是先给出一个例子
#include <iostream>using namespace std;int main(){int a;string buf,buf2;cin >> a;cin >> buf >> buf2;cout << buf << buf2 <<endl;}
当cin>>从缓冲区中读取数据时,若缓冲区中第一个字符是空格、tab或换行这些分隔符时,cin>>会将其忽略并清除,继续读取下一个字符,若缓冲区为空,则继续等待。
即在运行面板,我不断地摁回车,cin会略过,直到给a读入第一个数据(当然这个数据不一定是整型。)
可以看到,这里的输入窗口,在每个输入前,都含有若干个回车换行,cin是一律不读入的,因此可以正常的读入a和buf,buf2
3.1.3缓冲区和cin
先说结论:cin在缓冲区数据充足时不会请求键盘键入
cin读取数据也是从缓冲区中获取数据,缓冲区为空时,cin的成员函数会阻塞等待数据的到来。
一旦缓冲区中有数据,就触发cin的成员函数去读取数据。
而这也意味着,如果缓冲区有足够的数据,cin就不需要键盘的键入了
因此下面给出一个例子
#include <iostream>using namespace std;int main(){int a;char buf,buf2;cin >> a;cin >> buf >> buf2;cout << buf << buf2 <<endl;}
这里的调试窗口如下
可以看到啊,对aaaaa的缓冲区,buf读入之后,buf2直接读入,并且输出,程序结束
不需要第二次输入数据了
3.1.4cin.getline()和cin.get()的用法
先说结论:cin.getline() 与 cin.get() 的相同点是,都不会以空格符作为结束标志。区别是,cin.getline() 不会将行结束符(如换行符)残留在输入缓冲区中。
当学习了cin之后,会发现它存在一定的局限性
比如我仅想读入含有空格符的字符串
但是因为cin会以空格符作为结束符,因此会阻断读入
例如这个例子
#include <iostream>using namespace std;int main(){int a;string buf,buf2;cin >> a;cin >> buf >> buf2;cout << buf << buf2 <<endl;}
可以发现,buf是what+\0,而buf2读入了are+\0,这两个字符串内很明显无法包含空格
怎么处理呢?
我们引入getline和get函数,getline不会以空格为结束符,get是读入单个字符
其函数原型分别为
/*cin.get() 函数有多种重载形式,分为四种格式:无参,一参数,二参数,三个参数。其中 streamsize 在 VC++ 中被定义为 long long 型。其常用的的函数原型如下:*/int get(); istream& get(char& var); //读取单个字符istream& get( char* s, streamsize n ); //指定个数的字符串读取istream& get( char* s, streamsize n, char delim); //指定结束符和个数的字符串读取/*另外,cin.get() 函数还有两个重载形式不怎么使用,就不详述了,函数原型如下:*/istream& get (streambuf& sb);istream& get (streambuf& sb, char delim);/*cin.getline()函数作用:从标准输入设备键盘读取一串字符串,并以指定的结束符结束。函数原型有两个:*/istream& getline(char* s, streamsize count); //默认以换行符结束istream& getline(char* s, streamsize count, char delim); //指定换行符
他们强强联手,组合起来就能够实现我们的需求
还是给出若干个例子,用以介绍函数的具体用法
#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;}
结果上可以看出,我们成功利用cin.get()函数读入了空格,但是有一些小问题
array成功读入了缓冲区中含空格的字符串的what are you doing?(值得庆祝)
但是回车之后程序直接结束,a显示值为10,这就引发了一点小问题
首先我们要知道,回车符的ASCII码是10,那么问题就显而易见了
第一个问题:cin.get()函数读取一行时,遇到换行符时结束读取,但是不对换行符进行处理,换行符仍然残留在输入缓冲区。
第二个问题:cin.get()函数不会像cin一样略过第一个空白字符,导致它直接读入了上一个残留的回车换行符,并打印出其ASCII码
这里也可以解决办法:cin来代替cin.get(),这样cin不就会略过分隔符了吗
的确如此,但是如果使用了cin,就无法给a输入换行符了,这不是拆了东墙补了西墙吗?
鉴于以上几个问题,引出了cin.getline()函数
改写程序如下:
#include <iostream>using namespace std;int main() {char a;char array[20] = { NULL };cin.getline(array, 20);//原本的get改为getlinecin.get(a);cout << buf << " " << (int)a << endl;return 0;}
再次执行就会发现成功达到我们的要求
3.1.5getline()函数和get()函数
在上述讨论中,还有一个问题
第三个问题:cin.get()的形参只能是C风格的字符串,即字符型数组,不能使用C++的string类型变量
这就引出了getline()和get()函数
使用这两个函数需要
函数原型为:
//因为 getline() 函数的参数使用了 string 字符串,所以声明在了<string>头文件中了。//getline()函数的原型为:istream& getline (istream& is, string& str); // 默认以换行符\n分隔行istream& getline (istream& is, string& str, char delim);//gets() 是 C 中的库函数,在头文件 <stdio.h> 申明//由于该函数是 C 的库函数,所以不建议使用,既然是 C++ 程序,就尽量使用 C++ 的库函数吧。//另外,由于 gets() 实现不够安全,容易出现缓冲越界,用 fgets() 和 getline() 替代更好。gets() 在C++11中极不推荐使用,并在 C++14 中丢弃了该方法。char *gets(char *buffer);
getline() 利用 cin 可以从标准输入设备键盘读取一行,当遇到如下三种情况会结束读操作: (1)文件结束; (2)遇到行分隔符; (3)输入达到最大限度。
简单的看一个例子
#include <string> #include <iostream>using namespace std;int main() {char a;string buf;getline(cin,buf);//原本的cin.getline改为getlinecin.get(a);cout << buf << " " << (int)a << endl;return 0;}
注意,getline() 遇到结束符时,会将结束符一并读入指定的 string 中,再将结束符替换为空字符。因此,进行从键盘读取一行字符时,建议使用 getline,较为安全。
cin.getline() 与 getline() 类似,但是因为 cin.getline() 的输出是char*,getline() 的输出是 string,所以 cin.getline() 属于 istream 流,而 getline() 属于 string 流,二者是不一样的函数。
———————————————— 版权声明:本文为CSDN博主「恋喵大鲤鱼」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:C++ cin 详解之终极无惑_恋喵大鲤鱼的博客-CSDN博客_cin
3.1.5其他cin函数
这里列举一些具有丰富功能的cin函数
cin.gcount() //统计读入的字符串个数
getline(cin,buf) //buf是读入的字符串变量
//形参还可以写为(cin,buf,'c'),表示遇到c字符就停止读取,即增加了一个结束符
cin.get(b) //b是字符型变量
c++笔记2——cin原理及其用法相关推荐
- mysql 实时聚合分析,mysql累积聚合原理与用法实例分析
本文实例讲述了mysql累积聚合原理与用法.分享给大家供大家参考,具体如下: 累积聚合为聚合从序列内第一个元素到当前元素的数据,如为每个员工返回每月开始到现在累积的订单数量和平均订单数量 行号问题有两 ...
- python装饰器原理-Python装饰器原理与用法分析
这篇文章主要介绍了Python装饰器原理与用法,结合实例形式分析了Python装饰器的概念.原理.使用方法及相关操作注意事项,需要的朋友可以参考下 本文实例讲述了Python装饰器原理与用法.分享给大 ...
- python的编程模式-Python设计模式之状态模式原理与用法详解
本文实例讲述了Python设计模式之状态模式原理与用法.分享给大家供大家参考,具体如下: 状态模式(State Pattern):当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类 ...
- python装饰器原理-Python函数装饰器原理与用法详解
本文实例讲述了Python函数装饰器原理与用法.分享给大家供大家参考,具体如下: 装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值 ...
- python装饰器原理-python装饰器原理与用法深入详解
本文实例讲述了python装饰器原理与用法.分享给大家供大家参考,具体如下: 你会Python嘛? 我会! 那你给我讲下Python装饰器吧! Python装饰器啊?我没用过哎 以上是我一个哥们面试时 ...
- python定义私有变量的方法_Python面向对象程序设计之私有变量,私有方法原理与用法分析...
本文实例讲述了Python面向对象程序设计之私有变量,私有方法原理与用法.分享给大家供大家参考,具体如下: 私有变量,私有方法:python的私有化是为了规划私有属性,避免非相关的访问[假如!我有老婆 ...
- mysql 实时聚合分析_mysql滑动聚合/年初至今聚合原理与用法实例分析
本文实例讲述了mysql滑动聚合/年初至今聚合原理与用法.分享给大家供大家参考,具体如下: 滑动聚合是按顺序对滑动窗口范围内的数据进行聚合的操作.下累积聚合不同,滑动聚合并不是统计开始计算的位置到当前 ...
- java 字节缓冲_Java字节缓冲流原理与用法详解
本文实例讲述了Java字节缓冲流原理与用法.分享给大家供大家参考,具体如下: 一 介绍 BufferInputStresm和BufferOutputStream 这两个流类为IO提供了带缓冲区的操作, ...
- mysql的存储过程原理_mysql存储过程原理与用法详解
本文实例讲述了Mysql存储过程原理与用法.分享给大家供大家参考,具体如下: 本文内容: 什么是存储过程 存储过程的创建 存储过程的使用 查看存储过程 修改存储过程 删除存储过程 首发日期:2018- ...
最新文章
- updatehf.vbs:自动打补丁
- Android四种Activity的加载模式(转)
- C# C/S系统软件开发平台架构图(原创)
- C++位运算详解(转)
- **Java有哪些悲观锁的实现_Redis 分布式锁的正确实现方式(Java版)
- request获取页面html内容,request、request-promise、cheerio抓取网页内容
- Angular 路由的wild匹配
- .NET 4.5 HttpClient 中使用Cookie
- vnc 序列号在哪输入_VNC Viewer Plus 1.2.3 注册机
- 怎么让图片一直转圈_半夜跟着导航开进山路,货车绕了3小时仍原地转圈,小两口快急哭...
- 搜索文件夹中word文档中的关键字
- 【DJ-ZBS2 DH-70L两档切换漏电继电器】
- Ubuntu14.04安装文泉驿字体
- GoLang获取硬盘序列号
- python中plt.hist_关于python中plt.hist参数的使用详解
- 华为云×奇点云 | 828 B2B企业节,一起成就好生意
- govqq.com/post/12.html,更新30+!这些学校招生简章已公布!
- 微信的服务器 上海,昨下午部分用户无法收发文字信息和登录 
微信回应:上海机房服务器发生故障 现已恢复...
- 华为完成首次6GHz频谱试验;iPhone 支持 Siri 操作关机;Gitlab 禁止使用 Windows|极客头条
- 数据库标准语言SQL(六)——单表查询(二)