正文从这里开始。
入门
C++代码的基础结构
- 预处理指令
- main主函数
- 返回值语句
单工程多main函数
Clion是以工程管理代码,一个工程指一个代码。
- 由于main函数是程序入口,所以每个工程进允许1个main函数
cout 语句
帮助将内容打印(输出)到控制台(屏幕)上的代码语句
[!NOTE] 基本用法 cout << “字符串” <<…<<…<< endl;
代码注释
单行注释
以“//”开头,右侧为注释内容
多行注释
以“/ * ”开头,“* /”结束,内容可以换行
第一章 数据类型、运算符与表达式
常量、变量与标识符
常量
常量指在程序执行过程中值不变的量
字面常量
被写到代码内的常量
- 数值型
- 整型
- 实型
- 字符型
- 字符串
标识符
是对代码的实体 进行标识的符号,即各类实体的名字
- 变量
- 结构体
- 函数
- 类
符号常量
用标识符去定义的常量
[!NOTE] 语法 #define 标识符 常量 宏命令 建议大写 常量值
注意:
- 定义在代码的头部
- 符号常量名是标识符
- 字母建议全大写(和后续变量区分)
变量
变量的基础使用
变量的声明
==语法:变量类型 变量名;==
- int num;
[!NOTE] 变量快速定义 int a=10,b=20,c=30;
| int | 整型 |
|---|---|
| float | 实型 |
| char | 字符型 |
| string | 字符串 |
变量的赋值
==语法:变量名=变量值;==
变量的特征
变量存储的数据,是可以改变的
- 通过赋值语句
标识符命名
见名知意 下划线命名 一般用于变量 小驼峰法 一般用于变量、函数命名 大驼峰法 一般用于类命名
数据类型:整型
| 数据类型 | 占用空间 |
|---|---|
| short | 2 |
| int | 4 |
| long | 4、8 |
| long long | 8 |
无符号和有符号数字
在C++中,数字分为无符号和有符号数字
- 无符号:仅仅允许正数存在
- 有符号:可以允许负数存在 ==unsigend int== 无符号整型 4字节
控制结构
if逻辑判断语句
if else语句
else if语句
while循环语句
do while语句
for循环语句
循环的嵌套
变量的作用域
- {}称为代码块
- 全局变量和局部变量
转向语句
- continue语句
- break语句
- goto语句
- 无条件跳转 打标签: 跳转至标签处
- 不用
数组、指针、引用与结构体
数组
一维数组的声明
1、数据类型 数组名【数组长度】 2、数据类型 数组名【数组长度】={值1、值2…} 3、数据类型 数组名【】={值1、值2…}
- 数组下标从0开始索引
- 数组内数据类型一致,分配的内存连续
- 注意命名规范
- 没有初始值,自动补0
数组特点
任意类型均可构建数组
- 基本数据类型
- 复合数据类型
- 指针
- 枚举
固定大小(无边界检查)
即一旦建立,就固定大小 且C++不会数组边界检查
- 即索引超出范围,不会报错,但运行时会出现未知错误
内存连续且有序
sizeof(数组)/sizeof(数组某元素)=数组元素个数
元素可修改
不可修改类型
数组变量不记录数据
只是记录元素的*内存地址**
数组的遍历
即依次取出元素 1、while循环 2、for循环 3、高级for循环
字符数组
char s【】=“hello”;
- 比正常的数组多了个空字符,作为结束语句
- 即有6个元素
- 汉语文字适用于string类型,此方法只适用于char类型
多维数组
数组内的元素也是数组
- 用,分隔元素
二维数组
int v【3】【3】 三个元素,且三个元素都是包含三个元素的数组
- 调用 v【0】【1】=12
二维数组的遍历
用for循环
指针
声明
[!NOTE] int num = 10;
int * p; // 声明 p =& num; // 赋值 cout << * p // 取值
- 指针指的是内存地址
- p是指针变量,存放地址
- & 取内存地址
-
- 声明时,指针变量。使用时:取指针指向位置的数值
野指针和空指针
指针声明时立刻分配内存,但分配的内存不一定是干净的。 普通变量影响不大,但指针可能有安全问题
- 空指针:将指针赋值为“空”:NULL或者nullptr 空指针也不是正常的指针,只是过渡。
指针运算
- 指针可以进行加减运算,即+、-、++ 每次加减n,是对内存地址进行==n * 类型大小==的加减
- 数组对象本身记录的时内存地址(第一个元素地址),可以通过指针运算,完成使用指针存取数组元素
动态内存分配(堆区)
传统方式创建普通变量和数组,其内存空间由C++自动管理,称为:静态内存管理 动态内存管理:程序员手动管理内存
- new运算符申请空间,==提供该空间的指针==
- new int
- new double
- delete运算符,仅用于new申请的空间
- delete p
- 建议写完new ,立刻写delete
- 析构代码,将堆区开辟的数据释放
[!NOTE] 指针变量也可以像数组变量那样赋值/取值!
数组元素的移除
本质上是复制需要的元素到新的数组
数组元素的插入
创建新数组,将老数组元素和新数组元素一起赋值到新数组中
- 注意:新元素在指定位置插入(老数组元素要配合做下标增加)
指针悬挂
指针指向区域已经被回收(delete) 解决:
- 不要轻易进行指针间的互相赋值
- delete回收前,要确保此空间不再使用
常量指针(const)
指向const的指针
语法:将const写在* 之==前== 表示指向区域的==数据,是不变的,但可以更改指向==
- 内存中的数据不可变
- 指针的指向可变
const指针
语法:将const写在* 之==后==
[!NOTE] 数据类型 * const 指针 = 地址; 必须初始化地址,因为指针不可修改了
- 指针指向不可变
- 内存数据可变
指向const的const指针
==const 类型 * const 指针 = 地址;==
结构体
结构体是用户==自己定义==复合数据类型,可以包含==不同类型的不同成员==
[!NOTE] 相当于(自定义)数据类型
结构体基本语法
[!NOTE] 声明结构体 struct 结构体类型 { 成员1类型 成员1名称; … 成员N类型 成员N名称; };
[!NOTE] 创建变量 struct 结构体类型 变量(名); 变量(名) = {值1,值2,… };
[!NOTE] 访问成员 变量(名).成员名
点“.”表示访问成员
结构体成员默认值
在声明时,可以带上默认值
若进行赋值,则默认值不生效
结构体数组

