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

之前搞足迹地图把这个咕咕了,但突然觉得还是这个正事要紧…那就开始继续吧233

本篇内容包括:

  • 循环和关系表达式
  • 分支语句和逻辑运算符
  • 基本文件输入/输出
  • 函数基本知识
  • 指针

第5章 循环和关系表达式

5.4 基于范围的 for 循环(C++11)

对数组(或容器类,如vector和array)的每个元素执行循环:

1
2
3
4
5
6
double prices[]{4.99, 10.99, 6.87, 7.99, 8.49};
for (double &x : prices)
x *= 2;

for (int x : {1, 1, 2, 3, 5})
std::cout << x << std::endl;

5.5 循环和文本输入

5.5.4 文件尾条件

  • 检测到EOF后,cin 将两位(eofbitfailbit)都设置为1。可以通过成员函数 eof() 来查看 eofbit 是否被设置;如果检测到EOF,则 cin.eof() 将返回 bool 值 true,否则返回 false。同样,如果 eofbitfailbit 被设置为 1,则 fail() 成员函数返回 true,否则返回 false。

  • cin.clear() 方法可以:

    Sets the stream error state flags by assigning them the value of state. By default, assigns std::ios_base::goodbit which has the effect of clearing all error state flags.

  • istream 类提供了一个可以将 istream 对象(如 cin)转换为 bool 值的函数。cincin.fail()!cin.eof() 更通用,因为它可以检测到其他失败原因,如磁盘故障。

第6章 分支语句和逻辑运算符

6.2 逻辑表达式

6.2.5 逻辑运算符细节

逻辑AND运算符的优先级高于逻辑OR运算符。因此,表达式:

1
age > 50 || weight > 300 && donation > 1000

会被解释为

1
age > 50 || (weight > 300 && donation > 1000)

6.2.6 其他表示方式

并不是所有的键盘都提供了用作逻辑运算符的符号,因此C++标准提供了另一种表示方式,标识符 andornot 都是 C++ 保留字(AndAND 之类不是)。另外,它们并不是C语言中的保留字,但 C 语言程序可以将它们用作运算符,只要在程序中包含了头文件 iso646.h

6.5 switch 语句

如果所有的选项都可以使用整数常量来标识,则可以使用 switch 语句或 if else 语句。由于 switch 语句是专门为这种情况设计的,因此,如果选项超过两个,则就代码长度和执行速度而言,switch 语句的效率更高。

6.8 简单文件输入/输出

6.8.2 写入到文本文件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <fstream>

int main() {
int test;

std::ifstream input;
input.open("test.txt");
if (!input.is_open())
return 998244353;
input >> test;
input.close();

std::ofstream output;
output.open("test.txt");
if (!output.is_open())
return 998244353;
output << (test ^ 19260817) << std::endl;
output.close();

return 0;
}

第7章 函数—— C++ 的编程模块

7.1 复习函数的基本知识

7.1.1 定义函数

C++ 对于返回值的类型有一定的限制:不能是数组,但可以是其他任何类型——整数、浮点数、指针,甚至可以是结构和对象。(不过,虽然 C++ 函数不能直接返回数组,但可以将数组作为结构或对象组成部分来返回。)

7.1.2 函数原型和函数调用

  • 函数原型:prototype。

  • 函数原型不要求提供变量名,有类型列表就足够了。原型中的变量名相当于占位符,因此不必与函数定义中的变量名相同。

  • 在 C++ 中,不指定参数列表时应使用省略号。通常,仅当与接受可变参数的 C 函数(如printf())交互时才需要这样做。

7.3 函数和数组

7.3.1 函数如何使用指针来处理数组

在大多数情况下,C++ 和 C 语言一样,也将数组名视为指针。第4章介绍过,C++ 将数组名解释为其第一个元素的地址,但该规则有一些例外:

  • 数组声明使用数组名来标记存储位置
  • 对数组名使用 sizeof 将得到整个数组的长度(以字节为单位)
  • 将地址运算符&用于数组名时,将返回整个数组的地址,例如 &cookies 将返回一个32字节内存块的地址(如果 int 长4字节)。

7.3.5 指针和 const

  • C++ 禁止将 const 的地址赋给非 const 指针。如果读者非要这样做,可以使用强制类型转换来突破这种限制,详情请参阅第15章中对运算符 const_cast 的讨论。禁止将常量数组的地址赋给非常量指针将意味着不能将数组名作为参数传递给使用非常量形参的函数。

    1
    2
    3
    int sum(int arr[], int n);
    const int age[] = {1, 2, 3};
    sum(age, sizeof(age) / sizeof(age[0])); // invalid
  • 仅当只有一层间接关系(如指针指向基本数据类型)时,才可以将非 const 地址或指针赋给 const 指针:

    1
    2
    3
    4
    5
    6
    const int **pp2;
    int *p1;
    const int n = 13;
    pp2 = &p1; // not allowed, but suppose it were
    *pp2 = &n; // valid, both const, but sets p1 to point at n
    *p1 = 10; // valid, but changes const n
  • https://www.geeksforgeeks.org/difference-between-const-int-const-int-const-and-int-const/

7.4 函数和二维数组

int (*ar2)[4] 等价于 int ar2[][4]

7.9 递归

与C语言不同的是,C++不允许 main() 调用自己。

7.10 函数指针

与数据项相似,函数也有地址。函数的地址是存储其机器语言代码的内存的开始地址。

7.10.1 函数指针的基础知识

1
2
3
4
double pam(int);
double (*pf)(int) = pam;
double x = (*pf)(4); // call pam() using the pointer pf
double y = pf(4); // also call pam() using the pointer pf

真是非常棒的语法!为何 pf(*pf) 等价呢?一种学派认为,由于 pf 是函数指针,而 *pf 是函数,因此应将 (*pf)() 用作函数调用。另一种学派认为,由于函数名是指向该函数的指针,指向函数的指针的行为应与函数名相似,因此应将 pf() 用作函数调用使用。C++ 进行了折衷——这2种方式都是正确的,或者至少是允许的,虽然它们在逻辑上是互相冲突的。

7.10.3 深入探讨函数指针

函数指针数组:

1
const double *(*pa[3])(const double *, int) = {f1, f2, f3};

这里不能使用 auto,因为自动类型推断只能用于单值初始化,而不能用于初始化列表。

7.10.4 使用 typedef 进行简化

1
2
typedef const double *(*p_fun)(const double *, int);
p_fun pa[] = {f1, f2, f3};

(把 typedef 当成声明一个变量/函数即可)

Comments

Your browser is out-of-date!

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

×