cout

cout 用于在屏幕上显示消息,应该是 console output 的简写。它是 C++ostream 对象,该类被封装在 <iostream> 库中,该库定义的名称都放在命名空间 std 中,所以 cout 的全称是 std::cout
cout 被分类为流对象,这意味着可以使用数据流的。要在屏幕上显示消息,可以发送一串字符到 cout 。例如:

cout << "hello world!" ;  

如果要使用 cout ,需要包含库 <iostream>

cout 输出的格式控制

在使用 cout 时,可以将一些格式控制操作符放在语句中,来实现不同的输出效果。

以不同进制输出数字

cout 在输出数字时,默认是十进制的方式,还可以使用 hexoctdec 来控制输出的进制,这三个控制符都包含在 <iostream> 库中。例如:

using namespace std;
auto i = 65534;
cout.setf(ios::uppercase); //输出为大写字母
cout << hex << i << endl; //十六进制输出(默认为小写字母)
cout << oct << i << endl; //八进制输出
cout << dec << i << endl; //十进制输出
cout << setbase(16) << i << endl; //以16进制输出

其中的 setiosflags(ios::uppercase) 表示以大写字母输出(默认是 ios::lowercase), setbase(n) 方法表示以 n 进制输出,其中的 n 取值为 8、10 或者 16,其余值无输出。这两个函数都包含在库 <iomanip> 中。
使用 setiosflags() 时,可以使用 | 来同时设置多个位,例如:

cout << setiosflags(ios::scientific | ios::showpos) << 12.01 << endl;

控制浮点数的输出

可以通过 setprecision(n)setiosflags(ios::fixed)fixed 来对 cout 输出的精度进行控制。这几个控制符都包含在库 <iomanip> 库的 std 命名空间中。

#include <iostream>
#include <climits>
#include <iomanip>

int main(void)
{
    using namespace std;
    system("chcp 65001");
    system("cls");

    double p = 1233.141592653;
    cout << p << endl;
    cout << setprecision(3) << p << endl; //保留两位小数
    cout << setprecision(15) << p << endl;
    cout << setiosflags(ios::fixed);
    cout << p << endl;
    cout << fixed << p << endl;
    return 0;
}

运行结果如下:

1233.14
1.23e+03
1233.141592653
1233.141592653000089
1233.141592653000089

显示小数点和正负号

此外,还可以使用 setiosflags(ios::showpoint) 来显示小数点,使用 setiosflags(ios::showpos) 来显示正负号。例如:

double i2 = 100;
double d2 = -3.14;
cout << setprecision(4);
cout << setiosflags(ios::showpoint); //显示小数点
cout << i2 << endl;
cout << setiosflags(ios::showpos); //显示正负号
cout << d2 << "\t" << i2 << endl;

输出结果如下:

100.0000
-3.1400   +100.0000

默认显示6个有效位数。

设置宽度和对齐方式

可以通过 setw(n) 函数来设置输出的宽度,当不足宽度的时候,以空格填充剩余的空间,如果超出宽度,则忽略设置的宽度;使用 setiosflags(ios::left|ios::right) 来设置对齐方式。这些都定义在 <iomanip> 库中的 std 命名空间中。例如:

cout.fill(' ');
cout << setw(10) << 100 << setw(10) << 100 << endl;
cout << setiosflags(ios::left) << setw(10) << 100 << setw(10) << 100 << endl;
cout << setiosflags(ios::right) << setw(10) << 100 << setw(10) << 100 << endl;

输出结果为:

       100       100
100       100
       100       100

输出的结果默认为右对齐。

设置填充字符

在宽度大于字符数量时,cout 默认使用空格填充剩余的空间,可以使用 setfill('*') 来设置为其他的填充字符。例如:

cout << setfill('*') << setiosflags(ios::right) << setw(10) << 100 << setw(10) << 100 << endl;

使用 cout 的成员函数

ostream 类还有一些成员函数,通过 cout 来调用它们也可以控制格式输出。和前面的控制符不同的是,使用成员函数会影响后面所有使用默认格式的输出。如下表:

成员函数控制符说明
precision(n)setprecision(n)设置输出浮点数的精度为n
width(w)setw(w)指定输出宽度为w个字符
fill(c)setfill(c)在指定输出宽度的情况下,多余的空白使用字符c填充
setf(flag)setiosflags(flag)将摸个输出格式标志设置为1
unset(flag)resetiosflags(flag)将某个输出格式标志设置为0
cout.precision(5);
double x = 1123.23456;
cout << x << endl;

