首页 > 编程语言 >C++中 cin、cin.get()、cin.getline()、getline() 的区别

C++中 cin、cin.get()、cin.getline()、getline() 的区别

时间:2024-07-28 12:59:15浏览次数:18  
标签:读取 get cin C++ 缓冲区 换行符 getline

cin

我们先介绍c++中最常用的输入流对象cin

我们常用 cin >> num 来从缓冲区中读取数据到 num 中,num 的变量类型可以是多种类型,最常用的有 intstringchardoublefloat等等

void cin_test()
{
    std::cout<<"----------- cin test ---------"<<std::endl;
    std::string str;
    //fff ggg
    //fff   ggg
    std::cin>>str;
    std::cout<<str<<std::endl;

}

 在上述示例中,输入流的过程是这样的

  • 在键盘输入一个字符串“fff”,按下回车键
  • 字符串“fff”被存储到缓冲区中
  • cin读取缓冲区中的内容,并将内容存放到内存变量str中
  • 标准输出流cout将内存变量str的值进行输出

在上述过程里有两个步骤需要关注,分别是第二步和第三步

在第二步中,字符串“fff”被存储到缓冲区中,存储的内容其实是“fff”和一个换行符,因为我们在键盘输入字符串的最后按下的回车键

而在第三步中,cin读取缓冲区中的内容的时候,读取的是第一个非空白字符开始到第一个结束符之间的字符串,而这个结束符可以是空格,也开始是制表符,也可以是换行符。除此以外,空格、制表符、换行符是内置的 cin 的结束符,如果想用其他的字符来提前结束读取数据,需要自定义

 整个过程如下图所示

因此,当我们在键盘输入“fff空格ggg”时,经过cin的读取之后,内存变量被读取的内容应该fff,因为cin把空格视作结束符,而缓冲区中仍旧残留着“空格ggg\n”,如下图所示

但是同时我们可以利用该原理,从以空格或者制表符为分隔符的缓冲区数据中读取多个数据,按下相应的结束符,才会从缓冲区读取数据到变量中,cin 每次从缓冲区中读取一个字符串,以空格作为字符或者字符串的分隔符。如下所示 

void cin_test()
{
    std::cout<<"----------- cin test ---------"<<std::endl;
    std::string str;
    //fff ggg
    std::cin>>str;
    std::cout<<str<<std::endl;//fff
    
    //此时缓冲区中仍旧残留着ggg和换行符
    std::cin>>str;
    std::cout<<str<<std::endl;

}

由于 cin 在遇到空格或者制表符(/tab)时,会停止读取输入,因此第一个 cin 只会读取第一个字符串(第一个非空白字符开始到下一个空格字符结束之间的字符串)。这时候缓存区中还有残留的数据,因此下一个 cin 会直接从缓冲区中读取数据,而不会请求输入。

因此当我在键盘输入"fff ggg"时,第一次可以读取到“fff”,而缓冲区中仍旧残留着“ggg”,因此我可以继续读取,从而读取到ggg。

但是需要注意的是最后一个换行符会放在缓冲区中

void cin_test()
{
    std::cout<<"----------- cin test ---------"<<std::endl;
    std::string str;
    //fff ggg
    std::cin>>str;
    std::cout<<str<<std::endl;//fff
    std::cin>>str;
    std::cout<<str<<std::endl;
    
    char ch;
    std::cin.get(ch);//读取到缓冲区中的空格
    std::cout<<static_cast<int>(ch)<<std::endl;
}

如上所示,当我依旧输入"fff ggg",并按下回车后,cin依次从缓冲区中读取字符串fff和ggg,但是最后剩下的换行符会残留在缓冲区中

由于我们接下来要介绍的cin.get()每次只读取一个一个字符,因此我们可以从结果看出,当读取完fff和ggg之后,cin.get()把缓冲区中残留的换行符也读取出来了,其ASCII值为10

cin.get()

cin.get() 是C++标准库中的函数,用于从输入流中获取字符,包括空白字符(如空格、制表符和换行符)与 cin 不同,cin.get() 不会将制表符、空白字符(空格)视为终止输入的标志,因此您可以使用它来获取包括空白字符在内的整行文本。但是默认情况下,cin.get() 使用换行符(\n)作为定界符(终止读取数据的结束符),表示读取到换行符时结束

cin.get分别有以下几种重载

// single character (1)	从标准流中读取单个字符;
int get();
istream& get (char& c);

