c++中cout和cin

C++ pirmer笔记(三)

输入和输出

ps:写这些笔记只是为了记录一下自己的学习过程,上面的代码都是c++primerplus里面的,前面几个章节的内容有空会补起来

流和缓冲区

C++将输入和输入都看作字节流,输入流的两端连接着输入设备(键盘,文件,等)和程序,输入流的两端连接着输出设备(显示屏,打印机,文件等)和程序。

在从外部硬件读取信息的过程中,如果只有程序和外部的数据交流,那么程序每次从外部硬件中读取一个字节,处理完毕,在读取一个字节,这样的效率是很低的,所以创建了一个缓冲区,缓冲区先从外部硬件读取信息,存满缓冲区,然后程序再从缓冲区中读取处理信息,这样的效率会高很多。

在创建对象时(例如cout,cin),这些对象都会包含一个streambuff类来为缓冲区提供内存,并管理缓冲区

使用cout进行输出
  • cout重载了<<运算符,使之能对所有的基本类型进行输出,不用再像printf()一样用%占位符并搭配一系列参数

  • cout <<在处理指针时的不同

    const char * p1 = "hello";
    char array1[] = "good";
    int a = 5;
    int * p2 = &a;
    
    //char*的输出
    cout << *p1 << endl; // w,是指针指向的第一个字符
    cout << p1 << endl; // hello,整个字符串
    cout << &p1 << endl; // 002B00C, 输出的是指针p1的地址
    cout << (void*)p1 << endl;//0024FFD0, 输出的是“hello”字符串的地址
    
    //array1的输出
    cout << *p1 << endl; // w,是数组的第一个字符
    cout << p1 << endl; // good,整个字符串
    cout << &p1 << endl; // 0024FDA8, 输出的是数组第一个元素的地址
    cout << (void*)p1 << endl;//0024FDA8, 输出的是数组的地址
    
    //p2的输出
    cout << &p2 << endl; //输出p2指针的地址
    cout << p2 << endl;  //输出p2指向的地址,也就是a的地址
    cout << *p2 << endl; //对p2的地址解引用,也就是a的值
    cout << &a << endl;
    cout << a << endl;
    
    
    
  • 拼接输出

    重载的<<运算符和cout的成员函数会返回ostream&

    //这两种方式都会输出hello world!
    string str(" world");
    cout << "hello" << str << "!";
    cout.write(hello).write(str).write("!");
    
  • cout的一些常用方法

    • cout.put():显示一个字符,并返回cout对象
    • cout.write():显示一个字符串。并返回cout对象
  • 刷新缓冲区

    在控制台程序中,我们经常不需要等到缓冲区满在刷新缓冲区,例如,当缓冲区读取到换行符,便会刷新,在即将发生输入时,也将刷新缓冲区。

    可以使用endl(cout)强制刷新缓冲区并且换行,或者使用flush(cout)刷新缓冲区,也可以直接用

    cout<<endl; 或者 cout<<flush;

  • cout对输出格式的控制

    • 输出时的进制

      c++使用dec,hex,oct等控制符(实际上是函数)来选择输出进制

      hex(cout);//用十六进制输出,也可以用
      
      int a = 10;
      cout << a << endl; //A
      cout << oct << a << endl; //12
      cout << dec << a << endl; //10
      
      
    • 字段宽度

      cout.width(); //返回当前的宽度,以便保存
      cout.width(int n); //设置下一次输出的字段宽度,并返回上一次的字段宽度,只能用一次,之后会变成默认,
      //当字段宽度小于数据宽度时,c++会优先保证数据输出的完整性
      
      int wid = cout.width();
      cout << 12;
      cout.width(10);
      cout << "#12 ";
      cout << 12211;
      //12      #12 12211
      
    • 填充字符

      默认情况下,c++用空格填充字段中未被使用的部分,可以用fill()来改变填充字符,例如cout.fill( ‘*’ ),与字段宽度不同,fill()设置一次可以一直使用,直到被重新设置

    • 浮点数的显示精度

      浮点数精度的含义取决于输出模式,在默认模式下,精度指的是总位数,在定点模式和科学模式下,指的是小数点后面的位数。默认精度为6位,但后面的0不显示。

      可以用**cout.precision(int n)**控制显示精度,设置一次可以一直使用,直到被重新设置

    • 打印末尾的0和小数点

      在有些情况下打印出末尾的0将使得输出更加美观,例如$20.40比$20.4要美观,ios_base类为这个问题定义了一个函数cout.setf()来设置输出时的一些格式,并在类中定义了多个静态常量,在这里使用 cout.setf(ios_base::showpoint) 可以显示后面的0和小数点,

    • 再谈setf()

      第一种版本 fmtflags setf(fmtflags),其中fmtflags时bitmask类型,用于存储格式标记

      serf()控制了输出时的一些格式选项,ios_base类中有一个受保护的数据成员,其中个各个数据位控制了一些输出的格式标记,在重新设置格式时,如果还想要恢复原来的格式,可以将setf()的返回值保存下来

      可以使用unsetf()复位设置

      常用的一些格式标记

      常量含义
      ios_base::boolalpha输入和输出bool值,可以使用true和false
      ios_base::showbase对于输出,使用C++基数前缀(0,0X)
      ios_base::showpoint显示末尾的小数点
      os_base::uppercase对十六进制数输出,使用大写字母
      ios_base::showpos在正数前面加上+,仅对十进制有意义

      第二种版本 fmtflags setf(fmtflags,fmtflags),用于设置由多个数据位控制的格式选项

      第二个参数第一个参数含义
      ios_base::basefieldios_base::dec使用基数10
      ios_base::oct使用基数8
      ios_base::hex使用基数16
      ios_base::floatfieldos_base::fixed使用定点计数法
      ios_base:scientific使用科学计数法
      ios_base::adjustfieldios_base::left使用左对齐
      ios_base::right使用右对齐
      ios_base::internal符号或基数左对齐,值右对齐
    • 头文件iomanip

      c++在iomanip中提供给一些常用的设置格式的函数,例如serprecision(),setfill(),setw(),

      由于他们都是控制符可以与cout连接起来,例如cout<<setprecision(2)<<endl;

