通过cin(istream)读取输入

1
2
char buf[10]{};
std::cin >> buf; // 如果输入超过10个字符会缓冲区溢出

可以使用setw限制输入,以下代码会读取前9个字符,最后一个字符用于\0。 需要注意的是cin通过»读取遇到空白字符会结束读取。

1
2
3
#include <iomanip>
char buf[10]{};
std::cin >> std::setw(10) >> buf;

提取和空白符

1
2
3
4
5
6
7
8
int main()
{
    char ch{};
    while (std::cin >> ch)
        std::cout << ch;

    return 0;
}

当用户输入以下内容时

Hello my name is Alex

提取运算符会跳过空格和换行符。因此,输出是

HellomynameisAlex

通过get函数读取

1
2
3
4
5
6
7
8
int main()
{
    char ch{};
    while (std::cin.get(ch))
        std::cout << ch;

    return 0;
}

当用户输入以下内容时

Hello my name is Alex

不会跳过空格和换行符。输出是

Hello my name is Alex

get() 还有一个字符串版本,它接受要读取的最大字符数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
int main()
{
    char strBuf[11]{};
    // Read up to 10 characters
    std::cin.get(strBuf, 11);
    std::cout << strBuf << '\n';
    
    // 如果上述读取到换行,则下面读取不到
    // Read up to 10 more characters
    std::cin.get(strBuf, 11);
    std::cout << strBuf << '\n';
    return 0;
}

与读取cin.get(ch)不同的是,cin.get(strBuf, 11)不能读取换行符 ,这可能会导致一些意想不到的结果,但是同样能够读取空格。

通过getline函数读取

还有一个名为 getline() 的函数,其工作方式类似于 get(strBuf, 11),但会提取(并丢弃)分隔符(默认是换行)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
int main()
{
    char strBuf[11]{};
    // Read up to 10 characters
    std::cin.getline(strBuf, 11);
    std::cout << strBuf << '\n';

    // Read up to 10 more characters
    std::cin.getline(strBuf, 11);
    std::cout << strBuf << '\n';
    return 0;
}

std::string 的特殊版本 getline()

有一个特殊版本的 getline() 存在于 istream 类之外,用于读取 std::string 类型的变量。这个特殊版本不是 ostream 或 istream 的成员,并包含在 string 头文件中。以下是其使用示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#include <string>
#include <iostream>

int main()
{
    std::string strBuf{};
    std::getline(std::cin, strBuf);
    std::cout << strBuf << '\n';

    return 0;
}

您可能还需要使用一些其他有用的输入函数

ignore() 丢弃流中的第一个字符。

ignore(int nCount) 丢弃前 nCount 个字符。

peek() 允许您从流中读取一个字符,而无需将其从流中删除。

unget() 将最后读取的字符返回到流中,以便下一次调用可以再次读取它。

putback(char ch) 允许您将自己选择的字符放回流中,以便下一次调用读取。

通过ostream 和 ios 进行输出

通过setf()函数设置标志。

1
2
std::cout.setf(std::ios::showpos); // turn on the std::ios::showpos flag
std::cout << 27 << '\n';

这会输出 +27

要关闭标志,使用 unsetf() 函数

1
2
3
4
std::cout.setf(std::ios::showpos); // turn on the std::ios::showpos flag
std::cout << 27 << '\n';
std::cout.unsetf(std::ios::showpos); // turn off the std::ios::showpos flag
std::cout << 28 << '\n';

标志组

组标志含义
std::ios::basefieldstd::ios::dec以十进制打印值(默认)
std::ios::basefieldstd::ios::dec以十六进制打印值
std::ios::basefieldstd::ios::dec以八进制打印值

操纵符

操纵符含义
std::dec以十进制打印值
std::hex以十六进制打印值
std::oct以八进制打印值

示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
std::cout << 27 << '\n';

std::cout.setf(std::ios::dec, std::ios::basefield);
std::cout << 27 << '\n';

std::cout.setf(std::ios::oct, std::ios::basefield);
std::cout << 27 << '\n';

std::cout.setf(std::ios::hex, std::ios::basefield);
std::cout << 27 << '\n';

std::cout << std::dec << 27 << '\n';
std::cout << std::oct << 27 << '\n';
std::cout << std::hex << 27 << '\n';

输出

27
27
33
1b
27
33
1b

精度、表示法和小数点

组标志含义
std::ios::floatfieldstd::ios::fixed浮点数使用十进制表示法
std::ios::floatfieldstd::ios::scientific浮点数使用科学记数法
std::ios::floatfield(无)对于位数少的数字使用 fixed,否则使用 scientific
std::ios::floatfieldstd::ios::showpoint始终显示小数点和浮点值的尾随 0
操纵符含义
std::fixed值使用十进制表示法
std::scientific值使用科学记数法
std::showpoint显示小数点和浮点值的尾随 0
std::noshowpoint不显示小数点和浮点值的尾随 0
std::setprecision(int)设置浮点数的精度(定义在 iomanip 头文件中)
成员函数含义
std::ios_base::precision()返回浮点数的当前精度
std::ios_base::precision(int)设置浮点数的精度并返回旧精度

