内存地址
程序运行时,代码和需要的数据都被存储在内存中
内存是有序的字节序列,每个字节都有唯一的地址,使用该地址可以确定字节的位置,用以存储和获取数据
直接访问和间接访问
通过变量的名字直接访问为程序中定义的变量分配的内存单元,存取变量的值
使用变量的内存地址找到存放数据的单元,间接访问其中的内容
指针
指针的特点:
- 指针持有一个对象的地址,称为指针“指向”该对象
- 通过指针可以间接操纵它指向的对象
定义指针变量的语法
每个指针都有相关的类型,要在定义指针时指出
类型 *指针变量;
指针存放指定类型对象的地址,要获取对象的地址,使用取地址运算符“&”
如果指针指向一个对象,则可以通过指针间接访该对象,使用指针解引用运算符“*”
指向一个对象的指针有两个存储单元与之相关:
- 一个是指针自己的存储单元,里面存放着所指对象的地址;
- 另一个就是指针指向的对象的存储单元,里面存放该对象的值。
可以定义存放指针对象的地址的指针
**空指针:**指针值为0时是一个空指针,不指向任何对象地指针 (0,NULL)
//生成空指针的方式
int *p1 = 0;
int *p2 = NULL;
//不能写成下面的样子:
int zero = 0;
int *p4 = zero;
指针运算:
同类型的指针可以进行相等(==)或不相等(!=)的比较操作,比较的结果是布尔类型
可以进行加或整数值的算术运算
自增、自减运算适用于指向数组元素的指针
void*指针:
可以持有任何类型的地址值,即通用指针
相关的值是个地址,但是该地址保存的对象类型不知道
不能操纵void指针指向的对象,只能传送该地址值或者和其他地址值进行比较
不允许void指针到其他类型指针的直接赋值
存储空间分配策略
静态(编译时)分配空间
编译器在处理程序源代码时分配内存;
效率高,灵活性差,运行前就要知道程序需要的内存大小和类型
动态(运行时)分配空间
程序运行时调用运行时刻库函数来分配内存;
占用程序运行时间,更灵活
静态和动态内存分配在语法上的主要区别:
静态对象是有名字的变量,可以直接对其进行操作;动态对象没有名字,要通过指针间接地对它进行操作。
静态对象的空间分配与释放由编译器自动处理,动态对象的空间分配与释放必须由程序员显式地管理。
堆(heap)、自由存储区、动态存储区:
系统为所有程序提供了一个运行时可用的内存池,这个内存池被称为程序的自由存储区或堆
动态内存管理方法:
C++通过new和delete运算符进行动态存储空间的管理
new运算符
在堆上动态分配空间,创建对象,并返回对象的地址
一般将new返回的地址保存在指针变量中,以便间接访问堆上的对象。
new表达式的三种形式:
分配单个对象:new 类型 或者 new 类型(初始值)
分配多个连续存储的对象:new 类型[数组大小]
定位new,在指定位置分配空间:new (指针) 类型;
delete运算符:
new运算符分配的空间用delete运算符释放
释放new分配的单个对象的delete形式
delete 指针;
释放new分配的数组的delete形式
delete[] 指针;
定位new没有对应的delete表达式
空悬指针
执行delete运算后,指针ip指向的空间被释放,不能再使用ip指向的内存,但是ip这个指针变量自己的存储空间不受影响
delete后的ip不是空指针,而是“空悬指针”,即指向不确定的单元
delete之后,继续通过ip间接使用这个单元是非法的,会引起不可预料的运行错误
引用
引用又称为别名,它可以作为对象的另一个名字;
通过引用可以间接地操纵对象;
在程序中,引用主要用作函数的参数。
引用有类型标识符和一个说明符(&)来定义
type& refVariable = leftValue;
引用必须被初始化,初始值是一个有内存地址的对象
引用一旦初始化,就不能再指向其他的对象,对引用的所有操作都会被应用在它所指向的对象上
引用的初始化和赋值不同
- 初始化时引用被“绑定到”一个对象;
- 赋值时,引用被作为所绑定对象的别名
const限定指针
指向const对象的指针(非const )
const type *cp; 或者type const *cp;
cp是指向常量的指针,它所指向的内存中的内容不可以改变,即*cp的值不能改变
指向非const对象的const指针
type* const cp = initAddressValue;
cp是常量指针,初始化后值不能改变,指向固定的单元
const限定引用
const引用仅对引用自己可参与的操作进行了限定,对所指向的对象本身是不是常量未作限定。因为指向的对象也可能不是const,所以允许通过其他途径改变它的值
const限定的左值引用不可修改
const引用可以绑定到const对象
不能用非const引用指向const对象
数组与指针
使用数组时一般会转换为指针
int ia[5];
ia是一个int*类型的指针常量
ia和&ia[0]都表示数组第一个元素的地址
可以使用指针对数组进行访问
一维数组元素在内存中按下标顺序依次存放
一维数组a[n]的元素a[i]在内存中地址是a+i。
多维数组在内存中按行序存储
二维数组a[m][n]的元素a[i][j] 在内存中的地址是a+(i*n+j)
使用指针访问数组时需要控制指针的范围,确保指针指向数组的元素
库函数begin()和end()
让指针在数组上的使用更简单更安全
在头文件中定义
用法:
begin(数组名):返回指向数组第一个元素的指针
**end(数组名):**返回指向数组最后一个元素的下一个位置的指针
//在数组arr 中查找第一个负数:
int *pb = begin(arr), *pe = end(arr);
while(pb != pe && *pb >= 0)
++pb;
//逐个输出数组元素的循环
for(int p = begin(arr); p!= end(arr); ++p)
cout << *p << "\t";