Segmentation fault (core dumped)(段错误)

 

编程中通常碰到段错误的地方有哪些?  

粗略的分一下类 
 
(1)往受到系统保护的内存地址写数据 
 
    有些内存是内核占用的或者是其他程序正在使用,为了保证系统正常工作,
所以会受到系统的保护,而不能任意访问。 

例子1:

1       #include <stdio.h>
2
3       int main()
4       {
5               int i=0;
6
7               scanf("%d",i);
8               printf("i=%d\n");
9               return 0;
10      }

编译和执行一下

      $ gcc -o test test.c
      $

编译通过

执行

      $ ./test
        1
        Segmentation fault (core dumped)

输入1,报告段错误

        咋一看,好像没有问题哦,不就是读取一个数据然后给输出来吗?  
下面我们来调试一下,看看是什么原因?

      

$ gcc -g -o test test.c        --加-g选项查看调试信息 $ gdb ./test
(gdb) l                    --用l(list)显示我们的源代码
1 #include <stdio.h>
2
3 int main()
4 {
5 int i=0;
6
7 scanf("%d",i);
8 printf("i=%d\n");
9 return 0;
10 }
(gdb) b 7              --用b(break)设置断点
Breakpoint 1 at 0x400543: file test1.c, line 7.
(gdb) r                  --用r(run)运行,直到断点处
Starting program: /home/etk/cpp/test1
Breakpoint 1, main () at test1.c:7
7 scanf("%d",i);
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.80.el6_3.5.x86_64
(gdb) p i               --用p(print)打印变量i的值[看到没,这里i的值是0哦      
$1 = 0
(gdb) n                 --用n(next)执行下一步
1
Program received signal SIGSEGV, Segmentation fault.
0x004e3d45 in _IO_vfscanf_internal (s=0x31,
    format=0xffffffff <Address 0xffffffff out of bounds>, argptr=0x0,
    errp=0xb) at vfscanf.c:1772
1772 *ARG (unsigned int *) = (unsigned int) num.ul;
(gdb) c                 --用c(continue)继续执行
Program terminated with signal SIGSEGV, Segmentation fault.
The program no longer exists.
(gdb) q                --退出gdb 


果然 “不小心”把&i写成了i 
而我们刚开始初始化了i为0,这样不是试图向内存地址0存放一个值吗?实际上很多情况下,即使没有初始化为零,默认也可能是0,所以要特别注意。  

 

例子2:

  1 #include "stdio.h"
  2
  3 int main()
  4 {
  5         char *p;
  6         p=NULL;
  7         *p='a';
  8         printf("%c",*p);
  9         return 0;
 10 }

 $ gcc -g -o test test.c

例子3:

  1 #include "stdio.h"
  2
  3 int main()
  4 {
  5         char test[1];
  6
  7         printf("%c",test[1000000000]);
  8         return 0;
  9 }

 $ gcc -g -o test test.c

例子4:

  1 #include "stdio.h"
  2
  3 int main()
  4 {
  5         int b=10;
  6
  7         printf("%s\n",b);
  8
  9         return 0;
 10 }


试图把一个整数按照字符串的方式输出出去,这是什么问题呢? 由于还不熟悉调试动态链接库,所以 只是找到了printf的源代码的这里

声明部分: 

      int pos =0 ,cnt_printed_chars =0 ,i    unsigned char *chptr    va_list ap  %s格式控制部分: case 's': 
      chptr =va_arg (ap ,unsigned char *);       i =0  
      while (chptr [i ])       {... 
          cnt_printed_chars ++;           

          putchar (chptr [i ++]); 

      } 

        仔细看看,发现了这样一个问题,在打印字符串的时候,实际上是打印某个地址开始的所有字符,但是当你想把整数当字符串打印的时候,这个整数被当成了一个地址,然后printf从这个地址开始去打印字符,直到某个位置上的值为\0。所以,如果这个整数代表的地址不存在或者不可访问,自然也是访问了不该访问的内存segmentation fault。

  
类似的,还有诸如:sprintf等的格式控制问题 
比如,试图把char型或者是int的按照%s输出或存放起来,如: 
#include <stdio.h> #include <string.h> 
char c=‟c'; int i=10; char buf[100]; 
  
printf(”%s”, c); //试图把char型按照字符串格式输出 

printf(”%s”, i); //试图把int型按照字符串输出 
memset(buf, 0, 100); 
sprintf(buf, “%s”, c); //试图把char型按照字符串格式转换 
memset(buf, 0, 100); 
sprintf(buf, “%s”, i); //试图把int型按照字符串转换 

其他 :
  
其实大概的原因都是一样的,就是段错误的定义。 
但是更多的容易出错的地方就要自己不断积累,不段发现,或者吸纳前人已经积累的经验,并且注意避免
再次发生。 
  例如:   
<1>定义了指针后记得初始化,在使用的时候记得判断是否为NULL <2>在使用数组的时候是否被初始化,数组下标是否越界,数组元素是否存在等 
<3>在变量处理的时候变量的格式控制是否合理等 
  

如何发现程序中的段错误? 
  
有个网友对这个做了比较全面的总结
文章名字叫《段错误bug的调试》 
地址是:http://www.cublog.cn/u/5251/showart.php?id=173718 
应该说是很全面的。 
  
常用的调试方法有: 
  
(1)在程序内部的关键部位输出(printf)信息,那样可以跟踪 段错误 在代码中可能的位置 
  
为了方便使用这种调试方法,可以用条件编译指令#ifdef DEBUG和#endif把printf函数给包含起来,编译
的时候加上-DDEBUG参数就可以查看调试信息。反之,不加上该参数进行调试就可以。 
  
(2)用gdb来调试,在运行到段错误的地方,会自动停下来并显示出错的行和行号 
  
这个应该是很常用的,如果需要用gdb调试,记得在编译的时候加上-g参数,用来显示调试信息 对于这个,网友在《段错误bug的调试》文章里创造性的使用这样的方法,使得我们在执行程序的时候就
可以动态扑获段错误可能出现的位置: 
通过扑获SIGSEGV信号来触发系统调用gdb来输出调试信息。 
如果加上上面提到的条件编译,那我们就可以非常方便的进行段错误的调试拉。 

 

(3)还有一个catchsegv命令 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值