C/C++ 缓冲区问题、计时循环和基于范围的for循环

2023年7月4日10:09:29

缓冲区问题以及循环

一、C/C++输入的相关问题

1. 缓冲区问题

  • C/C++ 借助相应的缓冲区将标准输入设备的输入存储起来,然后由标准输出设备从缓冲区中读取数据并且输出。 一般编程所说的缓冲区指的是内存缓冲区,这是程序所设置的一块内存区域,用来暂存从其他设备读入的数据或即将写入其他设备的数据。为了减少使用read和write调用的次数,标准IO库提供了缓冲,只有在缓冲区填满或者缓冲区刷新,以及进程结束的时候才会进行实际I/O程序的操作。
  • 三种缓冲区:
    1. 全缓冲:输入或输出缓冲区被填满,会进行实际I/O操作。其他情况,如强制刷新、进程结束也会进行实际I/O操作。磁盘文件操作通常是全缓冲的,当内容的字节数等于缓冲区大小或者达到文件结尾,以及强制刷新。
    1. 行缓冲:只有在输入或者是输出中遇到换行符的时候才会进行I/O操作。一般来说,标准输入流(stdin)和标准输出流(stdout)是行缓冲。
    1. 无缓冲:没有缓冲区,数据会立即读入内存或者输出到外存文件和设备上。标准错误输出stderr是无缓冲的,这样能够保证错误信息及时反馈给用户,供用户排除错误。
  • 缓冲区刷新(对于行缓冲):(1). 缓冲区填满 (2). 缓冲区遇到换行符(前提:每个缓冲单元内存区有内容)(3). 特定函数刷新

2. 关于空格,换行符等空白符机制问题

2.1 空白在数值及单个字符中的处理

    1. cin与scanf的区别:在scanf中,空格,换行符等空白符默认识别为数值之间的分隔作用,但并不能分隔字符与字符,数值与字符;而cin却可以在数值与字符之间用空格,换行符来分隔,因为cin默认忽略空格,换行符和制表符。这与cin的封装相关。
    1. 因为scanf在单个字符输入时,是用%c将标准输入设备从键盘获取的有效字符存入缓冲区中,然后调用缓冲区则将其赋给字符变量。因此,在scanf函数调用中空格,换行符等空白符也会转换成相应ASCII码对应的二进制形式存储到缓冲区,则不会忽略空格,换行符;但是cin由于会忽略空格,换行符等空白,因此同样可以将它们作为分隔来将数值与字符,字符与字符之间分开,但cin不能将空白赋给字符变量。
//空格的测试
scanf("%f%c%d%f",&a,&ch,&b,&d);  //在输入的时候用空格将这些变量值分隔开,会产生错误情况。因为空格会被赋给ch,导致后面数据错乱
scanf("%f %c%d%f",&a,&ch,&b,&d); //这样输入的时候就可以正常分隔,因为在a和ch中间的空格被scanf双引号中的空格吸收
//换行符的测试
scanf("%c",&ch);                 //scanf同样会将换行符'\n'赋值给ch
printf("123%c",ch);              //因此在屏幕上结果为:123 光标在下一行,因为ch以字符形式输出效果为换行。

//同样地
scanf("%c%c",&ch1,&ch2);        //键盘上连续敲击两次<enter>键,在第二次<enter>键将换行符'\n'赋予ch2同时,缓冲区填满以此刷新,程序执行
printf("abc%c%c",ch1,ch2);      //因此在屏幕上结果为:abc 光标在a正下方两行位置处。
scanf("%c%c",&ch1,&ch2);    //键盘上输入空格<space>和换行符<enter>,则两者都被识别为单个字符,缓冲区填满,并且识别末尾换行符,程序执行
printf("ab%cc%c",ch1,ch2);  //因此在屏幕上结果为:ab c光标在a正下方
//如果在%c和%c之间加一个空格
scanf("%c %c",&ch1,&ch2);      //当scanf双引号中间有空白符的时候则会造成系统识别不了哪个是字符,因此此时无论是键盘输入空格还是换行符
printf("abc%c%c",ch1,ch2);     //都默认为有效字符前面的空白被跳过,因此若scanf双引号中有空白符的时候,则是除不可打印字符和空白符的
                               //ASCII字符开始计算,如依次输入两次空行,一次空格然后紧接着输入1,空格,3这三个字符的时候
                               //ch1被赋予了换行,ch2被赋予了1,因此是从显示字符1开始往前推算,如果前面有满足双引号格式中的序列,则将
                               //该序列依次赋予变量
                               
