参考链接

https://blog.csdn.net/xuleilx/article/details/7365424

http://www.blog.chinaunix.net/uid-28414100-id-5759543.html

https://blog.csdn.net/weixin_40005437/article/details/111210315

https://baike.so.com/doc/4335071-4539876.html

一、段错误的概念

存储器区段错误(英语:Segmentation fault,经常被缩写为segfault),又译为存储器段错误,也称访问权限冲突(access violation),是一种程序错误。

它会出现在当程序企图访问CPU无法寻址的存储器区段时。当错误发生时,硬件会通知操作系统产生了存储器访问权限冲突的状况。操作系统通常会产生核心转储(core dump)以方便程序员进行调试。通常该错误是由于调用一个地址,而该地址为空(NULL)所造成的,例如链表中调用一个未分配地址的空链表单元的元素。数组访问越界也可能产生这个错误。(摘抄自wiki)

段错误就是指访问的内存超出了系统所给这个程序的内存空间,通常这个值是由gd tr来保存的,他是一个48位的寄存器,其中的32位是保存由它指向的 gdt表,后13位保存 相应于gdt的下标,最后3位包括了程序是否在内存中以及程序的在cpu中的运行级别,指向 的gdt是由以64位为一个单位的表,在这张表中就保存着程序运行的代码段以及数据段的起 始地址以及与此相应的段限和页面交换还有程序运行级别还有内存粒度等等的信息。(摘自360百科)

二、编程中常遇到段错误的地方有那些

1. 指针指向非法内存

定义了指针变量,但是没有为其分配内存,即指针没有指向一块合法的内存。这里列举几个比较隐蔽的例子。

1.1 结构体指针变量的定义和引用错误

#include <stdio.h>struct student
{char *name;int score;
}stu,*pstu;int main()
{strcpy(pstu.name,"Jimy");stu.score = 99;return 0;
}

这里的pstu只是一个结构体指针,并没有分配具体的内存。

直接去引用pstu当然会出错。

关于结构体变量的定义可以查看我之前的一篇文章

1.2 结构体内部指针变量处理错误

还是上面的例子,稍作修改

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>int main(void)
{struct student{char *name = (char *)malloc(sizeof(char) * 10);int score;}stu, *pstu;pstu = (struct student*)malloc(sizeof(struct student));strcpy(pstu->name, "Jimy");pstu->score = 99;free(pstu); system("pause");return 0;
}

这里其实涉及到另外一个问题:

结构体在定义的时候,是不能在结构体内部赋值的。

所以这里的name指针虽然在结构体定义时已经分配空间,但是实际编译时,编译器不会执行后面malloc分配空间的操作。

解决方法:在外面手动分配内存

pstu->name = (char *)malloc(sizeof(char *)* 10);

2. assert校验指针参数

assert宏的使用说明:

1. assert是一个宏,而不是函数。

2. assert(表达式)。如果表达式中的值为假,则程序停止运行,并提示出错。若为真,则继续运行。

3. assert只在Debug版本起作用,Release版本被编译器优化掉。

当函数使用指针作为参数的时候,在函数入口处使用 assert(p == NULL)进行校验。当然这有一个要求,就是p在定义的时候已经初始化为NULL。

比喻上面1.2中的示例,因为name指针并没有被初始化为NULL,其内部是一个非NULL的乱码,即使校验也没有作用。

2. 指针分配内存太小

为指针分配了内存,但是内存大小不够,导致出现越界错误。

char *p1 = “abcdefg”;
char *p2 = (char *)malloc(sizeof(char)*strlen(p1));
strcpy(p2,p1);

p1 是字符串常量,其长度为7 个字符,但其所占内存大小为8 个byte。初学者往往忘了字符串常量的结束标志“\0”。这样的话将导致p1 字符串中最后一个空字符“\0”没有被拷贝到p2 中。解决的办法是加上这个字符串结束标志符:

char *p2 = (char *)malloc(sizeof(char)*strlen(p1)+1*sizeof(char));

3. 分配内存,但并未初始化

4. 内存越界

内存分配成功,且已经初始化,但是操作越过了内存的边界。这种错误经常是由于操作数组或指针时出现“多1”或“少1”。比如:

int a[10] = {0};for (i=0; i<=10; i++)
{a[i] = i;
}

5. 内存释放之后

既然使用free 函数之后指针变量p 本身保存的地址并没有改变,那我们就需要重新把p的值变为NULL:  p = NULL; 这个NULL 就是我们前面所说的“栓野狗的链子”。如果你不栓起来迟早会出问题的。比如:在free(p)之后,你用if(NULL != p)这样的校验语句还能起作用吗?例如:

char *p = (char *)malloc(100);
strcpy(p, “hello”);
free(p); /* p 所指的内存被释放,但是p 所指的地址仍然不变*/
…if (NULL != p)
{/* 没有起到防错作用*/strcpy(p, “world”); /* 出错*/
}

释放完块内存之后,没有把指针置NULL,这个指针就成为了“野指针”,也有书叫“悬垂指针”。这是很危险的,而且也是经常出错的地方。所以一定要记住一条:free 完之后,一定要给指针置NULL。同时留一个问题:对NULL 指针连续free 多次会出错吗?为什么?如果让你来设计free函数,你会怎么处理这个问题?

6. 内存已经释放了,但是继续通过指针使用

这里一般有三种情况:

第一种:就是上面所说的,free(p)之后,继续通过p 指针来访问内存。解决的办法就是给p 置NULL。

第二种:函数返回栈内存。这是初学者最容易犯的错误。比如在函数内部定义了一个数组,却用return 语句返回指向该数组的指针。解决的办法就是弄明白栈上变量的生命周期。