cout.width(20);
cout.fill('*');
cout << x << endl;

cin

cin 是 C++中的标准输入流对象,它是 istream 类的对象,包含在 <iostream> 库中, std 命名空间中。cin 主要用于从标准输入读取数据,这里的标准输入,指的是键盘。
当我们从键盘输入字符串的时候,需要按一下回车键才能够将这个字符串送入到缓冲区中。那么键入的回车键也会被转换为一个换行符,这个换行符也会被存储在 cin 的缓冲区并且被当做一个字符来计算。
cin 读取数据也是从缓冲区中读取数据,当缓冲区为空时,cin 的成员函数会阻塞等待数据的到来,一旦有数据,就触发函数去读取数据。所以,当缓冲区有残留数据时,cin 的函数会直接取得这些数据而不会请求键盘输入。

cin 常用的读取方法

当使用 cin 从标准输入读取数据时,通常用到的方法有 cin >>cin.get()cin.getline()

cin >>

cin >> 可以连续的从键盘读取数据,以空格、Tab 键或者换行符作为分隔符或者结束符。
当从缓冲区读取数据时,如果第一个字符是空白字符,cin>> 会忽略并将其清除,继续读取下一个字符,如果缓冲区为空,则继续等待。如果读取成功,字符后面的分隔符都是残留在缓冲区内的,cin >> 不做处理。

int a, b, c;
cin >> a >> b >> c;
cout << a << b << c << endl;

上面的代码,将会要求我们输入三个数,并以空白分隔,输出才算完成。
cin>> 等价于 cin.operator>>(),即调用成员函数 operator>>() 进行读取数据。
如果不想略过开头的空白字符,那就使用 noskipws 流控制符。如下:

cin >> noskipws >> a;

cin.get()

这个函数有多个版本的重载。如下:

int cin.get(); 
istream& cin.get(char& var);
istream& get(char* s, streamsize n);
istream& get(char* s, streamsize n, char delim);

其中的 streamsize 被定义为 long long 类型。

int cin.get() 和 istream& cin.get(char& var)

这两种版本都是一次读取一个字符。
例如下面的代码:

char c1, c2;
c1 = cin.get();
cin.get(c2);
cout << c1 << '\t' << (int)c2 << endl;

运行,输入 a,然后回车,输出如下:

a
a

如上面的代码:

  • cin.get() 从缓冲区读取单个字符时不忽略空白,直接将其读取,所以变量 c2 保存的是一个空行 \r。它的返回值是 int 类型,成功则返回读取字符的 ASCII 码值,遇到文件结束符时,返回 EOF,即 -1 。在 Windows 中,可以使用 Ctrl+Z 来输入文件结束符。
  • cin.get(char var) 如果成功返回的是 cin 对象,所以可以支持链式操作,比如 cin.get(a).get(c)
  • 可以使用 cin.get() 来删除缓冲区上一次遗留下来的换行符。
使用 cin.get() 读取一行

cin.get() 的后面两种重载形式,

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

可以用来读取一行。这两个版本的区别是,前者默认以换行符结束,后者可以指定结束符。参数里的 n 表示目标空间的大小。
例如下面的代码:

#include <iostream>

int main(void)
{
    using namespace std;
    system("chcp 65001");
    system("cls");

    char arr1[100] = {NULL};
    cin.get(arr1, 100);
    char a;
    cin.get(a);
    cout << arr1 << " " << (int)a << endl;

    system("pause");
    return 0;
}

运行的结果:

hello world  //输入
hello world 10

从上面的代码中,可以看出:

  • 读取一行时,遇到换行符时停止读取,但是对换行符不做处理,换行符依然残留在输入缓冲区。
  • 第二次使用 cin.get(a) 将换行符读入变量 a ,输出的 ASCII 码值为 10 。就是上一次残留的换行符。
  • 这种方法读取一行时,只能将字符串读入 C 风格的字符串中,即 char* ,使用 C++ 的 getline() 函数可以将字符串读入 string 类型。

cin.getline 读取一行

这个函数可以从键盘读取一个字符串,还可以以指定的结束符结束。它不会将换行符残留在缓冲区。函数有两个重载的版本,如下:

istream& getline(char* s, streamsize count); //默认的换行符结束
istream& getline(char* s, streamsize count, char delim); //delim 指定结束符

例如下面的代码:

#include <iostream>

