三十. C++

140 阅读12分钟

1.基础

1.1 注释

单行  //
多行  /* */

main只能有一个

1.2 变量

  • 变量存在的意义,方便我们管理内存空间

1.3 常量

  • 用于记录程序中不可更改的数据
  • #define abc = 23; 宏常量, 通常在文件的上方定义一个宏常量.
  • const int cc = 45; const 来修饰一个变量, 这个变量不可被修改.

1.4 关键字

  • 关键字是C++中预先保留的单词

1.5 标识符命名规则

  • 不能是关键字
  • 标识符只能是 字母数字下划线, 不以数字开头
  • 区分大小写

1.6 数据类型

(1) 整型

short(短整型):  2字节  -2^152^15-1
int(整型): 4字节  -2^312^31-1
long(整型): Windows 是4字节 Linux 324字节, 64位的是8字节  -2^312^31-1
long long(长长整型): 8字节 -2^632^63-1

sizeof(数据类型 / 变量) 来查看占用的内存空间

(2) 浮点型
单精度: float  4字节  7位有效数字
双精度: double  8字节  15~16位有效数字
默认情况下 编译器会把一个小数当成双精度, 用float去接收他  float a = 3.14 会将3.14转换成单精度
float b = 3.14f   // 默认情况下输出一个小数,最多会显示出6位有效数字

科学计数法: float f2 = 3e2;   float f3 = 3e-2;

(3) 字符型
char  1个字节  存的是对应的ASCII码表值.
不能用双引号, 用单引号
只能放一个字符

