C++学习:第4章

第4章

4.1 基础数据类型
  • 位:二进制数字,最小的内存单位;

  • 字节:由8个连续位组成;

  • 数据类型

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)唯一值,

基本数据类型大小

  • 运算符大小: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 有符号整数

各种整数类型之间的主要区别在于它们具有不同的大小 - 较大的整数可以容纳更大的数字。

有符号整数可以同时保存正数和负数(和 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(含)之间的任何整数值。

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;

如果无符号值超出范围,则将其除以大于该类型最大数的 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 标头中),这些整数在任何体系结构上都保证大小相同。

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

浮点数据类型始终是有符号的(可以保存正值和负值)

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 后缀用于表示浮点类型的文本。

浮点范围

浮点数的精度:6位

Inf,它代表无穷大。Inf 可以是正数或负数。

NaN,代表“不是一个数字”。

IND 代表不确定

4.9 布尔值 bool

布尔变量

布尔变量是只能有两个可能值的变量:truefalse

声明一个布尔变量,我们使用关键字 bool

了初始化或为布尔变量赋值 true,我们使用关键字 truefalse

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 表示 false1 表示 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'

初始化字符:

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'

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 文本

文本有时称为文本常量,因为它们的值无法重新分配。

文本类型

文本的类型是从文本的值推导出来的

文字后缀

如果文本的默认类型与预期不符,则可以通过添加后缀来更改文本的类型:

整型文本

通常不需要对整型文本使用后缀,但以下是示例:

#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

要使用八进制文本,请在文本前面加上 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、...

要使用十六进制文本,请在文本前面加上 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 数组)的只读访问,而无需创建副本。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值