CPP学习笔记

课程参考:

1. 基础篇

  • 导学-应用领域

    • 桌面应用: Windows桌面应用
    • 系统级软件:操作系统,驱动程序,数据库,网络协议
    • 底层架构:Java虚拟机、python解释器、AI核心库
    • 游戏开发:游戏引擎、服务器端、客户端
    • 嵌入式开发:工业控制、智能家电、航空航天、电子通讯
  • 编译与解释:

    • 编译型:由编译器把整个源代码翻译成机器码,最终生成二进制文件,一次性提交给计算机执行。代表:c, c++

    • 解释型:由解释器将代码逐行解释成机器码,并交给计算机执行。代表:python,JavaScript

    • .cpp ==compile==> .obj ==link==>.exe

  • C++标准

    • 98/03: v1.0 (重点)
    • 11: v2.0 (重点)
    • 14
    • 17
    • 20: v3.0

1.1 基础语法

1.1.1 HelloWorld

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include<iostream>
using namespace std;
// 主函数
int main() {
// std::cout 标准的输出流对象
// << 输出运算符
// std 命名空间
// :: 作用域解析运算符
// cout 控制台输出
// endl 换行符
std::cout << "Hello, World!" << std::endl;

// 使用using namespace std;后可以省略std::
cout << "Hello, World!" << endl;

string name;
cin >> name; // 从标准输入流读取数据到变量name中

// << name << "!" << endl; 链式输出: 中间的<<连接多个输出项, 不能使用 "+", 因为cout不是字符串类型


cout << "Hello, " << name << "!" << endl;

//system("pause"); // 暂停程序运行,等待用户按键. 直接调用系统命令,不建议使用
cin.get(); // 等待用户按键,更加安全和可移植

welcome(); // 调用自定义函数
return 0;
}

static void welcome() {
cout << "Welcome to C++ programming!" << endl;
}

1.1.2 注释

1
2
3
4
// 单行注释
/** 多行注释
* 和Java相同
*/

1.2 数据类型

1.2.1 变量

  • 变量定义
1
2
int a = 0, b;
b = 10;

注意:变量最好初始化,以避免发生未初始化错误

  • 作用域

在C++中,有“作用域(scope)“的概念,就是指程序中的某一段,某一部分,一般使用{}作为分隔。

定义在所有花括号外的名字具有”全局作用域“, 而在某个花括号内是”块作用域“(局部作用域)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<iostream>
using namespace std;

int number = 100; // 全局变量

int getNumber() {
return number;
}

int main() {

cout << "number全局变量number的值为: " << number << endl;

int number = 200; // 局部变量,屏蔽全局变量
cout << "number局部变量number的值为: " << number << endl;

cout << ::number << endl; // 访问全局变量,使用作用域解析运算符
cout << getNumber() << endl; // 访问全局变量,通过函数
}

1.2.2 常量

  • 使用#define

    1
    #define ZERO 0 // 宏定义常量, C语言的特性,在C++中不推荐使用
  • 使用const限定符

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #include<iostream>
    using namespace std;
    #define ZERO 0 // 宏定义常量, C语言的特性,在C++中不推荐使用(因为没有数据类型定义,无法进行类型的安全检查)

    const int MAX_SIZE = 1000; // 全局常量

    int main() {
    const int CON = 100; // 局部常量
    }

1.2.3 基本数据类型

(1) 整数与浮点数

  • short: 16 bit

  • int: 16~32 bit

  • long: 32 bit

  • long long: 64 bit

  • char: 8 bit

    • unsigned char
    • signed char (default)
  • bool: 1 bit

  • float: 32 bit

  • double: 64 bit

  • long double: 64 bit ~ 16 Byte

  • 无符号整型:

    • unsigned int
    • unsigned short
    • unsigned long
    • unsigned long long
  • wchar_t

    • wcout <<

(2) 数值表示

  • 十进制:普通表达 123

  • 八进制:0开头 0123

  • 十六进制:0x开头0x123

  • 默认什么都不加,是int类型

  • l或者L, 表示long类型

  • llLL, 表示long long类型

  • uU, 表示unsigned类型

(3) 字符串

本质是char数组

(4) 赋值时的类型转换

1
2
3
4
5
6
7
bool btrans = 12; // 实际 btrans = 1;
short strans = false; // 实际strans = 0;
float ftrans = true; // 实际ftrans = 1;
int iftrans = 3.22f; // 实际保留整数, iftrans = 3; 浮点数赋值给整数类型,只会保留整数
无符号数溢出会取模
有符号数溢出

