[Logo der Universität Bayreuth]
Universität Bayreuth

Mathematisches
Institut



 Einleitung

 Erste Schritte

 Mail und News

 Drucken

 KDE

 LaTeX/TeX

 Linksammlung

 Linuxtools

 Netzwerk

 Programmieren

 Windows

 X Window

 Anträge

 Kontakt

Fehlersuche mit dem Debugger <-

Fehlersuche mit dem gdb

Der gdb (Gnu DeBugger) ist der verbreitetste Debugger unter Linux. Da er sich an die unter anderen Unix-Dialekten vorherrschenden Konventionen hält, können sehr viele darauf aufbauende Werkzeuge auch unter Linux eingesetzt werden. Wir werden hier seine wichtigsten Kommandos und alles weitere lernen, was uns helfen kann, unsere Fehler mit ihm aufzuspüren. Der gdb ist sehr leistungsfähig, ist aber, weil er nur eine Kommandozeile hat, schwer zu bedienen. Um die Benutzung des gdb zu erleichtern, wurde der ddd (Data Display Debugger) entwickelt, der eine grafische Benutzerschnittstelle zum gdb darstellt (siehe Fehlersuche mit dem ddd).
Obwohl Sie später sicherlich mehr mit dem ddd arbeiten werden, ist es ratsam, diese Seite zu lesen, um mit dem gdb umgehen zu können. Damit werden Sie sich mit dem ddd besser auskennen.




Inhaltsverzeichnis

  1. Start des gdb
  2. Laden einer Core-Datei
  3. Start eines Programms im Debugger
  4. Ausgabe von Programmcode
  5. Haltepunkt
  6. Einzelschritte und Fortsetzung
  7. Verfolgung der Aufrufkette
  8. Untersuchung von Variablenwerten
  9. Beenden des gdb






top top


Start des gdb

Der Befehl zum Start des gdb ist "gdb", gefolgt vom Namen der ausführbaren Datei.
Beispielsweise (wie immer unter Linux):
   gdb a.out
       

Es funktioniert aber nicht, wenn Sie nach dem Befehl gdb den richtigen Namen der Sourcedatei (zum Beispiel: "aufgabe.cpp") eingeben. Der Debugger benötigt die ausführbare Datei.
Wichtig: Es ist auch sehr wichtig, dass Sie Ihr Programm mit der Option "-g" compilieren, weil diese Option zum Executable Debug-Informationen hinzufügt. Im normalen Ablauf verhält sich das Programm kaum anders als ohne diese Option.
Nachdem Sie den gdb gestarten haben erhalten Sie am Bildshirm den gdb-Prompt:
  (gbd)
       
Jetzt kann man gdb-Befehle eingeben.

top top


Laden einer Core-Datei

Wenn Ihr Programm beim Absturz einen Abzug des Speichers (core-Datei) erzeugt, können Sie diesen als zweites Argument beim Aufruf des Debuggers angeben. Der Debugger kann diesen Speicherauszug laden und damit sofort die Stelle anzeigen, an der der Absturz passierte.

Der Befehl lautet in seiner allgemeinen Form:
       (gdb) <Name des executables> <Name der core-Datei>
     

top top


Start eines Programms im Debugger

Der Debugger läuft. Jetzt können wir unser Programm innerhalb des Debuggers starten. Dies erfolgt mit dem Befehl "run". Weil der gdb eine Reihe von Kürzel für besonders häufig benutzte Kommandos kennt, können Sie anstelle von "run" auch nur "r" eingeben.
        Beispiel 1 (bsp1.cpp):
  #include <iostream>
  #include <iomanip>
  using namespace std;
  int main()
  {
     int Grundpreis , Endpreis;
     cout << "Geben Sie  den Gundpreis ein : ";
     cin >> Grundpreis;
     Endpreis = Grundpreis*1.16;
     cout << "Der Endpreis ist : " << Endpreis << "EUR" << endl;
     return 0;
  }
            
         Wir erhalten :
  hiwicip2@btcipmatx10:~ > g++ -g bsp1.cpp
  hiwicip2@btcipmatx10:~ > gdb a.out
  This GDB was configured as "i386-suse-linux"...
   (gdb) r
  Starting program: /home/hiwicip2/a.out
  Geben Sie den Gundpreis ein : 12
  Der Endpreis ist : 13.92 DM
  Program exited normally.
  Current language: auto; currently c
   (gdb)
         