//如果在%c和%c之间不是加的空白符,而是其他字符
scanf("%c,%c",&ch1,&ch2);      //这里当scanf双引号中不再是空白符的时候,依次输入空格逗号和回车,则ch1被赋予空格,ch2被赋予回车
printf("ab%cc%c",ch1,ch2);     

//由此可见,双引号中的格式相当于一个窗口,会去寻找满足窗口格式的有效字符序列然后赋值
//空格的测试
cin>>a>>ch>>b>>d; //用cin就不会遇到scanf的情况,因为默认忽略所有的空格,无论是数值和数值之间,还是字符与字符,亦或者数值与字符。
                  //当我们将a,ch,b,d的值依次输入到相应缓冲单元内存后,缓冲区都有内容且识别末尾换行符\n输入结束
                  
//换行符的测试
cin>>ch1>>ch1;             //连续输入敲击两次<enter>键,发现并没有反应,随后继续敲击却一直无反应,因为换行符在单个字符输入时候默认忽略
cout<<"hello"<<ch1<<ch2;   //执行不了,因为缓冲区未刷新

//缓冲内存单元刷新移动机制
char ch1,ch2;
cin>>ch1>>ch2;             //第一次:输入12  第二次:输入101  第三次:输入as
cout<<ch1<<endl<<ch2;      //第一次结果:1<enter>2 第二次结果:1<enter>0 第三次结果:a<enter>s

    1. 由此可见,缓冲区刷新实际操作大致如下:例如scanf("%c %c",&ch1,&ch2); 程序调用字节大小为2bety的缓冲区内存空间(2个%c,共2个字符大小),然后将键盘输入的字符依次填入缓冲区,当我们输入例如:a b+enter键击的时候,a b将缓冲区填满(当scanf双引号中有字符的时候,在输入的时候要在相应位置也输入相同字符,这是因为scanf 要求输入的格式必须与自己设定的保持一致),然后enter键击使程序接受执行指令但同时也将\n读入缓冲区,当系统识别到\n时认为输入结束,随后开始执行后续程序,系统开始寻找ch1与ch2的地址,并且将刚刚存入缓冲区的数据依次赋予ch1和ch2(当然我们也可以在两个单个字符之间不加任何东西,直接连着写,因为系统是一个字符一个字符地读取,缓冲单元内存填满后“指针”自动移动下一个缓冲单元),而当我们输入例如:\n \n的时候,最后一个\n填充了ch2的缓冲内存单元,同时在末尾也有了输入结束标志\n,所以两个条件同时满足(每个缓冲单元都有内容并且识别到末尾有换行符),随后开始执行后续程序。但因为换行符被当作内容给吸收,所以缓冲区不会溢出一个换行符。 临时缓冲区大小即输入输出给变量所需的内存空间大小,并且如果变量是离散数据则只有当同时满足两个条件:每个缓冲单元内存区有内容+识别末尾换行符\n 以后才会执行接下里的程序。如果是非离散数据,如字符串,则只需要满足缓冲区刷新即可(因为字符串变量是一个连续而完整的第一缓冲内存单元,因此无论输入了多少内容,包括只输入一个换行符,因为换行符本身也是一个输入内容,故只要识别了换行符就确认输入结束)
    1. C中对于单个字符的处理:(1). scanf函数通过%c格式转换输入,printf函数通过%c格式转换输出。(2). getchar()函数来读取单个字符,putchar()输出单个字符。
    1. C++中对于单个字符的处理:成员函数cin.get(char)或成员函数cin.get(),而这个不带参数的cin.get()也就等价于C中的getchar()函数。
    1. 在cin/scanf中数值之间使用空白来分隔,假设因为系统会通过读取空白来将“指针”移动到下一个缓存内存单元读取数据,例如上述中,键盘输入a空格b,则系统先申请一块sizeof(a)+sizeof(b)的缓冲区大小,“指针”刚开始指向a缓冲单元的地址,然后读取空格后系统会将“指针”移动到下一个,也就是b的缓冲内存单元地址上);而在cin/scanf中数值之前使用空白会默认跳过,如果在输入的时候不小心按了回车或者空格等空白符,没有关系,因为在首个数值之前的所有空白,cin/scanf都默认跳过,不会有任何影响(因此对于数值的输入来说cin和scanf是几乎等价的)。

