1.什么是指针?为什么需要指针。
对于这个问题,我们需要思考我们曾经学过的基本程序,它们是如何编译和存储的。指针就是一个地址,任何指针都一样,不存在大小之分。只不过在X86和X64环境下所占字节大小不一样。
那它有什么用呢?举个最基本的例子:"hello world"这个程序,如果你想要从键盘中输入,是怎么做到的呢?
首先我们仔细研究一下 scanf() 这个函数
首先,scanf函数的返回值是int类型,是为了表示成功读取并匹配到的输入项的个数。具体来说,返回值表示成功匹配到的输入项的个数,如果没有匹配到任何输入项,则返回0。如果发生错误或遇到文件结束符,则返回EOF(-1)。这样设计的目的是为了方便判断输入是否成功,并根据返回值进行相应的处理。
其次,参数部分由格式指示符和地址组成。变量列表:变量列表是一系列用于接收输入值的变量。变量列表中的变量必须与格式控制字符串中的格式指示符一一对应,用于存储对应格式的输入值。变量列表中的变量可以是基本数据类型(如int、float、char等),也可以是指针类型。
所以我们时常会在变量前加上一个'&'以表示拿到地址,从而放入或修改数据。如下:
#include<stdio.h>
#include<stdlib.h>
int main()
{
int m;//未初始化
int b = 521;//已初始化
scanf("%d %d", &m, &b);
printf("%d %d", m, b);
return 0;
}
既能初始化,又能赋值,所以有了地址,无疑增加我们操作数据的能力。
2.指针与数组之间的联系
指针通常使用‘*’表示,和其他数据一样,它是一种数据类型,有int*,char*等等,一颗星,为一级指针,如果给指针加上‘*’表示解引用,类似于数组通过下标访问。举个例子:
#include<stdio.h>
#include<stdlib.h>
int main()
{
int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };//创建数组
for (int i=0;i<10;i++)
{
printf("%d ", arr[i]);//通过下标访问
}
printf("\n");
int* p = (int*)malloc(sizeof(int)*10);
for (int i = 0; i < 10; i++)
{
*(p + i) = i;//赋值
printf("%d ", *(p+i));//通过指针访问
}
free(p);
p = NULL;
return 0;
}
显然,第一种是大家熟悉的数组创建方式,通过数组下标进行访问。第二种则是利用动态内存开辟空间,分配十个字节,并通过指针解引用,将值写入地址和打印出来。看看运行效果:
效果一样,底层逻辑是一样的。那么二维数组和二级指针效果是一样的。
3.二级指针是什么?
二级指针是指指向指针的指针。它是C语言中的一种特殊数据类型,用于存储指向指针的地址。
在C语言中,指针是一个变量,存储了一个内存地址。而二级指针则是指向指针的指针,它存储的是一个指针变量的地址。
二级指针的声明和使用方式如下:
int main()
{
int** pp; // 声明一个二级指针
int* p; // 声明一个指针
int num = 10; // 声明一个整数变量
p = # // 将指针p指向变量num的地址
pp = &p; // 将二级指针pp指向指针p的地址
printf("%d\n", **pp); // 输出变量num的值,使用二级指针需要使用两次解引用操作
return 0;
}
运行结果:
二级指针常用于需要修改指针变量本身的情况,例如在函数中传递指针的地址,以便在函数内部修改指针的指向。它也可以用于多级指针的情况,例如指向指向指针的指针(三级指针)等。
如果在二级指针内存储一级指针,则可以模拟二维数组
#include<stdio.h>
#include<stdlib.h>
int main()
{
int** p = (int**)malloc(sizeof(int) * 4);
for (int i = 0; i < 4; i++)
{
*(p+i) = (int*)malloc(sizeof(int) * 5);
}
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 5; j++)
{
scanf("%d",&p[i][j]);//数组下标输入
}
}
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 5; j++)
{
printf("%d ", p[i][j]);//数组下标访问
}
printf("\n");
}
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 5; j++)
{
printf("%d ", *(*(p + i) + j));//二级指针解引用访问
}
printf("\n");
}
free(p);
p = NULL;
return 0;
}
两种方式运行结果一样:
4.野指针是什么和如何防范
野指针是指指向无效或未知内存地址的指针。它是一个没有被正确初始化或者指向已经释放的内存的指针。
野指针可能会导致程序运行时的不可预测行为,包括崩溃、数据损坏和安全漏洞等。因此,在使用指针之前,应该始终确保指针被正确初始化或者指向有效的内存地址。
常见产生野指针的情况包括:
- 指针未被初始化:在声明指针变量后,没有为其分配有效的内存地址或者将其初始化为NULL。
- 指针指向已释放的内存:在释放内存后,没有将指针置为NULL或者重新分配有效的内存地址。
- 指针超出作用域:在函数内部定义的指针,在函数结束后可能会超出作用域,成为野指针。
- 指针操作错误:对指针进行错误的操作,如解引用空指针、指针运算超出边界等。
为了避免野指针的问题,应该养成良好的指针使用习惯:
- 始终为指针变量分配有效的内存地址或者将其初始化为NULL。
- 在释放内存后,将指针置为NULL。
- 避免指针超出作用域,确保指针在使用期间有效。
- 在使用指针之前,进行有效性检查,确保指针指向有效的内存地址。
- 避免对空指针进行解引用或者指针运算。
通过遵循这些指针使用原则,可以减少野指针的出现,提高程序的稳定性和安全性。
所以规范使用指针可为你的程序保驾护航。感谢收看,记得三联,摸摸哒!!!