1.2.4 运算符

  • 优先级和结合率: 3 - 5 * 2 / (3 % 4)

  • 算术运算符: *, /, %, +, -

  • 关系运算符: <, >, ==, >=, <=, !=

  • 逻辑运算符: &&, ||, &, |, !

  • 条件运算: a == b ? true : false

  • 位运算符

    • 位求反: ~
    • 左移:<<
    • 右移: >>
    • 与:&
    • 或:|
    • 异或:^ 相同为0,相异为1
  • 隐式类型转换

    1
    short s = 15.2 + 3; // 运算时隐式类型转化为double, 赋值时double浮点型隐式转化为整型
  • 强制类型转换

    1
    2
    3
    4
    5
    double d0 = 10 / 3.0; // 隐式类型转换
    double d1 = (double)10 / 3; //c语言风格强转
    double d2 = double(10) / 3; // cpp函数调用风格强转
    double d3 = static_cast<double> (10) / 3; // cpp强制类型转换符,更严格
    cout << "d0 = " << d0 << " d1 = " << d1 << " d2 = " << d2 << " d3 = " << d3 << endl;

1.2.5 复合数据类型

(1) 普通指针

  • 无效指针:

    • int* p没有进行初始化,那么它的内容是不确定的(内存中可能有值,那么解引用时*p可能读到内存中的任意地址,如果读到系统核心区域并进行了修改,可能导致系统异常)
  • 空指针

    • int* p = nullptr:空指针字面量 cpp
    • int* p = NULL 预处理变量(在底层定义的变量(常量)#define NULL 0)
    • int* p = 0 使用0, 0号地址在系统中必定不可分配,而在这里系统就会把其解析为nullptr
  • void*

    • 指向的数据对象可以是任意的数据类型

      1
      2
      3
      4
      int a = 10;
      string n = "sss";
      void* p = &a;
      p = &n;
    • 只能进行地址的存放和比较,不能对它进行数据访问, 例如直接对void*类型的指针进行解引用*p是不被允许的

(2) 指向指针的指针(多级指针)

1
2
3
4
int a = 1;
int* pa = &a;
int** ppa = &pa;
int*** pppa = &ppa

(3) 指向常量的指针

1
2
3
4
const int a = 10; // 常量a, 无法再被修改
const int* p = &a; // 指向常量的指针,解引用*p无法被修改(即无法进行*p = xx的赋值),但是可以将指针指向别处常量
const int b = 11;
p = &b;

(4) 指针常量

1
2
3
4
5
6
int c = 12, d = 13; // 指针常量,只能指向普通变量地址,无法指向常量地址(指针常量中常量的含义是指这个指针的地址是个常量,无法被修改,但是地址所指的内存中存放的数据是可以被修改的。)
int* const p1 = &c;// 指针常量,无法再指向别处(即无法再进行p1 = &b操作), 但是可以将指针所指内容修改,例如
cout << *p1 << endl;
// p1 = &d; 无法进行
*p1 = 14;
cout << *p1 << endl;

(5) 常量指针常量

1
const int* const p = &a; // 指针地址和指针指向的的常量都不能被修改

(6) 指针数组

1
2
int* p = arr; // 普通指针,指向一个数组
int* p_arr[4]; // 指针数组,一个数组,数组中每个元素都是一个int类型指针

(7) 数组指针

1
int(* arr_p)[5]; // 数组指针,一个指针,指向一个int数组,数组包含5个元素

虽然p, arr_p打印出来指向的地址都相同, 但是p的指针移动的步长是一个int类型的长度,而arr_p的步长则是一个长度为5int类型数组的长度。所以两者是不同的,知识他们的首地址相同。如果两者分别进行+1操作,其结果的地址将不同.

1
2
3
4
++p;
++arr_p;
cout << p << endl; //结果:0000007B29CFF59C
cout << arr_p << endl;//结果:0000007B29CFF5A4

1.3 流程控制

  • 顺序
  • 分支
  • 循环
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
using namespace std;

int main() {
int count = 0;
if (count == 0) {
cout << "Count is zero." << endl;
} else {
cout << "Count is not zero." << endl;
}

while (count < 5) {
cout << "Count: " << count << endl;
count++;
}

for (int i = 0; i < 5; i++) {
cout << "For Loop Count: " << i << endl;
}

switch(count) {
case 0:
cout << "Count is zero in switch." << endl;
break;
case 5:
cout << "Count is five in switch." << endl;
break;
default:
cout << "Count is neither zero nor five in switch." << endl;
}
}

return:

主函数中的return 0可以省略

1.4 函数

2. 进阶篇

2.1 对象和类

2.2 动态内存

2.3 标准库

2.4 异常处理

3. 高级篇

3.1 运算符重载

3.2 拷贝控制

3.3 面向对象编程

3.4 泛型编程