野指针
1,指针变量未初始化
2,指针变量直接释放,没有置NULL
3,指针变量超越了其指向变量的作用范围,这种情况下,其所指向的变量已经不存在,而我们认为对指针进行操作依然指向该变量,这种情况危害最大。
如果对野指针进行了操作,那么很有可能造成不可预计的后果,因为你不知道野指针指向的内存区域的具体情况。
野指针不做过多的介绍,要通过养成良好的编程习惯,尽量避免野指针的存在。
指针越界
指针越界,发生越界访问也会造成严重的后果。
typedef struct x
{
char a, b;
struct x *p;
}x;
int main(void)
{
x c,*q;
c.p = &c;
q = &c;//假设q=&c为0x00000000
q = q + 1;此时q=0x00000008
printf("%p\n",&c.a);
printf("%p\n", &c.b);
printf("%p\n", c.p->p);
printf("%p\n", q);
printf("%p\n",q->p);//此时q=0x00000012,所打印的是0x00000012内存处保存的值
c.p = c.p + 1;
printf("%p\n", c.p);
printf("%p", c.p->p);//同上
getchar();
return 0;
}
结构体指针p发生了越界,我们想要打印的值变成了下一片8字节内存里面的值,如果对该内存进行访问,那么可能造成不可预知错误。
对于结构体指针进行+1操作,其值直接加上结构体的大小,指向下一片结构体内存。
那么结构体指针如何访问结构体内部的变量呢?
1、在知道结构体的情况下直接使用->对结构体内部变量进行访问,获得是变量的值,而不是变量的地址,这是显式访问。而->在内部汇编代码上实际上也是根据地址加上偏移来实现对内存的访问。
printf("%p\n",q->a);
00D13D43 8B 45 E4 mov eax,dword ptr [q] ;此处将q里面保存的结构体首地址传给eax
00D13D46 0F BE 08 movsx ecx,byte ptr [eax] ;此处取了q地址偏移一个字节出的内存地址
00D13D49 8B F4 mov esi,esp
00D13D4B 51 push ecx
00D13D4C 68 B0 58 D1 00 push 0D158B0h
00D13D51 FF 15 10 91 D1 00 call dword ptr ds:[0D19110h] ;printf()函数打印
2、通过结构体的首地址+偏移来访问结构体的内部变量,隐式访问。
这里可以通过定义一个char类型的指针,因为char一般只有一个字节,访问起来方便。
通过指针对变量进行访问,实际上就是通过内存地址访问实现的,通过改变指针的值,从而实现了指向内存地址的改变。
指针
指针根据自身类型的不同,来决定自身的+1操作应该加上多少个字节,而不是只+1个字节。通常int 4个字节,char是1个字节,结构体是结构体的大小。