分段错误:11

Ari*_*nes 50 c segmentation-fault

我遇到了一些程序的问题,我搜索了有关分段错误的内容,我不太了解它们,我唯一知道的是,大概是我试图访问一些我不应该访问的内存.问题是我看到了我的代码并且不明白我做错了什么.

#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);
}
Run Code Online (Sandbox Code Playgroud)

谢谢你的时间.

unw*_*ind 97

本声明:

double F[1000][1000000];
Run Code Online (Sandbox Code Playgroud)

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

  • 这在7年后仍然有效。太棒了 (6认同)

Jon*_*ler 37

您的阵列占用大约8 GB的内存(1,000 x 1,000,000 x sizeof(双)字节).这可能是你问题的一个因素.它是一个全局变量而不是堆栈变量,所以你可能没问题,但你在这里推动限制.

将那么多数据写入文件需要一段时间.

您没有检查文件是否已成功打开,这也可能是一个麻烦的来源(如果它确实失败,很可能会出现分段错误).

你真的应该介绍一些1,000和1,000,000的命名常量; 它们代表什么?

你还应该编写一个函数来进行计算; 你可以使用inlineC99或更高版本(或C++)中的函数.代码中的重复是令人难以忍受的.

您还应该使用C99表示法main(),使用显式返回类型(void当您不使用argc或时,最好使用参数列表argv):

int main(void)
Run Code Online (Sandbox Code Playgroud)

出于好奇心,我拿了你的代码副本,将所有出现的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);
}
Run Code Online (Sandbox Code Playgroud)

这个程序写入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
Run Code Online (Sandbox Code Playgroud)

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

for (int i = COLS - 1; i < COLS; i++)
Run Code Online (Sandbox Code Playgroud)

时间大大减少,而且更加一致:

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
Run Code Online (Sandbox Code Playgroud)

在我看来,简单地将令人可怕的表达式写出一次是非常有益的.我当然不得不维持该程序而不是原始程序.