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

Für allgemeine Fragen zur Programmierung mit PureBasic.
dire3
Beiträge: 7
Registriert: 04.08.2014 13:51

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

Beitrag 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.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

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

Beitrag 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.
dire3
Beiträge: 7
Registriert: 04.08.2014 13:51

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

Beitrag 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.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

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

Beitrag 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
dire3
Beiträge: 7
Registriert: 04.08.2014 13:51

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

Beitrag 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)".
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

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

Beitrag von NicTheQuick »

Entweder du nutzt PushElement und PullElement oder du nimmst den Pointer von @*g\Objects() und nicht von @*mag.
dire3
Beiträge: 7
Registriert: 04.08.2014 13:51

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

Beitrag von dire3 »

Ich habe die Adresse jetzt durch "@*g\Objects()" ersetzt, um Konsistenz zum restlichen Code zu bewahren.
Antworten