利用cin进行输入
  • cin如何检查输出

    cin会跳过前面的空白字符(空格,换行符和制表符),直到非空白且符合条件的字符,一直读取,知道遇到下一个空白字符或不满足条件的字符

    int value;
    cin >> value; 
    //假设输入“   -123Z”
    //cin会跳过前面的空格,从'-'开始读取,知道遇到z,并将z留在缓冲区中,给下一次读取
    
  • 流状态

cin包含一个描述流状态的成员,由3个元素组成,eofbit,badbit,failbit,每个元素都是一位,可以为1或0,当三个位全部为0时,说明一切顺利

成员描述
eofbit如果到达文件尾,则设置为1
badbit如果流被破坏,则设置为1,例如读取文件错误
failbit如果输入操作未能读取预期的字符或输出操作没有写入预期的字符,则设置为1

获取和设置流状态的方法

方法描述
eof()如果eofbit被置位,则返回true
bad()如果badbit被置位,则返回true
fail()如果badbit或failbit被置位,则返回true
rdstate()返回流状态
exceptions()返回一个位掩码,指出那些标记导致异常触发
exceptions(isostate ex)设置哪些流状态会引发异常,例如如果ex为eofbit,则当eofbit被置位时,clear()将引发异常
clear(iostate s)将流状态设置为s,默认为0(good)
setstate(iostate s)调用clear(rdstate() | s)
  1. 设置流状态

    clear()将它的参数设置为状态,例如clear(eofbit),会将eofbit置位,其余两个清零

    setstate()只能影响参数中已经设置的位,例如setstate(eofbit),只会将eofbit置位,另外两个保持不变

  2. I/O 和异常

    exceptions()函数会返回一个位字段,包含3位,分别对应eofbit,badbit,failbit,修改流状态时,必然会调用clear(),修改之后,clear()将当前的流状态与exceptions()返回的值进行比较,如果返回值中的某一位被设置,且当前的流状态的那一位也被设置,则会引发异常

    cin.exceptions(eofbit);//当eofbit被置位时,将引发异常
    cin.exceptions(eofbit | failbit);//当eofbit或failbit被置位时,将引发异常
    
  3. 流状态的影响

    当流状态的任意一位被置位时,cin都会停止读取输入,知道三个位重新清零

    int input;
    int sum = 0;
    while (cin >> input)
    {
    	sum += input;
    }
    cout << "loop end" << endl;
    cout << "Enter a new number: \n";
    if (cin.fail()) //检测程序是否输入了预料之外的输入
    {
    	cout << "Unexcepted input" << endl;
    	cin.clear(); //清除标志位,使cin能够继续读取输入
    	//虽然清除了标志位,但是缓冲区的不合要求的字符仍然存在,所以用get()消除那些不好的字符,一直读到空白字符停止
    	while (!isspace(cin.get()))
    	{
    		continue;
    	}
    cout << "now you can input again: ";
    }
    cin >> input;
    
    
    
  • 其他istream类的方法

    处理字符数据

  1. get(char &ch)

    不会跳过空白字符,char版本将读取到的字符赋值给ch,void版本将输入字符转换为整型(通常是int)返回

    int ct = 0;
    char ch;
    cin.get(ch); //假设输出为 "I love C++<Enter>"
    while (ch != 'n')
    {
        cout << ch;
        ct++;
        cin.get(ch);
    }
    cout << ct << endl;
    //输出为"I love c++10"
     
    

    当把这里的get换成>>时,将出现问题,因为>>将跳过空白字符,程序会陷入无限循环

  2. get(void)

    get()函数将读取到的字符以整形的形式返回,也就是返回一个int值而不是cin对象,所以以下的代码是非法的

    cin.get().get() >> var;
    

