指针的运算
指针p可以加上或减去一个整数n,但指针的这种运算的意义和通常的数值的加减
运算的意义是不一样的,它是以单元为单位,如p指向int型整数,则一个单位是sizeof(int)
(1)示例1
char a[20]="You are my friend";
int *ptr=(int *)a;
ptr = ptr + 3;
char数组的每个单位是一个字节,而指针ptr指向的单元是4个字节
所以没加3前的 ptr 指向数组a的第1 - 4个字节(看作一个整体),加3后,ptr已经指向了数组a的第13 - 16个字节,即指向a[12] - a[15]这部分
(2)示例2
#include <iostream>
using namespace std;
int main() {
int array[20] = {0};
int *ptr = array; // 数组名array是地址,把它赋给指针ptr
for(int i = 0; i < 20; i++) {
*ptr = i;
ptr++;
}
ptr = array;
for (int i = 0; i < 16; i += 4) {
cout << *(ptr + 4) << endl;
// 等价于cout << ptr[4] << endl;
ptr += 4;
// 因为ptr指向的是int,而数组array也是int
// 所以指针ptr+4,等于下标i+4
}
return 0;
}
总结
一个指针(地址) ptrold 加(减)一个整数 n 后,结果是一个新的指针(地址) ptrnew,
ptrnew 的类型和 ptrold 的类型相同,ptrnew 所指向的类型和 ptrold所指向的类型也相同
ptrnew 的值将比 ptrold 的值增加(减少)了 n 乘sizeof(ptrold 所指向的类型)个字节
也就是说:ptrnew 所指向的内存区将比 ptrold 所指向的内存区向高(低)地址方向移动了 n 乘sizeof(ptrold 所指向的类型)个字节。
指针和指针进行加减:
- 两个指针不能相加,这是非法操作
因为进行加法后,得到的结果指向一个不知所向的地方,而且没有意义。 - 两个指针可以相减
但必须类型相同,可用于求数组大小,当然要记得除以sizeof(type)
数组和指针的关系*(p + 4) 和 p[4]
数组名array本质是一个指针,所以
int array[]={0,1,2,3,4,5,6};
int *p = array;
记住一点
*(p + 4) 和 p[4]是等价的
*(array + 4) 和 array[4]是等价的
而array[0]
等价于 p[0]
,因为p = array;
所以实际上,上面四个都是等价的
指针和结构的关系p->data; 和 (*p).data
struct node {
int data;
int time;
}node;
node Tu;
node *p = &Tu;
只要记住一点:(*p).data和p->data; 是等价的
指针的安全问题
(1)示例1
int a;
int *p = &a;
p += 1;
*p = 8;
上面的代码存在严重的错误,因为第三行代码p += 1
执行后,p指向了整型变量a相邻的高地址方向的一块储存区域,而我们居然用第四行代码往这块区域里写入数据,这非常危险,因为我们不知道它里面原来的内容是什么,万一是系统十分重要的数据呢
在数组int a[10]时类似地操作可行,那是因为我们已经申请了一个长度长度为10的连续空间,这部分空间是我们已知的且可随意写数据的
所以说,我们在使用指针时一定要非常清楚:这个指针究竟指向了哪里
(2)示例2
当我们使用指针的强制类型转换p1=(type *)p2 时,如果 sizeof(p2 的类型) 大于 sizeof(ptr1 的类型),那么在使用指针 p1 来访问 p2 所指向的存储区时是安全的。否则是会出现严重问题的
char t = 'a';
int *p;
p = (int *)&t;
*p = 520;
运行代码,可能不会报错,但这存在着安全隐患,因为p指向的是字符a
以及和它相邻高地址方向的三个字节,而后面三个字节的内容我们并不知道是什么,万一很重要的呢
(3)下面的代码是安全的,而且可以说明我的机器是小端模式
因为从t最后的值为48,可以看出p指向的是int4个字节中的低字节,而强制转换的char指针p默认是指向int4个字节中低地址的字节的,所以可以说明我的机器是小端模式(低字节在低地址)
int t = 7;
char *p;
p = (char *)&t;
*p = '0'; // 对应48:00110000 char 一个字节:0-127
cout << *p << endl;
cout << t << endl; // 输出48