最近在腾讯,百度等的面试中被问到了上面某个或几个问题,我这人一碰到笔试面试什么鬼的就是紧张,然后就乱说话,其实很多东西我知道,只是表达不清,也许自己没有去整理,所以其实大脑中概念不清晰,今天梳理一下,用自己的语言来描述下这些概念:
1.野指针
比如说吧:
int main(){
int *a=new int[6];
a[2]=99;
int *b =a;
cout<<a[2]<<endl;
cout<<b[2]<<endl;
delete []a; //释放了a指向的空间
cout<<b[2]<<endl; //此时b指向的内存已经释放了,b仍然使用,b指向未知区域
return 0;
}
输出:
99
99
0x22fe48
0x22fe40 //此时b的地址不是原来的地址了,而是未知的,看到反而是在低位地址
3932504
当程序运行时是作为一个进程,一个进程有自己的虚拟空间,低地址是程序代码和数据,然后是运行时堆,再然后是共享库(标准库之类的)然后是栈空间,用于函数局部调用时
此时b指向了低位的进程地址,此时操作野指针b读取可能不报错,但是一旦写数据,程序就奔溃了
在没有保护措施的情况下随意修改进程地址数据是很危险的,一般高位的OS内核地址都是进行保护的。
2.内存泄露
给出一段程序来说明,
void func(){
int *a = new int(10000);
....
}
void main(){
while(condition1){
func();
}
}
在main函数循环调用func,不断的分配内存空间,而且你要知道完全由你掌控,想分配多少就多少,但是你没有delete,OS认为这是你的事,然后不释放一直分配直到
内存耗尽程序崩掉,如果os没能kill掉,就会卡死。。死机了。。,
3.缓存区溢出
其实感觉跟那个野指针也类似但产生原因是不一样的
来看看危险的gets函数
char *gets(char *s)
{
int c;
char *dest =s;
while((c=getchar())!=' ' &&c!=EOF) *dest++=c;
*dest++=' '
if(c == EOF)
return NULL;
return s;
}
void echo()
{
char buf[4];
gets(buf);
puts(buf);
}
上面的buf很小,当你键盘输入很大的时候,没有办法确定为保存整个
字符串分配了足够的空间,所以你使用gets时候,很容易就对非法地址写入了
数据,而按照顺序表连续分配,你写入的是进程内高位地址的数据,这时你如果改写了其他的数据,如下一条指令的
地址,就会造成程序严重的错误,如果是执行了恶意代码,那你就被入侵了
4.栈溢出
其实很上面基本是一致的,这里用另一个代码来说明栈溢出
要知道栈空间是很小的,大概1MB左右,视不同的编译器不同。
所以如果在函数内,定义这种代码 int a[100000][10000000],一旦运行到该函数就会崩掉
比如你写了一堆函数,这个函数在最后运行,然后崩了,如果你不懂,你才不会考虑到是栈
溢出造成的错误,你会认为这个函数实在没有逻辑错误,最终你在其他函数上找原因,然后
这不是相当于过滤掉了特务。。。。所以程序员基础要打好