Seite 1 von 1

[List] "Absturz bei Verändern eines Elements"

Verfasst: 29.01.2015 19:25
von dire3
Hallo,

der Titel ist nicht allzu aussagekräftig, da mein Problem vermutlich sehr speziell ist. Mein Programm stürzt mit "Invalid Memory Access" ab, wenn ich ein Attribut eines Elements einer Liste verändere und "anschließend" auf das nachfolgende Element zugreifen möchte. Ein Auszug aus meinem Code, der zunächst problemlos läuft:

Code: Alles auswählen

  ; Iteriere über alle Elemente der Liste (Kommentare sind durchnummeriert)
  ResetList(*g\Objects())
  While NextElement(*g\Objects())
      Debug *g\Objects() ; 1.
      Define *mag.Object = *g\Objects()
      Define *mData.MagnetData = *mag\Data
      Debug "*mag = " + *mag
      Debug "Name = " + *mag\Name ; 2.
"*g" ist dabei eine Struktur:

Code: Alles auswählen

Structure GameField
  Array *Blocks.Object(0, 0)
  List *Objects.Object()
  Height.l
  Width.l
EndStructure
Wenn ich aber nun an einer anderen Stelle auf ein Element der Liste zugreife und dort ein Attribut verändere, knallt es in Zeile mit Kommentar 1, nachdem allerdings zuvor die Schleife mit dem veränderten Element noch problemlos durchläuft (d. h. es wird Kommentarzeile 2 ausgeführt, dann beim nächsten Durchlauf gibt es Probleme).

Ein Beispiel verdeutlicht vielleicht etwas besser, was ich meine. In der Liste sind 6 Elemente. Ich verändere das 4. Element (Code folgt unten). Die While-Schleife wird dann 4 Mal korrekt ausgeführt, beim Zugriff auf das 5. Element scheitert der Zugriff aber.

Der Code, der das Element verändert:

Code: Alles auswählen

    Define *obj.Object = MouseOverObject(*curLevel\GameField, MouseX(), MouseY()) ; Liefert das korrekte Element (Pointer sind identisch)
    
    If *obj <> #Null And *obj\Type = #Magnet
      Define *mData.MagnetData = *obj\Data
      Debug *mData\IsActive ; Liefert 0 (wie erwartet)
      *mData\IsActive = LNot(*mData\IsActive) ; Verändern des Wertes. Wird diese Zeile auskommentiert, läuft alles korrekt
      Debug *mData\IsActive ; Liefert 1 (wie erwartet) 
    EndIf
Auszug aus "Object":

Code: Alles auswählen

Structure Object
  Name.s       ; Non-unique name of the object
  *Data        ; Additional data if needed
EndStructure
Wird von "Data" ein Attribut geändert, stürzt das später Programm ab. Ändere ich hingegen "Name" von *obj, läuft es korrekt. An "Data" wurde bei Erzeugen des Objektes mit "AllocateStructure(MagnetData)" Speicher zugewiesen, der ja eigentlich auch unabhängig von der Umgebung vom Objekt sein sollte. Was geschieht hier also?

Ich hoffe, dass mein Problem klar geworden ist, und ein (oder mehrere) schlaue Menschen Rat haben.

Re: [List] "Absturz bei Verändern eines Elements"

Verfasst: 29.01.2015 19:44
von NicTheQuick
Was macht denn 'LNot()'? Hat das vielleicht irgendwelche Nebeneffekte?
Ansonsten wäre es schon praktisch, wenn man einen lauffähigen Code hätte, den man analysieren könnte.

Re: [List] "Absturz bei Verändern eines Elements"

Verfasst: 29.01.2015 21:53
von dire3
"LNot()" negiert das Argument einfach (gibt's das in PB vllt. schon? Ein "Not x" funktioniert nicht). Ein Minimalbeispiel liefere ich morgen nach.

Re: [List] "Absturz bei Verändern eines Elements"

Verfasst: 29.01.2015 22:26
von NicTheQuick
dire3 hat geschrieben:"LNot()" negiert das Argument einfach (gibt's das in PB vllt. schon? Ein "Not x" funktioniert nicht).
Du kannst es so machen:

Code: Alles auswählen

Debug "Logisch"
i.i = #True
Debug i
i = Bool(Not i)
Debug i
i = Bool(Not i)
Debug i

Debug "Binär"
i = -1
Debug i
i = ~i
Debug i
i = ~i
Debug i

Re: [List] "Absturz bei Verändern eines Elements"

Verfasst: 30.01.2015 20:34
von dire3
Hallo,

das Problem habe ich soeben entdeckt. Hätte ich gestern etwas mehr Code gepostet, wäre das sicherlich auch sofort aufgefallen. Innerhalb der While-Schleife habe ich noch eine While-Schleife, die ebenfalls über die Liste iteriert. Mithilfe von ChangeCurrentElement() soll am Ende der inneren Schleife das Element der äußeren wiederhergestellt werden. Im Grunde sieht das wie folgt aus:

Code: Alles auswählen

  ResetList(*g\Objects())
  While NextElement(*g\Objects())
    ; ...
      Define *mag.Object = *g\Objects()
      Define *mData.MagnetData = *mag\Data

      If *mData <> #Null And *mData\IsActive
        Define *magAddr.Object = @*mag ; <-- Adresse von *mag, nicht *g\Objects()
        
        ; Reset list to iterate through all objects and look for the box
        ResetList(*g\Objects())
        While NextElement(*g\Objects())
          If *g\Objects()\Type = #Box And *g\Objects()\Color = *mag\Color
            ; Do Stuff
            Break
          EndIf
        Wend
        
        ; Change to prev. position
        ChangeCurrentElement(*g\Objects(), *magAddr) ; Falsche Adresse, weil @*mag != @*g\Objects
      EndIf
    ; ...
  Wend
Es wird nicht die korrekte Adresse in "ChangeCurrentElement()" gesetzt, was verständlicherweise zu Problemen führt. Das geschieht aber nur, wenn IsActive auf #True gesetzt wird. Setze ich die korrekte Adresse, funktioniert alles wie gewollt.

Danke für den Tipp mit "Bool(Not x)".

Re: [List] "Absturz bei Verändern eines Elements"

Verfasst: 30.01.2015 22:23
von NicTheQuick
Entweder du nutzt PushElement und PullElement oder du nimmst den Pointer von @*g\Objects() und nicht von @*mag.

Re: [List] "Absturz bei Verändern eines Elements"

Verfasst: 31.01.2015 23:26
von dire3
Ich habe die Adresse jetzt durch "@*g\Objects()" ersetzt, um Konsistenz zum restlichen Code zu bewahren.