1.C语言
1.数组与指针
数组指针
定义:本质为指针,指向一个数组的地址,数组地址与数组首元素的地址相同。
指针数组
定义:本质为数组,数组内的元素为指针
函数指针
定义:指针内存放的是函数的地址,应用场景:回调函数,多态中的虚表虚函数
2.库函数的模拟实现
1.memcpy
用法:用于两个不相关的数组拷贝,函数结束,返回目标空间的起始地址。其中形参为两个地址:目标起始地址,数据起始地址,以及拷贝的字节数。(可能会存在破坏原字符串)
void * memcpy ( void * destination, const void * source, size_t num )
2.strstr
用法:搜索一个字符串在另一个字符串中的第一次出现。找到则返回第一次匹配的字符串的地址,未找到则返回NULL。
3.memmove
用法:memcpy函数只能用于不相关函数的拷贝,而memmove函数不仅能够适用于不相关函数,也适用相关函数的拷贝。它的形参和返回值与memcpy函数一样。
void * memmove ( void * destination, const void * source, size_t num )
3.结构体
1.内存对齐
结构体内的元素类型各不相同,计算结构体大小时,需要内存对齐,方便计算机去读写数据。
方法:1.首元素存放的地址为结构体变量偏移量为0的地址处
2.其他元素依次存放在结构体变量偏移量为:min{有效对齐值为自身对齐值, 指定对齐值} 的整数倍处。
3.总体对齐时,字节大小是min{所有成员中自身对齐值最大的, 指定对齐值} 的整数倍.
2.联合
用法:在“联合”中,各成员共享一段内存空间, 一个联合变量的长度等于各成员中最长的长度。 这里所谓的共享不是指把多个成员同时装入一个联合变量内, 而是指该联合变量可被赋予任一成员值,但每次只能赋一种值, 赋入新值则冲去旧值。
4.数据存储
1.原反补码
反码:正数的反码是其本身,负数的反码是在其原码的基础上符号位不变,其余各位取反
补码:正数的补码是其本身,负数的补码是在其原码的基础上除了符号位进行取反,并且在最后一位加1
作用:为了能让计算机执行减法:
[a-b]补=a补+(-b)补
2.大小端判断
3.类型提升和截断
5.编译链接
1.宏
2.编译链接的过程
2.C++
1.C++入门
1.函数重载
C++允许在同一作用域中声明几个同名函数,其形参列表(参数个数 或 类型 或 类型顺序)不同。
如何支持:C++通过函数修饰规则进行区分函数,只要参数不同,修饰出来的名字就不相同,从而实现函数重载。
2.引用与指针
引用 | 变量的别名,无独立内存空间 | 定义时要初始化 | 引用被使用后,不能再引用别的实体 | 无多级引用 | 引用不能为空 | sizeof中引用为引用类型大小 |
指针 | 存放变量的地址,有独立空间 | 定义时可不初始化 | 指针可以在随时指向其他同类型实体 | 有多级指针 | 指针可以为空 | sizeof中指针为地址空间所占字节大小 |
引用:变量的别名,无独立内存空间 定义时要初始化 引用被使用后,不能再引用别的实体
指针:存放变量的地址,有独立空间 定义时可为空 指针可以在随时指向其他同类型实体
3.nullptr和null
null的本质是宏定义的“0”,nullptr解决了这个问题
2.类和对象
1.与面向过程的区别
面向对象三大特性:封装,继承,多态。将一件事拆分成不同的对象,靠对象之间的交互完成。
面向过程:关注的四过程,分析出解决问题的步骤,通过函数调用逐步解决问题。
2.类大小计算
遵守内存对齐原则
3.class与struct的区别
struct定义的类默认访问权限是public,class定义的类默认访问权限是private。
4.this指针,默认成员函数
this指针的类型为const,本质是“成员函数”的形参,对象中不储存this指针。
5.运算符重载
6.友元,static成员
3.内存管理
1.内存分布
1.栈:非静态局部变量,函数参数,返回值
2.内存映射段:创建共享内存,进程间通信
3.堆:动态内存分配
4.数据段:全局数据和静态数据
5.代码段:可执行的代码,只读常量。
2.malloc/calloc/realloc
calloc:开辟空间后会初始化为0
realloc:将原空间扩容至指定大小
3.new/delete/free/malloc
new/delete | 是操作符 | 可以初始化,返回值为指定类型 | 调用构造,析构 |
malloc/free | 是函数 | 不能初始化,返回类型为void* | 不调用构造,析构 |
4.内存泄漏
解决方式:
1.多检查,泄漏检测工具
2.使用智能指针
4.模板
1.模板的格式
temple<class T>
void my_fac(T* a)
{}
2.原理,特化
特化:用不同类型的参数使用函数模板,分为隐式实例化和显式实例化
隐式实例化:让编译器根据实参的类型推演出模板参数的类型
显式实例化:在函数名后的<>中指定参数的类型
5.继承
1.什么是继承,继承的意义
作用:使代码可以复用,在原有类(基类)特性的基础上进行扩展,增加功能,产生新的类(派生类),呈现了面向对象程序设计的层次结构,继承是类设计层次设计的复用。
2.赋值切片
派生类可以赋值给基类的对象、指针和引用,即把派生类中父类的那部分切分赋值过去。
重定义(隐藏):子类中的成员与父类中的成员同名,从而使得子类成员屏蔽掉了父类对同名成员的直接访问。
3.多继承
定义:一个子类有多个父类时,这种关系称为多继承。
解决菱形继承的冗余性和二义性:虚拟继承,虚基表指针组成的虚基表。
4.继承与组合
public继承:is-a,每个子类对象都是一个基类对象
组合:has-a,B组合了A,即每个B对象里都有一个A对象。
6.多态
1.静态多态和动态多态
静态多态是指在编译期间就确定了程序的行为,如函数重载。
动态多态是在程序运行期间,根据拿到的类型确定程序的具体行为,调用函数。
2.纯虚函数和抽象类
抽象类:在虚函数后写上=0,则这个函数为纯虚函数,包含纯虚函数的类叫做抽象类,抽象类不能实例化对象。
作用:只有重写纯虚函数,子类才能实例化对象。其保证了子类必须重写,纯虚函数更体现了多态的特点:接口继承。
3.重载,重写,重定义
重载:在同一作用域内,函数名相同,形参列表(参数个数 / 类型 / 类型顺序)不同。
重写:子类继承父类,函数名/参数/返回值都必须相同(协变例外)。
重定义:子类继承父类,函数名相同,只要不是重写就是重定义。
4.多态原理
前提:1.虚函数重写。2.使用基类的指针或引用调用虚函数(会用到继承中的赋值切片)。
原理:虚表,虚指针
形参所属类不同,其虚表不同,虚函数指针不同,从而找到对应的虚函数,实现对应的功能。
7.C11
1.范围for
2.lamda表达式
捕捉列表+参数列表(可省略)+mutable(可省略)+返回值类型(可省略)+函数体
3.右值引用
右值如:字面常量,表达式返回值,函数返回值,右值不能取地址。
应用场景:当函数返回对象是局部变量时,只能传值返回,会导致最少一次拷贝构造。此时用右值引用,即会调用移动构造,节省资源。
8.智能指针
1.RALL
利用对象生命周期来控制程序资源的一种简单技术。
好处:不需要显式释放资源
保证对象所需的资源在其生命期内始终有效
2.auto_ptr/uniqur_ptr/shared_ptr/weak_ptr
auto_ptr:管理权转移
uniqur_ptr:简单粗暴的防拷贝
shared_ptr:通过引用计数实现多个shared_ptr对象之间共享资源
3.STL
1.容器
1.序列式容器
string, vector, list, deque
2.关联式容器
map, set, unordered_map, unordered_set, bit_set
2.迭代器
3.适配器
1.常见的容器适配器
stack, queue, prioirty_queue
4.仿函数
1.定义
使类具有函数的功能,多用于比较
5.算法
1.常见的算法
find,reverse,sort,swap,lower_bound/upper_bound ,next_permutation
6.空间配置器
简易版的内存池