指针的初始化
声明一个指针变量并不会分配内存地址,因此在使用这个指针之前必须进行初始化,或指向现有内存,或给他分配动态内存
指针的初始化是用**&操作符完成的,他用于产生操作数的内存地址**
int a = 112;
int *b = &a;
b中存储的内容是一个地址,而不是整形或者浮点型类型,b的内容和a的存储地址一致
间接访问 / 解引用指针 (*)
通过一个指针访问他所指向的地址
a为一个int型变量,b为一个int *类型指针,存储了a的地址,则利用单目操作符( * )可以间接访问a的值,即
*b 的值 = a的值 = 112
ps: 对一个NULL指针进行解引用是非法的!!!当需要对一个指针进行解引用操作时,必须保证他不是一个NULL指针!!!
指针在创建时必须要初始化!!!!!
int *a; // 声明了一个a的指针变量
*a = 12; // 赋值语句, 把12存储在了a指向的内存空间中
a被声明后,并没有初始化,所以我们不知道a所指向哪一块内存空间,所以并不能知道12被存在哪里
所以,在使用间接访问( * 解引用指针)的时候,必须确保这个指针已经被初始化了!!!!!!
易错点:指针常量
假设我们已经知道了某个变量的地址: 如int型变量a的地址为100,
我们想要改变这个地址内所存储的数据(即a的值)
*100 = 25; // 错误!!
上面这个写法看起来像是想把25赋值给变量a(因为a的地址为100),但是这种写法是错误的!!因为字面值100是一个整型,而间接访问操作只能用于指针类型表达式!!!!
正确的写法是将整型强制转化为一个指针类型表达式以后,再进行赋值
*(int *)100 = 25;
指针的指针
指针的运算
1、指针 +/- 一个整数 = 另一个指针
若p为一个char * ,那么p + 1 = 下一个char
若p为一个int *, 那么 p + 1 = 下一个int
但是,若指针 - 一个整数后,产生的指针所指向的位置在数组第一个元素之前,那么这个操作是不合法的!
sizeof(*p)永远等于他的类型长度!!
sizeof(char *) = 1
sizeof(int *) = 4
sizeof(double *) = 8
例:
1、vp指向了这个数组的首地址
2、&value[N_VALUES]代表指向最后一个元素后面的那个内存地址(???),经过5次以后,他指向第6位
注意:
① 可以获取到这个位置,但不允许对这个位置的值进行间接访问操作
② 可以获取数组最后一位的下一个地址,但不能获取数组第一位的前一个的地址,即
vp < &values[N_VLAUES] // 合法,可以获取数组最后一位的下一个地址,但不允许修改
vp >= &values[0] // 不合法,不能获取数组第一位的前一个的地址
3、将每个float都置为0
① 先对vp进行一个复制
② vp++(因为++优先级高于*),指向下一个float位置
③ 间接访问操作*,对每个float位置进行值操作
2、指针 - 指针 = 相隔多少个元素(前提:俩指针必须指向同一数组)
只有当两个指针都指向同一数组的元素时,指针相减才有意义!
警告
数组指针
当数组作为一个函数参数进行传递时,传递的实际上是一个地址
void swap(int a[]) // 这里写void swap(int a[10]) 或者 void swap(int *a)都是一样的
{
cout << *a;
}
int main()
{
int a[10] = {1,2,3,4,5,6,7,8,9,10};
int i = 0;
swap(a);
}
二维指针
int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
a : 代表整个数组的首地址 int (*a)[4]类型 size= 3组 * 4个 * 4 = 48
a[0]: 代表第0行的首地址,int *类型 size = 4个 * 4 = 16
&a[0][0] :代表第0行第0列地址 int*类型 size= 4
*(a + 1) : 第1行地址 int*类型 size = 4个 * 4 = 16
&a[1] : int(*a)[4] size= 4(??)