Seite 1 von 2

Schleife in Prozedur: 1. Aufruf OK, 2. Aufruf endlos

Verfasst: 28.07.2010 21:51
von Mok
Hallo.
Ich hab schon seit einiger zeit ein Brett vorm Kopf und komm selber nicht auf den Fehler, daher bitte ich euch, mir zu helfen.
Also, hier ist meine Stack-Include (von mir nach PB übersetzt, Quelle ist die Musterlösung einer C-Hausübung)

Code: Alles auswählen

EnableExplicit

Macro _ret
  ProcedureReturn
EndMacro

Structure Stack
  *Val
  *Next.Stack
EndStructure

Procedure InitStack()
  Protected.Stack *Temp
  *Temp = AllocateMemory(SizeOf(Stack))
  _ret *Temp
EndProcedure

Procedure CountStack(*Stack.Stack)
  Debug "____Called."
  Protected.Stack *Temp
  Protected.i Count
  
  If *Stack = #Null : _ret 0 : Else
    *Temp = *Stack\Next
    
    While *Temp <> #Null
      Debug "____Inner Loop"
      Count = Count + 1
      *Temp = *Temp\Next
    Wend
    Debug "____Outer Loop"
    _ret Count
  EndIf
EndProcedure

Procedure IsStackEmpty(*Stack.Stack)
  _ret (CountStack(*Stack) = 0)
EndProcedure

Procedure Push(*Stack.Stack, *Item)
  Protected.Stack *Temp
  
  If *Stack = #Null : _ret #False : Else
  
  *Temp = InitStack()
  *Temp\Val = *Item
  *Temp\Next = *Stack\Next
  *Stack\Next = *Temp
  
  _ret #True : EndIf
EndProcedure

Procedure Pop(*Stack.Stack)
  Protected.Stack *Temp 
  Protected *VAL0__
  
  If IsStackEmpty(*Stack) Or *Stack = 0 : _ret #False : Else
  
  *Temp = *Stack\Next
  *VAL0__ = *Temp\Val
  *Stack\Next = *Temp\Next
  FreeMemory(*Temp)
  
  _ret *VAL0__ : EndIf
EndProcedure

Procedure FreeStack(*Stack.Stack)
  FreeMemory(*Stack)
EndProcedure

Define.Stack *MyStack = InitStack() ;Aufruf OK
Define.i Item = 5
Debug Push(*MyStack,@Item) ;Rückgabewert ist 1 => Aufruf OK
Debug "---"
Debug Pop(*MyStack) ;Rückgabewert ist eine Adresse => Aufruf OK
FreeStack(*MyStack) ;Aufruf OK
Debug "---" ;Das wird noch gedruckt
Debug IsStackEmpty(*MyStack) ;Hier wird aufgrund des Aufrufs von IsStackEmpty() und weiters durch den Aufruf von CountStack() nichts ausgegeben.
Debug Push(*MyStack,@Item)

Re: Schleife in Prozedur: 1. Aufruf OK, 2. Aufruf endlos

Verfasst: 28.07.2010 21:59
von STARGÅTE
Der Grund ist du erzeugst ein zyklischen Bezug:
Das heißt:

Code: Alles auswählen

While *Temp <> #Null
      Debug "____Inner Loop"
      Count = Count + 1
      *Temp = *Temp\Next
    Wend
Dort ist zB:
*Temp = 4063608
*Temp\Next wäre zB 4071056
Aber der näche also *Temp\Next\Next wäre wieder 4063608
Somit gibs da n Schleife.

Checke also noch mal das setzen deiner Next-Pointer ...

Re: Schleife in Prozedur: 1. Aufruf OK, 2. Aufruf endlos

Verfasst: 28.07.2010 22:01
von Mok
@STARGÅTE: Irgendwann muss *Next ja mal auf Null zeigen, weil sonst hätte man ja nen unendlichen Stack

Re: Schleife in Prozedur: 1. Aufruf OK, 2. Aufruf endlos

Verfasst: 28.07.2010 22:26
von STARGÅTE
Jo, vllt bei anderen,
Aber in deinem Code gibs eben nKreisbezug.

Weil das 1. zum 2. Zeigt und das 2. zum 1. ...
das wird nie null, weil immer nur 2 elemente beteilig sind, die sich immer wieder gegenseitig aufrufen.

