Segmentierungsfehler: 11

Lesezeit: 7 Minuten

Ich habe ein Problem mit einem Programm, ich habe nach Segmentierungsfehlern gesucht, verstehe sie nicht ganz, das einzige, was ich weiß, ist, dass ich vermutlich versuche, auf einen Speicher zuzugreifen, auf den ich nicht zugreifen sollte. Das Problem ist, dass ich meinen Code sehe und nicht verstehe, was ich falsch mache.

#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);
}

Vielen Dank für Ihre Zeit.

  • An welchem ​​Punkt tritt der Segfault auf?

    – Jeff Mercado

    6. Oktober 2012 um 19:10 Uhr

  • ^ Versuchen Sie, Valgrind zu verwenden, um die Zeilennummer zu erhalten, in der der Segfault auftritt. Es ist im Allgemeinen ziemlich offensichtlich, wenn Sie es auf eine Zeile eingegrenzt haben. Wenn nicht, posten Sie, um welche Zeile es sich handelt, und wir können helfen.

    – 1”

    6. Oktober 2012 um 19:11 Uhr


  • Wenn Sie Ihren Code sehen, muss Ihr Compiler zunächst einen Segmentierungsfehler aufweisen …

    – Gefahrenhirn

    6. Oktober 2012 um 19:12 Uhr

  • Es kompiliert, es sagt Segmentierungsfehler, wenn ich es ausführe, ./Program

    – Ariramnes

    6. Oktober 2012 um 19:14 Uhr

  • Ihr Programm wird segfault, wenn es nicht erstellen kann P1.txt. Sie sollten das System immer fopen (und andere Routinen, die fehlschlagen können) für Fehler.

    – Jim Balter

    6. Oktober 2012 um 20:06 Uhr

Diese Erklärung:

double F[1000][1000000];

würde auf einem typischen x86-System 8 * 1000 * 1000000 Bytes belegen. Das sind etwa 7,45 GB. Es besteht die Möglichkeit, dass Ihrem System beim Versuch, Ihren Code auszuführen, nicht genügend Arbeitsspeicher zur Verfügung steht, was zu einem Segmentierungsfehler führt.

  • Diese gilt auch noch nach 7 Jahren. Genial.

    – Yoshi

    23. Januar 2019 um 1:37 Uhr

Benutzeravatar von Jonathan Leffler
Jonathan Leffler

Ihr Array belegt ungefähr 8 GB Speicher (1.000 x 1.000.000 x Größe von (doppelten) Bytes). Das könnte ein Faktor für dein Problem sein. Es ist eher eine globale Variable als eine Stapelvariable, also sind Sie vielleicht in Ordnung, aber Sie stoßen hier an Grenzen.

Das Schreiben so vieler Daten in eine Datei wird eine Weile dauern.

Sie überprüfen nicht, ob die Datei erfolgreich geöffnet wurde, was ebenfalls eine Fehlerquelle sein könnte (wenn dies fehlschlägt, ist ein Segmentierungsfehler sehr wahrscheinlich).

Sie sollten wirklich einige benannte Konstanten für 1.000 und 1.000.000 einführen; was repräsentieren sie?

Sie sollten auch eine Funktion schreiben, um die Berechnung durchzuführen; Sie könnten eine verwenden inline Funktion in C99 oder höher (oder C++). Die Wiederholung im Code ist quälend anzusehen.

Sie sollten auch die C99-Notation für verwenden main()mit dem expliziten Rückgabetyp (und vorzugsweise void für die Argumentliste, wenn Sie sie nicht verwenden argc oder argv):

int main(void)

Aus reiner Neugier habe ich eine Kopie Ihres Codes genommen, alle Vorkommen von 1000 in ROWS geändert, alle Vorkommen von 1000000 in COLS geändert und dann erstellt enum { ROWS = 1000, COLS = 10000 }; (wodurch die Problemgröße um den Faktor 100 reduziert wird). Ich habe ein paar kleinere Änderungen vorgenommen, damit es unter meinen bevorzugten Kompilierungsoptionen sauber kompiliert wird (nichts Ernstes: static vor den Funktionen und dem Hauptarray; file wird ein lokaler zu main; Fehler überprüfen Sie die fopen()etc.).

Ich habe dann eine zweite Kopie erstellt und eine Inline-Funktion erstellt, um die wiederholte Berechnung durchzuführen (und eine zweite, um tiefgestellte Berechnungen durchzuführen). Das bedeutet, dass der monströse Ausdruck nur einmal ausgeschrieben wird – was sehr wünschenswert ist, da es Konsistenz gewährleistet.

#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);
}

Dieses Programm schreibt an P2.txt Anstatt von P1.txt. Ich habe beide Programme ausgeführt und die Ausgabedateien verglichen; die Ausgabe war identisch. Als ich die Programme auf einem größtenteils im Leerlauf befindlichen Computer (MacBook Pro, 2,3 GHz Intel Core i7, 16 GiB 1333 MHz RAM, Mac OS X 10.7.5, GCC 4.7.1) ausführte, erhielt ich ein einigermaßen, aber nicht vollständig konsistentes Timing:

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

Fast die gesamte Zeit wird jedoch für Platten-I/O aufgewendet. Ich habe die Festplatten-I/O auf die allerletzte Datenzeile reduziert, also die äußere I/O for Schleife wurde:

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

Die Timings wurden erheblich reduziert und sehr viel konsistenter:

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

Die Vereinfachung im Code durch das einmalige Ausschreiben des grässlichen Ausdrucks scheint mir sehr vorteilhaft zu sein. Ich würde dieses Programm sicherlich viel lieber pflegen müssen als das Original.

Benutzeravatar von Blitzkoder
Blitzkoder

Auf welchem ​​System arbeitest du? Haben Sie Zugriff auf eine Art Debugger (gdb, Debugger von Visual Studio usw.)?

Das würde uns wertvolle Informationen liefern, wie die Codezeile, wo das Programm abstürzt… Außerdem kann die Menge an Speicher untragbar sein.

Darf ich Ihnen außerdem empfehlen, die numerischen Grenzen durch benannte Definitionen zu ersetzen?

Als solche:

#define DIM1_SZ 1000
#define DIM2_SZ 1000000

Verwenden Sie diese immer dann, wenn Sie sich auf die Array-Dimensionsgrenzen beziehen möchten. Es hilft, Tippfehler zu vermeiden.

Führen Sie Ihr Programm mit aus Valgrind von verlinkt Verteidigung. Das wird Ihnen sagen, wo der Zeiger dereferenziert wird, und höchstwahrscheinlich Ihr Problem beheben, wenn Sie alle Fehler beheben, von denen sie Ihnen erzählen.

1414730cookie-checkSegmentierungsfehler: 11

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy