目录
- 1.指针是什么
- 2.指针和指针类型
- 3.野指针
- 4.指针运算
- 5.指针和数组
- 6.二级指针
- 7.指针数组
1.指针是什么
指针是什么?
指针理解的2个要点:
1.指针是内存中一个最小的单元编号,也就是地址
2.平时口语中说的指针,通常指的是指针变量,用来存放内存地址的变量
一个内存单元是一个字节
内存空间如何管理?
切割成内存的单元-1byte(字节)
总结:指针就是地址,口语中说的指针通常指的是指针变量,指针变量就是一个变量,指针变量是一个用来存放地址的变量
指针变量:里边存放的是地址,而通过这地址,就可以找得到一个内存单元
内存中每个字节都有自己的地址
a是整型变量占用四个字节,&a取出的是四个字节中的第一个字节的地址,0x00cffb24就是四个字节中的第一个字节的地址
问题:
- 一个小的内存单元到底是多大?(一个字节)
- 如何编址?
经过仔细的计算和权衡我们发现一个字节给一个对应的地址是比较合适的
对于32位的机器,假设有32根地址线,那么假设每根地址线在寻址的时候产生高电平(高电压)和低电平(低电压)就是(1或0);
那么32根地址线产生的地址就会是:
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001
...
11111111 11111111 11111111 11111111
这里就有2的32次方个地址
每个地址标识一个字节,2的32次方的地址就可以管理2的32次方个字节的空间,那我们就可以给(2^32Byte==2^32/1024KB==2^32/1024/1024MB==2^32/1024/1024/1024GB==4GB)4G的空间进行编址
- 在32位的机器上,地址是32个0或者一组成二进制序列,那地址就得用4个字节的空间来存储,所以一个指针变量的大小就应该是4个字节
- 那如果在64位机器上,如果有64个地址线,那一个指针变量的大小是8个字节,才能存放一个地址
总结:
- 指针变量是用来存放地址的,地址是唯一一块地址空间的
- 指针的大小在32位平台是4个字节,在64位平台是8个字节
2.指针和指针类型
int num = 10;
p=#
要将&num(num的地址)保存到p中,p就是一个指针变量,我们给指针变量相应的类型
char *pc=NULL;//当我们不知道给指针赋什么值得时候,我们就给指针赋上NULL
//NULL本质上还是0
char *pi=NULL;
short *ps=NULL;
sizeof是的打印无符号整型的unsigned int
所以这里用%u打印是最合适的,%zu是sizeof专门用于打印得格式
现在观察a的情况,这里只改变了一个字节
结论:
- 指针类型决定了指针在被解引用的时候访问几个字节
如果是int*的指针,解引用访问4个字节;如果是char*的指针,解引用就访问1个字节
2.1指针+-整数
这里我们看到,pa和pc打印都是a的地址,但是在访问下一个字节时,int*类型的pa是跳过4个字节,char*类型的pc是跳过1个字节
结论:
- 指针大的类型决定了指针+-1操作时,跳过几个字节,决定了指针的步长
注意:
int*和float*是不可以通用的,因为站在pi的角度,pi里面存放的是整型类型的数据;站在pf的角度,pf里面存放的是浮点型的数据
它们两个是不一样的,整形数据的存储和浮点型数据的存储是存在差异的,不能混用
2.2指针的解引用
指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)
3.野指针
概念:野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
3.1野指针成因
1.指针未初始化
这里的p就是野指针,局部变量未初始化,默认为随机值
2.指针越界访问
当i=10时,越界访问,此时p是野指针 (当指针指向的范围超出数组arr的范围时,p就是野指针)
3.指针指向的空间释放
a出了作用于范围就被销毁,此时p就是野指针
如果想要打印*p里的内容,在这块空间还没有被其他变量使用(或者没有被覆盖)时,此时依旧能打印出10,这块空间里存放的还是10,只是这块空间不再属于a,如果这块空间已经被其他创建的变量使用,这里就不能打印10了
3.2如何避免野指针
1.指针初始化
当我们不知道给指针赋上什么值,给它赋上NULL
下面这样是可以的
0地址在内存中是不允许访问的,给p2赋上空指针,再对p2进行解引用是错误的
在使用指针的时候,我们需要看它是不是空指针,如果不是空指针我们才能使用
2.小心指针越界
3.指针指向空间释放及时置NULL
4.避免返回局部变量的地址
5.指针在使用之前检查有效性
4.指针运算
- 指针+-整数
- 指针-指针:得到的数的绝对值是指针和指针之间元素的个数(前提是指向同一块空间的指针才能相减)
使用指针-指针的方法实现strlen函数(计算字符串长度)
int my_strlen(char*s)
{
char* p=s;
while(*p!='\0')
p++;
return p-s;
}
- 指针的关系运算
for(vp=&values[N_VALUES];vp>&values[0])
{
*--vp=0;
}
代码简化,这段代码修改如下:
for(vp=&values[N_VALUES-1];vp>=&values[0];vp--)
{
*vp=0;
}
实际在绝大部分的编译器上是可以顺利完成任务的,然而我们还是应该避免这样写,因为标准不保证它可行
标准规定:
允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较
允许与p2相比较,不允许与p3相比较
5.指针和数组
数组:一组相同类型的元素
指针变量:是一个变量,存放的是地址
指针就是指针,不是数组;数组就是数组,也不是指针
指针的大小:4/8个字节,指针是存放地址的,地址的存放需要多大空间,指针变量的大小就是多少;数组的大小取决于数组的元素个数和每个元素的类型
6.二级指针
7.指针数组
指针数组是数组,指针数组是存放指针的数组
可以用指针数组模拟一个二维数组