Erklärung: Program exited normally.
Das bedeutet, dass das Programm ganz normal ohne Problem gelaufen ist und sich beendet hat

Das kann ganz anders passieren.


       Beispiel 2 (bsp2.cpp):
  #include <iostream>
  #include <fstream>
  #include <iomanip>
  using namespace std;
  double Berechnung(int N);
  int main()
  {
    const int N=25;
    double erg;
    ifstream fin;
    fin.open("auf.ein");
    if (fin.fail())
    {
         return 1;
    }
    fin.close();
    erg=Berechnung(N);
    cout << "Ergebnis" << erg << endl;
    return 0;
  }
  void Berechnung(int N)
  {
     double n=0;
     return n+(9*N)+121;
  }
       
      Wir erhalten:
       hiwicip2@btcipmatx10:~ > g++ -g bsp2.cpp
       hiwicip2@btcipmatx10:~ > gdb a.out
       GNU gdb 4.18
       Copyright 1998 Free Software Foundation, Inc.
      (gdb) r
       Starting program: /home/hiwicip2/a.out
       Program exited with code 01.
       Current language: auto; currently c
      (gdb)
         
Erkärung: Program exited with code 01 (nicht: normally)
Das bedeutet, dass das Programm nicht mit dem exit-Wert 0, sondern mit dem exit-Wert 1 beendet wurde (hier: durch die Anweisung "return 1;".
Unser Programm endet also schon in der if-Schleife.
Hier ist das Programm bereits in der if-Schleife beendet worden. Aber warum?
Um diese Frage beantworten zu können, werden wir den Ablauf des Programm Schritt für Schritt verfolgen.

top top


Ausgabe von Programmcode

Um genau zu wissen, was in unserem Programm passiert, sollten wir den Programmcode vor Augen haben. Die Ausgabe des Programmcodes erfolgt durch das Kommando " list" oder "l" in Kurzform. Damit erhalten Sie ein paar Zeilen vom Programmcode. Die Anzahl der ausgegebenen Zeilen können Sie ändern, indem Sie "set listsize <Anzahl>" eingeben. Der Befehl "list" versteht auch als Argument eine Zeilennummer oder einen Funktionsnamen, ab denen Sie den Code anschauen wollen. Sie können auch als Argument "+" oder "-" eingeben, um die Zeilen vor bzw. nach dem letzten Codeausschnitt anzuzeigen.
    Für Beispiel 2 (bsp2.cpp):
       (gdb) set listsize 3 // Größe des Ausschnitt =3 Zeilen
       (gdb) list
       6 int main()
       7 {
       8 const int N=25;
       (gdb) l - // 3 vorherige Zeilen anschauen
       2 #include <iostream>
       3 #include <fstream>
       4 using namespace std;
       (gdb) l 10 // Programmcode ab Zeile 10 anschauen
       9 double n,erg;
       10
       11 ifstream fin;
    

top top


Haltepunkt

Das Kommando zum Setzen eines Haltepunkts ist break oder einfach b. Der gbd bietet dann zwei verschiedene Argumente. Die Nummer der Zeilen, bei der das Programm stehen bleiben soll oder den Namen einer Funktion bzw. Methode, zu deren Beginn gestoppt werden soll.
     Mit dem Argument Zeilennummer bezieht sich der Haltepunkt auf die Datei, in der das Programm sich gerade befindet.
     Wenn Sie einen Funktionsnamen als Argument angeben, fügen Sie den Funktionnamen nach break an. Das Programm hält genau bei der ersten Anweisung dieser Funktion an.
Für Beispiel 2(bsp2.cpp):
            (gdb) b 9
           Breakpoint 1 at 0x804882e: file bsp2.cpp, line 9.
            (gdb) b Berechnung
           Breakpoint 2 at 0x8048976: file bsp2.cpp, line 26.
            (gdb)
      
Wenn Sie viele Haltepunkte verwenden und schon den Überblick verloren haben, gibt es den Befehl info breakpoints. Mit diesem Befehl können Sie eine Liste mit allen gesetzten Haltepunkten sehen.
Für unser Beispiel:
            (gdb) info breakpoints
           Num Type Disp Enb Address What
           1 breakpoint keep y 0x08048820 in main at bsp2.cpp:9
           2 breakpoint keep y 0x08048976 in Berechnung(double,double,int) at bsp2.cpp:26
            (gdb)
    
Wenn Sie einen Haltepunkt nicht mehr brauchen, können Sie diesen löschen. Dafür gibt es zwei Kommandos clear und delete
Das Kommando clear ist praktisch das Gegenstück zu break und versteht dieselben Argumente.
Das Kommando delete erwartet die Nummer des zu löschenden Haltepunkt.
Für unser Beispiel (bsp2.cpp):
         (gdb) clear Berechnung
         Deleted breakpoint 2
         (gdb) delete 1
         (gdb) info breakpoints
         No breakpoints or watchpoints.
     

top top

Wenn Sie nicht ganz auf einen Haltepunkt verzichten wollen, können Sie ihn deaktivieren durch das Kommando disable und nachher wieder einschalten mit dem Kommando enable. Den aktuellen Zustand des Breakpoints können Sie aus der mit info breakpoints erhältlichen Liste entnehmen. Diese zwei Kommandos erwarten als Argument die Nummer des Haltepunktes.
Hier:
       (gdb) b 11
       Breakpoint 3 at 0x8048820: file bsp2.cpp, line 11.
       (gdb) b 13
       Breakpoint 4 at 0x804884f: file bsp2.cpp, line 13.
       (gdb) disable 3
       (gdb) info breakpoints
       Num Type Disp Enb Address What
      3 breakpoint keep n 0x08048820 in main at bsp2.cpp:11
      4 breakpoint keep y 0x0804884f in main at bsp2.cpp:13
      
Nachdem Sie die Haltepunkte gesetzt haben, können Sie dann wieder das Programm mit run laufen lassen.
          (gdb) r
          Starting program: /home/hiwicip2/a.out
          Breakpoint 4, main () at bsp2.cpp:14
          14 if (fin.fail())
         (gdb) enable 3
         (gdb) r
         The program being debugged has been started already.
         Start it from the beginning? (y or n) y
         Starting program: /home/hiwicip2/a.out
         Breakpoint 3, main () at bsp2.cpp:11
         11 ifstream fin;
     (gdb)
    

top top


Einzelschritte und Fortsetzung

Zur Ausführung in Einzelschritten gibt es im wesentlichen vier Kommandos:
  • next, kurz n
  • step,kurz s
  • until,kurz u
  • und finish.
  • Mit dem Befehl next können Sie in der gerade betrachteten Funktion Zeile um Zeile weitergehen (nach einem Haltepunkt zum Beispiel). Steht in einer Zeile ein Funktionsaufruf, so wird dieser als ganzes ausgeführt und das Programm stoppt in der darauffolgenden Zeile wieder.

           Für unser Bespiel 3 (bsp3.cpp):
           (gdb) b 15
           Starting program: /home/hiwicip2/a.out
           Breakpoint 1, main () at bsp3.cpp:17
           17 cout<<"Geben Sie  'n'  Anzahl von Studenten ein (n>0) : ";
           (gdb) n
           18 cin>>n;
           (gdb) n
           Geben Sie 'n' Anzahl von Studenten ein (n>0) : 1
           19 cout<<"Geben Sie  'm'  Anzahl von Fächern ein (m>0): ";
           (gdb) n
           20 cin>>m;
           (gdb) n
           Geben Sie 'm' Anzahl von Fächern ein (m>0): 2
           24 tabelle= new double*[n];
           (gdb) n
           25 for(i=0;i<n+3;i++)
           (gdb) n
           26 tabelle[i]=new double[m];
           (gdb) n
           26 tabelle[i]=new double[m];
           (gdb) n
           26 tabelle[i]=new double[m];
           (gdb) n
           26 tabelle[i]=new double[m];
           (gdb) n
           33 eingabe( tabelle,n,m);
           (gdb) n
           Geben Sie Punkten des 1.ten Studentes ein // Hier wird Die Funktion 
           Fürs 1.te Fach : 1 // eingabe() ausgeführt (nicht Zeilenweise)
           Fürs 2.te Fach : 1
           35 for (i=0;i<n;i++)
         (gdb)
         


    top top

  • Der Befehl step funktioniert fast genauso wie next. Steht in einer Zeile ein Funktionsaufruf, so springen Sie mit diesem Befehl in die erste Zeile der Funktion und können dort wieder zeilenweise debuggen.

           Für unser Bespiel 3 (bsp3.cpp):
     (gdb) b 33
         Breakpoint 1 at 0x8048a47: file bsp3.cpp, line 33.
         (gdb) r
         Starting program: /home/hiwicip2/a.out
         Geben Sie 'n' Anzahl von Studenten ein (n>0) : 1
         Geben Sie 'm' Anzahl von Fächern ein (m>0): 2
         Breakpoint 1, main () at bsp3.cpp:33
         33 eingabe( tabelle,n,m);
         (gdb) s
         eingabe (tabelle=0x804a1a0, n=1, m=2) at bsp3.cpp:56
         56 for (int i=0;i<n;i++)
         (gdb) s
         58 cout<<"Geben Sie Punkten des "<<i+1<<".ten Studentes ein";
         (gdb) s
         0x4003f595 in ostream::operator<< () at iostream.cc:568
         568 iostream.cc: Datei oder Verzeichnis nicht gefunden.
         (gdb) s
         0x400cfc43 in __internal_flockfile (stream=0x4005b220)
         at ../sysdeps/generic/lockfile.c:27
         27 ../sysdeps/generic/lockfile.c: Datei oder Verzeichnis nicht gefunden.
         Current language: auto; currently c
         (gdb) s
         0x4003f595 in ostream::operator<< () at iostream.cc:568
         568 iostream.cc: Datei oder Verzeichnis nicht gefunden.
         Current language: auto; currently c++
         (gdb)
         
    Das Problem bei dieser Vorgehenweise haben Sie vielleicht erkannt. Sie geraten tiefer in System- oder Bibliotheksroutinen (z.B. beim Debuggen in diese Funktionen, die aber nicht mit Debug-Informationen compiliert wurden) und verlieren zudem den Überblick über den Ablauf Ihres Programms.

    Tipps: Benutzen sie next, wenn Sie sich schon in einer Unterfunktion befinden, bis Sie den nächsten Funktionsaufruf erreichen. Dort entscheiden Sie je nach Bedarf zwischen next und step.


  • Der Befehl until ist sehr ähnlich zu next. Den Unterschied merkt man bei Schleifen. Wenn Sie sich am Ende einer Schleife befinden (und eine weitere Iteration ansteht), gelangen Sie mit next wieder an den Anfang. Wenn Sie jedoch until eingeben, werden alle noch austehenden Iterationen sofort ausgeführt und das Programm stoppt in der Zeile,die auf die Schleife folgt.

    Beispiel (bsp3.cpp)
               Mit next
           Starting program: /home/hiwicip2/a.out
           Geben Sie 'n' Anzahl von Studenten ein (n>0) : 2
           Geben Sie 'm' Anzahl von Fächern ein (m>0): 3
           Geben Sie Punkten des 1.ten Studentes ein
           Fürs 1.te Fach : 1
           Fürs 2.te Fach : 1
           Fürs 3.te Fach : 1
           Geben Sie Punkten des 2.ten Studentes ein
           Fürs 1.te Fach : 1
           Fürs 2.te Fach : 1
           Fürs 3.te Fach : 1
           Breakpoint 1, main () at bsp3.cpp:35
           35 for (i=0;i<n;i++)
           (gdb) n
           37 cout<i+1<<".Student  |  ";
           (gdb) n
           38 for(j=0;j<m;j++)
           (gdb) n
           40 cout<<<<tabelle[i][j]"  |  " ;
           (gdb) n
           42 }
           (gdb) n
           40 cout<<tabelle[i][j]<<"  |  " ;
           (gdb) n
           42 }
           (gdb) n
           40 cout<<tabelle[i][j]<<"  |  " ;
           (gdb) n
           42 }
           (gdb) n
           43 cout<<endl;
           (gdb) n
           1.Student | 1 | 1 | 1 |
           44 }
            
            Mit until
           Starting program: /home/hiwicip2/a.out
           Geben Sie 'n' Anzahl von Studenten ein (n>0) : 2
           Geben Sie 'm' Anzahl von Fächern ein (m>0): 3
           Geben Sie Punkten des 1.ten Studentes ein
           Fürs 1.te Fach : 1
           Fürs 2.te Fach : 1
           Fürs 3.te Fach : 1
           Geben Sie Punkten des 2.ten Studentes ein
           Fürs 1.te Fach : 1
           Fürs 2.te Fach : 1
           Fürs 3.te Fach : 1
           Breakpoint 1, main () at bsp3.cpp:35
           35 for (i=0;i<n;i++)
           (gdb) n
           37 cout<<i+1<<".Student  |  ";
           (gdb) n
           38 for(j=0;j<m;j++)
           (gdb) n
           40 cout<<tabelle[i][j]<<"  |  " ;
           (gdb) u
           42 }
           (gdb) u
           43 cout<<endl;
           (gdb) u
           1.Student | 1 | 1 | 1 |
           44 }
                    

    top top


  • Das Kommando finish dient dazu, die Funktion, in der Sie sich gerade befinden, zu beenden. Sie springen aber nicht sofort zurück, dafür gibt es den Befehl return. Bei finish werden alle Anweisungen bis zum regulären Ende der Funktion abgearbeitet. Das Programm stoppt bei der nächsten Zeile in der aufrufenden Funktion. Wenn Sie finish in der main()-Funktion eingeben, dann wird das Programm bis zum Ende ausgeführt.

    Beispiel (bsp3.cpp)
         Starting program: /home/hiwicip2/cvs-rep/cip_www/download/debugger/a.out
         Geben Sie 'n' Anzahl von Studenten ein (n>0) : 1
         Geben Sie 'm' Anzahl von Fächern ein (m>0): 2
         Breakpoint 1, main () at bsp3.cpp:33
         33 eingabe( tabelle,n,m);
         (gdb) s
         eingabe (tabelle=0x804a1a0, n=1, m=2) at bsp3.cpp:57
         57 for (int i=0;i<n;i++)
         (gdb) n
         59 cout<<"Geben Sie Punkten des "<<i+1<<".ten Studentes ein";
         (gdb) finish  //Befehl finish
         Run till exit from #0 eingabe (tabelle=0x804a1a0, n=1, m=2) at bsp3.cpp:59
         Geben Sie Punkten des 1.ten Studentes ein
         Fürs 1.te Fach : 1
         Fürs 2.te Fach : 2
         0x8048a5b in main () at bsp3.cpp:33
         33 eingabe( tabelle,n,m);  //Die Funktion eingabe() ist beendet.
         (gdb) n
         35 for (i=0;i<n;i++)
         (gdb)
               


    Tipps: Der Befehl finish ist auch hilfreich, wenn Sie versehentlich beim Debuggen in System- oder Bibliotheksroutinen landen. Damit können Sie wieder leicht zurückspringen.


