定义:在计算机科学中,指针( Pointer )是编语言中的一个对象,利用地址,它的值直接指向( points to )存在电脑存储器中另一个地方的值。由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为“指针”。意思是通过它能找到以它为地址的内存单元。
指针是个变量,存放内存单元的地址(编号)。通过指针可以找到该地址所对应的变量进行相关操作,对应到代码:
#include
int main()
{
int a = 5;//在内存中开辟一块空间
int* pa = &a;//利用&操作符可以取出变量a的地址
//地址可以存放在指针变量中
*pa = 6;
printf("%d\n", a);
return 0;
}
指针的大小在32位平台上是4个字节,在64位平台中是8个字节。
我们发现不管是什么类型的指针,既然都是四个字节的大小,那么能不能做一个通用指针呢,为什么还要区分出各种类型的指针呢,答案当然是否定的。
我们随便找一个可以占满四个存储空间的的数字来说明指针特性:
#include
int main()
{
int a = 0x11223344;
int * pa = &a;
*pa = 0;
return 0;
}
由此可以看出指针类型的意义:
1.指针类型决定了,指针解引用的权限有多大(int类型指针解引用可以访问四个字节、char类型指针解引用可以访问一个字节、double类型指针解引用可以访问八个字节)
2.指针类型决定了,指针走一步,能走多远(步长)
概念:野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
#include
int main()
{
//这里的p就是一个野指针
int* p;//p是一个局部的指针变量,指针变量不初始化的话的,默认是一个随机值
*p = 20;//非法访问内存
return 0;
}
#include
int main()
{
int arr[10] = { 0 };
int* p = &arr;
int i = 0;
for (i = 0; i <= 10; i++)
{
*p = i;
p++;
}
return 0;
}
当i=10时,循环依然会进入,当i=10时*p已经越界,程序崩溃
#include
int* test()
{
int a = 4;//局部变量
return &a;
}
int main()
{
int*pa = test();
*pa = 21;//局部变量已经销毁,解引用出来并不是a原先的值
return 0;
}
1.指针初始化(不知道指针应该初始化为什么时,直接初始化为NULL) |
2.小心指针越界 |
3.指针指向空间释放即使置NULL |
4.指针使用之前检查有效性 |
指针的运算包括:1.指针+-整数;2.指针-指针;3.指针的关系运算
两个指针相减的前提:两个指针指向同一个空间
指针-指针得到的两个指针之间的元素个数,证明如下代码:
在了解完指针相减的知识点后,我们可以用这种方法
利用指针-指针模拟实现strlen的功能
ps:strlen函数的模拟实现方法在前面也有提到,链接附上C语言函数专题攻略附练习讲解(从0到1)【纯干货】(自定义函数+递归+应用实例)-CSDN博客
int my_strlen(char* str)
{
char* start = str;
while(*str != '\0')
{
str++;
}
return str - start;
}
int main()
{
char str[] = "abc";
int len = my_strlen(str);
printf("%d\n", len);
return 0;
}
指针与数组之间的联系非常紧密,我在前面的博客中做了详细的介绍,这里不过多赘述,在此附上链接:数组【从零到一】【纯干货】-CSDN博客
在对指针有了更加深入的了解之后,我们写代码的时候就可以更加地灵活,以下面代码为例,我们来看看如何用指针的知识来初始化数组:
指针变量也是变量,是变量就要开辟空间来存放,就必然有自己的地址,那么指针变量的地址存放在哪里?这就是二级指针。
对于二级指针的运算:*ppa通过对ppa中的地址进行解引用,找到的是*pa,所以*ppa-->pa,由于*pa-->a,所以**ppa-->a.
int main()
{
int arr[10];//整形数组-存放整形的数组就是整形数组
char ch[5];//字符数组-存放的是字符
//指针数组-存放指针的数组
int* pa[5];//整形指针的数组
char* ppa[5];//字符指针的数组
return 0;
}