找回密码
 立即注册
查看: 78|回复: 0

段错误产生原因及解决方法

[复制链接]

11

主题

0

回帖

43

积分

新手上路

积分
43
发表于 2022-9-10 11:19:52 | 显示全部楼层 |阅读模式
什么是段错误?
所谓的段错误 就是指访问的内存超出了系统所给这个程序的内存空间,通常这个值是由gdtr来保存的,他是一个48位的寄存器,其中的32位是保存由它指向的gdt表, 后13位保存相应于gdt的下标,最后3位包括了程序是否在内存中以及程序的在cpu中的运行级别,指向的gdt是由以64位为一个单位的表,一旦一个程序发生了越界访问,cpu就会产生相应的异常保护,于是segmentation fault就出现了
通过上面的解释,段错误应该就是访问了不可访问的内存,这个内存区要么是不存在的,要么是受到系统保护的。
下面是一些段错误例子:

1.访问不存在的内存地址
如下面代码,p没有申请空间就直接拷贝数据:
int main(int argc, char *argv[])
{
   char *p = NULL;
   strncpy(p, "abc", 3);//p没有申请空间就直接使用
   return 0;
}
2.访问只读的内存地址
错误做法:往字符串常量空间拷贝新的数据
int main(int argc, char *argv[])
{
    char *p = "test";
    strcpy(p, "TEST1");
    return 0;
}
3.访问系统保护的内存地址
int main(int argc, char *argv[])
{
    int *p = (int *)0;
    *p = 100;
    return 0;
}
4.栈溢出
int main(int argc, char *argv[])
{
    main(argc, argv);
}
5.内存越界(数组越界,变量类型不一致等)
int main()
{  
    char test[1];  
    printf("%c", test[1000000000]);  
    return 0;
}
这里是比较极端的例子,但是有时候可能是会出现的,是个明显的数组越界的问题
或者是这个地址是根本就不存在的
下面我给大家介绍两种常用的段错误调试方法
1.使用printf输出调试信息
这个是看似最简单但往往很多情况下是十分有效的调试方式,也许我们用的最多的调试方式。简单来说,就是在程序的重要代码附近加上printf输出信息,这样可以跟踪并打印出段错误在代码中最可能出现的位置。
以下面这段错误代码为例:
现在在代码中添加printf调试信息:
int main(int argc, char *argv[])
{
    printf("line:%d\n", __LINE__);  //单纯打印代码行数
    char *p = NULL;
  
    printf("line:%d\n", __LINE__);  //单纯打印代码行数
    strncpy(p, "abc", 3);         //   /p没有申请空间就直接使用
    printf("line:%d\n", __LINE__);  //单纯打印代码行数
    return 0;
}
2. 使用gcc和gdb
想详细了解gdb调试工具可以访问下面的网址:
调试步骤:
1、为了能够使用gdb调试程序,在编译阶段加上-g参数,还是以下面这段错误代码为例:
int main(int argc, char *argv[])
{
   char *p = NULL;
   strncpy(p, "abc", 3);//p没有申请空间就直接使用
   return 0;
}
编译代码添加-g选项
gcc -g -o xxx xxx.c
编译程序,然后用gdb调试:

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|粤嵌技术交流空间

GMT+8, 2025-7-8 03:34 , Processed in 0.715735 second(s), 18 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表