3.处理单字节数据时的选择

  • 当希望能够跳过空白字符时,应当使用>>,如果要用cin.get(),则必须处理每一次输入时的回车键
  • 在get方法中,优先选用get(char &);
  • get(void)的优点是,可以将C程序中所有的getchar()替换为cin.get(),将所有的putchar(ch)替换为cout.put(ch),来将一个C程序变为C++程序

4.处理字符串输入

  1. istream & get(char*,int,char) / istream & getline(char*,int,char)

第一个参数为读取字符串的地址,第二个参数要比读取最大字符串的长度大一,留给空字符,第三个字符表示分割字符,当程序读到分割字符时(默认为换行符),即使没有读满,也会立即停止, 区别是get将分割字符留在缓冲区中,getline则将分割字符提出并丢弃

  1. istream & get(char*,int) / istream & getline(char*,int)

将第三个参数的分割字符默认为换行符,其余不变

  1. istream & ingore(int = 1, int = EOF)

第一个参数是读取的最大字符数,第二个参数是分割字符

5.字符串的意外输入

方法行为
getline(char *,int)如果没有读取任何字符(换行符也会被视为读取了一个字符),则failbit置位, 如果读取了最大数目的字符,且行中还有其他字符,则failbit置位
get(char *, int)如果没有读取任何字符,则failbit置位

6.其他istream方法

  • read() 读取指定数目的字符数,但不会给最后加上空字符,因此不能将输入转换为字符串,不是专为键盘输入设计,最常用与write()函数搭配,来完成文件输入和输入
  • peek()返回输入中的下一个字符,但不抽取下一个字符,相当于查看下一个字符,可以根据返回值是否为换行符或EOF,来判断是否读取完毕
  • putback()将一个字符放回到输入缓冲区中,例如当用cin.get()读取一个字符来判断条件但并不需要将他取出来,此时用putback()可以将他放回去,作为下一次输入读取的第一个字符
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值