第三种:内存使用太复杂,弄不清到底哪块内存被释放,哪块没有被释放。解决的办法是重新设计程序,改善对象之间的调用关系。

三、如何发现程序中的段错误并处理

1.以一段简单的code来重现core dump错误

#include <stdio.h>int main(void)
{int *p = NULL;printf("%d\n", *p);return 0;
}

编译运行,看到Segmentation fault了

再执行ls看下,此时并没有看到core dumped文件,问题在哪?

问题在于需要需要系统参数设置

ulimit -c 1024

再去运行刚才的.out文件就可以看到core dump文件了。

2. 通过gdb查看分析core dump文件

运行gdb命令查看core文件

gdb -c core ./a.out

这时候就可以找到错误的原因了。

四、利用backtrace和objdump分析段错误

之后在更新吧。。。。今天太晚了

【C语言】 --- 段错误相关推荐

  1. [转] Linux C语言 段错误bug的调试

    原来看过一次,后来当自己有段错误的时候,才想起来这个很有用.如果不用他的方法,段错误很恶心的,不好找出来的. 下面就是原文,不过 最初出处不得而知 ======================= 复制 ...

  2. c语言 段错误 指针,求教为什么指针动态申请了空间,scanf的时候还会段错误

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 while(1) { printf("是否要创建新一条学生信息?(y/n)\n"); scanf("%s",ch) ...

  3. pta c语言段错误,PTA常见错误

    1.最常犯的错误:格式错误. 在PTA程序检测中,输入输出要严格按照题目要求.输出的格式要完全按照题目要求来,该空格地方空格,该换行要换行.否则,就算你运行结果是对的,PTA还是提示你格式错误 格式错 ...

  4. c语言 段错误 核心已转移,c语言使用DES_ncbc_encrypt以及段错误 (核心已转储) 解决...

    1.首先安装ssl库文件 sudo apt-get install libssl-dev 引入头文件 #include 2.定义调用方法 void call_cbc(){ DES_cblock key ...

  5. c语言 memset 段错误,段错误之memset对类对象的误用

    1.问题描述 实际项目中,定义一个如下的基类和子类,均包含有虚函数. //基类 class OriginalTask { public: OriginalTask() {}; virtual ~Ori ...

  6. Rust语言——无虚拟机、无垃圾收集器、无运行时、无空指针/野指针/内存越界/缓冲区溢出/段错误、无数据竞争...

    2006年,编程语言工程师Graydon Hoare利用业余时间启动了Rust语言项目.该项目充分借鉴了C/C++/Java/Python等语言的经验,试图在保持良好性能的同时,克服以往编程语言所存在 ...

  7. linux c代码出现段错误,Linux下段错误(C语言)

    问题描述:在Linux下编程有时会出现段错误的提醒,出现这种错误有可能是因为以下几种原因 1.数组越界:如果在初始化或者接收输入时内容超过了定义好的数组元素个数时会出现段错误,Linux的数组越界检查 ...

  8. c语言fscanf 发生段错误,亚嵌教育

    亚嵌教育 46期C语言复习串讲课堂笔记 (2012-2-20) 知识点汇总 (以下知识点内容基本按照<一站式编程>章节顺序) 程序概念 指令 (代码段) 函数调用 printf() 运算( ...

  9. 约瑟夫环c语言出现段错误,算法竞赛入门经典 紫书 第四章

    一点小问题 关于判断素数的几点 //该函数有严重缺点: //不能用于n==1和n较大的情况 //在n接近int的最大值时: //若i=46340时,i*i=2147395600//若i=46341时, ...

  10. C语言再学习 -- 段错误(核心已转储)

    参看:Linux下的段错误产生的原因及调试方法 参看:Linux环境下段错误的产生原因及调试方法小结 参看:维基百科--Segmentation fault 参看:LINUX内核段错误调试详细指南精品 ...

最新文章

  1. 《数据分析实战 基于EXCEL和SPSS系列工具的实践》一3.4 数据量太大了怎么办
  2. [Winform]检测exe是否已经运行,并将其置顶
  3. 这家研究院太年轻,竟跟世界级选手“叫板”
  4. 巧用脚本为木马“整容”
  5. java 时间工具类 大于_Java 时间工具类
  6. P4381 [IOI2008]Island
  7. mysql 修改编码不成功解决办法
  8. 通过shell发送邮件
  9. Badboy录制测试脚本
  10. 工厂方法与抽象工厂模式的区别
  11. WEB应用支持RESTFUL风格方法
  12. matlab 计算hog特征,Matlab计算图像HOG特征
  13. CAD制图初学入门:CAD软件中属性定义的相关应用
  14. pc安装android,在电脑上安装安卓的过程
  15. android textview字体为宋体,安卓开发--textView的字体样式设置(设置宋体,微软雅黑等)...
  16. SQL注入入侵动网站(MSSQL)
  17. AV1代码学习:encoder_encode函数
  18. Altium Designer系列:添加泪滴
  19. applecare多少钱?_AppleCare和AppleCare +有什么区别?
  20. Bibilibili 1024程序员节 CTF 启蒙

热门文章

  1. 2023届计算机毕业设计源码
  2. Tomcat之—— linux/centos 解决Tomcat内存溢出
  3. SM951 NVMe 版本安装Win7 的正确方法
  4. 基于Selenium的Web UI自动化实现(java)
  5. 邢山虎:指责加班是特定时期的悖论,历史将予以澄清
  6. Apizza 升级了,更好的 api 接口管理和文档编写,欢迎大家访问吐槽!!
  7. ascll码表 ASCALL码表
  8. 2017全国省市区县 json数据
  9. 太阳时的计算的Python程序
  10. 【激光雷达】激光雷达点云数据的技术流程和点云预处理的方法