top top


Verfolgung der Aufrufkette

Wenn wir uns in einer Unterfunktion unseres Programmes befinden, ist es immer sehr hilfreich zu wissen, wo genau (in welcher Zeile) diese Funktion angerufen ist. Dafür gibt es das Kommando backtrace oder kurz bt.

Für unser Beispiel 3 (bsp3.cpp)
     (gdb) r
     Starting program: /home/hiwicip2/cvs-rep/cip_www/download/debugger/a.out
     Geben Sie 'n' Anzahl von Studenten ein (n>0) : 1
     Geben Sie 'm' Anzahl von Fächern ein (m>0): 2
     Breakpoint 1, main () at bsp3.cpp:33
     33 eingabe( tabelle,n,m);
     (gdb) s
     eingabe (tabelle=0x804a1a0, n=1, m=2) at bsp3.cpp:57
     57 for (int i=0;i<n;i++)
     (gdb) s
     59 cout<<"Geben Sie Punkten des "<<i+1<<".ten Studentes ein";
     (gdb) bt // Befehl backtrace
     #0 eingabe (tabelle=0x804a1a0, n=1, m=2) at bsp3.cpp:59 // Wir befinden uns in der Zeile 59
                                                                                                 der Funkt.eingabe()
     #1 0x8048a5b in main () at bsp3.cpp:33 // Diese Funktion wurde in der Zeile 33
                                                                                                   der main-Funkt. aufgerufen.
     (gdb)
     