2.2 空白符在字符串数组中的处理

    1. cin与scanf对于字符串中空白符的处理:两者在读取字符串的时候,都是通过空白来确定字符串的结束位置。 也就是说cin与scanf两者都会将输入中的空白转换成空字符(\0)来作为结束标记。因此两者都是面向单词的输入,如果我们要将一句完整的英文句子输出,则需要定义N个组成该句子的子字符串数组,然后每个单词依次存入这N个数组中,再将N个数组连续输出。
//例如输出hello world
char str1[50],str2[50];
cin>>str1>>str2;              //键盘输入:hello world
//scanf("%s%s",str1,str2);
cout<<str1<<str2<<endl;       //屏幕输出:helloworld<enter>
                              //因为在输入的时候hello world中间的空白符被用来确定字符串的结束位置,因此空格被转换成了空字符存入到str1数组,故hello与world之间并没有空格,而且无论你输入的时候在中间输入多少个空格都不会在输出的时候显示出来,而world后的换行符被认为是缓冲区字符串输入的结束,缓冲区刷新,并且将换行符转换成空字符存入str2数组,enter键击使程序继续执行。

//如果我们在字符串前面也加空格会如何呢?
char str1[50],str2[50];
scanf("%s%s",str1,str2);            //键盘输入:hello         world
cout<<str1<<str2<<endl;             //屏幕输出:helloworld<enter>
                                    //由此可见:在字符串前置位的空白也会默认跳过
    1. 由上述例子中我们可以总结两点:cin和scanf可以说在字符串数组输入方面是等价关系的。(1).字符串中间的空白默认为结束标记,空白被转换为空白符\0放置字符串数组末尾。 (2).字符串前置位的空白,和数值前面的空白一样,都默认跳过,从首个字符开始存储。
    1. 由此可见,我们用cin是输入不了带空格的完整的英文句子的,那么我们怎么样处理带空格的英文句子呢?C语言中提供了专门处理字符串的函数gets(),而C++中提供了成员函数cin.get(char*,LEN)和cin.getline(char*,LEN,结束符(char)),若cingetline()中不规定省略或者不规定结束符,则默认空字符为结束符。

3. C++中利用缓冲区特性,通过循环来实现用单个字符变量输出字符串

  • 在知道缓冲区特性,和循环特性以后,可以利用两者的结合,完成一项任务:逐字符地读取来自文件或键盘的文本。简而言之,就是用单个字符变量输入输出字符串文本。

