分段错误:11

Posted

技术标签:

【中文标题】分段错误:11【英文标题】:segmentation fault : 11 【发布时间】:2012-09-27 14:17:02 【问题描述】:

我遇到了一些程序的问题,我搜索了分段错误,但我不太了解它们,我唯一知道的是我可能正在尝试访问一些我不应该访问的内存。问题是我看到我的代码并且不明白我做错了什么。

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

#define   lambda   2.0
#define   g        1.0
#define   Lx       100
#define   F0       1.0
#define   Tf       10
#define   h       0.1
#define   e       0.00001

FILE   *file;

double F[1000][1000000];

void Inicio(double D[1000][1000000]) 
int i;
for (i=399; i<600; i++) 
    D[i][0]=F0;



void Iteration (double A[1000][1000000]) 
long int i,k;
for (i=1; i<1000000; i++) 
    A[0][i]= A[0][i-1] + e/(h*h*h*h)*g*g*(A[2][i-1] - 4.0*A[1][i-1] + 6.0*A[0][i-1]-4.0*A[998][i-1] + A[997][i-1]) + 2.0*g*e/(h*h)*(A[1][i-1] - 2*A[0][i-1] + A[998][i-1]) + e*A[0][i-1]*(lambda-A[0][i-1]*A[0][i-1]);
    A[1][i]= A[1][i-1] + e/(h*h*h*h)*g*g*(A[3][i-1] - 4.0*A[2][i-1] + 6.0*A[1][i-1]-4.0*A[0][i-1] + A[998][i-1]) + 2.0*g*e/(h*h)*(A[2][i-1] - 2*A[1][i-1] + A[0][i-1]) + e*A[1][i-1]*(lambda-A[1][i-1]*A[1][i-1]);
    for (k=2; k<997; k++) 
        A[k][i]= A[k][i-1] + e/(h*h*h*h)*g*g*(A[k+2][i-1] - 4.0*A[k+1][i-1] + 6.0*A[k][i-1]-4.0*A[k-1][i-1] + A[k-2][i-1]) + 2.0*g*e/(h*h)*(A[k+1][i-1] - 2*A[k][i-1] + A[k-1][i-1]) + e*A[k][i-1]*(lambda-A[k][i-1]*A[k][i-1]);
    
    A[997][i] = A[997][i-1] + e/(h*h*h*h)*g*g*(A[0][i-1] - 4*A[998][i-1] + 6*A[997][i-1] - 4*A[996][i-1] + A[995][i-1]) + 2.0*g*e/(h*h)*(A[998][i-1] - 2*A[997][i-1] + A[996][i-1]) + e*A[997][i-1]*(lambda-A[997][i-1]*A[997][i-1]);
    A[998][i] = A[998][i-1] + e/(h*h*h*h)*g*g*(A[1][i-1] - 4*A[0][i-1] + 6*A[998][i-1] - 4*A[997][i-1] + A[996][i-1]) + 2.0*g*e/(h*h)*(A[0][i-1] - 2*A[998][i-1] + A[997][i-1]) + e*A[998][i-1]*(lambda-A[998][i-1]*A[998][i-1]);
    A[999][i]=A[0][i];



main() 
long int i,j;
Inicio(F);
Iteration(F);
file = fopen("P1.txt","wt");
for (i=0; i<1000000; i++) 
    for (j=0; j<1000; j++) 
        fprintf(file,"%lf \t %.4f \t %lf\n", 1.0*j/10.0, 1.0*i, F[j][i]);
    

fclose(file);

感谢您的宝贵时间。

【问题讨论】:

段错误发生在什么时候? ^ 尝试使用 Valgrind 获取发生段错误的行号。一旦您将其缩小到一行,这通常是相当明显的 - 如果没有,请发布它是哪一行,我们可以提供帮助。 看到你的代码,首先你的编译器一定出现了分段错误...... 它编译,当我运行它时它说分段错误,./Program 如果您的程序无法创建 P1.txt,则会出现段错误。你应该总是系统 fopen(和其他可能失败的例程)失败。 【参考方案1】:

您的数组占用大约 8 GB 内存(1,000 x 1,000,000 x sizeof(double) 字节)。这可能是您的问题的一个因素。它是一个全局变量而不是堆栈变量,所以你可能没问题,但你在这里突破了限制。

将这么多数据写入文件需要一段时间。

您没有检查文件是否已成功打开,这也可能是问题的根源(如果确实失败,则很可能是分段错误)。

您确实应该为 1,000 和 1,000,000 引入一些命名常量;它们代表什么?

您还应该编写一个函数来进行计算;您可以在 C99 或更高版本(或 C++)中使用 inline 函数。代码中的重复令人痛苦。

您还应该对main() 使用C99 表示法,并带有显式返回类型(当您不使用argcargv 时,最好将void 用于参数列表):

int main(void)

出于好奇,我复制了您的代码,将所有出现的 1000 更改为 ROWS,将所有出现的 1000000 更改为 COLS,然后创建 enum ROWS = 1000, COLS = 10000 ;(从而将问题大小减少了 100 倍)。我做了一些小改动,所以它可以在我喜欢的编译选项集下干净地编译(没什么大不了的:static 在函数前面和主数组;file 成为main 的本地;错误检查fopen()等)。

