1.指针的定义
指针就是一个变量,是一个用来专门储存地址的变量。比如在一个走廊里,两侧有很多房间,每个房间都挂有门牌号,门牌号就是每个房间的地址,通过门牌号可以找到指定的房间。指针就相当于是用来存放这些门牌号的变量,通过指针就可以找到以它为地址的内存单元。
用代码来说
int main()
{
int a = 0;//在内存中开辟一块空间
int* p = &a;//取出a的地址,把a的地址储存在p变量中,p就是一个指针变量
return 0;
}
- 如何给内存单元编地址?
机器分为32位和64位,就32位的机器来说,有32根地址线,每根电线都产生一个正电或负电的电信号(用1或0表示),那么32根地址线产生的地址就会是:
00000000 00000000 00000000 00000000
00000000 00000000 00000000 0000001
…
…
11111111 11111111 11111111 11111111
这里就会有2的32次方个地址,若给一个单元赋为1个字节,那么2^32byte == 4GB,有4G的空闲区域进行编址.
总结
1.在32位的机器上,地址是由32个0或1组成的,则地址就要用4个字节的空间来储存,则一个指针变量的大小就是4个字节;64位的机器的指针变量大小就是8个字节
2.指针类型
我们都知道,变量有不同的类型,那么指针也有不同的类型
int main()
{
int a = 10;
int *pa = &a;
char *pb = &a;
float *pc = &a;
short *pd = &a;
double *pe = &a;
printf("%d",sizeof(int *));//4
printf("%d",sizeof(char *));//4
printf("%d",sizeof(float *));//4
printf("%d",sizeof(short *));//4
printf("%d",sizeof(double *));//4 所有的指针变量的大小都是4
}
- 既然指针变量不管是什么类型大小都是4个字节,那么指针变量和类型有什么关系呢
3.指针类型的意义
- 指针±整数
# include <stdio.h>
int main()
{
int a = 0;
int *pa = &a;
char *pc = &a;
printf("%p\n", pa);
printf("%p\n", pa+1);
printf("%p\n", pc);
printf("%p\n", pc+1);
return 0;
}
说明指针类型决定了向后走一步能走多远(步长)
- 整型指针
#include<stdio.h>
int main()
{
int a = 0x11223344;//十六进制,
int *pa = &a;//指针变量pa接收a的地址
*pa = 0;//指针变量进行解引用操作,将a的地址改为0,此时解引用访问了4个字节
return 0;
}
- 字符指针
#include<stdio.h>
int main()
{
int a = 0x11223344;//十六进制
char * pc = &a;//将a的地址放到pc里面去
*pc = 0;//指针变量进行解引用操作,将a的地址改为0,此时解引用只访问了0个字节
return 0;
}
说明指针类型的另一个意义是指针解引用的权限有多大
比如,如果想从当前地址向后访问4个字节,那么就把这个地址放到int 型指针里;如果想从当前地址向后访问1个字节,就把这个地址放到char类型指针里
4.野指针
野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
野指针出现的原因
1.指针未初始化
int main()
{
int *p;//指针未初始化,默认随机值,造成野指针
*p = 0;//非法访问内存
return 0;
}
2.指针越界访问
int main()
{
int arrr[10] = { 0 };
int *p = arr;
int i = 0;
for (i = 0; i <= 10;i++)
{
*p = i;
p++;//当指针指向的范围超出数组arr的范围时,就会造成越界访问,这时p就是野指针
}
return 0;
}
3.指针指向的空间释放
int *test()
{
int a = 10;
return &a;//当调用完函数的时候,临时开辟的a的变量的空间释放,p成为野指针
}
int main()
{
int *p = test();
*p = 20;
return 0;
}
5.规避野指针的方法
- 指针初始化
当指针变量p不知道应该初始化为什么地址的时候,直接初始为NULL (int *p = NULL)
- 小心指针越界
- 指针指向的空间释放时,及时放置NULL
- 指针使用之前检查有效性
6.指针和数组
- 首先,我们需要直到数组名是什么
eg:
int main()
{
int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
printf("%p\n", arr);
printf("%p\n", &arr[0]);
return 0;
}
可见数组名和数组首元素地址是一样的
因此可以看下面一段代码
int main()
{
int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
int *p = arr;
int sz = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < sz; i++)
{
printf("&arr[%d] = %p< == >p+%d = %p\n", i, &arr[i], i, p+i);
}
return 0;
}
从这里我们可以看出,p+i 其实就是arr数组下标为i的地址,既然这样,我们就可以用指针直接访问数组
int main()
{
int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
int *p = arr;
int sz = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < sz; i++)
{
printf("%d ",*(p+i));
}
return 0;
}
7.二级指针
二级指针就是存放指针变量地址的变量
8.指针数组
我们知道,数组有整型,有字符类型,那么也有指针类型
整型数组里存放的数据类型是整型,字符类型数组存放的数据类型是char 型,那么指针数组存放的数据类型都是指针类型。