Programm überspringt Abfrage (if(element==NULL))

blub11

Mitglied
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 :)
 
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! :)
 
Zuletzt bearbeitet:
Hi.

blub11 hat gesagt.:
C:
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:
C:
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.
 
Zuletzt bearbeitet:
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 :(
 
@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  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 :p


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! ;)
 
Zuletzt bearbeitet:
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.
 
Zuletzt bearbeitet:
@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)...
 
@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.
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:
C:
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ß
 
Zuletzt bearbeitet:
Ok das mit dem absolut notwendigen return is jetzt klar..


Code:
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..
 
Zurück