1.野指针和空指针
把这两个放在一起,是因为这个实在是没有什么重要的知识点,还是先看一下吧。
int main()
{
int *p;
int *p1=nullptr;
return 0;
}
指针p为野指针,也就是说在定义一个指针时没有初始化为nullptr,那么这个指针会指向一个随机地址,这就是野指针,野指针是非常危险的。
p1在我们定义的时候初始化为空,p1就是一个空指针。
注意我这里用的是nullptr,不是NULL,nullptr在C++中是专门为了初始化或赋值一个指针为空时用的关键字,为什么不用NULL呢?这里简单说一下,本专栏后期会专门有一期文章介绍C++中nullptr。
在C语言编译器中,NULL的定义为#define NULL 0或者#define NULL (void*)0;NULL是根据宏定义的字面常量0或者无类型指针0常量,那么这种情况有时候会导致二义性,这里就不举例子了,后期文章可以仔细去看一下,为了解决这种情况,在C11中标准中,处于兼容性的考虑,字面常量0的二义性并没有消除,但标准还是为二义性给出了新的答案,就是nullptr(一个所谓“指针空值类型”的常量)。
2.失效指针
失效指针是本章的一个重点,那么什么是失效指针呢?我们来举例说明:
int main()
{
int *r=(int *)malloc(sizeof(int));
*r=100;
free(r);
r=nullptr;
return 0;
}
free完之后,我们的指针r就是一个失效指针,此时我们再通过r去访问malloc申请来的空间,就会报错,因为free之后,说明我们的指针r和堆区已经没有关系了,但是我们的指针r还是指向堆区的那块空间,所以为了安全起见,我们free完之后,都会将指针置为空。
同理,还有哪些情况是类似于free之后变成了失效指针的情况呢?比如文件的打开和关闭,fclose()。
接下来看这种情况:
int *fun()
{
int a=10;
return &a;
}
乍一看,感觉这个代码没什么问题,其实是有很大的安全问题的,我们现在再主函数中调用一下。
int main()
{
int* p = fun();
printf("%d", *p);
return 0;
}
结果:
这不是很正确嘛?我们再来加一段代码
int* fun()
{
int a = 10;
return &a;
}
void arr()
{
int brr[100] = { 0 };
}
int main()
{
int* p = fun();
arr();
printf("%d", *p);
return 0;
}
在调用完fun函数时,再调用一下arr函数,此时的结果确变成了0;
这是因为调用fun函数时,栈需要给fun函数开辟栈帧,里面存放变量a,值为10,等fun函数结束后这部分栈需要归还系统,在主函数调用后打印出来的只不过是残留值 ,指针p还指向原来变量a的地址,当我们调用arr函数后,arr栈帧里面有brr这个数组,大小为100个,值全为0,brr会把原来的残留值冲洗掉,再打印时发现p指向的地址空间被冲洗掉成立0。
所以我们不可以轻易将函数中的局部变量以指针或引用方式返回。
以下这三种情况才可以:
int g_max=0;//全局变量可以以指针返回
int *fun(int *p)
{
static int a=10;//静态局部变量可以以指针返回
retunr p;//函形参是一个指针可以以指针返回
}