int main(void)
{
    using namespace std;

    char arr1[100] {0};
    cin.getline(arr1, 100);
    cout << arr1 << endl;

    system("pause");
    return 0;
}

cin 的条件状态

使用 cin 读取键盘输入时,一旦出错,cin 将设置条件状态(condition state)。条件状态定义如下:

  • goodbit :无错误
  • eofbit :已经到达文件尾
  • failbit :非致命的输入/输出错误,可挽回
  • badbit :致命的输入/输出错误,无法挽回

这些条件状态都有对应的成员函数,可以用来设置、读取当前的条件状态。这些成员函数如下:

函数说明
cin.eof()如果流 cin 的 eofbit 为1,则返回 true
cin.fail()如果流 cin 的 failbit 位为1,则返回 true
cin.bad()如果流 cin 的 badbit 位为1,则返回 true
cin.good()如果流 cin 的 goodbit 位为1,则返回 true
cin.clear(flags)清空状态标志位,将给定的标志位 flags 设置为0,无返回值,如果不带参数,那么则是将清除所有的非good状态
cin.setstate(flags)将对应的 flags 设置为1,无返回值
cin.rdstate()返回当前状态。返回值类型为 iostate
cin.ignore()它有两个参数,第一个是整型,第二个是 char 类型。它表示从输入流 cin 中提取第一个参数指定的字符数量,然后将这些字符忽略,如果提取的数量达到指定值或者字符等于第二个参数指定的字符时,该函数将终止。否则,继续等待,直到两个条件之一满足。第二个参数默认值为 EOF

例如下面的代码:

#include <iostream>

int main(void)
{
    using namespace std;
    system("chcp 65001");
    system("cls");
    
    int a;
    while(true)
    {
        cin >> a;
        cout << "位状态:good=" << cin.good() << ", eof=" << cin.eof() << ", bad=" << cin.bad() << ", fail=" << cin.fail() << endl;
        //文件尾,可以使用Ctrl+Z
        if(cin.eof())
        {
            cout << "文件尾命令" << endl;
            exit(1);
        }
        if(cin.fail())
        {
            cout << "输入的非数字。" << endl;
            cin.clear();
            cin.ignore(1000,'\n'); //忽略后面的所有内容
            continue;
        }
    }
    system("pause");
    return 0;
}

运行结果:

1
位状态:good=1, eof=0, bad=0, fail=0
a
位状态:good=0, eof=0, bad=0, fail=1
输入的非数字。
^Z
位状态:good=0, eof=1, bad=0, fail=1
文件尾命令

我们可以看到,在输入正确的类型(int)后,good 位标志为1。输入非数字时,fail 位被设置。当使用 clear() 函数进行清除状态后,除 good 位外所有的位都被设置为0。

其他用于读取的函数

这些函数不是 cin 的成员函数,但也可以用于读取输入。

gets() 函数

gets() 函数可以一直读取,直到遇到换行符或者文件尾,它的读取不设上限,所以必须保证缓冲区足够大。它不会让换行符残留在缓冲区。它是 C 语言的库函数。使用如下:

#include <iostream>

int main(void)
{
    using namespace std;

    char arr1[100] {0};
    gets(arr1);
    cout << arr1 << endl;

    system("pause");
    return 0;
}

getchar() 函数

getchar() 读取一个字符并返回,可以读取空白,遇到换行符停止。也会处理结尾的换行符。

#include <iostream>

int main(void)
{
    using namespace std;

    char c;
    c = getchar();
    cout << c << endl;

    system("pause");
    return 0;
}

getline() 函数

getline() 函数读取一整行,它是在 std 命名空间中的全局函数,这个函数的参数使用了 string 类型,所以声明在了 <string> 头文件中。
getline() 从标准输入设备中读取一行,当遇到下面三种情况之一会结束读取:

  1. 文件结束 EOF。
  2. 遇到行分隔符。
  3. 输入达到最大的限度。

这个函数有两个重载的版本:

istream& getline(istream& is, string& str); //默认以换行符 \n 分隔行
istream& getline(istream& is, string& str, char delim); //指定分隔符

例如下面的代码:

#include <iostream>

int main(void)
{
    using namespace std;
    
    while(true)
    {
        string str;
        getline(cin, str);
        cout << str << endl;
    }
    system("pause");
    return 0;
}

getline() 函数遇到结束符时,会将结束符一并读入指定的 string 中,再将结束符替换为空字符。


Mr_神棍
1 声望1 粉丝