das wird also dort nicht irgendwann null

Re: Schleife in Prozedur: 1. Aufruf OK, 2. Aufruf endlos

Verfasst: 29.07.2010 08:41
von helpy
Hallo,

Denke den ganzen Aufbau nochmal durch!

1. FreeStack wird so nicht funktionieren, sondern zu einem Memory-Leak führen, denn mit jedem Push erzeugst Du mit InitStack ein neues Stack-Element, das mit AllocateMemory() neuen Speicher beansprucht. Deshalb musst Du bei FreeStack auch eine Schleife einbauen, die jedes Stack-Element durchgeht und den zugehörigen Speicher freigibt.

2. Schau Dir Push() genau an! Die beiden Zeilen

Code: Alles auswählen

  *Temp\Next = *Stack\Next
  *Stack\Next = *Temp
erzeugen bereits einen Zirkelschluss!

3. Ein Stack (Stapel) funktioniert doch so, dass Du mit Push() ein Element AUF den Stapel legst und mit Pop() das letzte Element vom Stapel wieder runter holst. Wenn *Stack.Stack immer auf das erste Element (den Stapel-Anfang) zeigt, dann brauchst Du doch immer eine Schleife, um das letzte Element zu ermitteln und da das neue dran zu hängen (Push) bzw. das letzte Element vom Stapel runter zu holen (Pop). Den Sonderfall "Leerer Stack" muss man entsprechend behandeln.
==> Also beide Prozeduren Push() und Pop() noch mal neu durchdenken und überarbeiten!

lg,
guido

Re: Schleife in Prozedur: 1. Aufruf OK, 2. Aufruf endlos

Verfasst: 29.07.2010 16:25
von Mok
Ich lauf irgendwie nur im Kreis. Je mehr ich verbessern will, desto schlimmer wird's. Dabei ist es doch eine Übersetzung einer Musterlösung und die sollte eigentlich in Ordnung sein. :roll:

Re: Schleife in Prozedur: 1. Aufruf OK, 2. Aufruf endlos

Verfasst: 29.07.2010 18:06
von helpy
Falls Du keine fix-fertige Lösung von jemand anderem suchst, sondern etwas lernen möchtest, dann schläfst Du mal eine Nacht drüber und versuchst es morgen ganz von vorne ;-)

... evt zeichnest Du Dir den Stack auf Papier und welcher Zeiger (Next) wohin zeigt.
... dann gehst Du alles Schritt für Schritt durch.

lg,
guido

Re: Schleife in Prozedur: 1. Aufruf OK, 2. Aufruf endlos

Verfasst: 29.07.2010 20:15
von Mok
helpy hat geschrieben:Falls Du keine fix-fertige Lösung von jemand anderem suchst[...]
as hab ich auch nie getan...
Push & Pop müssten doch so funktionieren:

Code: Alles auswählen

Procedure Push(*Stack.Stack, *Item)
  Protected.Stack *Temp
  
  If *Stack = #Null : _ret #False : Else
  
  *Temp = InitStack()
  *Temp\Val = *Item
  If IsStackEmpty(*Stack)
    *Temp\Next = #Null
  Else
    *Temp\Next = *Stack\Next
  EndIf
  *Temp = *Stack
  
  _ret #True : EndIf
EndProcedure

Procedure Pop(*Stack.Stack)
  Protected.Stack *Temp 
  Protected *Value
  
  If IsStackEmpty(*Stack) Or *Stack = #Null : _ret #False : Else
  
  *Value = *Stack\Val
  *Stack = *Stack\Next
  
  _ret *Value : EndIf
EndProcedure
Tunse aber nicht :freak:

Re: Schleife in Prozedur: 1. Aufruf OK, 2. Aufruf endlos

Verfasst: 29.07.2010 21:49
von mk-soft
Nicht das "Next" speichern, sondern das Previous" speichern.

Re: Schleife in Prozedur: 1. Aufruf OK, 2. Aufruf endlos

Verfasst: 30.07.2010 14:19
von Mok
mk-soft hat geschrieben:Nicht das "Next" speichern, sondern das Previous" speichern.
Das Previous kann nicht existieren, weil es im Stack nur ein Next gibt (FILO)