Segmentation fault (mit Debugger nicht nachvollziehbar)



  • Hi
    Ich ärgere mich schon seit Tagen mit folgendem Code herum:

    double* DiffLsg(double (*f)(double,double),double xmin,double xmax,double fxmin,double fxmax,int n, int it)
        {
        //Initialisierungen
        double ih =n/(2*(xmax-xmin));
        double h =2.*(xmax-xmin)/n;
        double hy;//Genauigkeit in y-Richtung
        double diff;
        int iter;
        int i,j;
    
        //erzeuge die ausgabe, eine Liste aller Einträge von f(x);
        double* result=(double*)malloc(n*sizeof(double));
        printf("Speichergroesse %d\n",n*sizeof(double));
        result[n-1]=fxmax; //Diese Zeile ist später zum Debuggen beigefügt worden
                           //Um zu sichern, dass hier noch alles in Ordnung scheint.
        printf("Adresse %d\n",(int)result);
    
        //belege f(x) mit 0
        for (i=1; i<(n-1); i++)
          {
          result[i]=0;
          }
    
        //Randbedingungen
        result[0]=fxmin;
        printf("n ist: %d\n",n);
        printf("Adresse %d\n",(int)result);
        result[n-1]=fxmax;//Hier tritt der Segmentation fault auf!
    
        printf("Bis hier 1"); //Wird nicht mehr ausgeführt
        // Den Rest erspare ich Euch
        }
    

    Der Code kompiliert fehlerfrei und ohne Warnungen. Dabei erhalte ich folgende Ausgabe:

    Speichergroesse 400
    Adresse 166572040
    n ist: 50
    Adresse 166572040
    Segmentation fault
    

    Aufgerufen wird diese routine durch folgenden Befehl:

    double* result=DiffLsg(f,0.,1.,1.,2.7,n,n);
    

    wobei const int n=50 gesetzt ist.

    Wenn ich das Programm mit dem Debugger ddd ausführe, erhalte ich bei normaler Ausführung wieder den Segmentation fault. Wenn ich aber Einzelschritte im Bereich ausführe, passiert er diese Passage ohne Fehler.

    Weiss irgendwer, wieso dieser Segmentation fault auftritt? Mir ist leider nicht klar, wo ich hier auf nicht reservierten Speicher zugreife.

    Achso: Ich habe die "bose Zeile" aus Debug-Gründen etwas höher nochmals eingebaut, wo diese unbehelligt passiert wird. Dennoch wäre das Löschen dieser Zeile leider keine Lösung, da dann dieser Fehler später auftritt. So habe ich immernoch das Wissen darüber, dass die Ursache in diesem Bereich liegen muss.



  • printf schreibt deine Ausgaben nicht zwingend sofort auf die Konsole. Häufig ist \n ein Flush-Trigger, aber um sicher zu gehen, dass die Ausgabe sofort erscheint, schreib

    fflush(stdout);
    

    dahinter.

    Allerdings wäre es insgesamt sinnvoller, den Debugger dazu zu befragen. Ich habe länger nicht mehr mit ddd gearbeitet, also kann ich dir nicht sagen, wo du das klicktechnisch findest, aber das gdb-Kommando, nach dem du suchst, ist "backtrace". Beispiel:

    $ cat -n test.c
         1	void foo() {
         2	  char *p = 0;
         3	  *p = 'a';
         4	}
         5	
         6	int main(void) {
         7	  foo();
         8	}
    $ gcc -g test.c
    $ gdb ./a.out 
    GNU gdb (GDB) 7.1
    Copyright (C) 2010 Free Software Foundation, Inc.
    *blabla*
    Reading symbols from /home/user/a.out...done.
    (gdb) run
    Starting program: /home/user/a.out 
    b
    Program received signal SIGSEGV, Segmentation fault.
    0x00000000004004a4 in foo () at test.c:3
    3	  *p = 'a';
    (gdb) backtrace
    #0  0x00000000004004a4 in foo () at test.c:3
    #1  0x00000000004004b7 in main () at test.c:7
    (gdb)
    

    Das sagt dir, der Segfault passiert in test.c in Zeile 3, aufgerufen aus test.c, Zeile 7.



  • Tigerle schrieb:

    double* result=(double*)malloc(n*sizeof(double));
    

    Hat zwar nichts mit deinem Problem zu tun, ist dennoch ein Fehler:
    Der Rückgabewert von malloc() wird nicht gecastet.



  • Deine Information ist veraltet.

    Das Casten des Rückgabewerts von malloc war vor langer, langer Zeit mit ein paar Compilern unschön, weil es unter Umständen Warnungen unterdrückte, dass malloc implizit deklariert wurde, wenn man vergaß, stdlib.h einzubinden. Das war problematisch, wenn man plattformunabhängigen Code schreiben wollte, aber auf einer Plattform arbeitete, auf der int die gleiche Breite wie ein Zeiger hat. Neuere Compiler warnen in solchen Fällen aber eh, so dass sich die Problematik erledigt hat.

    Gleichzeitig ist Code, in dem der Rückgabewert von malloc nicht gecastet wird, kein gültiges C++ (Ausgenommen solcher, in dem der Rückgabewert einem void* zugewiesen wird), was einem bei einer möglichen Portierung einen Haufen zusätzliche Arbeit machen kann.

    Es muss allerdings gesagt werden, dass beide Argumente nicht besonders stark sind - es ist kein Fehler, malloc zu casten, es ist in C aber auch nicht erforderlich. Es ist Ansichtssache, welche Variante man bevorzugt, und es ist mit Sicherheit nicht bedeutend genug, dass man es in jedem Thread, in dem man es entdeckt und zu dem man nichts Konstruktives beizutragen hat, wieder auswalzen müsste.



  • Kann kein Fehler reproduzieren 😞



  • Danke, seldon. Dein Hinweis, dass ich die Ausgabe von printf erzwingen muss, und die Ratschläge zur Bedienung von gdb brachten mich dazu festzustellen, dass ich den Fehler im falschen Bereich suchte.

    (Das mit dem fflush war mir neu, aber ich wundere mich gerade über mich selber, dass \n in der ausgabe vergessen zu haben...

    Hier kann geschlossen werden 🙂


Anmelden zum Antworten