结构体指针

结构体指针数组
函数
函数的作用
将一段代码封装
函数的定义与声明
语法:
[!NOTE] 返回值类型 函数名 (参数列表) { 函数体语句 return返回值 }
- 若无需返回值,则返回值类型为void
函数的声明
==函数类型 函数名(形参)==
函数的调用
[!NOTE] 语法:函数名(参数)
- 定义函数时,是形参
- 调用时,是实参。实参的值传递给形参。
- 值传递,此时,==若形参变化,并不会影响实参==。
参数的值传递与地址传递
值传递
用普通变量作形参,本质上是赋值给形参
地址(指针)传递
使用指针变量作形参,本质是将内存地址传递给函数,用指针完成函数体逻辑
函数的常见样式
1、无参无返 2、有参无返 3、无参有反 4、有参有返
- 有返回值要进行接受
函数的嵌套调用
函数作为一个独立的代码单元,可以在函数内调用其他函数,且无限制!
函数的分文件编写
作用:让代码结构更清晰 步骤:
- 创建.h的头文件
- 创建.cpp源文件
- 在头文件中写函数的声明
- 在源文件中写函数的定义
函数传入数组
数组传参时,会退化为指针!!!
[!NOTE] 创建(三者完全一致) void func(int arr[]) void func(int arr【10】) void func(int * arr)
- arr均被看作指针(地址传递)
- 函数体内,sizeof无法统计数组大小,得到是8字节(指针本身大小)
- 函数接受数组传入,建议附带数组长度(否则难以统计)
- ==void func(int arr[], int legth) ==
引用
对已存在的变量起别名。
[!NOTE] 与指针的区别 指针可以改指向 别名不可以!
语法:==int &b = a==
- 引用对象不可改
- 创建时必须初始化(赋值)
- 引用不可为空(null)
引用传参
像普通变量那样操作,但对==实参本身可以产生影响。==
- 值传递
- 地址传递
- 引用传递
引用的本质
是创建了一个==指针常量== 复杂的(指针)操作由编译器自动完成
函数返回指针及局部变量作用域的问题
[!NOTE] 语法 返回值类型 * 函数名(形参) { 函数; return 指针; }
局部变量,会被自动清理内存
- 需要使用动态内存管理(new和delete)
- 也可以用static语句
static 关键字
表示静态,将内容存入静态内存区域,可以修饰变量和函数 即霸占内存,持续存在,直至程序结束
- tsatic 数值类型 变量
- 修饰局部变量,可以延长生命周期到整个程序运行周期
函数返回数组
可以使用static。但==不推荐==(占内存) 推荐在函数外创建好数组,传入函数 (地址传递/引用传递)操作即可。
函数高级
函数占位参数
声明函数时,形参列表中用数据类型来占位 语法:==返回值类型 函数名 (数据类型){}==
- 必须传值
- 可以有默认参数
函数重载
可以让函数名系统,提高复用性
条件:
1、同一作用域下 2、函数名称相同 3、函数参数类型不同、或者个数不同、或者顺序不同 调用时,根据传入的参数自动调用。
- 函数的返回值不可以作为函数重载的条件
注意事项
引用作为重载条件
函数重载碰到默认参数
不屑默认参数,避免二义性
内存分区
程序运行前
在程序编译后,生成exe程序,未执行该程序前分为两个区域:
代码区
存放函数体的二进制代码
- 由操作系统进行管理
- 共享
- 只读
全局区
存放全局变量和常量,字符串常量
- 该区域的数据在程序结束后由操作系统释放
程序运行后
栈区
存放函数的(形)参数值,局部变量
[!NOTE] 不要返回局部变量的地址
- 栈区的数据由编译器管理开辟和释放
堆区
由程序员分配释放,程序结束时,操作系统自动回收。 ==主要在函数中使用,并返回指针==
- 在C++中主要利用new在堆区开辟内存
- 用delete手动释放
创建数组
类和对象
[!NOTE] C++面向对象的三大特性:==封装、继承、多态 == C++认为:万事万物皆为对象 对象上有其属性行为
封装
封装的意义
C++面向对象的三大特性之一
将属性和行为作为一个整体,表现生活中的事物
[!NOTE] 语法 class 类名 { 访问权限: 属性(数据成员的说明) 访问权限: 行为(成员函数的说明) }; 类的实现 即实例化(通过一个类 创建一个对象的过程)
==用“.”访问类中的属性==
- 如:类名.属性1=值; ==也用行为给属性赋值==
[!NOTE] 类中的属性和行为,称为成员 属性也称:成员属性 成员变量 行为也称:成员函数 成员方法
将属性和行为加以权限控制
- 公共权限public
- 类内/外都可访问
- 保护权限
- 类内可以访问 类外不可
- 私有权限
- 类内可以访问 类外不可
[!NOTE] 详见继承 父子关系
struct和class区别
在C++中,唯一区别:
- class默认权限是 private
- struct默认权限是 public
成员属性设为私有
优点:
- 将所有成员属性设为私有,可以自己控制读写权限
- 对于写权限,我们可以检测数据的有效性 方法: 提供对外的==公共接口== (创建函数)
- 接收数据
- 提供数据
对象特性
对象的初始化和清理
构造函数和析构函数
这两个函数编译器自动调用,完成对象的初始化和清理
- 若我们不提供构造和析构函数,编译器会自动提供,但是空实现
- 只调用一次
构造函数
创建对象时,为对象的成员赋值,即初始化。
- 自动调用 语法:==类名 () {}==
析构函数
对象销毁前系统自动调用,清理工作 语法:==~类名 () {}==
构造函数的分类和调用
分类
有参/无参构造函数
普通/拷贝构造函数
调用
- 括号法
- 显示法
- 隐式转换法
拷贝构造函数调用时机
1、使用一个已经创建完毕的对象来初始化一个新对象 2、值传递的方式给函数参数传值 3、值方式返回局部对象
构造函数调用规则
默认下,c++编译器至少会给类添加3个函数
- 默认构造函数(无参,函数体为空)
- 默认析构函数(无参,函数体为空)
- 默认拷贝构造函数,对属性进行值拷贝
规则
- 如果用户定义有参构造函数,c++不在提供默认无参构造,但会提供默认拷贝函数
- 如果用户定义有参拷贝函数,c++不在提供其它普通构造函数
深拷贝与浅拷贝
初始化列表
用来初始化属性 语法:==构造函数(): 属性1(值1), … {}==
类对象作为类成员
c++类中的成员可以是另一个类的对象,成该成员为:对象成员
- 此时,构造时,先构造其他类对象,再构造自身。
- 析构的顺序相反
静态成员
在成员前加==static==
静态成员变量
- 所有对象共享一份数据
- 在编译阶段分配内存
- ==类内声明,类外初始化==
[!NOTE] 域运算符“::” 在大型项目中,通常将类的接口(保存为头文件)和类的实现分离。
==返回类型 类名::函数名(形参表) { 函数体 }== 静态成员变量,不属于某个对象上,所有对象都共享同一份数据
- 通过类名 访问
- 通过对象 访问
[!NOTE] 静态成员变量也有访问权限
静态成员函数
- 所有对象共享一个函数
- 静态成员函数只能访问静态成员变量