初阶指针
一.内存
在我们理解指针之前,首先要理解内存
1.内存是计算机上的一种存储空间
2.程序运行时会载入内存
3.程序中如果有数据需要存储,需要向内存申请内存空间
在这里我们可以通过任务管理器,查看内存使用情况
那么计算机中内存是如何划分的呢?
二.指针
接下来我们用代码来更深入的理解指针
int main()
{
int a = 5; //向内存申请4个字节的空间
//&取地址
int* pa = &a;
//分开来解释的话:
//pa是指针变量用来存放a的地址(地址又叫指针)
// * 表明pa是指针变量
//int 表示pa指向的变量a是int类型的变量
//看成整体的话:
// 和 int a = 5;一样
// int* 是变量pa的类型
return 0;
}
接下来我们通过调试来查看内存中的情况
通过上面的图片我们可以清楚的知道,指针变量中存储的是该变量的首地址(低地址)
三.得到变量的地址,我们能做什么呢?
可能这样问不太好理解,那我换个问法,如果得到一个人的地址我们能做什么?当然是能够通过地址找到它啦。
问题二:
找到它我们能做什么呢?
答案是:可以给它寄点东西过去(改变它原有的值)
四.指针变量的大小
在不同位的机器上指针的大小不同
在32为机器中产生32个bit位(四个字节)的个地址
在32位机器上指针变量的大小就是四个字节
同理在64位机器上指针变量的大小是八个字节
五.指针的两种理解
1.指针就是地址
2.口头上的指针一般是指指针变量
六.指针类型的意义
指针和变量一样有类型如
char *pc = NULL;
int *pi = NULL;
short *ps = NULL;
long *pl = NULL;
float *pf = NULL;
double *pd = NULL;
我们都知道,指针在不同机器中的大小不一样,在32位机器中时4个字节,在64位机器中是8个字节,那么既然在同一台机器中指针大小相同,为什么会有指针类型呢?,在这里我们就需要了解指针类型的意义。
1.指针类型决定访问权限的大小
将一个变量的地址放在不同类型的指针中,打印出的地址是相同的,那么我们在看下面代码的不同:
通过对比我们发现,char*的指针只改变了一个字节的数字
这是因为char类型的大小是一个字节,通过解引用访问时只能访问一个字节,同理其他类型也是如此。
因此,当我们需要访问多大的空间时,就使用合适的指针类型。
2.指针类型决定指针的步长(+1,跳过多少字节)
总结:指针的类型决定了指针向前或者向后走一步有多大(距离)
七.野指针
概念:野指针就是指针指向的空间是随机的(不确定的)
1.野指针的成因
1.指针未初始化
int main()
{
int *p;//局部变量指针未初始化,默认为随机值
*p = 20;
return 0; }
2.指针数组越界
int main()
{
int arr[10] = {0};
int *p = arr;
int i = 0;
for(i=0; i<=11; i++)
{
//当指针指向的范围超出数组arr的范围时,p就是野指针
*(p++) = i;
}
return 0;
}
3.指针指向的空间被释放
注意:此时这里虽然打印出了10,但是这只是巧合,正好那部分空间没有被占用或者修改。
在这里我们稍微加点东西,就会导致值发生变化
八.如何规避野指针?
1.初始化指针(可置空指针(NULL))。
2.小心指针越界
3.指针指向的空间被释放时,即使置空指针
4.避免返回局部变量的地址
5.指针使用之前检查有效性
九.指针的运算
1.指针 + - 整数
指针加减整数就是上面提到的步长。
2.指针减指针的绝对值是指针间的元素个数
前提:两个指针指向同一块空间!!!。
3.指针关系运算(大小关系)
int main()
{
float values[5];
float* vp;
for (vp = &values[5]; vp > &values[0]; )
{
*--vp = 0;
}
return 0;
}
此时虽然数组虽然越界,但是并没有访问,是不影响的
但是若将代码简化一下之后
int main()
{
float values[5];
float* vp;
for (vp = &values[4]; vp >= &values[0];vp--)
{
*vp = 0;
}
return 0;
}
此时,指针变量vp向前走了一步,这时候虽然在绝大部分的编译器上是可以顺利完成任务的,然而我们还是应该避免这样写,因为标准并不保证它可行。
标准规定:
允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。
十.指针和数组的区别和联系
区别:
指针:是一种变量,是用来存储地址的,大小是4/8个字节。
数组:是一组相同类型元素的集合,可以放多个元素,数组的大小取决于元素个数和元素的类型。
联系:
数组名是首元素的地址,地址可以放在指针变量中。同时也可以用过指针访问数组。
十一.二级指针
二级指针是什么?那指针是什么?口头中的指针一般指的是指针变量,指针变量用来存储变量的地址。此时的指针变量是有地址的。
因此二级指针可以理解为存储一级指针地址的指针。
int main()
{
int a = 19;
int* pa = &a;
int** ppa = &pa;//二级指针
return 0;
}
让我们画图来理解一下:
同时二级指针的使用和一级指针是一样的
十二指针数组
在这之前我们需要知道,指针数组是指针还是数组?
答案是:数组
我们可以这样理解,指针数组就是存放指针的数组。
int main()
{
int a = 10;
int b = 20;
int c = 30;
int* arr[3] = { &a, &b, &c }; //指针数组
int i = 0;
for (i = 0; i < 3; i++)
{
printf("%d ", **(arr + i));
//printf("%d ", *(arr[i]));
}
return 0;
}
接下来我们可以使用几个一维数组模拟出二维数组:
到这里初阶指针就结束了,后面还会有指针进阶的知识和大家分享。