3.1 使用原始cin进行输入不带空格的文本

    1. 注意:因为cin会跳过单个字符输入中的空白,因此如果使用cin输入单个字符来完成文本的输入输出,在我们已经知道了缓冲区原理(即键盘上输入的文本都会先存储到缓冲区中,等待回车输入换行符来确定文本输入结束,即缓冲区刷新,之后才进行接下来的程序并调用缓冲区中存储的这些文本来赋值给字符变量)后,输入的结束没有任何问题(回车键即可),那么如何让程序判断输出的结束呢?因为单个字符的读取不像字符串中cin自动将空白设定为结束标记,空白在单个字符的读取中都默认跳过,哪怕是回车产生的换行符,因此在用cin进行的文本输入中不仅不能输出带空格的文本,而且文本需要选择某个特殊字符——有时被称为哨兵字符,将其作为停止标记。
char ch;
cin >> ch;     //Enter characters;enter # to quit: see ken run#really fast
while(ch!='#')    //test the character
{
   cout << ch;    //echo the character         
   cin >> ch;     //get the next character
}                 //最终输出结果:seekenrun;
    1. 对上面程序进行分析:while中的条件对于ch读入的第一个字符进行测试,如果不为哨兵字符,则接着依次调用缓冲区逐个给ch赋值,直到遇到#字符结束输出。发送给cin的输入被缓冲,意味着只有在用户按下回车键后,他输入的内容才会被发送给程序。这就是在运行程序时,可以在#后面输入字符的原因。按下回车键后,整个字符序列将被发送给程序,但程序在遇到#字符后将结束对输入的处理。

3.2 使用cin.get(char)来完成cin不能输入的带空格的字符序列

    1. 通过逐个字符读取输入的程序,需要检查每个字符,包括空格,制表符和换行符。cin所属的istream类(在iostream中定义)中包含一个能够满足这种要求的成员函数cin.get(char)。
    1. 成员函数cin.get(char)读取输入流中的下一个字符(即使是空白符),并且将其赋给变量。
    1. 因此在使用成员函数cin.get(char)的时候,哨兵字符可以是换行符,也就是说换行符来结束输入流的缓冲,也将缓冲区的换行符赋给ch作为结束标记。
char ch;
cin.get(ch);          //Enter characters;enter # to quit:see ken run#really fast
while(ch!='#')        
{
     cout<<ch; 
     cin.get(ch);
}                     //最终输出结果:see ken run

//也可以将换行符来作为结束标志
char ch;
cin.get(ch);
while(ch!='\n')  //see ken run really fast<enter>
{
      cout<<ch;
      cin.get(ch); //输出:see ken run really fast
}
    1. 对上述程序进行分析: 在输入以后按下回车给缓冲区留下换行符,系统识别换行符则缓冲区刷新,后续程序运行,当ch被赋值给换行符时结束循环输出。 现在,该程序回显了每个字符,并将全部字符计算在内,其中包括空格。输入仍被缓冲,因此输入的字符个数仍可能比最终到达程序的要多。
    1. 注意成员函数cin.get(ch)调用将一个值放在ch变量中,这意味着将修改该变量的值,而C语言中只能将值打印输出如putchar(ch),如果在C语言中,要修改变量的值,必须将变量的地址传递给函数,但cin.get(ch)调用时,传递的是ch,而不是&ch,这在C语言中是无效的,但是C++中是有效的,只要函数将参数声明为引用即可。引用是C++在C语言的基础上新增的一种类型。头文件iostream将cin.get(ch)的参数声明为引用类型,因此该函数可以修改其参数的值。

3.3 使用cin.get(void)来完成cin不能输入的带空格的字符序列

  • 由之前的知识我们知道cin.get()这个成员函数由于C++的OOP具有函数重载的特性,因此有不同的版本。因此加上3.2中的cin.get(char)到目前为止就有了三个版本。(1).用于处理面对行对象的字符串数组cin.get(str,sizeof(str));(注意该成员函数不吸收换行符且保留在缓冲区中,因此一般需要在后面加个cin.get()来吸收,但会自动在读取完字符串数据后在末尾加上空字符);(2).等价于C语言中的getchar(),用返回值来给单个字符变量赋值的成员函数cin.get(void);(3).也是用来给单个字符变量赋值的成员函数cin.get(ch);这三个成员函数的函数名都一样,但是它们的参数不一样,因此属于函数重载,属于三个不同的函数实体,编译器将通过参数列表来识别对应相应的函数类型。
  • 如果使用cin.get(ch),则编译器将使用一个接受char参数的版本;如果没有提供参数,则编译器将使用不接受任何参数的cin.get()版本。但两者区别很大,函数cin.get(ch)的返回值是一个cin对象,函数功能是将传入的参数赋值;函数cin.get()的返回值是一个int数据,函数功能是接受键盘输入的一个字符,并且将该字符转换成int型作为返回值返回。
