第4章
4.1 基础数据类型
位:二进制数字,最小的内存单位;
字节:由8个连续位组成;
数据类型
![](https://i-blog.csdnimg.cn/blog_migrate/a66e76c9b6fc97d1d8211ea2dba8f70a.png)
4.2 void
void:不能用于定义变量
void用于指示函数不返回值
void writeValue(int x) // void here means no return value
{
std::cout << "The value of x is: " << x << '\n';
// no return statement, because this function doesn't return a value
}
使用空参数列表而不是void来指示函数没有参数
4.3 对象大小和运算符大小
对象大小:具有 n 位(其中 n 是整数)的对象可以容纳
(2 的 n 次幂,通常也写为 2^n)唯一值,
基本数据类型大小
![](https://i-blog.csdnimg.cn/blog_migrate/b103ea1f1ee4c6d50a476eaab805c475.png)
运算符大小:sizeof 运算符是一个一元运算符,它采用类型或变量,并以字节为单位返回其大小。
#include <iostream>
int main()
{
std::cout << "bool:\t\t" << sizeof(bool) << " bytes\n";
std::cout << "char:\t\t" << sizeof(char) << " bytes\n";
std::cout << "wchar_t:\t" << sizeof(wchar_t) << " bytes\n";
std::cout << "char16_t:\t" << sizeof(char16_t) << " bytes\n";
std::cout << "char32_t:\t" << sizeof(char32_t) << " bytes\n";
std::cout << "short:\t\t" << sizeof(short) << " bytes\n";
std::cout << "int:\t\t" << sizeof(int) << " bytes\n";
std::cout << "long:\t\t" << sizeof(long) << " bytes\n";
std::cout << "long long:\t" << sizeof(long long) << " bytes\n";
std::cout << "float:\t\t" << sizeof(float) << " bytes\n";
std::cout << "double:\t\t" << sizeof(double) << " bytes\n";
std::cout << "long double:\t" << sizeof(long double) << " bytes\n";
return 0;
}
bool: 1 bytes char: 1 bytes wchar_t: 2 bytes char16_t: 2 bytes char32_t: 4 bytes short: 2 bytes int: 4 bytes long: 4 bytes long long: 8 bytes float: 4 bytes double: 8 bytes long double: 8 bytes
在变量名称上使用 sizeof 运算符
#include <iostream>
int main()
{
int x{};
std::cout << "x is " << sizeof(x) << " bytes\n";
return 0;
}
x is 4 bytes
4.4 有符号整数
各种整数类型之间的主要区别在于它们具有不同的大小 - 较大的整数可以容纳更大的数字。
![](https://i-blog.csdnimg.cn/blog_migrate/dbe2c2eeaf505417567800a66f617cbc.png)
有符号整数可以同时保存正数和负数(和 0)
定义有符号整数
short s; // prefer "short" instead of "short int"
int i;
long l; // prefer "long" instead of "long int"
long long ll; // prefer "long long" instead of "long long int"
整数类型还可以采用可选的有符号关键字,按照惯例,该关键字通常放在类型名称之前:
signed short ss;
signed int si;
signed long sl;
signed long long sll;
但是,不应使用此关键字,因为它是多余的,因为默认情况下整数是有符号的
整数变量的范围由两个因素决定:它的大小(以位为单位)以及它是否是有符号的。
根据定义,8 位有符号整数的范围为 -128 到 127。这意味着有符号整数可以安全地存储 -128 和 127(含)之间的任何整数值。
![](https://i-blog.csdnimg.cn/blog_migrate/1d1dc9c5de74a436a65b10c8a76a6457.png)
n 位有符号变量的范围为 到
当整数除法导致分数结果时会发生什么:
#include <iostream>
int main()
{
std::cout << 8 / 5 << '\n';
return 0;
}
1
当对两个整数进行除法(称为整数除法)时,C++总是产生整数结果。由于整数不能容纳小数值,因此任何小数部分都会被简单地删除(不四舍五入!),8 / 5 产生值 1.6。删除小数部分 (0.6),保留 1 的结果。
4.5 无符号整数
无符号整数(只能容纳非负整数)
定义无符号整数:
使用无符号关键字
unsigned short us;
unsigned int ui;
unsigned long ul;
unsigned long long ull;
![](https://i-blog.csdnimg.cn/blog_migrate/ddd1ff087b90ffdcaa99a0c6f3477cfa.png)
如果无符号值超出范围,则将其除以大于该类型最大数的 1,并仅保留余数。
数字 280 太大,无法容纳我们的 1 到 0 的 255 字节范围。大于 1 的类型的最大数字是 256。因此,我们将 280 除以 256,得到 1 个余数 24。24 的其余部分是存储的内容。
这是思考同一件事的另一种方式。任何大于类型可表示的最大数字的数字都只是“环绕”(有时称为“模包装”)。255 在 1 字节整数的范围内,因此 255 没问题。但是,256 超出了范围,因此它环绕到值 0。257 环绕到值 1。280 环绕到值 24。
#include <iostream>
int main()
{
unsigned short x{ 65535 }; // largest 16-bit unsigned value possible
std::cout << "x was: " << x << '\n';
x = 65536; // 65536 is out of our range, so we get wrap-around
std::cout << "x is now: " << x << '\n';
x = 65537; // 65537 is out of our range, so we get wrap-around
std::cout << "x is now: " << x << '\n';
return 0;
}
x was: 65535 x is now: 0 x is now: 1
也可以绕另一个方向。0 可以用 2 字节无符号整数表示,所以这很好。-1 不可表示,因此它环绕到范围的顶部,产生值 65535。-2 环绕到 65534。等等
#include <iostream>
int main()
{
unsigned short x{ 0 }; // smallest 2-byte unsigned value possible
std::cout << "x was: " << x << '\n';
x = -1; // -1 is out of our range, so we get wrap-around
std::cout << "x is now: " << x << '\n';
x = -2; // -2 is out of our range, so we get wrap-around
std::cout << "x is now: " << x << '\n';
return 0;
}
x was: 0 x is now: 65535 x is now: 65534
在保存数量(甚至应该是非负的数量)和数学运算时,优先使用有符号数字而不是无符号数字。避免混合使用有符号和无符号数字。
4.6 固定宽度的整数和size_t
整数变量的大小不固定?
缺点:
对于int类型,最小大小为2字节,但在现代体系结构上通常是4字节。如果假设int是4个字节,则可能在int实际上是2字节的体系结构上行为不正常;
如果您假设 int 只有 2 个字节以确保最大的兼容性,那么在 int 为 4 字节的系统上,每个整数浪费了 2 个字节,并使内存使用量翻倍!
固定宽度整数
为了解决上述问题C99 定义了一组固定宽度的整数(在 stdint.h 标头中),这些整数在任何体系结构上都保证大小相同。
![](https://i-blog.csdnimg.cn/blog_migrate/00b986225168265e6359f4487f8b2141.png)
C++正式采用这些固定宽度的整数作为C++11的一部分。可以通过包含标头来访问它们,标头在 std 命名空间中定义它们。下面是一个示例:<cstdint>
#include <cstdint> // for fixed-width integers
#include <iostream>
int main()
{
std::int16_t i{5};
std::cout << i;
return 0;
}
缺点:
首先,不保证在所有体系结构上定义固定宽度的整数。
其次,如果使用固定宽度的整数,则在某些体系结构上,它可能比更宽的类型慢。
快速整数和最小整数
快速类型(std::int_fast#_t 和 std::uint_fast#_t)提供宽度至少为 # 位的最快有符号/无符号整数类型(其中 # = 8、16、32 或 64)。例如,std::int_fast32_t 将为您提供至少为 32 位的最快有符号整数类型。
最小类型(std::int_least#_t 和 std::uint_least#_t)提供宽度至少为 # 位的最小有符号/无符号整数类型(其中 # = 8、16、32 或 64)。例如,std::uint_least32_t 将为您提供至少为 32 位的最小无符号整数类型。
#include <cstdint> // for fixed-width integers
#include <iostream>
int main()
{
std::cout << "least 8: " << sizeof(std::int_least8_t) * 8 << " bits\n";
std::cout << "least 16: " << sizeof(std::int_least16_t) * 8 << " bits\n";
std::cout << "least 32: " << sizeof(std::int_least32_t) * 8 << " bits\n";
std::cout << '\n';
std::cout << "fast 8: " << sizeof(std::int_fast8_t) * 8 << " bits\n";
std::cout << "fast 16: " << sizeof(std::int_fast16_t) * 8 << " bits\n";
std::cout << "fast 32: " << sizeof(std::int_fast32_t) * 8 << " bits\n";
return 0;
}
least 8: 8 bits least 16: 16 bits least 32: 32 bits fast 8: 8 bits fast 16: 32 bits fast 32: 32 bits
可以看到 std::int_least16_t 是 16 位,而 std::int_fast16_t 实际上是 32 位。这是因为在作者的机器上,32 位整数的处理速度比 16 位整数快。
然而,这些快速和最小整数有其自身的缺点:首先,没有多少程序员真正使用它们,缺乏熟悉会导致错误。其次,快速类型会导致与我们看到的 4 字节整数相同的内存浪费。最严重的是,由于快速/最小整数的大小可能会有所不同,因此程序可能会在解析为不同大小的体系结构上表现出不同的行为。
最佳选择
当整数的大小无关紧要时首选(例如,数字将始终适合 2 字节有符号整数的范围)。例如,如果您要求用户输入他们的年龄,或者从 1 到 10 计数,则 int 是 16 位还是 32 位并不重要(数字适合任何一种方式)。这将涵盖您可能遇到的绝大多数情况。int
在存储需要保证范围的数量时首选。std::int#_t
在执行位操作或需要明确定义的环绕行为时首选。std::uint#_t
尽可能避免以下情况:
用于保存数量的无符号类型
8 位固定宽度整数类型
快速和最小固定宽度类型
任何特定于编译器的固定宽度整数 - 例如,Visual Studio定义了__int8,__int16等。
std::size_t 定义为无符号整数类型,通常用于表示对象的大小或长度。
可以使用 sizeof 运算符(返回 std::size_t 类型的值)来请求 std::size_t 本身的大小:
#include <cstddef> // std::size_t
#include <iostream>
int main()
{
std::cout << sizeof(std::size_t) << '\n';
return 0;
}
4
4.7 科学计数法简介
有效数中的数字(“e”之前的部分)称为有效数字。有效位数定义数字的精度。有效位数越多,数字越精确。
4.8 浮点数float
浮点数据类型始终是有符号的(可以保存正值和负值)
![](https://i-blog.csdnimg.cn/blog_migrate/43d94fa856611c8e89d60d9ef8a69cfd.png)
float fValue;
double dValue;
long double ldValue;
使用浮点文本时,请始终至少包含一个小数位(即使小数为 0)。这有助于编译器了解该数字是浮点数而不是整数。
int x{5}; // 5 means integer
double y{5.0}; // 5.0 is a floating point literal (no suffix means double type by default)
float z{5.0f}; // 5.0 is a floating point literal, f suffix means float type
默认情况下,浮点文本默认为双精度类型。f 后缀用于表示浮点类型的文本。
浮点范围
![](https://i-blog.csdnimg.cn/blog_migrate/5a357a5f97bab43e0c3cf44cf1071335.png)
浮点数的精度:6位
Inf,它代表无穷大。Inf 可以是正数或负数。
NaN,代表“不是一个数字”。
IND 代表不确定
4.9 布尔值 bool
布尔变量
布尔变量是只能有两个可能值的变量:true 和 false。
声明一个布尔变量,我们使用关键字 bool。
了初始化或为布尔变量赋值 true,我们使用关键字 true 和 false。
bool b1 { true };
bool b2 { false };
b1 = false;
bool b3 {}; // default initialize to false
逻辑 NOT 运算符 (!) 可用于将布尔值从真翻转为假,或将假翻转为真:
bool b1 { !true }; // b1 will be initialized with the value false
bool b2 { !false }; // b2 will be initialized with the value true
打印布尔值时,std::cout 打印 0 表示 false,1 表示 true:
#include <iostream>
int main()
{
std::cout << true << '\n'; // true evaluates to 1
std::cout << !true << '\n'; // !true evaluates to 0
bool b{false};
std::cout << b << '\n'; // b is false, which evaluates to 0
std::cout << !b << '\n'; // !b is true, which evaluates to 1
return 0;
}
1 0 0 1
想让std::cout打印“true”或“false”而不是0或1,你可以使用std::boolalpha。下面是一个示例:
#include <iostream>
int main()
{
std::cout << true << '\n';
std::cout << false << '\n';
std::cout << std::boolalpha; // print bools as true or false
std::cout << true << '\n';
std::cout << false << '\n';
return 0;
}
1 0 true false
可以使用 std::noboolalpha 将其关闭
整数到布尔值的转换
在整数可以转换为布尔值的任何上下文中,整数 0 将转换为 false,任何其他整数将转换为 true。
#include <iostream>
int main()
{
std::cout << std::boolalpha; // print bools as true or false
bool b1 = 4 ; // copy initialization allows implicit conversion from int to bool
std::cout << b1 << '\n';
bool b2 = 0 ; // copy initialization allows implicit conversion from int to bool
std::cout << b2 << '\n';
return 0;
}
true false
std::cin 只接受布尔变量的两个输入:0 和 1(不为真或假)
要允许 std::cin 接受 “false” 和 “true” 作为输入,必须启用 std::boolalpha 选项:
4.10 if语句简介
if (condition)
true_statement;
由于条件的计算结果为 true,因此后续语句将执行。
if-else 语句
如果 condition 的计算结果为布尔值 true,则执行true_statement。否则false_statement执行
if (condition)
true_statement;
else
false_statement;
非布尔条件
条件表达式将转换为布尔值:非零值将转换为布尔值 true,零值将转换为布尔值 false。
#include <iostream>
int main()
{
if (4) // nonsensical, but for the sake of example...
std::cout << "hi";
else
std::cout << "bye";
return 0;
}
4.11 字符char
一个字符可以是单个字母、数字、符号或空格
char数据类型是整型,
字符文本始终放在单引号之间('g'、'1')
![](https://i-blog.csdnimg.cn/blog_migrate/0fb4dd8f5a5a01b15b8181c53b8233d4.png)
初始化字符:
char ch2{ 'a' }; // initialize with code point for 'a' (stored as integer 97) (preferred)
打印字符:
使用 std::cout 打印字符时,std::cout 将 char 变量输出为 ASCII 字符:
#include <iostream>
int main()
{
char ch1{ 'a' }; // (preferred)
std::cout << ch1; // cout prints character 'a'
char ch2{ 98 }; // code point for 'b' (not preferred)
std::cout << ch2; // cout prints a character ('b')
return 0;
}
ab
输入字符
#include <iostream>
int main()
{
std::cout << "Input a keyboard character: ";
char ch{};
std::cin >> ch;
std::cout << "You entered: " << ch << '\n';
return 0;
}
Input a keyboard character: q You entered q
请注意,std::cin 将允许您输入多个字符。但是,变量 ch 只能容纳 1 个字符。因此,只有第一个输入字符被提取到变量 ch 中。其余的用户输入保留在 std::cin 使用的输入缓冲区中,可以通过后续调用 std::cin 来提取。
#include <iostream>
int main()
{
std::cout << "Input a keyboard character: "; // assume the user enters "abcd" (without quotes)
char ch{};
std::cin >> ch; // ch = 'a', "bcd" is left queued.
std::cout << "You entered: " << ch << '\n';
// Note: The following cin doesn't ask the user for input, it grabs queued input!
std::cin >> ch; // ch = 'b', "cd" is left queued.
std::cout << "You entered: " << ch << '\n';
return 0;
}
Input a keyboard character: abcd
You entered: a
You entered: b
字符的大小:始终为一个1个字节。
换行符:'\n';
水平制表符:'\t'
![](https://i-blog.csdnimg.cn/blog_migrate/4ccda775ec0e68574bae489abf27804c.png)
4.12 类型转换和static_cast
隐式类型转换:
#include <iostream>
void print(double x) // print takes an double parameter
{
std::cout << x;
}
int main()
{
int y { 5 };
print(y); // y is of type int
return 0;
}
将int类型转换为double类型
#include <iostream>
void print(int x) // print now takes an int parameter
{
std::cout << x;
}
int main()
{
print(5.5); // warning: we're passing in a double value
return 0;
}
将double类型转换为int类型,将会发出警告
通过static_cast运算符进行显示类型转换
static_cast<new_type>(expression)
static_cast 将表达式中的值作为输入,并返回转换为 new_type 指定的类型(例如 int、bool、char、double)的值。
#include <iostream>
void print(int x)
{
std::cout << x;
}
int main()
{
print( static_cast<int>(5.5) ); // explicitly convert double value 5.5 to an int
return 0;
}
使用 static_cast 将字符转换为 int
#include <iostream>
int main()
{
char ch{ 97 }; // 97 is ASCII code for 'a'
std::cout << ch << " has value " << static_cast<int>(ch) << '\n'; // print value of variable ch as an int
return 0;
}
a has value 97
将无符号数字转换为有符号数字
#include <iostream>
int main()
{
unsigned int u { 5u }; // 5u means the number 5 as an unsigned int
int s { static_cast<int>(u) }; // return value of variable u as an int
std::cout << s;
return 0;
}
4.13 常量变量和符号变量
到目前位置,所看到的变量都是非常量--它的值可以随时更改(通过分配新值)
int main()
{
int x { 4 }; // x is a non-constant variable
x = 5; // change value of x to 5 using assignment operator
return 0;
}
其值无法更改的变量称为常量变量
常量关键字:const
const double gravity { 9.8 }; // preferred use of const before type
int const sidesInSquare { 4 }; // "east const" style, okay but not preferred
常量变量必须在定义时初始化,然后不能通过赋值更改该值:
int main()
{
const double gravity; // error: const variables must be initialized
gravity = 9.9; // error: const variables can not be changed
return 0;
}
常量函数参数
函数参数可以通过关键字成为常量:const
#include <iostream>
void printInt(const int x)
{
std::cout << x << '\n';
}
int main()
{
printInt(5); // 5 will be used as the initializer for x
printInt(6); // 6 will be used as the initializer for x
return 0;
}
常量返回值
函数的返回值也可以变为 const:
#include <iostream>
const int getValue()
{
return 5;
}
int main()
{
std::cout << getValue() << '\n';
return 0;
}
符号常量
符号常量是赋予常量值的名称。常量变量是一种类型的符号常量,因为变量具有名称(其标识符)和常量值。
#include <iostream>
#define MAX_STUDENTS_PER_CLASS 30
int main()
{
std::cout << "The class has " << MAX_STUDENTS_PER_CLASS << " students.\n";
return 0;
}
由于类对象宏具有名称,并且替换文本是常量值,因此具有替换文本的类对象宏也是符号常量。
4.14 编译时常量、常量表达式和constexpr
常量表达式
常量表达式是编译器可在编译时计算的表达式。要成为常量表达式,表达式中的所有值必须在编译时已知(并且调用的所有运算符和函数都必须支持编译时计算)。
当编译器遇到常量表达式时,它可以在编译时计算表达式,然后将常量表达式替换为计算结果。
#include <iostream>
int main()
{
int x { 3 + 4 };
std::cout << x << '\n';
return 0;
}
7
编译时常量
编译时常量是其值在编译时已知的常量。文字(例如“1”、“2.3”和“Hello, world!”)是一种编译时常量。
但是常量变量呢?常量变量可能是编译时常量,也可能不是编译时常量。
如果 const 变量的初始值设定项是常量表达式,则其为编译时常量。
#include <iostream>
int main()
{
const int x { 3 }; // x is a compile-time const
const int y { 4 }; // y is a compile-time const
const int z { x + y }; // x + y is a constant expression, so z is compile-time const
std::cout << z << '\n';
return 0;
}
编译时 const 的初始值设定项可以是任何常量表达式。以下所有内容都将是编译时 const 变量:
const int z { 3 }; // 3 is a constant expression, so z is compile-time const
const int a { 1 + 2 }; // 1 + 2 is a constant expression, so a is compile-time const
const int b { z * 2 }; // z * 2 is a constant expression, so b is compile-time const
编译时 const 变量通常用作符号常量:
const double gravity { 9.8 };
使用非常量表达式初始化的任何 const 变量都是运行时常量。运行时常量是其初始化值在运行时之前未知的常量。
#include <iostream>
int getNumber()
{
std::cout << "Enter a number: ";
int y{};
std::cin >> y;
return y;
}
int main()
{
const int x{ 3 }; // x is a compile time constant
const int y{ getNumber() }; // y is a runtime constant
const int z{ x + y }; // x + y is a runtime expression
std::cout << z << '\n'; // this is also a runtime expression
return 0;
}
关键字constexpr
声明 const 变量时,编译器将隐式跟踪它是运行时常量还是编译时常量。在大多数情况下,除了优化目的之外,这无关紧要,但在一些奇怪的情况下,C++需要编译时常量而不是运行时常量(我们将在稍后介绍这些主题时介绍这些情况)。
constexpr(“常量表达式”的缩写)变量只能是编译时常量。如果 constexpr 变量的初始化值不是常量表达式,编译器将出错。
#include <iostream>
int five()
{
return 5;
}
int main()
{
constexpr double gravity { 9.8 }; // ok: 9.8 is a constant expression
constexpr int sum { 4 + 5 }; // ok: 4 + 5 is a constant expression
constexpr int something { sum }; // ok: sum is a constant expression
std::cout << "Enter your age: ";
int age{};
std::cin >> age;
constexpr int myAge { age }; // compile error: age is not a constant expression
constexpr int f { five() }; // compile error: return value of five() is not a constant expression
return 0;
}
4.15 文本
文本有时称为文本常量,因为它们的值无法重新分配。
文本类型
文本的类型是从文本的值推导出来的
![](https://i-blog.csdnimg.cn/blog_migrate/e67f324fff5ead18aed18324ae6f9563.png)
文字后缀
如果文本的默认类型与预期不符,则可以通过添加后缀来更改文本的类型:
![](https://i-blog.csdnimg.cn/blog_migrate/6e617138c015124e6037771b1f7d7651.png)
整型文本
通常不需要对整型文本使用后缀,但以下是示例:
#include <iostream>
int main()
{
std::cout << 5; // 5 (no suffix) is type int (by default)
std::cout << 5L; // 5L is type long
return 0;
}
浮点文本
#include <iostream>
int main()
{
std::cout << 5.0; // 5.0 (no suffix) is type double (by default)
std::cout << 5.0f; // 5.0f is type float
return 0;
}
有两种不同的方法可以声明浮点文本:
double pi { 3.14159 }; // 3.14159 is a double literal in standard notation
double avogadro { 6.02e23 }; // 6.02 x 10^23 is a double literal in scientific notation
Magic numbers(幻数)
含义不明确或以后可能需要更改。
constexpr int maxStudentsPerSchool{ numClassrooms * 30 };
setMax(30);
4.16 数字系统(十进制、二进制、十六进制和八进制)
默认情况下,C++程序中的数字假定为十进制
十进制:以10为基数
在二进制中,只有 2 位数字:0 和 1,因此称为“基数 2”。在二进制中,我们这样计数:0, 1, 10, 11, 100, 101, 110, 111, ...
十进制(以 10 为基数)、二进制(以 2 为基数)、十六进制(以 16 为基数)和八进制(以 8 为基数)
八进制以 8 为基数 - 也就是说,唯一可用的数字是:0、1、2、3、4、5、6 和 7
![](https://i-blog.csdnimg.cn/blog_migrate/f230b154799188c884b09e51711c4f95.png)
要使用八进制文本,请在文本前面加上 0(零):
#include <iostream>
int main()
{
int x{ 012 }; // 0 before the number means this is octal
std::cout << x << '\n';
return 0;
}
10
十六进制以 16 为基数。在十六进制中,我们这样计数:0、1、2、3、4、5、6、7、8、9、A、B、C、D、E、F、10、11、12、...
![](https://i-blog.csdnimg.cn/blog_migrate/f40cbcd490199e41f71a9a15af560940.png)
要使用十六进制文本,请在文本前面加上 0x。
#include <iostream>
int main()
{
int x{ 0xF }; // 0x before the number means this is hexadecimal
std::cout << x << '\n';
return 0;
}
15
在 C++14 中,我们可以通过使用 0b 前缀来使用二进制文字:
数字分隔符
由于长文本可能难以阅读,因此 C++14 还添加了使用引号 (') 作为数字分隔符的功能。
#include <iostream>
int main()
{
int bin { 0b1011'0010 }; // assign binary 1011 0010 to the variable
long value { 2'132'673'462 }; // much easier to read than 2132673462
return 0;
}
另请注意,分隔符不能出现在值的第一个数字之前:
int bin { 0b'1011'0010 }; // error: ' used before first digit of value
以十进制、八进制或十六进制输出值
#include <iostream>
int main()
{
int x { 12 };
std::cout << x << '\n'; // 默认十进制
std::cout << std::hex << x << '\n'; // 十六进制
std::cout << x << '\n'; // 十六进制
std::cout << std::oct << x << '\n'; // 八进制
std::cout << std::dec << x << '\n'; // 十进制
std::cout << x << '\n'; // 十进制
return 0;
}
以二进制形式输出值
使用<bitset>头文件
要使用 ,我们可以定义一个变量并告诉我们要存储多少位。位数必须是编译时常量。 可以使用无符号整数值(任何格式,包括十进制、八进制、十六进制或二进制)进行初始化。
#include <bitset> // for std::bitset
#include <iostream>
int main()
{
// std::bitset<8> means we want to store 8 bits
std::bitset<8> bin1{ 0b1100'0101 }; // binary literal for binary 1100 0101
std::bitset<8> bin2{ 0xC5 }; // hexadecimal literal for binary 1100 0101
std::cout << bin1 << '\n' << bin2 << '\n';
std::cout << std::bitset<4>{ 0b1010 } << '\n'; // create a temporary std::bitset and print it 创建一个具有4位的临时(未命名)对象,使用二进制文本对其进行初始化,以二进制形式打印值,然后丢弃该临时对象
return 0;
}
11000101 11000101 1010
4.17 字符串 std::string
#include <iostream>
int main()
{
std::cout << "Hello, world!\n";//字符串文本Hello, world!
return 0;
}
std::string简介
使用<string>头文件
#include <string> // allows use of std::string
int main()
{
std::string name {}; // empty string
return 0;
}
就像普通变量一样,您可以按预期初始化或为 std::string 对象赋值:
#include <string>
int main()
{
std::string name { "Alex" }; // initialize name with string literal "Alex"
name = "John"; // change name to "John"
return 0;
}
字符串也可以包含数字:
std::string myID{ "45" }; // "45" is not the same as integer 45!
字符串输出
std::string可以使用以下命令按预期输出对象:std::cout
#include <iostream>
#include <string>
int main()
{
std::string name { "Alex" };
std::cout << "My name is: " << name << '\n';
return 0;
}
My name is: Alex
空字符串不会打印任何内容:
#include <iostream>
#include <string>
int main()
{
std::string empty{ };
std::cout << '[' << empty << ']';
return 0;
}
[]
字符串输入 std::cin
#include <iostream>
#include <string>
int main()
{
std::cout << "Enter your full name: ";
std::string name{};
std::cin >> name; // this won't work as expected since std::cin breaks on whitespace
std::cout << "Enter your age: ";
std::string age{};
std::cin >> age;
std::cout << "Your name is " << name << " and your age is " << age << '\n';
return 0;
}
Enter your full name: John Doe Enter your age: Your name is John and your age is Doe
当用于从中提取字符串时,仅返回它遇到的第一个空格的字符。任何其他字符都留在里面,等待下一次提取。
使用 std::getline() 输入文本
要将整行输入读入字符串,使用 std::getline()
#include <string> // For std::string and std::getline
#include <iostream>
int main()
{
std::cout << "Enter your full name: ";
std::string name{};
std::getline(std::cin >> std::ws, name); // read a full line of text into name
std::cout << "Enter your age: ";
std::string age{};
std::getline(std::cin >> std::ws, age); // read a full line of text into age
std::cout << "Your name is " << name << " and your age is " << age << '\n';
return 0;
}
#include <string>
#include <iostream>
int main()
{
std::cout << "Enter your full name: ";
std::string name{};
std::getline(std::cin >> std::ws, name); // read a full line of text into name
std::cout << "Enter your age: ";
std::string age{};
std::getline(std::cin >> std::ws, age); // read a full line of text into age
std::cout << "Your name is " << name << " and your age is " << age << '\n';
return 0;
}
Enter your full name: John Doe Enter your age: 23 Your name is John Doe and your age is 23
std::ws
输入操纵器,这些操纵器会改变接受输入的方式。输入操纵器告诉在提取之前忽略任何前导空格。前导空格是出现在字符串开头的任何空格字符(空格、制表符、换行符)。
#include <string>
#include <iostream>
int main()
{
std::cout << "Pick 1 or 2: ";
int choice{};
std::cin >> choice;
std::cout << "Now enter your name: ";
std::string name{};
std::getline(std::cin >> std::ws, name); // note: added std::ws here
std::cout << "Hello, " << name << ", you picked " << choice << '\n';
return 0;
}
Pick 1 or 2: 2 Now enter your name: Alex Hello, Alex, you picked 2
将提取运算符 (>>) 与 std::cin 一起使用会忽略前导空格。
std::getline() 不会忽略前导空格,除非您使用输入操纵器 std::ws。
字符串长度
#include <iostream>
#include <string>
int main()
{
std::string name{ "Alex" };
std::cout << name << " has " << name.length() << " characters\n";
return 0;
}
Alex has 4 characters
返回一个无符号整数,如果要为变量分配长度,则应避免编译器警告有关有符号/无符号转换:应避免
int length { static_cast<int>(name.length()) };
得到有符号整数的长度:std::ssize()
#include <iostream>
#include <string>
int main()
{
std::string name{ "Alex" };
std::cout << name << " has " << std::ssize(name) << " characters\n";
return 0;
}
复制字符串的成本很高,应尽可能避免
通过在双引号字符串文字后使用后缀来创建带有类型的字符串文字
#include <iostream>
#include <string> // for std::string
#include <string_view> // for std::string_view
int main()
{
using namespace std::literals; // easiest way to access the s and sv suffixes
std::cout << "foo\n"; // no suffix is a C-style string literal
std::cout << "goo\n"s; // s suffix is a std::string literal
std::cout << "moo\n"sv; // sv suffix is a std::string_view literal
return 0;
};
4.18 std::string_view简介
为了解决初始化(或复制)成本高昂的问题,引入了 C++17(位于 <string_view> 标头中)。 提供对现有字符串(C 样式字符串文本、或 char 数组)的只读访问,而无需创建副本。
#include <iostream>
#include <string_view>
void printSV(std::string_view str) // now a std::string_view
{
std::cout << str << '\n';
}
int main()
{
std::string_view s{ "Hello, world!" }; // now a std::string_view
printSV(s);
return 0;
}
std::string_view支持constexpr
#include <iostream>
#include <string_view>
int main()
{
constexpr std::string_view s{ "Hello, world!" };
std::cout << s << '\n'; // s will be replaced with "Hello, world!" at compile-time
return 0;
}
将std::string转换为std::string_view
#include <iostream>
#include <string>
#include <string_view>
void printSV(std::string_view str)
{
std::cout << str << '\n';
}
int main()
{
std::string s{ "Hello, world" };
std::string_view sv{ s }; // Initialize a std::string_view from a std::string
std::cout << sv << '\n';
printSV(s); // implicitly convert a std::string to std::string_view
return 0;
}
将std::string_view转换为std::string
#include <iostream>
#include <string>
#include <string_view>
void printString(std::string str)
{
std::cout << str << '\n';
}
int main()
{
std::string_view sv{ "balloon" };
std::string str{ sv }; // okay, we can create std::string using std::string_view initializer
// printString(sv); // compile error: won't implicitly convert std::string_view to a std::string
printString(static_cast<std::string>(sv)); // okay, we can explicitly cast a std::string_view to a std::string
return 0;
}
文本:std::string_view
#include <iostream>
#include <string> // for std::string
#include <string_view> // for std::string_view
int main()
{
using namespace std::literals; // easiest way to access the s and sv suffixes
std::cout << "foo\n"; // no suffix is a C-style string literal
std::cout << "goo\n"s; // s suffix is a std::string literal
std::cout << "moo\n"sv; // sv suffix is a std::string_view literal
return 0;
};
std::string 提供了一种简单安全的方法来处理文本字符串。std::string 位于 <string> 标头中。 初始化和复制成本很高。std::string
std::string_view 提供对现有字符串(C 样式字符串文本、std::string 或 char 数组)的只读访问,而无需创建副本。