tutorials.de Buch-Aktion 05/2012
ERLEDIGT
JA
ANTWORTEN
13
ZUGRIFFE
283
EMPFEHLEN
  • An Twitter übertragen
  • An Facebook übertragen
AUF DIESES THEMA
ANTWORTEN
  1. #1
    blub11 blub11 ist offline Mitglied Bronze
    Registriert seit
    Feb 2011
    Beiträge
    29
    Hallo!
    Hab ein neues Problem:

    Bei der Abfrage in einer rekursiven Funktion, ob denn das übergebene Element einer doppelt verketteten Liste ==NULL ist, geht das Programm einfach nicht rein...Debuggt wurde und anscheinend gibt es eine Speicherverletzung..Hab schon rumprobiert und alles nochmal durchgeschaut, aber ich weiß einfach nicht weiter..Da es sich um ein Projekt handelt, wollte ich hier ungern alle Header usw. posten. Könnte sich das vielleicht jemand mal netterweise anschauen, dann würde ich ihm das Projekt und den genauen Problemort per PM schicken

    Grüße
     

  2. #2
    Avatar von sheel
    sheel sheel ist offline Moderator
    tutorials.de Moderator
    Registriert seit
    Jul 2007
    Beiträge
    4.501
    Hi

    wenn die Dateimenge das einzige Problem ist: lads als Zip hier im Forum rauf.
     

  3. #3
    blub11 blub11 ist offline Mitglied Bronze
    Registriert seit
    Feb 2011
    Beiträge
    29
    ist oben

    Der Fehler liegt in der graf_ausgabe.h in Zeile 67 (ist auch noch kommentiert).
    Angelegt werden davor eigentlich durch die Benutzereingabe z.B. 4 Elemente (1 durch die "create"-Funktion mit dem Kopf-Zeiger und die 3 restlichen durch die "add"-Funktion in der datenstrukturen.h..ausgehend von der menue.h)..Daher weiß ich nicht, warum er da nicht in die if-Bedigung mit der NULL-Abfrage reingeht?!

    Bei der Benutzereingabe ist die Eingabe bei der ersten Abfrage egal, und bei der dritten nach der einzulesenden Datei bitte "test.txt" eingeben (die liegt im Verzeichnis).

    Beste Grüße!
    Geändert von blub11 (04.08.11 um 15:12 Uhr)
     

  4. #4
    deepthroat deepthroat ist offline Mitglied Diamant
    tutorials.de Premium-User
    Registriert seit
    Jun 2005
    Beiträge
    8.168
    Hi.

    Zitat Zitat von blub11
    Code c:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    void hoehe_berechnen(struct stellplaetze *kopf, struct container *container, struct stellplaetze *lkw, struct stellplaetze *frachter)
    {
        if(kopf==NULL) //HIER GEHT ER NICHT REIN! ANSCHEINEND IST DAS ELEMENT NACH DEM LETZTEN ELEMENT NICHT NULL? DANACH STÜRZT DAS PROGRAMM AB (LOGISCHERWEISE)
        {
           ...
        }
        ...
        kopf->hoehe+=1; /* PENG! */
        hoehe_berechnen(kopf, container->next, lkw, frachter);
    Ob die Bedingung der if-Abfrage in Zeile 3 nun war ist oder nicht, spielt eigentlich nie eine Rolle, du rufst in jedem Fall die Funktion rekursiv auf bzw. greifst auf den Zeiger zu...

    Es sollte wohl ungefähr so aussehen:
    Code c:
    1
    2
    3
    4
    5
    6
    
    if (kopf == NULL) {
       ...
    } else {
      kopf->hoehe+=1;
      hoehe_berechnen(...);
    }
    Gruß

    PS: Übrigens definiert man keine Funktionen in Headerdateien. Im Grunde hättest du genauso gut alles hintereinander in eine Datei klatschen können... Headerdateien enthalten nur Deklarationen, die Definitionen befinden sich dann in der C/C++ Datei.
    Geändert von deepthroat (03.08.11 um 15:07 Uhr)
     
    If at first you don't succeed, try again. Then quit. No use being a damn fool about it.

  5. #5
    Avatar von sheel
    sheel sheel ist offline Moderator
    tutorials.de Moderator
    Registriert seit
    Jul 2007
    Beiträge
    4.501
    Was mir beim Durchschauen so auffällt:
    Man sollte keine kompletten Funktionen in .h-Dateien stecken, sondern in h und cpp aufteilen.
    Nur die Signaturen, Präprozessorzeug, typedefs etc. in die h
    Sobald du Variablen in .h-Dateien schreibst bekommst du sowieso Linkerfehler.

    Und dieses Programm wäre ein Paradebeispiel, wo man OO gut gebrauchen könnte...
    Oder zumindest includes auch in den Dateien, die die Funktionen wirklich brauchen.
    Macht man menue.h auf, sieht create und kann alle anderen Dateien nach create absuchen...

    Nirgends im ganzen Programm hast du ein einziges free
    Und so viel mallocs...

    Zum Programm...ich mach mal den Debugger an...
    edit: doch nicht...so offensichtlich
     

  6. #6
    blub11 blub11 ist offline Mitglied Bronze
    Registriert seit
    Feb 2011
    Beiträge
    29
    @deppthroat: Also so ganz verstanden hab ich dich nicht ):
    Die Reihenfolge der Anweisungen muss so, wie sie ist, eigentlich beibehalten werden..ich mals dir mal auf und beschreibe, wie das alles funktionieren soll:


    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
                      +-----+
                      |1  46|
                      +-----+
                      +-----+      +-----+                       +-----+
                      |2  45|      |1 47|                         |2 48|
                      +-----+      +-----+                       +-----+
    -------            -------     -------   ------- ------     \-------/
    0-----0             1             2        3        4         \ 5 /
    LKW                   Container-Standplätze                 Frachter

    Dabei sind die ganzen Container-Standplätze (s. die inner Mitte) in einer doppelt verketteten Liste angelegt..Und die Stellplätze zeigen jeweils nochmal auf eine doppelt verkettete Liste mit Containern.

    Mit der Funktion hoehe_berechnen wollen wir alle Stellplätze durchgehen und dann schauen, wieviele Container auf ihm lagern. Dazu prüfen wir zuerst, ob der "kopf" der Stellplatz-Liste existiert, dann ob überhaupt ein Container auf dem Stellplatz existiert..Falls ja, soll er den Wert "hoehe", der in dem jeweiligen Stellplatz existiert (s. Struct) um 1 hochgezählt werden.
    Danach soll er die Funktion rekursiv aufrufen mit dem nächsten Container (container->next), der über dem aktuellen liegt.

    Falls dieser Container dann nicht existiert, soll er die Funktion mit dem nächsten Stellplatz (kopf->next aufrufen) und dort wieder alles durchgehen..bis er ans Ende der Stellplatz Liste gelangt (hier Stellplatz: 4).
    Beim letzten Durchlauf der Container-Stellplatz-Liste (also nach Abarbeitung des Container Nr. 4 wird in Z. 72 kopf->next übergeben und da dieser nicht existiert, gelangt er bei diesem erneuten Aufruf in die IF-Bedingung "if(kopf==NULL)" und ruft die Fanktion nacheinander mit zwei anderen Stellplätzen auf (LKW und Frachter), die er nach dessen Höhe abfragt.

    So sollte es aussehen


    E: Es wurde der Text nochmal editiert!

    E²: Die free()s kommen ja noch! All die Sachen mit malloc() werden ja für spätere Funktionen noch benötigt! Den Sachen mit den Headern werd ich mich aber nochmal widmen, danke!
    Geändert von blub11 (03.08.11 um 15:39 Uhr)
     

  7. #7
    deepthroat deepthroat ist offline Mitglied Diamant
    tutorials.de Premium-User
    Registriert seit
    Jun 2005
    Beiträge
    8.168
    Zitat Zitat von blub11 Beitrag anzeigen
    Also so ganz verstanden hab ich dich nicht ):
    Wen? Bitte zitieren und gezielt Fragen stellen oder jemanden direkt ansprechen.

    Du hast dort eine Endlos-Rekursion erstellt. Die Funktion kehrt nie zurück, sie wird sich immer wieder selbst aufrufen. Das kann so nicht funktionieren.

    Anscheinend möchtest du die Länge von allen Listen berechnen und addieren. Da stellt sich mir die Frage warum die Funktion keinen Rückgabewert hat und du das Ergebnis offenbar im Kopf speicherst. Das ist etwas seltsam. Und zu kompliziert.

    Schreibe dir eine Funktion die von einer gegebenen Liste die Länge berechnet.

    Gruß

    PS: Rekursion scheint mir auch nicht unbedingt allzu elegant für dieses Problem zu sein.
    Geändert von deepthroat (03.08.11 um 15:38 Uhr)
     
    If at first you don't succeed, try again. Then quit. No use being a damn fool about it.

  8. #8
    blub11 blub11 ist offline Mitglied Bronze
    Registriert seit
    Feb 2011
    Beiträge
    29
    @deepthroat: Aber wieso endlos-Rekursion? Wenn die Bedingung "if(kopf==NULL)" funktionieren würde, dann wären es doch mit der anderen Bedingung zusammen m.M. nach genug Abbruchbedingungen?!
    Also wenn er in der if-Bedingung "if(kopf==NULL)" ist und später zu
    " hoehe_vergleichen(lkw, kopf, frachter);" kommt, geht er ja aus der Funktion raus.

    Also ich möchte nicht die Länge aller (zwei) Listen addieren..Nur die der Liste mit den Containern (also die Menge der Container, die auf jedem Stellplatz liegen(=Höhe)). Und dabei wird, wenn es keine weiteren Container auf einem Stellplatz gibt, zum nächsten Stellplatz gesprungen (kopf->next), so lange, bis auch diese Liste ihr Ende erreicht "if(kopf==NULL)".

    Und die Höhe muss ich in jedem Stellplatz speichern, denn diese werden später alle noch miteinander verglichen (in anderen FUnktionen)...
     

  9. #9
    deepthroat deepthroat ist offline Mitglied Diamant
    tutorials.de Premium-User
    Registriert seit
    Jun 2005
    Beiträge
    8.168
    Zitat Zitat von blub11 Beitrag anzeigen
    @deepthroat: Aber wieso endlos-Rekursion? Wenn die Bedingung "if(kopf==NULL)" funktionieren würde, dann wären es doch mit der anderen Bedingung zusammen m.M. nach genug Abbruchbedingungen?!
    Nein.
    Zitat Zitat von blub11 Beitrag anzeigen
    Also wenn er in der if-Bedingung "if(kopf==NULL)" ist und später zu
    " hoehe_vergleichen(lkw, kopf, frachter);" kommt, geht er ja aus der Funktion raus.
    Irrtum. (\edit: diese Zeile wird übrigens nie erreicht, da direkt vorher erstmal die Funktion rekursiv aufgerufen wird, Widerstand ist zwecklos - es gibt kein Entkommen... )

    Die Ausführung geht immer nach dem if Block weiter. Egal ob die Bedingung des if nun wahr ist oder nicht!

    Wenn du die Funktion beenden willst, mußt du irgendwo ein return hinschreiben bzw. dafür sorgen, das die Funktion sich nicht immer wieder neu aufruft.

    Ich würde es ungefähr so versuchen:
    Code c:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
    size_t berechne_hoehe(struct stellplaetze* kopf) {
      size_t ret = 0;  
     
      for (; kopf; kopf = kopf->next) {
        if (kopf->container)
          ret += list_length(kopf->container);
      }
      return ret;
    }
     
    ...
     
     
    stellplaetze->hoehe = berechne_hoehe(stellplaetze);
    lkw->hoehe =  berechne_hoehe(lkw);
    frachter->hoehe = berechne_hoehe(frachter);

    Wobei, wenn du die Höhe in den einzelnen Listen speicherst, könntest du evtl. diese Information beim Einfügen und Löschen aktuell halten, so das jederzeit die Höhe verfügbar ist und eben nicht erst komplett berechnet werden muss.

    Gruß
    Geändert von deepthroat (03.08.11 um 16:21 Uhr)
     
    If at first you don't succeed, try again. Then quit. No use being a damn fool about it.

  10. #10
    blub11 blub11 ist offline Mitglied Bronze
    Registriert seit
    Feb 2011
    Beiträge
    29
    Ok das mit dem absolut notwendigen return is jetzt klar..


    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
    void hoehe_berechnen(struct stellplaetze *kopf, struct container *container, struct stellplaetze *lkw, struct stellplaetze *frachter)
    {
     
        if(kopf==NULL) //HIER GEHT ER NICHT REIN! ANSCHEINEND IST DAS ELEMENT NACH DEM LETZTEN ELEMENT NICHT NULL? DANACH STÜRZT DAS PROGRAMM AB (LOGISCHERWEISE)
        {
            hoehe_berechnen(lkw, lkw->container, lkw, frachter);
            hoehe_berechnen(frachter, frachter->container, lkw, frachter);
            hoehe_vergleichen(lkw, kopf, frachter);
        }
        if(container==NULL) hoehe_berechnen(kopf->next, kopf->next->container, lkw, frachter);
        else
        {
        kopf->hoehe+=1;
        hoehe_berechnen(kopf, container->next, lkw, frachter);
        }
    }

    Irrtum. (\edit: diese Zeile wird übrigens nie erreicht, da direkt vorher erstmal die Funktion rekursiv aufgerufen wird, Widerstand ist zwecklos - es gibt kein Entkommen... )
    Das will mir nicht in Kopf ):
    Wenn er die Funktion denn immer wieder rekursiv mit dem nächsten Stellplatz aufruft und meinetwegen bei Stellplatz 4 Schluss ist (weil wir nur 4 eingegeben haben), ruft er doch die Funktion noch einmal auf mit dem (nicht vorhandenen) Stellplatz 5 auf..Und am Anfang wird dann gleich geprüft, ob Stellplatz 5 (=kopf) ==NULL ist....Glaub ich sitz hier schon zu lange vor ):
    Das hat immer so funktioniert mit doppelt verketteten Listen und rekursiven Funktionen ):
    Würde es halt gerne auf die rekursive Weise lösen..
     

  11. #11
    Steiner_B Steiner_B ist offline Mitglied Platin
    Registriert seit
    Mar 2004
    Ort
    Wien
    Beiträge
    573
    Hallo,

    Eine If-Bedingung wirkt sich nie auf den Code aus, welcher nach dem Ende des Ifs steht. Das bedeutet, wie schon oben beschrieben:
    Code cpp:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    void hoehe_berechnen(struct stellplaetze *kopf, struct container *container, struct stellplaetze *lkw, struct stellplaetze *frachter)
    {
        if(kopf==NULL)
        {
           //Wenn Kopf NULL ist kommt man hier rein
        }
        
        //und egal ob wir oben in dem IF drin waren oder nicht, wir kommen auf jeden Fall hier her
        kopf->hoehe+=1;
        hoehe_berechnen(kopf, container->next, lkw, frachter);
    }

    Daher wird die Funktion IMMER rekursiv aufgerufen, und hört somit nie auf.
     

  12. #12
    blub11 blub11 ist offline Mitglied Bronze
    Registriert seit
    Feb 2011
    Beiträge
    29
    Ja genau hehe aber ich frage mich ja seit dem 1. Post, wieso "kopf" anscheindend nicht =NULL ist..da suche ich ja schon so lange rum..): Trotzdem danke schonmal an euch
     

  13. #13
    deepthroat deepthroat ist offline Mitglied Diamant
    tutorials.de Premium-User
    Registriert seit
    Jun 2005
    Beiträge
    8.168
    Zitat Zitat von blub11 Beitrag anzeigen
    Ja genau hehe aber ich frage mich ja seit dem 1. Post, wieso "kopf" anscheindend nicht =NULL ist..da suche ich ja schon so lange rum..):
    Weil deine Funktion so falsch ist, dass es vorher knallt bevor kopf in Zeile 67 erfolgreich auf NULL getestet werden würde.

    Insbesondere in Zeile 73 prüfst du ob container == NULL ist. Wenn das der Fall ist, rufst du die Funktion hoehe_berechnen rekursiv auf. Dabei greifst du auf kopf->next->container zu. Falls kopf allerdings auf das letzte Element der Liste zeigt, gibt es kein nächstes Element; d.h. kopf->next ist NULL... BOOM!

    Zitat Zitat von blub11 Beitrag anzeigen
    Würde es halt gerne auf die rekursive Weise lösen..
    Rekursion ist aber leider in C/C++ limitiert. D.h. wenn deine Liste sehr groß ist, wächst die Rekursionstiefe proportial an und dein Programm wird abstürzen wenn der Stackspeicher überschritten wird. Eine iterative Lösung ist in C/C++ vorzuziehen, außer man kann davon ausgehen, dass die Rekursionstiefe eine kleine obere Grenze besitzt.

    Gruß
    Geändert von deepthroat (04.08.11 um 10:52 Uhr)
     
    If at first you don't succeed, try again. Then quit. No use being a damn fool about it.

  14. #14
    blub11 blub11 ist offline Mitglied Bronze
    Registriert seit
    Feb 2011
    Beiträge
    29
    Ok jetzt ist es schon besser
    Danke für die Hilfe, wir haben mittlerweile auch eine iterative Lösung erarbeitet

    Grüße
     

Ähnliche Themen

  1. Abstand zum nächsten Element auf null?
    Von robat2oo6 im Forum CSS
    Antworten: 3
    Letzter Beitrag: 22.03.10, 20:05
  2. Mysql-Abfrage mit Null-Werten
    Von Spechter im Forum Relationale Datenbanksysteme
    Antworten: 9
    Letzter Beitrag: 16.10.08, 14:23
  3. IS NOT NULL (SQL-Abfrage)
    Von f_mal im Forum Relationale Datenbanksysteme
    Antworten: 4
    Letzter Beitrag: 05.09.05, 16:07
  4. SQL Abfrage (NULL Werte ausgeben)
    Von superjoe im Forum Relationale Datenbanksysteme
    Antworten: 3
    Letzter Beitrag: 01.08.05, 14:58
  5. DB Abfrage NOT NULL ?
    Von Frankster im Forum PHP
    Antworten: 5
    Letzter Beitrag: 12.09.03, 14:25

Stichworte