指针和动态内存分配
一,内存空间的访问方式:
- 通过变量名访问
- 通过地址访问
- 指针的概念(地址类型的变量)
- 指针:内存地址,用于间接访问内存地址
- 指针变量:用于存放地址的变量
语法: int i; int *ptr = &i; &是取地址符 *表示所定义的变量是指针
Int* 表示这个指针所指向的对象是int类型
*ptr = 3; 这是一个指针运算,寻址的过程,以ptr内容为地址,去寻找地址所指向的目的地。 等价于 i = 3;
3.与地址相关的运算
指针运算符:* 指针类型变量内容的寻址运算 知道地址求内容
地址运算符:& 知道内容求地址
- 指针的初始化
- 语法形式 : 存储类型 数据类型 *指针名 = 初始地址 ;
- 例: static int *pa = &a;
- 注意事项:
用变量地址做为初值时,该变量必须已经在指针初始化之前就声明过,且变量类型应与指针类型一致。可以用一个已有合法值的指针去初始化另一个指针变量。不要用一个内部非静态变量去初始化static指针。
整数0可以赋给指针,表示空指针。
指向常量的指针 : const int *p = &a; 只能通过指针去访问常量,不能改变常量
指针类型的常量: int * const p = &a; 可以改变指针指向的变量的值,不能改变指针的值
- 指针类型的算术运算
- 指针p加上或减去n:其意义是指针当前指向位置的前方或后方第n个数据的起始位置
- 指针的++、--运算:意义是指向下一个或前一个完整数据的起始
- 当指针指向连续存储的同类型数据时,指针与整数的加减运算和自增自减运算才有意义
- 定义指向数组元素的指针
- 定义与赋值
例: int a[10] , *pa; pa = &a[0]; 或 pa = a;
2,等效的形式
*pa就是 a[0], *(pa + 1) = a[1]......
a数组的名字就是数组的首位地址
所以,a[i] = pa[i] = *(pa + i) = *(a+i)
- 指针数组
- 指针数组:数组元素是指针类型
- 例:Point *pa[2]; 由pa[0]和pa[1]组成
- 数组的名字就是数组第一个元素的地址
- 以指针作为函数参数
为什么需要指针做参数:
需要数据双向传递的时候(引用也可以达到此效果)
需要传递一组数据,只传首地址运行效率比较高
- 指针类型的函数
- 定义:若函数的返回值是指针,则该函数是指针类型的函数
- 语法形式: 存储类型 数据类型 *函数名() { //函数体 };
- 不要将非静态的局部地址作为函数的返回值,i在子函数中定义局部变量后将其地址返回给主函数,就是非法地址。返回的指针要确保在主调函数中是有效的合法的地址。
- 指向函数的指针
- 定义:函数指针指向的是程序代码存储区
- 语法形式: 存储类型 数据类型 (*函数指针名)() { //函数体 };
- 函数指针的典型用途——实现函数回调
通过函数指针调用的函数:例如将函数的指针作为参数传递给函数,使得在处理相似事件的时候可以灵活的使用不同德方法
调用者不关心谁是被调用者:只需知道存在一个具有特定原型和限制条件的被调用函数
- 对象指针
- 通过对象指针访问对象成员: 对象指针名 -> 成员名
Ptr -> getX() 相当于 (*ptr).getX();
2. this指针
隐含于类的每一个非静态成员函数中
指出成员函数所操作的对象:当通过一个对象调用成员函数时,系统先将该函数的地址赋给this指针,然后调用成员函数,成员函数对对象的数据进行操作时,就隐含的使用了this指针。
- 动态内存分配(不知道程序运行时要处理的数据规模有多大,就用动态内存分配)
- 动态申请内存操作符new
New 类型名T (初始化参数列表)
功能:在程序执行期间,申请用于存放T类型对象的内存空间,并以初值列表赋初值
结果值:成功:T类型的指针,指向新分配的内存。失败:抛出异常
2.释放内存操作符delete
Delete 指针p
功能:释放指针p所指向的内存,p必须是new操作的返回值
- 申请和释放动态数组
- 分配:new 类型名T【数组长度】
数组长度可以是任何整数类型表达式,在运行时计算。
2.释放:delete【】 数组名p
释放指针p所指向的数组,p必须是用new分配得到的数组首地址
3.将动态数组封装成类
在构造函数中申请动态内存,在析构函数中释放所申请的动态内存
- vector对象
- 为什么需要vector:封装任何类型的动态数组,自动创建和删除。数组下标越界检查
- 定义: vector <元素类型> 数组对象名(数组长度)
Vector <int> arr(5); 建立大小为5的int类型数组
3.对数组元素的引用:
对象名【下标表达式】 vector数组对象名不表示数组首地址
4.获得数组长度
Vector对象名.size();
- 浅层复制与深层复制
- 浅层复制:实现对象间数据元素的一一对应复制(复制构造函数)
- 深层复制:当被复制的对象数据成员是指针类型时,不是复制该成员本身,而是将指针所指对象进行复制。
- 移动构造
之前,如果要将源对象的状态转移到目标对象只能通过复制,在某些情况下,我们没有必要复制,只需要移动他们。
- 从键盘写入字符串
String类型
Getline( cin, 将字符串存入的变量名,以什么符号作为结束)