//使用cin.get()来完成带空格的字符序列的输入
char ch;          //也可以直接定义int ch,两者在存储ASCII字符常量方面来说没有任何区别,因为存储数据的本质都是二进制整型数据
ch=char(cin.get());
while(ch!='\n')
{
    cout<<ch;
    ch=char(cin.get());
}

3.4 文件尾条件

  • 使用诸如#等符号来表示输入结束很难令人满意,因为这样的符号可能就是合法输入的组成部分,其他符号(如@和%)也是如此。如果输入来自于文件,则可以使用一种功能更强大的技术——检测文件尾(EOF)。C++输入工具和操作系统协同工作,来检测文件尾并将这种信息告知程序。
  • 首先,很多操作系统(包括Unix,Linux和Windows命令提示符模式)都支持重定向,允许用文本替换键盘输入。例如,假设在Windows中有一个名为gofish.exe的可执行程序和一个名为fishtale的文本文件,则可以在命令提示符模式下输入下面的命令:gofish<fishtale 这样,程序将从fishtale文件(而不是键盘)获取输入。
  • 其次,很多操作系统都允许通过键盘来模拟文件尾条件。在Unix中,可以在行首按下Ctrl+D来实现,在Windows命令提示符模式下,可以在任意位置按Ctrl+Z和Enter。
  • 因此,我们不用哨兵字符来使程序识别结束标记,而是在编程环境能够检测EOF(end of file)的情况下,可以使用键盘输入中来模拟EOF。因为检测的EOF后(即系统检测到程序员用键盘敲击Ctrl+Z+enter),cin将eofbit和failbit都设置为1,那么我们可以通过成员函数eof()和fail()来查看eofbit和failbit是否被设置。如果检测到EOF,则cin.eof()和cin.fail()将返回bool值true,否则返回false。
char ch;
cin.get(ch); //或者ch=cin.get();
while(cin.fail()==false) //或者while(cin.eof()==false)   注意这里是检测到EOF就将eofbit/failbit设为1,因此必须要0才是循环继续
{
    cout<<ch;
    cin.get(ch);//或者ch=cin.get();
}
  • 注意:有些系统不支持来自键盘的模拟EOF。cin.get()可以用来锁住屏幕,知道可以读取为止,但是这种方法在这里并不适用,因为检测EOF时将关闭对输入的进一步读取。然而,可以用计时循环来使屏幕在一段时间内是可见的。
  • cin方法检测EOF时,将设置cin对象中一个指示EOF条件的标记。设置这个标记后,cin将不读取输入,再次调用cin也不管用。对于文件输入,这是有道理的,因为程序不应该读取超过文件尾的内容。然而,对于键盘输入,有可能使用模拟EOF来结束循环,但稍后要读取其他输入。cin.clear()方法可以清除EOF标记,使输入继续进行。
  • 当然,ch=cin.get()可以用文件尾EOF来控制循环条件,但是ch在这里不能为char型,要定义为int型,因为char默认是unsigned类型,而EOF在iostream中宏定义为值-1,-1不是ASCII码字符集中的有效字符,因此如果要用此方式:(ch=cin.get())!=EOF的时候,需要将ch定义为int型