Dieses Kommando ist auch sehr geeignet, wenn das Programm wie in unserem Fall (bsp3.cpp) abstürzt.
Wenn wir mit run das Programm läufen lassen, erhalten wir:
 Program received signal SIGSEGV, Segmentation fault.
          0x400d822a in chunk_free (ar_ptr=0x401632c0, p=0x804a1a8) at malloc.c:3049
          3049 malloc.c: Datei oder Verzeichnis nicht gefunden.
          Current language: auto; currently c
          (gdb)
   
Das Programm stürzt ab. Aber wo passiert es?
Wenn wir das Kommando bt eingeben, erhalten wir:
        (gdb) bt
         #0 0x400d822a in chunk_free (ar_ptr=0x401632c0, p=0x804a1a8) at malloc.c:3049
         #1 0x400d81cf in free () at malloc.c:2952
         #2 0x400483b4 in __builtin_vec_delete () at ./cp/new2.cc:63
         #3 0x8048b6c in main () at bsp3.cpp:48
        (gdb)
   
Jetzt wissen wir, wo die Funktion, die zum Absturz führt, aufgerufen wurde. Es bleibt jetzt genauer zu schauen, was in der Zeile 48 passiert.

top top


Untersuchung von Variablenwerten

Bei der Fehlersuche kann man auch den Inhalt von Variable ausgeben lassen und schauen, wie sie sich verhalten. Die Ausgabe von Variablen erfolgt durch den Befehl print oder kurz p. Man kann also den Inhalt von Intergraldatentypen (Datentyp für ganzzahlige Werte) und Gleitpunktdatentypen ganz einfach anschauen, indem man print, gefolgt vom Namen der Variable, eingibt.
Beipiel (Bsp3):
    Geben Sie 'n' Anzahl von Studenten ein (n>0) : 1
    Geben Sie 'm' Anzahl von Fächern ein (m>0): 2
    (gdb) p n
    $1 = 1
    (gdb) p m
    $2 = 2
    