// c-string (2)	从标准流中读取字符串并存储在c标准的s字符串中;
istream& get (char* s, streamsize n);
istream& get (char* s, streamsize n, char delim);

// stream buffer (3)	
istream& get (streambuf& sb);
istream& get (streambuf& sb, char delim);

可以看到,cin.get()会读取指定个数的字符并遇到换行符时终止读取,而cin则连续读取,只要遇到空白字符(空格、制表符、换行符等)就终止读取

此外,接收cin.get()读取的内容的内存变量类型需要时字符数组或者字符类型,不能是std::string流

如下所示,我们做个实验

void cinget_test()
{
    std::cout<<"----------- cin.get() test ---------"<<std::endl;
    char str[100];
    //fff ggg
    std::cin.get(str,100);//最多读取100个字符并存储到字符数组str中
    std::cout<<str<<std::endl;

    char ch;
    //读取缓冲区中最后一个换行符
    std::cin.get(ch);
    std::cout<<static_cast<int>(ch)<<std::endl;
    std::cout<<"------------------------------"<<std::endl;
}

 在键盘输入"fff ggg",可以看到,cin.get一次性把字符串"fff ggg"读取到了,但是将最后的换行符残留在了缓冲区中,而我们再次从缓冲区中使用cin.get读取一个字符时,读取到的正是这个残留的换行符(ASCII值为10)

因此,cin.get() 与 cin 都是遇到相应的结束符才会结束从缓冲区读取数据,它们都不对换行符进行处理,换行符都会残留在缓冲区中。如果下次不想从上一次的缓冲区中读取数据,可以使用 cin.ignore() 忽略上一个缓冲区中的数据,或者使用 cin.getline()。 

cin.getline()

cin.getline() 是C++标准库中的函数,用于从输入流中读取一行文本,并允许您指定一个定界符字符来结束读取。默认的定界符是换行符 (\n),表示读取到换行符时结束。但您可以通过提供第三个参数来指定自定义的定界符字符。

cin.getline() 与 cin >> 、cin.get() 的使用基本一致,唯一的区别就是 cin >> 、cin.get() 遇到结束符终止从缓存区读取数据时,换行符会残留在缓冲区中,而使用 cin.getline() 换行符不会残留在缓冲区中。

我们使用这段代码进行测试,这段代码与上述测试cin.get()的代码完全一样,只是函数换成了cin.getline,但是呈现的效果是不同的 

void cingetline_test()
{
    std::cout<<"----------- cin.getline() test ---------"<<std::endl;
    char str[100];
    std::cin.getline(str,100);
    std::cout<<str<<std::endl;

    char ch;
    std::cin.get(ch);
    std::cout<<static_cast<int>(ch)<<std::endl;
    std::cout<<"------------------------------"<<std::endl;
}

 

如图所示,当我从键盘输入"fff ggg"并按下回车后,cin.getline会一次性将字符串"fff ggg"读取出来,但是并不会将换行符残留在缓冲区中,因此当执行到cin.get(ch) 时,缓冲区中并没有数据,它会等待我们从键盘输入数据,图片里显示的那个空行是我再次在键盘敲下了一个回车键之后,cin.get()读取到之后输出的

getline()

getline是单独的一个函数,它的作用与cin.getline几乎一样,它可以连续从缓冲区中读取数据,并遇到换行符终止读取,同时不会将换行符残留在缓冲区中,而它与cin.getline的区别,除了用法稍显不同,它可以从缓冲区中读取到的数据可以存储到std::string中,而cin.getline只能存储到字符数组或字符中

void getline_test()
{
    std::cout<<"----------- getline() test ---------"<<std::endl;
    std::string str;
    //读取缓冲区的数据并存储到std::string类型的str变量中
    getline(std::cin,str);
    std::cout<<str<<std::endl;

    char ch;
    std::cin.get(ch);
    std::cout<<static_cast<int>(ch)<<std::endl;
    std::cout<<"------------------------------"<<std::endl;
}

可以看到,其效果呈现出来与cin.getline是一样的

用法总结

  • cin.get() 和 cin.getline() 是输入流中的,使用之前需要包含头文件 。cin 是输入输出流中的,使用之前需要包含头文件 。getline() 是字符串流的,使用之前需要包含头文件 。
  • 从标准输入读取单个或者是多个变量(以空格、制表符、换行符隔开),尤其是整型变量,或者从多行读取整型变量到数组,使用 cin。
  • 从标准输入读取单个字符,推荐使用输入流中的 cin.get()。
  • 从标准输入读取单行字符串、多行字符串的,推荐使用字符串流中的 getline()。
  • cin、cin.get() 会将换行符残留在缓冲区中,getline() 和 cin.getline() 不会。

