内存地址:
程序运行时,代码和需要的数据都被存储在内存中。内存是有序的字节序列,每个字节都有唯一的地址,使用该地址可以确定字节的位置,用以存储和获取数据。
直接访问和间接访问:
通过变量的名字直接访问为程序中定义的变量分配的内存单元,存取变量的值。
使用变量的内存地址找到存放数据的单元,间接访问其中的内容。
指针
特点:指针持有一个对象的地址,称为指针“指向”该对象。通过指针可以间接操纵它指向的对象。
定义语法:
- 类型 *指针变量;
取地址运算符“&”:
指针存放指定类型对象的地址,要获取对象的地址,使用取地址运算符“&”。
如:
int ival = 120;
int *pi = &ival; // pi存放int变量ival的地址
指针解引用运算符“*”:
如果指针指向一个对象,则可以通过指针间接访该对象,使用指针解引用运算符“*”。
如:
int x = 100, y = 20;
int *pi = &x;
*pi = y; // 间接操作pi指向的x,即x = y
指向一个对象的指针有两个存储单元与之相关:
指针变量:32位无符号整数,系统分配4个字节
- 一个是指针自己的存储单元,里面存放着所指对象的地址;
- 另一个就是指针指向的对象的存储单元,里面存放该对象的值。
可以定义存放指针对象的地址的指针:
int ival = 1024;
int *pi = &ival;
int **ppi = π //ppi是指向指针的指针,存放pi的地址
#include <iostream>
using namespace std;
int main( )
{
int ival=1024;
int *pi=&ival;
cout << " sizeof(pi):" << sizeof(pi) << endl; //指针在内存中所占大小
cout << " sizeof(ival):" << sizeof(ival) << endl; //ival在内存中所占大小
cout << " &pi:" << &pi << endl; //指针在内存中的地址
cout << " pi:" << pi << endl; //指针中存放的内容,即ival的地址
cout << " &ival:" << &ival << endl; //ival的地址
cout << " *pi:" << *pi << endl; //指针所指内存中存放的内容,即ival的值
cout << " ival:" << ival << endl; //ival的值
rerurn 0;
}
指针的类型:
- 指针的类型即指针指向的类型
- 每个指针都有相关的类型,需要在定义指针时指出
- 指针的类型指出了如何解释该内存地址保存的内容,以及该内存区域应该有多大
- 不同类型指针的表示方法和保存的地址值并没有分别,区别只是指针指向的对象类型不同
字符型 1个字节
doubloe 8个字节
指针的值:
指针不能保存非地址值,也不能被赋值或初始化为不同类型的地址值 不产生二义性
空指针:
指针值为0时是一个空指针,即不指向任何对象的指针
表示空指针的2种方法:
- 0
- 预处理常量NULL
不能写成下面的样子:
int zero = 0;
int *p4 = zero;
使用指针的注意事项:
- 定义指针时,应该对指针进行初始化
- 同类型的指针可以进行相等(==)或不相等(!=)的比较操作,比较的结果是布尔类型
- 指针可以进行加或减整数值的算术运算
- 自增、自减运算适用于指向数组元素的指针
存储空间分配策略:
静态(编译时)分配空间:
- 编译器在处理程序源代码时分配内存;
- 效率高,灵活性差,运行前就要知道程序需要的内存大小和类型
动态(运行时)分配空间:
- 程序运行时调用运行时刻库函数来分配内存;
- 占用程序运行时间,更灵活
静态和动态内存分配在语法上的主要区别:
- 静态对象是有名字的变量,可以直接对其进行操作;动态对象没有名字,要通过指针间接地对它进行操作。
- 静态对象的空间分配与释放由编译器自动处理,动态对象的空间分配与释放必须由程序员显式地管理。