概述
我们运行程序时经常会遇到异常崩溃,也就是我们常说的crash,下面我想总结一下crash出现的原因。而导致crash的主要原因就是段错误(Segmentation Fault)是不是很熟悉,相信每个运行过C程序的小伙伴都见过这两个单词,而且这种错误一般不给其他提示,看着很纠结。导致段错误的原因一般有
1.尝试访问我们系统中不存在的内存位置
2.试图在只读存储位置上进行写操作。
第一种原因就是字面意思,我想也不用解释了吧,比较常见一种情况是对空指针的读取操作。我们来看下第二种,举个小例子:
int main()
{
char *str = "crash";
*(str+1) = 'n';
return 0;
}
执行上面的代码就是报错:Segmentation fault (core dumped)
在代码中我们定义了字符串常量str,然后我们试图在字符串中加入一个字母n。我们知道字符串在内存中是作为常量保存的,就类似于数字0.1.2…,假设把“crash”看做数字0,n看做1,上面的行为就类似于给数字本身赋值,0 = 1,我们知道这种赋值是非法的。
3.试图访问受保护的内存位置, 例如内核内存
4.内存耗尽
4.1 堆栈溢出:发生不终止的内存位置递归的情况。
#include<stdio.h>
void fun(int x)
{
if (x == 1)
return;
x = 6;
fun(x);
}
int main()
{
int x = 5;
fun(x);
}
4.2 内存泄漏:
如果我们通过某个程序动态申请一些内存,但是用完后没有及时释放。当下次我们再调用这个程序时又会申请一次内存(请注意因为上一次申请的内存没有释放,所以我们以为只是使用第二次申请的内存,但是系统会认为两次申请的内存我们都在使用,因此第一次申请的内存还是处于被占用状态)多次调用程序之后,内存就会被耗尽,就会出现动态申请内存失败,程序就会crash。
int main()
{
for (int i=0; i<10000000; i++)
{
int *ptr = (int *)malloc(sizeof(int));
}
}
5.缓冲区溢出
相信越界这个词大家都听过,其中最为常见的就是数组越界。
#include <stdio.h>
int main()
{
char A[4] = "";
strcpy(A, "crash");
return 0;
}
这种情况会不会crash要看运气,对,你没看错是运气,谁也无法确定A后面的内存是什么,如果是不可写的,那你很幸运,它会立刻crash,你可以发现这个问题。如果是可写的,那你修改了该处的内存,造成内存破坏,那么有可能会等一段时间才在别处发生Crash,这时候你就会一头雾水或者改了一些本来正确的部分,它却还在这里逍遥法外。
所以处理数组时一定要格外小心,时刻关注有没有越界
1.所有数组遍历的循环,都要加上越界判断。
2.用下标访问数组时,要判断是否越界。
6.除以零
整数除以零默认的处理方式是终止进程
有点数学常识的都知道整数除以0是不允许的,在计算机中也是,这种情况其实出现的很少,但一旦出现,又很难被发现,所以
在做整数除法时,要判断被除数是否为0的情况。