参考

【C/C++基础】C++中 cin、cin.get()、cin.getline()、getline() 的区别-CSDN博客

标签:读取,get,cin,C++,缓冲区,换行符,getline
From: https://blog.csdn.net/qq_58158950/article/details/138499272

相关文章

  • 【C++软件调试技术】使用 Windbg 分析软件异常时的诸多细节与技巧总结
    目录1、dump文件1.1、dump文件的生成方式1.2、dump文件的大小2、pdb符号文件2.1、pdb文件的路径设置2.2、pdb文件的时间戳与名称问题2.3、如何确定要找哪些pdb文件?3、使用Windbg静态分析dump文件以及动态调试程序的一般步骤4、确定发生异常或崩溃的业务模块,到业务模块......
  • 【C++进阶学习】第九弹——哈希的原理与实现——开放寻址法的讲解
    前言:在前面,我们已经学习了很多存储机构,包括线性存储、树性存储等,并学习了多种拓展结构,效率也越来越高,但是是否有一种存储结构可以在大部分问题中都一次找到目标值呢?哈希可能能实现目录一、哈希的概念二、哈希冲突三、哈希冲突解决3.1开放寻址法节点结构插入操作查......
  • Codeforces Round 962 (Div. 3) A - D详细题解(思路加代码Python,C++(垃圾灰名小白想
             吐槽一下,这次比赛不知道怎么的,可能是div3参加的人比较多吗,代码题解上去后全是inqueue,比赛的过程中我还看了提交的,80多页几千个提交全是inqueue,我的代码等了**半个多小时才运行,然后发现timelimit真的有点搞心态,思路在下一题我还要反过来去优化上一题,不过......
  • Visual Studio C++ 安装以及使用教程
    官网下载网址https://visualstudio.microsoft.com/zh-hans/VisualStudio:面向软件开发人员和Teams的IDE和代码编辑器(microsoft.com)下载好后双击运行跳出该界面,等待加载结束在组件选择界面,只需要选择这一项,勾选好后点击安装即可下载完后,点击图标打开C++点击创......
  • 【免费领源码】Java/Mysql数据库+SSM校园兼职网站 25557,计算机毕业设计项目推荐上万套
    摘 要当今人类社会已经进入信息全球化和全球信息化、网络化的高速发展阶段。丰富的网络信息已经成为人们工作、生活、学习中不可缺少的一部分。人们正在逐步适应和习惯于网上贸易、网上购物、网上支付、网上服务和网上娱乐等活动,人类的许多社会活动正在向网络化发展。兼职......
  • 【免费领源码】Java/Mysql数据库+springboot驾校预约管理系统 25540,计算机毕业设计项
    摘 要随着科学技术的飞速发展,各行各业都在努力与现代先进技术接轨,通过科技手段提高自身的优势;对于驾校预约管理系统当然也不能排除在外,随着网络技术的不断成熟,带动了驾校预约管理系统,它彻底改变了过去传统的管理方式,不仅使服务管理难度变低了,还提升了管理的灵活性。这种......
  • C++字体库开发之go语言绑定六
    export.h#defineFONTVIEW_API__declspec(dllimport)typedefvoid*GoFontSetPtr;#ifdef__cplusplusextern"C"{#endifFONTVIEW_APIGoFontSetPtropenFontSet(constchar*stream,size_tsize);FONTVIEW_APIvoidfreeFontSet(GoFontSetPtrfontset);......
  • 三种语言实现二分(C++/Python/Java)
    题目给定一个按照升序排列的长度为......
  • C++模板——泛型编程
    目录1.什么是泛型编程2.函数模板2.1定义格式2.2实例化及原理 2.3参数匹配原则3.类模板 3.1定义格式3.2实例化 4.非类型模板参数 5.模板的特化 5.1概念5.2函数模板和类模板特化6.模板的分离编译 1.什么是泛型编程 如何实现一个通用的加......
  • C++基础(1)
    1.命名空间1.1namespace的价值在C/C++中,变量、函数和后⾯要学到的类都是⼤量存在的,这些变量、函数和类的名称将都存在于全局作⽤域中,可能会导致很多冲突。使⽤命名空间的⽬的是对标识符的名称进⾏本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的......