刚开始学c的时候,最头疼的事情是编译总是通不过,郁闷的要死,只要编译通过了,就兴奋的要死。现在,最头疼的事情是什么呢,编译没问题,但是程序跑的时候会出现Segmentation fault!

这个东西非常的恼人,在还是菜鸟阶段不会用gdb的时候,实在解决不了就放弃了,或者用一些对内存管理没有要求的语言来曲线救国了,但是自从开始接触了gdb这类的调试语句之后,发现了出现

Segmentation fault的一些情况,以及解决的方法,写出来总结下:

Segmentation fault 本质就是内存错误,在c/c++语言里,就是指针错误,这个错误产生的原因是你错误的使用了内存,访问了你不该访问的东西,常见的可归类如下:

1.数组越界,你定义了一个大小为10的数组array[10],但是c是从0开始计数的,最后的数组元素是array[9],然后你去访问了a[10],这样就读到了一块不属于你的内存,结果出现了Segmentation fault.

当然,这个是最简单的错误。注意点就会解决。

2.指针的问题。指针本质就是一个数字,IA32下就是一个4字节32位的数字,类似0xAB0011FF这个样子的,如果是x86-64位下的话,就是类似于0xAABBCCDDEEFF0011这种类型8字节64位的,这个数字表示

的是一个内存地址,计算机根据这块内存地址找到内存为此地址的内容,根据其类型读取。这里特别说一下NULL指针,在gdb里,你可以看到NULL实际上就是0x0,当然,前面有其类型,比如(void*) 0x0,这个样子的,

所以,如果你解引用这个NULL指针,其实就是要求计算机去访问内存为0的地址,结果可想而知。当然,有些人觉得自己没蠢到去解引用这个地址,当然,通常情况下这个错误不是这么直接的,但是本质确是一样的,我

举个具体的例子你感受下:

void changept(int* cpt){

  cpt=0x48;

  printf("in function,the pointer is: %x\n",cpt);

}

int main(){

  int *s=0x20AB;

  *s=0x332A;

  printf("before calling function,the pointer is: %x\n",s);

  changept(s);

  printf("after calling function,the pointer is: %x\n",s);

  return 0;

}

能想像出答案是什么吗,在函数changept中,我们改变了指针cpt 的值,注意是指针本身的值,或者说是这个指针需要指向的地址,但是在函数调用之后,指针显示的地址还是没有改变,但是在函数调用中,我们发现指针的值变了。这当然是因为c语言本身的一个特性,函数是传值调用,你传进去一个指针,注意这个指针是个数字,比如例子中的0x20ab,结果函数在调用时复制了这个值给局部变量(这个局部变量是同类型指针),然后局部变量获得了0x20ab这个地址,接下来让局部变量去指向了新的地址0x48,函数调用结束后这个指针消失,但是原来的指针确还是指向原来的值。好,问题就出在这里,如果我要在函数中为这个指针分配一个内存,比如cpt=(int*)malloc(sizeof(int)*10);注意,从堆上分配的内存让这个局部指针指向了另一个地址,作为参数的指针实际上还是悬空的,没有指向新开辟的地址,如果程序员想用这个悬空指针(他可能认为已经获得了内存)去访问这个开僻的新内存,那么实际上他访问的还是原来的内存,这样就会造成指针的错误引用,造成Segmentation fault这样的错误。所以,不要在函数中改变指针本身的值

解决上述问题的方法很简单,把函数changept的参数改成(int** cpt),*cpt=0x48,调用的时候就是changept(&s). 结果就正确了. 为啥呢,这个很简单,你传进去的是存储这个指针的内存地址,也是个数字,比如0x88, 0x88所指向的内存空间里存储着这个指针0x20AB,然后呢,局部变量获得了0x88这个地址,也指向了指针0x20ab,解引用0x88,获取0x20ab的值,并改为0x48, 此时指向0x20ab的指针已经被修改了,于是函数调用后的结果也变了。这个时候,假如要为原来指向0x20ab的指针申请了新的地址,那么指针也就指向了新的地址,这个时候访问这段开辟出的地址就没有问题了。所以,要想改变指针的值,要给函数传入这个指针的地址,或者说是指向指针的指针。

