段错误(Segmentation fault)

段错误

背景

在使用MPI并行化矩阵乘向量的实验中,发现如果矩阵的规模规模较大时,就会导致段错误。
将错误代码进行简化,如下所示

/*
File name: seg_error.c
How to compile: gcc -g -Wall -o seg_error seg_error.c
*/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(){
    int m, n;
    double *a;
    printf("Please input m and n: ");
    scanf("%d%d", &m, &n);
    a = malloc(m * n * sizeof(double));
    memset(a, 0, sizeof(double) * m * n);

    free(a);
    return 0;
}

输出如下所示
请添加图片描述

Debug

之前在找段错误的bug时,我一般是先使用printf来确定引发段错误的代码,然后再进一步寻找引发段错误的原因。但是最近我发现使用GDB可以更加快速地找到引发段错误的代码,尤其是当程序较大时
使用GDB调试的过程如下所示:

  1. 首先使用gcc编译,需要加上-g选项:gcc -g -Wall -o seg_error seg_error.c
  2. 然后直接使用gdb运行seg_error:gdb ./seg_error
  3. 进入gdb后,输入r开始运行程序
  4. 程序会一直执行直到发生段错误,此时输入where即可找到引发段错误的代码

过程如下所示:
请添加图片描述
从上面可以看出,引发段错误的代码在seg_error.c的第16行处,即memset(a, 0, sizeof(double) * m * n);
接下来便是去找引发段错误的原因了,这个就需要根据具体的代码来判断了。经过一番debug,最终发现了问题所在:

  1. 传递给mallc的参数是m * n * sizeof(double),编译器把该语句编译成了先把m和n相乘,得到的结果再和sizeof(double)相乘,m和n都是int类型,由于输入时m和n较大,两者相乘直接溢出,溢出的结果再和sizeof(double)相乘便得到了一个错误的值。
  2. 传递给memset的参数是sizeof(double) * m * n,编译器把该语句编译成了先把sizeof(double)和m相乘,得到的结果再和n相乘,由于sizeof(double)是size_t类型(在我的电脑里,size_t就是unsigned long类型而且该类型为64位),因此会先把m强制转化为size_t类型后再和sizeof(double)相乘,此时不会发生溢出,得到的结果再和n相乘,同理,会先把n强制转化为size_t类型,因此最终的结果是正确的值
  3. 由于我输入的m和n均为131072( 2 17 2^{17} 217),因此m * n * sizeof(double)得到的值实际上是0,但是sizeof(double) * m * n的值为137438953472,因此memset会引发段错误
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值