段错误产生原因

        嵌入式C开发,或多或少都遇到段错误(segmentation fault )。

        段错误(Segmentation fault)是一种运行时错误,在程序运行时可能由于某些原因而发生。

        下面是一些典型的段错误产生的原因:

  • 访问不存在的内存地址

  • 访问只读的内存地址

  • 栈溢出

  • 内存越界

  • 当尝试释放已释放的内存(使用指针)时,也可能发生分段错误错误

  • ……

实例

        1. 访问不存在的内存地址

#include <stdio.h>

int main(int argc, char **argv)
{
    printf("==================segmentation fault test==================\n");

    int *p = NULL;
    *p = 1234;

    return 0;
}

      2. 访问只读的内存地址

#include "stdio.h"
#include <stdlib.h>
#include "string.h"
void main()
{
	printf("==================segmentation fault test==================\n");
	char Data[] = "qwertyuiop";
	char *data = NULL;	//即使初始化为空,指针data可能是指向了一个只读的内存:memcpy执行失败,造成空指针解引用(空指针间接引用)
	memcpy (data,Data,sizeof(Data));	//引用空指针
	printf ("data is %s.\nand sizeof(Data) is %d.\n", data, sizeof(Data));
	free(data);
	data = NULL;
}
#include <stdio.h>

int main(int argc, char **argv)
{
    printf("==================segmentation fault test==================\n");

    char *str = "hello";
    str[0] = 'H';

    return 0;
}

         3. 栈溢出  

        程序的有效内存还可以再分为多个区域,每个区域都有不同的作用,比如代码区、全局数据区、堆区、栈区、动态链接库区等。栈就是这些内存分区中的一个。

        那么,栈是用来做什么的呢?整个内存都是用来存储数据的,栈也不例外。栈用来存储程序的局部数据。

        对于C/C++来说,局部数据是指在函数内部定义的数据,例如在函数内部定义的变量、指针、参数、结构体、数组、对象、引用等,它们都要保存到栈中。

        栈为什么会溢出?

        对每个程序来说,栈能使用的内存是有限的,一般是 1M~8M,这在编译时就已经决定了,程序运行期间不能再改变。如果程序使用的栈内存超出最大值,就会发生栈溢出(Stack Overflow)错误,程序就崩溃了。

#include <stdio.h>

static void test(void)
{
    char buf[1024 * 1024] = {0};    //每次递归均会分配存储区
    static int i = 0;
    i++;
    printf("i = %d\n", i);
    test();    //递归
}

int main(int argc, char **argv)
{
    printf("==================segmentation fault test==================\n");

    test();

    return 0;
}

        什么情况下才会发生栈溢出呢?

        最常见的就是递归。每次递归就相当于调用一个函数,函数每次被调用时都会将局部数据(在函数内部定义的变量、参数、数组、对象等)放入栈中。

        递归1000次,就会将1000份这样的数据放入栈中。这些数据占用的内存直到整个递归结束才会被释放,在递归过程中只会累加,不会释放。如果递归次数过多,并且局部数据也多,那么会使用大量的栈内存,很容易就导致栈溢出了。

        4. 内存越界

#include <stdio.h>

int main(int argc, char **argv)
{
    printf("==================segmentation fault test==================\n");

    static char arr[5] = {0, 1, 2, 3, 4};

    printf("arr[10000] = %d\n", arr[10000]);    //访问下标超出了数组长度

    return 0;
}

        5. 当尝试释放已释放的内存(使用指针)时,也可能发生分段错误错误

#include "stdio.h"
#include <stdlib.h>
#include "string.h"
void main()
{
	char Data[] = "qwertyuiop";
	char *data = NULL;
	data = (char *) malloc(12);
	if(data == NULL)
		return;
	memcpy (data,Data,sizeof(Data) );
	printf ("data is %s.\nand sizeof(Data) is %d.\n", data, sizeof(Data) );
	free(data);
	data = NULL;	//data = NULL;
	free(data);
}

        1)交叉编译环境:data = NULL;存在与不存在时结果:均正确,不会产生段错误

        2)windows编译环境:data = NULL;存在与不存在时结果:均正确,不会产生段错误

        3)gcc编译环境: data = NULL;存在时:正确;不存在时:错误,会产生段错误

        1)多次释放的指针为空指针:释放空指针其实也等于啥也没做,所以释放空指针释放多少次都没有问题。
        2)多次释放的指针不为空指针:产生段错误。(gcc环境会报错,windows环境和交叉编译环境运行正常)

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值