3.5 利用cin.get(ch)的返回值cin对象在条件表达式中的类型自动转化代替哨兵字符检测

  • 方法cin.get(ch)的返回值是一个cin对象,然而istream类提供了一个可以将istream对象(如cin)转换为bool值得函数;当cin出现在需要bool值得地方(如在while循环条件的测试条件中)时,该转换函数将被调用。如果最后一次读取成功了,则转换得到的bool值为true,否则为false。但是这个方法是建立在编程环境可以检测EOF的情况下的。
//利用cin对象在条件表达式中的布尔转换来检测
char ch;
while(cin.get(ch)) //注意,这里就不能用另一个版本的get替换了,因为cin.get(void)返回值不是cin对象,而是int数据
{
   cout <<ch;
}
  • 这样,cin.get(char)只被调用一次,而不是两次:循环前一次,循环结束后一次。为判断循环测试条件,程序必须首先使用cin.get(ch)。如果成功,则将值放入ch中。然后,程序获得函数调用的返回值,即cin。接下来,程序对cin进行bool转换,如果输入成功,则结果为true,否则为false。

二、计时循环

等待一段时间:编写延时循环

  • ANSI C和C++库中有一个函数有助于利用系统时钟来完成计时工作,这个函数名为clock(),函数返回程序开始执行后所使用的系统时间。这里有两个复杂的问题:首先,clock()返回时间的单位不一定是秒;其次,该函数的返回类型在某些系统上可能是long,在另一些系统上可能是unsigned long或其他类型。
  • 但头文件ctime(C语言中为time.h)提供了这些问题的解决方案。首先,它定义了一个符号常量——CLOCKS_PER_SEC,该常量等于每秒钟包含的系统时间单位数。因此,将系统时间除以这个常量,就可以得到秒(或者将秒数乘以该常量,就可以得到以系统时间单位为单位的时间)。其次,ctime将clock_t作为clock()返回类型(即系统时间单位)的别名,这意味着可以将变量声明为clock_t类型,编译器则会自动将其转换为long,unsigned long或适合系统的其他类型。
#include<iostream>
#include<ctime>

int main()
{
     using namespace std;
     cout<< "Enter the delay time, in seconds:";
     float secs;
     cin >> secs;
     clock_t delay=secs*CLOCKS_PER_SEC;
     cout << "starting\a\n";
     clock_t start=clock();  //设置起始时间节点   再用clock()返回实际总时长,减去这个节点时间段,得到的就是从开始到目前的时间间隔
     while(clock()-start<delay)  //或者(clock()/CLOCKS_PER_SEC)-(start()/CLOCK_PER_SEC)<secs
     ;   //空语句
     cout << "Done\a\n";
     return 0;
}

三、基于范围的for循环(C++ 11)

  • C++ 11新增了一种循环:基于范围(range-based)的for循环 。这简化了一种常见的循环任务:对数组(或如vector和array等模板容器类)的每个元素(注意是每一个,不是部分)执行相同的操作。
//如对每个元素打印
double prices[5]={4.99,10.99,6.87,7.99,8.49};
for(double x:prices)
    cout<<x<<std::endl;

//对每个元素赋值
int a[10],i=0;
for(int x:a)
{
     x=i+1;
     i++;
}

  • 其中,x最初表示数组prices的第一个元素。显示第一个元素后,不断执行循环,而x依次表示数组的其他元素。后面程序同理。
//要修改数组的元素,需要使用不同的循环变量语法:
for(double &x : prices)
    x=x*0.8;             //20% off sale
  • 符号&表明x是一个引用变量,这种声明让数组中的元素可以被修改。

总结

1. 计算字符串有效长度

  • C++中对于字符串的存储有两种:(1)用数组逐个存放字符以达到存放字符串 ,这种方法计算字符串的有效长度方法为:调用string.h头文件中声明的strlen()函数,strlen(Array_Name),返回值为字符串数组有效长度; (2)C++中字符串也被定义为了一种数据类型,被string定义的对象,计算其有效长度的方法为:调用string类中成员函数size(),Array_Name.size(),返回值为string对象的有效长度。

