C++ Primer Plus “阅读”笔记(一)

前言

我感觉我自己也难以忍受自己写的 C with STL 了,于是决定看看 CPPPP(雾)并记下一些之前不会的东西。

然而,所谓阅读,或许只是一次 skimming 吧?或许会烂尾吧?下次一定仔细看.jpg

本篇内容包括:

  • 数组初始化
  • 字符串
  • 结构
  • 枚举

第1章 预备知识

None

第2章 开始学习 C++

None

第3章 处理数据

None

第4章 复合类型

4.1 数组

4.1.3 C++11 数组初始化方法

  • 初始化数组时,可省略等号

    1
    double earnings[]{1.2e4, 1.6e4, 1.1e4, 1.7e4};
  • 列表初始化禁止缩窄转换

    1
    2
    3
    long plifs[] = {25, 92, 3.0};           // invalid
    char slifs[] = {'h', 'i', 1122011, 0}; // invalid
    char tlifs[] = {'h', 'i', 112, 0}; // valid

4.2 字符串

4.2.4 每次读取一行字符串输入

  • getline

    std::basic_istream<CharT,Traits>::getline
    basic_istream& getline( char_type* s, std::streamsize count ); (1)
    basic_istream& getline( char_type* s, std::streamsize count, char_type delim ); (2)
    Extracts characters from stream until end of line or the specified delimiter delim.

    e.g.

    1
    2
    3
    const int str_len = 100;
    char str[str_len];
    std::cin.getline(str, str_len);
  • get

    • 建议使用 get() 而不是 getline()

    • 变体:

      1. 工作方式与 getline() 类似,它们接受的参数相同,解释参数的方式也相同,并且都读取到行尾。但 get() 并不再读取并丢弃换行符,而是将其留在输入队列中。

      2. 只读取一个字符,类似 getchar()

      3. 使用不带任何参数的 cin.get() 调用可读取下一个字符(即使是换行符)。

      4. 将两个类成员函数拼接起来(合并)

        1
        std::cin.get(str, str_len).get();

        之所以可以这样做,是由于 cin.get() 返回一个 cin 对象,该对象随后将被用来调用 get() 函数。getline() 也同理。

  • 错误处理

    get()(不是 getline())读取空行后将设置失效位(failbit)。这意味着接下来的输入将被阻断,但可以用下面的代码来恢复输入:

    1
    cin.clear();

    如果输入行包含的字符数比指定的多,则 getline()get() 将把余下的字符留在输入队列中,而 getline() 还会设置失效位,并关闭后面的输入。

  • 混合输入字符串和数字

    注意到数字后的回车之类的字符会导致字符串读取失败,可使用下列代码解决:

    1
    2
    (std::cin >> number).get();
    std::cin.get(str, str_len);

4.3 string 类介绍

4.3.3 string 类的其他操作

1
2
std::string str{"Hello World!"};
std::cout << str.size() << std::endl;

4.3.5 其他形式的字符串字面值

  • char 类型外,C++ 还有类型 wchar_t ;而 C++11 新增了类型 char16_tchar32_t。可创建些类型的数组和这些类型的字符串字面值。对于这些类型的字符串字面值,C++ 分别使用前缀 LuU 表示。

  • C++11 还支持 Unicode 字符编码方案 UTF-8。在这种方案中,根据编码的数字值,字符可能存储为1~4个八位组。C++ 使用前缀 u8 来表示这种类型的字符串字面值。

  • C++11 新增的另一种类型是原始(raw)字符串。在原始字符串中,字符表示的就是自己。原始字符串将 "()" 用作定界符,并使用前缀R来标识原始字符串:

    1
    std::cout << R"(I've said "Hello World!")" << std::endl;

    原始字符串语法允许在表示字符串开头的 "( 之间添加其他字符,这意味着表示字符串结尾的 ") 之间也必须包含这些字符,如:

    1
    std::cout << R"233("(Who wouldn't?)", she whispered.)233" << std::endl;

4.4 结构简介

4.4.6 结构中的位字段

与 C 语言一样,C++ 也允许指定占用特定位数的结构成员,这使得创建与某个硬件设备上寄存器对应的数据结构非常方便。字段的类型应为整型或枚举(稍后将介绍),接下来是冒号,冒号后面是一个数字,它指定了使用的位数。可以使用没有名称的字段来提供间距。每个成员都被称为位字段(bit field)。下面是一个例子:

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
struct torgle_register {
unsigned int SN : 4;
unsigned int : 4;
bool goodIn : 1;
bool goodTorgle : 1;
};
int main() {
std::cout << sizeof(torgle_register);
return 0;
}

上述代码输出为4这个结构体对齐的理论我以后还要再研究研究。(Flag)

4.6 枚举

4.6.2 枚举的取值范围

先看下面的代码

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

enum bits{one = 1, two, four = 4, eight = 8};

int main() {
bits myflag = bits(6);
std::cout << myflag << std::endl;
return 0;
}

它的输出是 6,但注意到 6 并不是枚举值。

合法的原因是 6 在枚举定义的取值范围内。取值范围的定义如下。

  • $$ UpperBound = 2^{\lceil \log_2(\max \limits_{0 \le i<n} \lbrace x_i \rbrace) \rceil} $$

  • $$ LowerBound=\begin{cases} 0 & \min \limits_{0 \le i<n} \lbrace x_i \rbrace >= 0 \\ -2^{\lceil \log_2(-\min \limits_{0 \le i<n} \lbrace x_i \rbrace) \rceil} & \min \limits_{0 \le i<n} \lbrace x_i \rbrace < 0 \end {cases} $$

4.7 指针和自由储存空间

4.7.6 使用 new 来创建动态数组

1
2
int* psome = new int[10];
delete[] psome;

4.10 数组的替代品

4.10.2 模板类 array(C++11)

1
2
#include <array>
std::array<int, 5> arr;

注意:数组长度必须是常量表达式

4.10.3 比较数组、vector 对象和 array 对象

arrayat() 成员函数可以检查越界访问,但显然用 at() 而不是 [] 时速度会减慢。

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×