目录
指针概念
指针的定义
在计算机科学中,指针(Pointer)是编程语言中的一个对象,利用地址,它的值直接指向(points to)存在电脑存储器中另一个地方的值。由于通过地址能找到所需的内存单元,可以说地址指向该内存单元。因此,将地址形象化的称为“指针”。意思是通过它能找到以它为地址的内存单元。
理解指针的两个要点:
- 指针是内存中一个最小单元的编号,也就是地址
- 平时口语中说的指针,通常指的是指针变量,是用来存放地址的变量
这是官方对指针的定义,其实我们可以理解为:在内存中,内存被细分为一个个大小为一个字节的内存单元,每一个内存单元都有自己对应的地址。
形象地比喻,我们把一个个内存单元看成一个酒店房间,我们的指针就是我们手里的门禁卡上面写着所指向的房间序列也就是地址,通过指针我们就能对应地找到所开辟的内存空间,并调用其中的数据,即用指针指向内存单元
指针变量就是用来存放地址的变量(放在指针中的值都被当成地址来处理)
#include<stdio.h>
int main()
{
int a=1;
int *p=NULL;
p=&a;
return 0;
}
这里p就是指针变量,它存放着a的地址
指针的大小
32位机器有32根地址线,每根地址线都能发出0或1,所以由32位机器发出的地址信号总共有2^32种排列方式:
所以
在32位的机器上每个地址是32位,而8个bit位为一个字节,所以在32位机器上指针大小为4个字节
同理在64位机器上,指针大小为8个字节
指针类型
指针有哪些类型
因为指针是指向具有类型的变量的地址,所以指针肯定也有不同的类型
指针的定义方式是type+ *
char * 类型的指针存放的是char类型的变量地址;
int * 类型的指针存放的是int类型的变量地址;
float * 类型的指针存放的是float类型的变量地址等。
指针类型有什么意义
指针类型决定指针在被解引用的时候访问的权限
例如:整型指针解引用访问4个字节(如图)
字符指针解引用访问1个字节等等
指针类型也决定了指针向前或向后走一步走多大的距离
#include<stdio.h>
int main()
{
int a=10;
int *pa=&a;
char*pd=&a;
printf("%p\n",pa);
printf{"%p\n",pd);
printf("%p\n",pa+1);
printf{"%p\n",pd+1);
return 0;
}
(这里的pd的指针类型与a的数据类型不统一,这里只是为了方便展示地址的变化,在平时的编程中一定要注意类型要统一!)
得到的结果是:
用图表示如下:
野指针
野指针的含义:
指针指向的位置是不可知的(随机的,不正确的,没有明确限制的),就如同上述所说,我们使用自己的门牌卡(指针)去访问自己订的房间(内存单元),只有进入自己所订的房间才是合法的,如果闯入其他的房间就是非法访问,是违法的;而当我们退房时(内存空间释放),我们手中的门牌卡(指针)也是没有权限再去访问我们之前的房间(内存单元);
造成野指针的原因:
- 指针未初始化
- 指针越界访问
- 指针指向的空间释放
如何规避野指针
- 指针初始化
- 小心指针越界
- 指针指向空间释放即时置NULL
- 避免返回局部变量的地址
- 指针使用之前检查有效性
指针运算
1.指针+-整数
#include<stdio.h>
int main()
{
int arr[5] = { 0 };
int* p = arr;
int i = 0;
for (i = 0; i < 5; i++)
{
*(p + i) = i;
}
return 0;
}
2.指针- 指针
int my_strlen(char* p)
{
char* pc = p;
while (*p != '\0')
p++;
return p - pc;
}
指针-指针的绝对值是是两个指针之间的元素个数, strlen函数的模拟实现就可以运用指针-指针的代码实现(两个指针必须指向同一块空间)
指针的关系运算
指针的关系运算指的是指针之间大小的比较
例如我们想将一个数组中的元素全部置为0,有两种方法:
1.从前往后置0
#include<stdio.h>
int main()
{
int arr[5] = { 1, 2, 3, 4, 5 };
int* p = &arr[0];
for (p = &arr[0]; p <= &arr[4]; p++)
{
*p = 0;
}
return 0;
}
2.从后往前置0
#include<stdio.h>
int main()
{
int arr[5] = { 1, 2, 3, 4, 5 };
int* p = &arr[4];
for (p = &arr[4]; p >= &arr[0]; p--)
{
*p = 0;
}
return 0;
}
规范的使用方法是第一种,从前往后置0;
因为指针关系运算的标准规定:
允许指向数组元素的指针与指向数组最后一个元素后面那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存进行比较。
二级指针
其实,存放普通变量的地址的指针叫一级指针,存放一级指针变量的地址的指针叫二级指针,存放二级指针变量地址的指针叫三级指针,以此类推
二级指针是指向一级指针变量地址的指针
#include<stdio.h>
int main()
{
int a=10;
int *p=&a;
int **pp=&p;
printf("%d\n",*p);
printf("%p\n", p);
printf("%p\n", *pp);
printf("%d\n",**pp);
printf("%p\n",&a);
printf("%p\n",p);
printf("%p\n",pp);
return 0;
}
得到的结果:
可知:对二级指针pp第一次解引用时即*pp,得到的值就是一级指针变量p的值,即为a的地址,再解引用即**pp,就等于a的值,相当于对一级指针p解引用;