2. 前缀递增递减(++),后缀递增递减(–)和解引用运算符(*)的优先级

  • 前缀递增、前缀递减和解引用运算符的优先级相同,以从右到左的方式进行结合。
  • 后缀递增和后缀递减的优先级比前缀运算符以及解引用运算符的优先级高,后缀递增和后缀递减这个运算符以从左到右的方式进行结合。

3. 副作用和顺序点

  • 首先,==副作用(side effect)==指的是在计算表达式时对某些东西(如存储在变量中的值)进行了修改;==顺序点(sequence point)==是程序执行过程中的一个点,在这里,进入下一步之前将确保对所有的副作用进行了评估。
  • 在C++中,语句中的分号就是一个顺序点,这意味着程序处理下一条语句之前,赋值运算符,递增递减运算符执行的所有修改即副作用都必须完成。任何完整的表达式末尾都是一个顺序点
  • 如:y=(4+ x++)+(6+ x++); 这个语句中,完整的表达式是以分号结束的,因此分号是一个顺序点,因此C++只保证程序执行到下一条语句之前,x的值将被递增两次,但C++并没有规定是在计算每个子表达式之后将x的值递增,还是在整个表达式计算完毕后才将x的值递增两次。但一般来说副作用是在到达一个顺序点时才起作用,也就是说这里是保留x原来的数值,在y被赋值结束以后,x直接递增两次。又如:(x=1,x++,y=x)这个逗号表达式中每个逗号为一个顺序点,因此y最后值为2。

4. 缓冲区问题

    1. 缓冲区:计算机读取数据时, 在内存中开辟的临时存储数据的区域。简单说来是一块连续的计算机内存区域, 可以保存相同数据类型的多个实例。
    1. 在标准I/O库中提供了缓冲区,因此输入都是键盘先将数据发送到并传输到缓冲区,再不断通过调用缓冲区将数据依次存入目标的内存单元,同理输出是将目标的内存单元存储的数据调用放到缓冲区,再通过调用缓冲区来读取数据输出到屏幕。
    1. 标准I/O操作都是系统识别文本换行符进行的,只有系统在缓冲区读入到换行符后才进行缓冲区刷新,开始执行后续的I/O实际操作。
    1. 利用缓冲区原理,我们可以利用单个字符变量通过循环逐个读取缓冲区事先存储好的字符序列并输出,以达到输出英文句子的效果。
    1. 空白符在cin离散数据对象输入中都默认被忽略掉,因此cin只能面向单词。
    1. 在cin对于多个离散数据对象的输入中,前置位的空白符都将忽略跳过,数据中间的空白符作为分隔符。
    1. 在cin一系列输入中,在字符串序列前置位的空白符也同样是被忽略跳过的。
    1. C++中cin处理不了带空格等空白符的字符串序列,需要通过成员函数来处理字符串数组:cin.getline(Array_Name,LEN,char(指定的结束符)),cin.get(Array_Name,LEN);同样的,cin也处理不了单个空白符字符的输入赋值等操作,需要通过成员函数处理:cin.get(void),cin.get(ch),可以用来吸收回车或赋值空白符等操作。
    1. 对于缓冲区末尾的换行符(缓冲区刷新标志),cin因为会跳过所有空白符,因此将留在缓冲区;cin.get(char*,LEN)也会将留在缓冲区。但对于来说,cin.get(ch),cin.get(void)和cin.getline(char*(Array_Name),sizeof(Array_Name),char(指定的结束符))都可以吸收。此外,在对于字符串的处理上,都会自动在字符串末尾添加空字符\0。

参考书籍:《C++ Prime plus》

  • 作者:Arbitrary007
  • 原文链接:https://blog.csdn.net/Arbitrary007/article/details/115411084
    更新时间:2023年7月4日10:09:29 ,共 11358 字。