如果使用 fixed 或 scientific 表示法,精度决定了小数部分显示多少位小数。请注意,如果精度小于有效数字的数量,则数字将被四舍五入。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
std::cout << std::fixed << '\n';
std::cout << std::setprecision(3) << 123.456 << '\n';
std::cout << std::setprecision(4) << 123.456 << '\n';
std::cout << std::setprecision(5) << 123.456 << '\n';
std::cout << std::setprecision(6) << 123.456 << '\n';
std::cout << std::setprecision(7) << 123.456 << '\n';

std::cout << std::scientific << '\n';
std::cout << std::setprecision(3) << 123.456 << '\n';
std::cout << std::setprecision(4) << 123.456 << '\n';
std::cout << std::setprecision(5) << 123.456 << '\n';
std::cout << std::setprecision(6) << 123.456 << '\n';
std::cout << std::setprecision(7) << 123.456 << '\n';

结果

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
123.456
123.4560
123.45600
123.456000
123.4560000

1.235e+002
1.2346e+002
1.23456e+002
1.234560e+002
1.2345600e+002

如果既不使用 fixed 也不使用 scientific,则精度决定应显示多少有效数字。同样,如果精度小于有效数字的数量,则数字将被四舍五入。

1
2
3
4
5
std::cout << std::setprecision(3) << 123.456 << '\n';
std::cout << std::setprecision(4) << 123.456 << '\n';
std::cout << std::setprecision(5) << 123.456 << '\n';
std::cout << std::setprecision(6) << 123.456 << '\n';
std::cout << std::setprecision(7) << 123.456 << '\n';

结果

1
2
3
4
5
123
123.5
123.46
123.456
123.456

使用 showpoint 操纵符或标志,可以使流写入小数点和尾随零。

1
2
3
4
5
6
std::cout << std::showpoint << '\n';
std::cout << std::setprecision(3) << 123.456 << '\n';
std::cout << std::setprecision(4) << 123.456 << '\n';
std::cout << std::setprecision(5) << 123.456 << '\n';
std::cout << std::setprecision(6) << 123.456 << '\n';
std::cout << std::setprecision(7) << 123.456 << '\n';

宽度、填充字符和对齐方式

组标志含义
std::ios::adjustfieldstd::ios::internal数字的符号左对齐,值右对齐
std::ios::adjustfieldstd::ios::left符号和值左对齐
std::ios::adjustfieldstd::ios::right符号和值右对齐(默认)
操纵符含义
std::internal数字的符号左对齐,值右对齐
std::left符号和值左对齐
std::right符号和值右对齐
std::setfill(char)设置参数作为填充字符(定义在 iomanip 头文件中)
std::setw(int)将输入和输出的字段宽度设置为参数(定义在 iomanip 头文件中)
成员函数含义
std::basic_ostream::fill()返回当前填充字符
std::basic_ostream::fill(char)设置填充字符并返回旧填充字符
std::ios_base::width()返回当前字段宽度
std::ios_base::width(int)设置当前字段宽度并返回旧字段宽度

为了使用这些格式化器中的任何一个,我们必须首先设置字段宽度。这可以通过 width(int) 成员函数或 setw() 操纵符完成。请注意,右对齐是默认设置。

1
2
3
4
5
std::cout << -12345 << '\n'; // print default value with no field width
std::cout << std::setw(10) << -12345 << '\n'; // print default with field width
std::cout << std::setw(10) << std::left << -12345 << '\n'; // print left justified
std::cout << std::setw(10) << std::right << -12345 << '\n'; // print right justified
std::cout << std::setw(10) << std::internal << -12345 << '\n'; // print internally justified

这会产生结果

1
2
3
4
5
-12345
    -12345
-12345
    -12345
-    12345

需要注意的是,setw() 和 width() 只影响下一个输出语句。它们不像其他一些标志/操纵符那样是持久的。

现在,让我们设置一个填充字符并执行相同的示例

1
2
3
4
5
6
std::cout.fill('*');
std::cout << -12345 << '\n'; // print default value with no field width
std::cout << std::setw(10) << -12345 << '\n'; // print default with field width
std::cout << std::setw(10) << std::left << -12345 << '\n'; // print left justified
std::cout << std::setw(10) << std::right << -12345 << '\n'; // print right justified
std::cout << std::setw(10) << std::internal << -12345 << '\n'; // print internally justified

这会产生输出

1
2
3
4
5
-12345
****-12345
-12345****
****-12345
-****12345