Man kann auch den Inhalt von Arrays anschauen. Dazu gibt man die Arrayeinträge als normale Variablen aus.
Beispielsweise:
    (gdb) p tabelle[0][1]
    $4 = 1
    
Gerade bei Arrays will man meist nicht nur einzelne Werte anschauen, sondern den Inhalt des ganzen Arrays. Das kann man zeilenweise machen. Man ergänzt das Zeichen " @" nach dem Name des Arrayelements, ab dem man die Elemet anschauen will und gibt danach eine Zahl an. Diese Zahl ist die Anzahl von Elementen, die man ab diesem Arrayelement anschauen will.
Beispielsweise:
     (gdb) p tabelle[0][1]@2  // Wir wollen uns die 2 Elemente tabelle[0][1] und tabelle[0][2] anschauen.
     (gdb)
     $5 = {1, 1}
    
Eine andere Art der Ausgabe erfolgt durch das Kommando display. Damit können Sie erreichen, dass der gdb die angegebene Variable jedes Mal ausgibt, wenn das Programm stoppt.
Beispiel 3 (bsp3):
      (gdb) display i
       1: i = 0
       (gdb) n
       38 for(j=0;j<m;j++)
       1: i = 0
       (gdb) n
       40 cout<<tabelle[i][j]<<"  |  " ;
       1: i = 0
       (gdb) n
       42 }
       1: i = 0
       (gdb) n
       40 cout<<tabelle[i][j]<<"  |  " ;
       1: i = 0
       (gdb) n
       42 }
       1: i = 0
       (gdb) n
       43 cout<<endl;
       1: i = 0
       (gdb) n
       1.Student | 1 | 1 |
       44 }
       1: i = 0
       (gdb) n
       37 cout<<i+1<<".Student  |  ";
       1: i = 1
       (gdb) n
       38 for(j=0;j<m;j++)
       1: i = 1
       (gdb) n
       40 cout<<tabelle[i][j]<<"  |  " ;
       1: i = 1
       (gdb) n
       42 }
       1: i = 1
       (gdb) n
       40 cout<<tabelle[i][j]<<"  |  " ;
       1: i = 1
       (gdb) n
       42 }
       1: i = 1
       (gdb) n
       43 cout<<endl;
       1: i = 1
       (gdb) n
       2.Student | 1 | 1 |
       44 }
       1: i = 1
       (gdb) n
   

