14. 指针1
- 任何时候指针只能有两种状态,NULL状态和正常状态。
- 仅仅给出地址,计算机无法正确有效地读写数据。
- 指针是一个具有解释方式信息的地址
分析指针时关心两件事:
1.在哪里
2.是什么
理解了指针的解释方式,就可以任意解释内存中的数据
举例:
unsigned char *p = NULL;
int n = 999;
int ary[] = { 1,2,3 };//数组名是数组第0个元素类型的指针常量
p = (unsigned char *)&n;
printf("%X\n", n); //直接访问,按变量自身的类型,输出3E7
printf("%X\n", p[0]);//间接访问,按指针定义时的类型,输出E7
指针的运算:
type *ptr = ...
int n = ...
ptr[n] = *(type *)((int)ptr + sizeof(type) * n)
1.对指针做下标运算,得到指针定义时类型的变量:
int *p = NULL;
int n = 3;
printf("%X\n", &p[n]);//获取的是地址,不会访问p[n],所以不会引发异常,输出C
printf("%X\n", p[n]); //会访问p[n], 会引发异常
2.对指针做加法运算,必须加整数类型,得到同类型的指针常量:
ptr + n = (type * const)((int)ptr + sizeof(type) * n)
2.1 const限定符
int const *ptr = ary;//const在*左边的,间接访问的目标是常量,不能间接写入
int *const ptr = ary;//const在*右边的,指针自身是常量,指针变量不能修改
3.对指针做减法运算,必须减同类型指针,得到整形常量:
type *ptrA = ...
type *ptrB = ...
ptrA - ptrB = ((int)ptrA - (int)ptrB) / sizeof(type)
修改一个字节改变内存属性:
const char g_szText[] = "Hello11";
int main() {
char szBuff[] = "Hello World";
const char *psz = "Hello World";
puts(szBuff);
puts(psz);
puts(g_szText);
char *p = (char *)psz;
p[0] = '1';
p = (char *)g_szText;
p[0] = '2';
getchar();
return 0;
}
正常编译以上代码,可以观察到&g_szText和psz很近。但是继续运行会崩溃,因为改写了只读区的数据。
打开磁盘中的exe文件,找到.rdata,两行半的位置最后有一个字节40,4写为二进制是
0 1 0 0
w r e s
四个字母代表Write,Read,Execute,Share
改为1100,即C,内存属性变为可读可写。
再次调试,发现可以修改了,程序也没崩溃。