(4) 转义字符
\a 报警
\b 退格,将当前位置移动到前一列.
\f 换页,将当前位置移动到下一页开头.
\n 换行,将当前位置移动到下一行开头.
\r 回车,将当前位置移动到本行开头.
\t 水平制表
\v 垂直制表
\\ 表示单斜杠
\` 表示单引号
\" 双引号
\? 表示一个问号
\0 表示数字0
\ddd 8进制转义字符,d范围0~7
\xhh 16进制转义字符, h范围09, af,A~F

(5) 字符串
C风格的字符串   char str1[] = "hello"  这里要用双引号

C++风格的字符串 string str2 = "tom"   这里也是只能用 双引号



(6) 布尔类型 一个字节
true  1  
false 0

(7) 数据的输入 cin

1.7 运算符

  • 算术运算符(正号 负号 加减乘除, % ++ --) 两个小数之间是不可以做取模运算的
  • 赋值运算符
  • 比较运算符
  • 逻辑运算符 || && !

2.程序流程结构

2.1 选择结构

  • if, else if, else
  • 三目
  • switch

2.2 循环结构

  • while
  • do while
  • for

2.3 跳转结构

  • break
  • continue
  • goto语句

3.数组

3.1 定义

数组特点: 放在一块连续的内存空间,数组中每个元素都有相同的数据类型.

int arr[5]   长度为5的数组, 定义数组必须有初始的长度

int arr2[5] = {10, 3, 5, 6}  有初始值, 初始值比数组长度小,用0填补


如果不写初始长度, 默认使用初始化时的元素个数.
int arr3[] = {3,4,5,67}

数组名的用途: 
统计整个数组在内存中的长度: sizeof(arr)
获取数组在内存中的首地址, 直接打印arr即可, 看某个元素的地址 &arr[0]

3.2 多维数组

int arr[2][3]
int arr2[2][3] = { {1,3,5},  {34,5,7} }
int arr3[2][3] = {3,4,6,7,8,9}
int arr4[][3] = {33,45,675,56,5,99}

4. 函数

int add(int num1, int num2) {
    int sum = num1 + num2
    return sum
}

函数的 值传递
函数的 指针传递


int main() {}

int max(int a, int b){   // 如果把这个函数写在main函数之后会报错
    return a>b ? a:b;
}
---------------------------
函数声明可以多次,定义只能有一次, 如果在前边声明了, 在main里再用就不会报错, 即使函数的定义在main之后.
int max(int a, int b);
int mac(int a, int b);

int main() {}

int max(int a, int b){   // 函数定义
    return a>b ? a:b;
}



函数的分文件编写:
    创建.h的头文件, 在头文件中函数声明
    
    创建.cpp的源文件,在源文件中函数的定义
    
    源文件中要引入头文件 #include "test123.h"
    
    引入时,双引号是自定义的头文件.  尖括号是系统头文件

5. 指针

5.1 指针的基本操作

int a = 30;

前言: 每个变量都可以从3个方面来描述它.  类型  值  存放在哪个内存地址
    那么指针变量也是一样, 它有类型 值 和自己存放在哪个地址. 
    所不同的是 指针他的值记录的是另外一个变量的内存地址
    打印a的值: cout << a << endl;
    打印a的地址: cout << &a << endl;
    打印a的类型: cout << typeid(a).name() << endl;

指针的作用: 可以通过指针间接访问内存

(1)
定义指针: 
int a = 10
int * p;
p = &a;   // 让指针的值 等于a的地址  (或者 int * p = &a;)

使用指针: 
前边加* , 可以通过解引用的方式来找到 指针指向的内存里边的内容.
例如:
    a这个变量所对应的空间是 {a的地址0111, a的值10, a的类型是int}
    p这个变量所对应的空间是 {p的地址1000,  p的值是0111 即为a的地址, p的类型是指针,  *p的值是10}
    *p则代表 p用自己的值作为, 另外一个空间的地址,来取另外一个空间的值.  这个过程就是解引用
    
(2) 指针所占用的内存空间是 (32位)4个字节或者8个字节, 指针也是一种数据类型.

(3) 空指针
int * p = NULL 
空指针: 指针变量 指向内存中编号为0的空间
用途: 初始化指针变量
注意: 空指针指向的内存是不可以访问的. 不能查,不能赋值
    0~255号内存是系统站用的,因此不可以访问.

(4) 野指针
指针指向的是非法的内存空间
int * p = (int *) 0x1100;
在我们的程序中,尽量避免这种错误

5.2 修饰指针

常量指针 const修饰指针
指针常量 const修饰常量
const同时修饰
-------------------------------
    int a = 99;
    int * p = &a;
    
    a这个变量所对应的空间是 {a的地址0111, a的值10}
    p这个变量所对应的空间是 {p的地址1000,  p的值是0111 即为a的地址}
    *p则代表 p用自己的值作为, 另外一个空间的地址,来取另外一个空间的值.  这个过程就是解引用.    *p就是指针指向的值.
    
    常量指针 const int * p = &a;  表示a变量对应空间的值不能更改, 即指针指向的值不能更改
    指针常量  int * const p = &a;  表示p的值不能更改, 即指针的指向不能更改.
    都是常量  const int * const p = &a;

5.3 指针和数组

int arr[10] = {1,2,3,4,5,6,7,8,9,10}
int * p = arr
p++   // 让指针向后偏移了4个字节

5.4 指针和函数

函数值传递, 地址传递,
void swap01(int * a, int * b) {
    *a = 3
    *b = 4
}

int main() {
    int a = 10;
    int b = 20;
    swap01(&a, &b)
    
    // 这个打印  ab 值会改变
}

6. 结构体

6.1 基本

  • 结构体属于用户 自定义的数据类型, 允许存储不同的数据类型
定义: 
struct  结构体名  变量
struct  结构体名  变量  = { 成员值1,  成员值2 }

struct Student {
    string name;
    int  age;
}

struct Student s1;
s1.name = "张三"
s1.age = 18

struct Student s2 ={
    "王五", 8
}

struct Student777 {
    string name;
    int age;
}  s3

6.2 结构体数组

struct Student = {
    string name;
    int age;
}

struct Student stuArray[3] = {
    {"张三", 18},
    {"李四", 28},
    {"王五", 28}
}

6.3 结构体指针

6.4 结构体嵌套

6.5 结构体做函数参数

6.6 结构体中const使用场景

7. 内存

7.1 内存的分区模型

代码区: 存放函数体的二进制代码, 由操作系统进行管理
全局区: 存放全局变量和静态变量以及常量
栈区: 由编译器自动分配释放, 存放函数的参数值, 局部变量等.
堆区: 由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收.

(1)程序运行前: 
编译----------> 生成exe -----------> 执行exe程序
在程序编译后,生成exe可执行程序, 未执行该程序前分为两个区域:
    代码区: 
        存放CPU执行的机器指令
        代码区是共享的,共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可
        代码区是只读的,使其只读的原因是防止意外地修改了它的指令.
    全局区:
        此区域存放 全局变量和静态变量,还有字符串常量,全局常量,但是不包括局部常量.
        全局区还包含了常量区,字符串常量和全局常量也存放在此.
        该区域的数据在程序结束之后 由操作系统释放.
        
(2) 程序运行之后
栈区: 由编译器自动释放,存放函数的参数值,局部变量等.
    注意,不要返回局部变量的地址,栈区开辟的数据由编译器自动释放.
    
堆区: 数据由程序员管理开辟和释放.
      数据利用new关键字进行开辟内存.

(3) new操作符
C++中利用new操作符在堆区开辟数据.
堆区开辟的数据,由程序员手动开辟, 开辟用new, 手动释放, 释放利用操作符delete

int * func() {
    int * a = new int(10);
    return a;
}

int main() {
    int * p = func()
}

8. 引用 (给变量起别名)

8.1 基本

数据类型 &别名 = 原名
int a = 10;
int &b = a;
b = 20;
打印a 也是20.

8.2 引用注意事项

  • 引用定义时必须 同时初始化, int &b; 这样是错误的
  • 引用在初始化后,不可以改变.

8.3 引用做函数参数

可以利用引用的技术 让形参修饰实参,  可以简化指针修改实参.

1. 值传递
void mySwap01(int a , int b) {
    int temp = a;
    a = b;
    b = temp;
}

2. 地址传递
void mySwap02(int * a, int * b) {
    int temp = *a;
    *a = *b;
    *b = temp
}

3. 引用传递
int mySwap03(int & a, int & b) {
    int temp = a;
    a = b;
    b = temp;
}

int main() {
    int a = 10;
    int b = 20;
    mySwap01(a,b);
    mySwqp02(&a, &b);
    mySwap03(a, b);
}

8.4 引用做函数的返回值

不要返回局部变量的引用.
int & test01 () {
    int a = 10;   // 局部变量存放在四区中的 栈区.    如果加上static后, 会放在全局区.
    return a;
}

函数的调用可以作为左值.

8.5 引用的本质, 是指针常量

8.6 常量引用

  • 用来修饰形参, 防止误操作
const int & ref = 10;   // 不可以修改

void showValue(const int &val) {
    val = 1000;   // 此行会报错, val是不可以修改的
}

9. 高级函数

9.1 函数的默认参数

  • 默认参数要放在最后边.

9.2 函数占位参数

void func(int a, int){   // 后边这个int  就是占位参数
    cout << a<< endl;
}

9.3 函数重载

  • 同一作用域下
  • 函数名称相同
  • 函数参数类型不同, 或者个数不同,或者顺序不同
  • 引用作用重载的条件, 有const和没有const, a会调用没有const的, 10会调用有const的
void func(int &a) {

}
void func(const int &a) {

}

int a =10;
func(a);
func(10);
  • 函数重载碰到默认参数, 会出现二义性

10. 类和对象

10.1 封装

  • 构造函数
  • 析构函数

10.2 继承

10.3 多态

11. 对文件的操作

  • 程序运行时产生的数据都属于临时数据, 程序一旦运行结束都会被释放.
  • 通过文件可以将数据持久化
  • C++中对文件操作需要包含头文件fstream
  • 操作文件的三大类: ofstream写操作, ifstream读操作, fstream读写操作

11.1 文本文件

  • 文件以文本的ASCII码形式存储在计算机中.
(1) 写文件
包含头文件 #include<fstream>
创建流对象 ofstream aaa;
打开文件   aaa.open('文件路径', 打开方式)
写数据     aaa << "写入的数据"
关闭文件   aaa.close()

(2) 文件的打开方式
ios::in   读文件而打开
ios::out  写文件而打开
ios::ate  初始位置: 文件尾
ios::app  追加方式写文件
ios::trunc  如果文件已经存在了, 先删除在创建 
ios::binary 二进制方式

可以多选用 | 隔开

(3) 读文件
#include <fstream>
ifstream ifs;
ifs.open('文件路径',打开方式)
ifs.is_open() 来判断是否打开了
第一种: 
第二种:
第三种:
第四种:

ifs.close()

11.2 二进制文件

  • 文本以文本的二进制形式存储在计算机中,用户一般不能直接读懂它们
二进制的打开方式:  ios::binary
(1) 写文件: ostream & write(const char * buffer, int len)
参数说明: 字符指针buffer指向内存中一段存储空间. len是读写的字节数


class Person {
    char m_name[64];   // 字符数组
    int m_age;
    
}

void test01() {
    // 包含头文件
    
    // 创建流对象
    ofstream ofs;
    // 打开文件
    ofs.open("person.txt", ios::out || ios::binary)
    
    // 写文件
    Person p = {"张三", 18}
    ofs.write((const char *) &p, sizeof(Person))
    
    
    // 关闭文件
    ofs.close()
}

(2) 读文件
void test02() {
    ifstream ifs;
    ifs.open("person.txt", ios::in || ios::binary)
    ifs.is_open()
    
    
    Person p;
    ifs.read( (char * )&p, sizeof(Person))
    
    ifs.close();
}

12. 模板 ???

13. STL ???

14. string容器

15. vector容器

16. deque容器

17. stack容器

18. queue容器

19. list容器

20. set容器

21. map容器

22. 函数对象

23.常用遍历方法

24. 常用查找算法

25. 常用拷贝和替换算法

26. 常用其他算法