top top

Interressant sind die Schleifenvariablen. Bei dem Beispiel 3 hatten wir einen Absturz bei der for-Schleife in der Zeile 48 gehabt. Dieses Kommando ist also sehr geeignet, um nachzuschauen, wie oft die Schleife durchlaufen wird.
Starting program: /home/hiwicip2/cvs-rep/cip_www/download/debugger/a.out
          Geben Sie 'n' Anzahl von Studenten ein (n>0) : 2
          Geben Sie 'm' Anzahl von Fächern ein (m>0): 4
          Geben Sie Punkten des 1.ten Studentes ein
          Fürs 1.te Fach : 1
          Fürs 2.te Fach : 2
          Fürs 3.te Fach : 3
          Fürs 4.te Fach : 4
          Geben Sie Punkten des 2.ten Studentes ein
          Fürs 1.te Fach : 2
          Fürs 2.te Fach : 1
          Fürs 3.te Fach : 4
          Fürs 4.te Fach : 3
          1.Student | 1 | 2 | 3 | 4 |
          2.Student | 2 | 1 | 4 | 3 |
          Breakpoint 1, main () at bsp3.cpp:47
          47 for( i=0;i<m;i++)
          Current language: auto; currently c++
          (gdb) display i
          1: i = 2 // i wurde schon in der vorherigen for-Schleife benutzt.
          (gdb) n
          48 delete []tabelle[i];
          1: i = 0 // Die neue Iteration fängt an.
          (gdb) n
          48 delete []tabelle[i];
          1: i = 1
          (gdb) n
          48 delete []tabelle[i];
          1: i = 2 // Die Iteration sollte schon bei i=1 aufhören, weil
                                                       //wir nur 2 Elemente allokiert haben (n=2)
          (gdb) n
          48 delete []tabelle[i];
          1: i = 3
          (gdb) n
          Program received signal SIGSEGV, Segmentation fault.
          0x400d8178 in free () at malloc.c:2952
          2952 malloc.c: Datei oder Verzeichnis nicht gefunden.
          Current language: auto; currently c
          (gdb)
      