3. 数值类型,尽量不要用unsigned这类无符号类型的整数,比如你申请一块地址,malloc(sizeof(int)*a),如果a=-1的话(IA32 下是 补码 表示0xFFFFFFFF,unsigned a 会导致这个数变成一个超大的数,当然这个数还是0xFFFFFFFF,但是作为无符号来解读的话就是一个超大的数了,是2^32-1这样一个数,堆上分配不出这么大的空间,导致程序出现意想不到的问题。此外,如果你的程序在一个循环内,如果用无符号的数去和类似负数之类的比,可能产生死循环或者内存越界。

4.字符串,其实主要就是注意,如果你用strlen之类的函数,记得分配内存的时候要加1,因为strlen不包含‘\0'在内,否则还会产生越界,造成segmentation fault.

其实以上问题避免了,应该会杜绝90%以上的段错误,但是,更本质的是,你应该多学习计算机底层的机制,毕竟,c的强大就是它既有高级语言的便捷,也有底层语言的强大,而了解指针也就相当与掌握了c语言的核心,终将帮助你提高自身的编程修养!

论Segmentation fault的更多相关文章

  1. Caffe Python MemoryDataLayer Segmentation Fault

    转载请注明出处,楼燚(yì)航的blog,http://home.cnblogs.com/louyihang-loves-baiyan/ 因为利用Pyhon来做数据的预处理比较方便,因此在data_l ...

  2. php php-5.6.4.tar.bz2 apache 兼容问题 child pid 27858 exit signal Segmentation fault

    环境 [root envirotar]# uname -a Linux i2..el6.x86_64 # SMP Thu Jul :: UTC x86_64 x86_64 x86_64 GNU/Lin ...

  3. Segmentation fault (core dumped)

    问题: 在Linux中实现快速排序时,没有加入终止条件,结果出现Segmentation fault (core dumped)这个问题,Segmentation fault (core dumped ...

  4. centos yum Segmentation fault 问题解决办法

    今儿在centos 使用yum 安装软件时出现了 ”Segmentation fault“ 错误提示,google一大把执行 yum clean all 命令后,再执行还是没用,最后把 zlib.x. ...

  5. 内存分配与Segmentation fault

    为了方便使用,我做了如下结构体的嵌套使用: struct operation{ int num; char name[100]; char owner[100]; char msg[100];}; s ...

  6. qt 单文档程序关闭时在delete ui处出现segmentation fault

    做了个显示图片的单文档程序. qt 单文档程序关闭时在delete ui处出现segmentation fault. 调试发现调用两次mainwindow析构函数. http://blog.csdn. ...

  7. linux Ubuntu(Segmentation fault)段错误出现原因及调试方法

      在linux下编译了一个程序,尝试运行的时候出现: Segmentation fault (core dumped) 初步确认为...完全不知道是什么玩意. 于是找度娘了. ----------- ...

  8. 记一次PHP“Segmentation fault”调试经历

    遇到的问题: 在linux上安装php5.5.26.phalcon2.0扩展.xhprof扩展,均正常安装,并可单独运行.但放在一起运行时出现“Segmentation fault”错误.注:xhpr ...

  9. segmentation fault

    今天在hanoi问题上出现了segmentation fault 在gcc编译的过程中 没出现error,然而程序运行到一半就出现segmentation fault: 上网发现 这条语句是非法的内存 ...

随机推荐

  1. Maven私有仓库搭建和使用

    下载和安装 下载地址: http://www.sonatype.com/nexus-repository-oss 安装: Linux版的无需安装,直接解压即可,然后进入bin目录下,运行./nexus ...

  2. 安装中文版cacti监控华为交换机流量并实现95计费

    摘要:一. 装置yum源: 以网易yum源为例 1. 下载repo文件 下载地点:http://mirrors.163.com/.help/CentOS6-Base-163.repo 2.备份并调换体 ...

  3. HBase内部操作日志说明

    版本:0.94-cdh4.2.1 1. Split Region [regionserver60020-splits-1397585864985] INFO org.apache.hadoop.hba ...

  4. Vs2015智能提示英文?

    Vs2015智能提示英文? 装了vs2015代码的智能提示全部变成英文了   找到这个目录 C:\Program Files (x86)\Reference Assemblies\Microsoft\ ...

  5. linux 网卡启动方法

    CentOS 7默认的网卡名称是eno16777736 一般人的是 eth0 编辑配置文件 vi /etc/sysconfig/network-scripts/ifcfg-eno16777736把 O ...

  6. Tomcat服务相关

    1. 将Tomcat安装成服务. 找到bin\service.bat文件,往cmd命令行窗口一拉,如果只提示service /remove [../..]那就是Tomcat和java的路径配置没问题. ...

  7. 帝国cms 页面统计

    <script src=[!--news.url--]e/public/ViewClick/?classid=[!--classid--]&id=[!--id--]&addcli ...

  8. 在windows编译MariaDB

    OS: Windows XP sp3 IDE: VS2010 MariaDB: V5.5 (到目前为止2016.5,中文域(.cn)只有清华大学 TUNA 镜像源可用) (.tar.gz为源码:.zi ...

  9. MySQL数据库(表)的导入导出(备份和还原)

    一)在同一个数据库服务器上面进行数据表间的数据导入导出: 1. 如果表tb1和tb2的结构是完全一样的,则使用以下的命令就可以将表tb1中的数据导入到表tb2中: insert into db2.tb ...

  10. 用Python遍历目录

    用Python遍历指定目录下的文件,一般有两种常用方法,但它们都是基于Python的os模块.下面两种方法基于Python2.7,主要用到的函数如下: 1.os.listdir(path):列出目录下 ...