野指针的三种类型
1)指针变量没有被初始化。任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的,它会乱指一气。所以,指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存。
char *p; //此时p为野指针
2)指针p被free或者delete之后,没有置为NULL,让人误以为p是个合法的指针。
char *p=new char[10]; //指向堆中分配的内存首地址,p存储在栈区
cin>> p;
delete []p; //p重新变为野指针
3)指针操作超越了变量的作用范围。
char *p=new char[10]; //指向堆中分配的内存首地址
cin>> p;
cout<<*(p+10); //可能输出未知数据
常见问题
1)指针指向常量存储区
char *p="abc";
p指向的是一个字符串常量,不能对*p的内容进行写操作,如srtcpy(p,s)是错误的,因为p的内容为“abc”字符串常量,该数据存储在常量存储区,但可以对指针p进行操作,让其指向其他的内存空间。
2)资源泄露
#include<iostream>
using namespace std;
void main()
{
char *p=new char[3]; //分配三个字符空间,p指向该内存空间
p="ab"; //此时p指向常量“ab”,而不再是new char分配的内存空间了,从而造成了资源泄漏
delete []p; //释放时报错
}
此时运行会直接卡死
改进方案:
#include<iostream>
using namespace std;
void main()
{
char *p=new char[3]; //分配三个字符空间,p指向该内存空间
strcpy(p,"ab"); //将"ab"存储到p指向的内存空间
delete []p; //释放时报错
}
3)内存越界
char *p=new char[3]; //分配三个字符空间,p指向该内存空间
strcpy(p,"abcd"); //将abcd存处在分配的内存空间中,由于strlen("abcd")=4>3,越界
delete []p; //ok
4)返回值是指针
#include<iostream>
using namespace std;
char *f()
{
char p[]="abc";
return p;
}
void main()
{
cout<<f()<<endl;
}
数组p[]中的内容为“hello world”,存储在栈区,函数结束时内容被清除,p变为野指针,可能导致乱码
改进方案1:加static限定,延长数组生存期
#include<iostream>
using namespace std;
char *f()
{
static char p[]="abc";//此时数组为静态数组,存储在全局/静态区,生存期到程序结束,因此函数结束时不会销毁p
return p;
}
void main()
{
cout<<f()<<endl;
}
改进方案2:定义成指针型数组
#include<iostream>
using namespace std;
char *f()
{
char *p="abc";//"abc"存储在文字常量区,p是指向常量的指针,生存期到程序结束
return p;
}
void main()
{
cout<<f()<<endl;
}
改进方案3:动态分配存储空间,存储在堆区
#include<iostream>
using namespace std;
char *f()
{
char *p=new char[5]; //动态分配存储空间,p指向堆区
strcpy(p,"abc"); // 这里不能用p="abc",前面已经说明
return p;
}
void main()
{
cout<<f()<<endl;
}