Jetzt wissen wir, wo der Fehler steht. Wir haben Speicherplätze gelöscht, die wir nicht reserviert haben.
Nach der Korrektur zu Beispiel 3 in File "bsp3_korr.cpp" erhalten wir:
(gdb) r
               Starting program: /home/hiwicip2/a.out
               Geben Sie 'n' Anzahl von Studenten ein (n>0) : 2
               Geben Sie 'm' Anzahl von Fächern ein (m>0): 4
               Geben Sie Punkten des 1.ten Studentes ein
               Fürs 1.te Fach : 1
               Fürs 2.te Fach : 1
               Fürs 3.te Fach : 1
               Fürs 4.te Fach : 1
               Geben Sie Punkten des 2.ten Studentes ein
               Fürs 1.te Fach : 1
               Fürs 2.te Fach : 1
               Fürs 3.te Fach : 1
               Fürs 4.te Fach : 1
               1.Student | 1 | 1 | 1 | 1 |
               2.Student | 1 | 1 | 1 | 1 |
               Program exited normally. es ist jetzt OK !
               Current language: auto; currently c
               (gdb)
      

top top


Beenden des gdb

Nachdem wir das Problem gefunden haben können wir der Debug-Sitzung beenden. Dies erfolgt mit dem Kommando quit, kurz q.
Wenn das Programm noch beim Laufen ist, erhalten Sie:
    (gdb) q
    The program is running. Exit anyway? (y or n)
Sie können dann mit dem Kommando continue das Programm bis zum regulären Ende laufen lassen oder aber das Programm an dieser Stelle abbrechen.





top top

top top

Robert Baier ([e-mail-Adresse von Robert Baier])
© 2003 Robert Baier;
© 1999-2002 Robert Baier, Sascha Herrmann
Debugger-Seiten: © 2003 Robert Baier, Ekue-sse Situ Tomety
[Seitenzähler] Last modified: 22.07.2015