然后我创建了第二个副本并创建了一个内联函数来进行重复计算(以及第二个进行下标计算)。这意味着可怕的表达式只被写出一次——这是非常可取的,因为它确保了一致性。

#include <stdio.h>

#define   lambda   2.0
#define   g        1.0
#define   F0       1.0
#define   h        0.1
#define   e        0.00001

enum  ROWS = 1000, COLS = 10000 ;

static double F[ROWS][COLS];

static void Inicio(double D[ROWS][COLS])

    for (int i = 399; i < 600; i++) // Magic numbers!!
        D[i][0] = F0;


enum  R = ROWS - 1 ;

static inline int ko(int k, int n)

    int rv = k + n;
    if (rv >= R)
        rv -= R;
    else if (rv < 0)
        rv += R;
    return(rv);


static inline void calculate_value(int i, int k, double A[ROWS][COLS])

    int ks2 = ko(k, -2);
    int ks1 = ko(k, -1);
    int kp1 = ko(k, +1);
    int kp2 = ko(k, +2);

    A[k][i] = A[k][i-1]
            + e/(h*h*h*h) * g*g * (A[kp2][i-1] - 4.0*A[kp1][i-1] + 6.0*A[k][i-1] - 4.0*A[ks1][i-1] + A[ks2][i-1])
            + 2.0*g*e/(h*h) * (A[kp1][i-1] - 2*A[k][i-1] + A[ks1][i-1])
            + e * A[k][i-1] * (lambda - A[k][i-1] * A[k][i-1]);


static void Iteration(double A[ROWS][COLS])

    for (int i = 1; i < COLS; i++)
    
        for (int k = 0; k < R; k++)
            calculate_value(i, k, A);
        A[999][i] = A[0][i];
    


int main(void)

    FILE *file = fopen("P2.txt","wt");
    if (file == 0)
        return(1);
    Inicio(F);
    Iteration(F);
    for (int i = 0; i < COLS; i++)
    
        for (int j = 0; j < ROWS; j++)
        
            fprintf(file,"%lf \t %.4f \t %lf\n", 1.0*j/10.0, 1.0*i, F[j][i]);
        
    
    fclose(file);
    return(0);

此程序写入P2.txt 而不是P1.txt。我运行了两个程序并比较了输出文件;输出是相同的。当我在一台大部分空闲的机器(MacBook Pro、2.3 GHz Intel Core i7、16 GiB 1333 MHz RAM、Mac OS X 10.7.5、GCC 4.7.1)上运行程序时,我得到了合理但不完全一致的时间:

Original   Modified
6.334s      6.367s
6.241s      6.231s
6.315s     10.778s
6.378s      6.320s
6.388s      6.293s
6.285s      6.268s
6.387s     10.954s
6.377s      6.227s
8.888s      6.347s
6.304s      6.286s
6.258s     10.302s
6.975s      6.260s
6.663s      6.847s
6.359s      6.313s
6.344s      6.335s
7.762s      6.533s
6.310s      9.418s
8.972s      6.370s
6.383s      6.357s

但是,几乎所有时间都花在了磁盘 I/O 上。我将磁盘 I/O 减少到最后一行数据,因此外部 I/O for 循环变为:

for (int i = COLS - 1; i < COLS; i++)

时间大大减少并且更加一致:

Original    Modified
0.168s      0.165s
0.145s      0.165s
0.165s      0.166s
0.164s      0.163s
0.151s      0.151s
0.148s      0.153s
0.152s      0.171s
0.165s      0.165s
0.173s      0.176s
0.171s      0.165s
0.151s      0.169s

在我看来,只写一次可怕的表达式来简化代码是非常有益的。我当然宁愿维护那个程序而不是原来的程序。

【讨论】:

【参考方案2】:

你在什么系统上运行?您是否可以访问某种调试器(gdb、Visual Studio 的调试器等)?

这将为我们提供有价值的信息,例如程序崩溃的代码行...此外,内存量可能令人望而却步。

另外,我可以建议您用命名定义替换数字限制吗?

这样:

#define DIM1_SZ 1000
#define DIM2_SZ 1000000

在您希望引用数组维度限制时使用它们。这将有助于避免输入错误。

【讨论】:

【参考方案3】:

使用链接到efence 的valgrind 运行您的程序。这将告诉您指针被取消引用的位置,并且如果您修复了它们告诉您的所有错误,则很可能会解决您的问题。

【讨论】:

【参考方案4】:

此声明:

double F[1000][1000000];

在典型的 x86 系统上将占用 8 * 1000 * 1000000 字节。这大约是 7.45 GB。尝试执行代码时,您的系统可能内存不足,从而导致分段错误。

【讨论】:

这在 7 年后仍然有效。太棒了。

以上是关于分段错误:11的主要内容,如果未能解决你的问题,请参考以下文章

分段错误:11 - C 函数

C++:当我添加看似无关的代码行时,分段错误消失了

C ++ 11分段错误试图将数组(<算法>)动态复制到向量中

输入 glBegin() 后的 OpenGL 分段错误

动态二维数组。为啥是分段错误?

为啥写作主要;在 C 中给出一个段错误