Struktur-Variable über Funktion per Zeiger kopieren

Für allgemeine Fragen zur Programmierung mit PureBasic.
Beefi
Beiträge: 88
Registriert: 16.01.2017 17:38

Struktur-Variable über Funktion per Zeiger kopieren

Beitrag von Beefi »

Hi,

ich benötige wieder eure Hilfe :) Und zwar kann ich keine Struktur-Variable mit über einen Zeiger kopieren.
Eine Struktur mit gesamten Inhalt ist ja leicht per "=" kopierbar. Hier ein Beispiel:

Code: Alles auswählen

Structure MeineStruktur
    Eins.i
    Zwei.i
    Drei.i
EndStructure

Define Test_A.MeineStruktur
Test_A\Eins = 1
Test_A\Zwei = 2
Test_A\Drei = 3

Define Test_B.MeineStruktur = Test_A
Ich würde so eine Zuweisung gerne über den Rückgabewert einer Funktion machen, mit einem Zeiger. Das funktioniert aber nicht.
Es kommt immer ein Fehler, dass man einer Struktur keinen Wert Zuweisen kann.
Hier ein Beispiel, wie ich es gerne machen würde:

Code: Alles auswählen

Structure MeineStruktur
    Eins.i
    Zwei.i
    Drei.i
EndStructure


Procedure.i Kopieren()
    
    Static *Test_A.MeineStruktur
    *Test_A\Eins = 1
    *Test_A\Zwei = 2
    *Test_A\Drei = 3
    
  ProcedureReturn *Test_A
EndProcedure


Define Test_B.MeineStruktur = Kopieren()
Kann mir jemand einen Tip geben, was ich falsch mache? Bzw. ob mein Vorhaben überhaupt möglich ist? Vielleicht ist mein Gedankenansatz ja auch völlig falsch :mrgreen:

Viele Grüße
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: Struktur-Variable über Funktion per Zeiger kopieren

Beitrag von ts-soft »

Man kann die Zuweisung an einen Pointer gleichen Typs machen (auskommentierter Code) oder kopieren:

Code: Alles auswählen

Structure MeineStruktur
  Eins.i
  Zwei.i
  Drei.i
EndStructure

Procedure.i Kopieren()
  Static *Test_A.MeineStruktur
  *Test_A = AllocateMemory(SizeOf(MeineStruktur))
  *Test_A\Eins = 1
  *Test_A\Zwei = 2
  *Test_A\Drei = 3
  
  ProcedureReturn *Test_A
EndProcedure

; Define *Test_B.MeineStruktur = Kopieren() 
; Debug *Test_B\Eins
; Debug *Test_B\Zwei
; Debug *Test_B\Drei

Define Test_B.MeineStruktur
CopyMemory(Kopieren(), @Test_B, SizeOf(MeineStruktur))
Debug Test_B\Eins
Debug Test_B\Zwei
Debug Test_B\Drei
Gruß
Thomas
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
helpy
Beiträge: 635
Registriert: 29.08.2004 13:29

Re: Struktur-Variable über Funktion per Zeiger kopieren

Beitrag von helpy »

Drei Ansätze!

1. Ergebnis-Variable mit an die Prozedur übergeben:

Code: Alles auswählen

EnableExplicit

Structure MeineStruktur
  Eins.i
  Zwei.i
  Drei.i
EndStructure

Procedure.i Kopieren(*Result.MeineStruktur)
  Static Test_A.MeineStruktur
  Test_A\Eins = 1
  Test_A\Zwei = 2
  Test_A\Drei = 3
  
  CopyStructure(@Test_A, *Result, MeineStruktur)
EndProcedure

Define Test_B.MeineStruktur
Kopieren(@Test_B) 

Debug Test_B\Eins
Debug Test_B\Zwei
Debug Test_B\Drei
2. Nach Prozeduraufruf das Ergebnis kopieren: (ähnlich wie ts-soft nur mit CopyStructure)

Code: Alles auswählen

EnableExplicit

Structure MeineStruktur
  Eins.i
  Zwei.i
  Drei.i
EndStructure

Procedure.i Kopieren()
  Static Test_A.MeineStruktur
  Test_A\Eins = 1
  Test_A\Zwei = 2
  Test_A\Drei = 3
  
  ProcedureReturn @Test_A
EndProcedure

Define Test_B.MeineStruktur
CopyStructure( Kopieren(), @Test_B, MeineStruktur )

Debug Test_B\Eins
Debug Test_B\Zwei
Debug Test_B\Drei
3. Oder nur mit Pointer arbeiten:

Code: Alles auswählen

EnableExplicit

Structure MeineStruktur
  Eins.i
  Zwei.i
  Drei.i
EndStructure

Procedure.i Kopieren()
  Protected  *Test_A.MeineStruktur = AllocateMemory(SizeOf(MeineStruktur))
  *Test_A\Eins = 1
  *Test_A\Zwei = 2
  *Test_A\Drei = 3
  
  ProcedureReturn *Test_A
EndProcedure

Define *Test_B.MeineStruktur
*Test_B = Kopieren()

Debug *Test_B\Eins
Debug *Test_B\Zwei
Debug *Test_B\Drei

FreeMemory(*Test_B)
Dabei muss aber gut darauf geachtet werden, dass der allokierte Speicher wieder freigegeben wird, wenn er nicht mehr benötigt wird.
Windows 10
PB Last Final / (Sometimes testing Beta versions)
Beefi
Beiträge: 88
Registriert: 16.01.2017 17:38

Re: Struktur-Variable über Funktion per Zeiger kopieren

Beitrag von Beefi »

Super, vielen Dank euch beiden :allright:
Ich werde die Lösungen heute Abend gleich mal ausprobieren und mich melden.
Benutzeravatar
mk-soft
Beiträge: 3701
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Struktur-Variable über Funktion per Zeiger kopieren

Beitrag von mk-soft »

Ich bevorzuge AllocateStructure. Somit funktioniert es auch mit String, List und Maps

Es gibt viele Wege. Man kann auch ein Pointer auf ein Pointer übergeben.

Code: Alles auswählen


EnableExplicit

Structure MeineStruktur
  Eins.i
  Zwei.i
  Drei.i
  Text.s
EndStructure

Procedure.i InitData(*Result.integer)
  Protected *mem.MeineStruktur
  *mem = AllocateStructure(MeineStruktur)
  If *mem
    *Result\i = *mem
  Else
    ProcedureReturn #False
  EndIf
  With *mem
    \Eins = 1
    \Zwei = 2
    \Drei = 3
    \Text = "Hallo Welt"
  EndWith
  ProcedureReturn #True
  
EndProcedure

Define *Test_B.MeineStruktur
Define Test_C.MeineStruktur
Debug InitData(@*Test_B) 

Debug *Test_B\Eins
Debug *Test_B\Zwei
Debug *Test_B\Drei
Debug *Test_B\Text


Define Test_C.MeineStruktur
CopyStructure(*Test_B, Test_C, MeineStruktur)
Debug Test_C\Eins
Debug Test_C\Zwei
Debug Test_C\Drei
Debug Test_C\Text

Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
helpy
Beiträge: 635
Registriert: 29.08.2004 13:29

Re: Struktur-Variable über Funktion per Zeiger kopieren

Beitrag von helpy »

mk-soft hat geschrieben:Ich bevorzuge AllocateStructure. Somit funktioniert es auch mit String, List und Maps
Da gebe ich Dir recht! Würde ich auch so machen.
Windows 10
PB Last Final / (Sometimes testing Beta versions)
Beefi
Beiträge: 88
Registriert: 16.01.2017 17:38

Re: Struktur-Variable über Funktion per Zeiger kopieren

Beitrag von Beefi »

Hi,

also ich habe jetzt eure Lösungsvorschläge studiert und getestet. Vielen vielen Dank an alle...das Problem ist jetzt gelöst :mrgreen:
Die AllocateStructure()-Version funktioniert...ABER der entscheidende Punkt war bei mir die Funktion CopyStructure(), auf die ich nur durch eure Hilfe gekommen bin.
Ich hätte wohl in meinem Beispiel anfügen sollen, dass die Struktur anschließend einer Map zugewiesen werden muss.
Die Fehlermeldung lag dann letztendlich an diesem Umstand...so, dass es ganz normal mit Zeigern funktioniert.

Ich habe nochmal ein kleines Beispiel zusammengeschrieben:

Code: Alles auswählen

EnableExplicit

Structure Fahrzeug
  Name.s
  Kilometerstand.i
  Alter.i
EndStructure


NewMap FahrzeugHalle.Fahrzeug()


Procedure.i ErzeugeFahrzeug()
  
  Static Temp.Fahrzeug
  Temp\Name = InputRequester("Fahrzeugname", "Gib einen Fahrzeugnamen ein:", "")
  Temp\Kilometerstand = 50000
  Temp\Alter = 5
  
  ProcedureReturn @Temp
EndProcedure


; Hauptcode
Define *EinAuto.Fahrzeug = ErzeugeFahrzeug()
Define AutoName.s = *EinAuto\Name
AddMapElement(FahrzeugHalle(), AutoName)

;FahrzeugHalle(AutoName) = *EinAuto            ;    <- Das funktionierte ursprünglich nicht
CopyStructure(*EinAuto, FahrzeugHalle(AutoName), Fahrzeug)   ;   <- CopyStructure löst mein Problem


Debug FahrzeugHalle(*EinAuto\Name)\Name
Debug FahrzeugHalle(*EinAuto\Name)\Alter
Debug FahrzeugHalle(*EinAuto\Name)\Kilometerstand
Welchen Vorteil würde jetzt AllocateStructure bringen?

Ich muss schon sagen, umso tiefer ich in PureBasic einsteige, umso mehr erinnert es mich an C :mrgreen:
Nur die Syntax ist anders und die Bibliotheken sind einfach nur genial.
Benutzeravatar
Sicro
Beiträge: 955
Registriert: 11.08.2005 19:08
Kontaktdaten:

Re: Struktur-Variable über Funktion per Zeiger kopieren

Beitrag von Sicro »

Wenn dein Beispiel-Code nicht so sehr von deinem eigentlichen Code abweicht, wäre es so einfacher:

Code: Alles auswählen

EnableExplicit

Structure Fahrzeug
  Name$
  Kilometerstand.i
  Alter.i
EndStructure

NewMap FahrzeugHalle.Fahrzeug()

Procedure.i ErzeugeFahrzeug(Map FahrzeugHalle.Fahrzeug())
  
  Protected FahrzeugName$ = InputRequester("Fahrzeugname", "Gib einen Fahrzeugnamen ein:", "")
  If FahrzeugName$ = "" : ProcedureReturn #False : EndIf
  
  If Not AddMapElement(FahrzeugHalle(), FahrzeugName$)
    ProcedureReturn #False
  EndIf
  
  With FahrzeugHalle()
    \Name$          = FahrzeugName$
    \Kilometerstand = 50000
    \Alter          = 5
  EndWith
    
  ProcedureReturn #True
EndProcedure

; Hauptcode
ErzeugeFahrzeug(FahrzeugHalle())
ForEach FahrzeugHalle()
  With FahrzeugHalle()
    Debug \Name$
    Debug \Alter
    Debug \Kilometerstand
  EndWith
  Debug "------"
Next
Bild
Warum OpenSource eine Lizenz haben sollte :: PB-CodeArchiv-Rebirth :: Pleasant-Dark (Syntax-Farbschema) :: RegEx-Engine (kompiliert RegExes zu NFA/DFA)
Manjaro Xfce x64 (Hauptsystem) :: Windows 10 Home (VirtualBox) :: Neueste PureBasic-Version
Benutzeravatar
#NULL
Beiträge: 2235
Registriert: 20.04.2006 09:50

Re: Struktur-Variable über Funktion per Zeiger kopieren

Beitrag von #NULL »

hi beefi
du benutzt in deinem letzen beispiel eine static variable ohne pointer. bei mehreren aufrufen von ErzeugeFahrzeug() würde dann immer nur das eine Fahrzeug geändert aber kein neues erzeugt. ts-soft verwendet einen static pointer und immer einen neuen speicherbereich und helpy verwendet zwar keinen pointer - ausser für den parameter - aber stattdessen CopyStructure() und beim aufruf von Kopieren() gibt man seinen eigenen speicherbereich an, darum wird es bei ihren beispielen auch mit mehreren fahrzeugen funktionieren.
du kannst auch nicht einfach Static in Protected ändern, denn dann würdest du einen pointer zurückgeben, der nach aufruf der funktion nicht mehr gültig ist.
Beefi hat geschrieben:;FahrzeugHalle(AutoName) = *EinAuto ; <- Das funktionierte ursprünglich nicht
weil deine map vom typ structure ist. mit typ pointer auf structure würde es gehen:

Code: Alles auswählen

NewMap *FahrzeugHalle.Fahrzeug()
*FahrzeugHalle(AutoName) = *EinAuto
static macht meiner meinung nach in keinem der hier verwendeten beispiele wirklich sinn, und stammt wahrscheinlich nur aus deinem ursprünglichen codebeispiel. sinnvoll wäre es höchstens für eine art von singleton oder aus geschwindigkeitsgründen, die sich aber bei verwendung von allocate und copy vermutlich sowieso erledigen.
my pb stuff..
Bild..jedenfalls war das mal so.
Beefi
Beiträge: 88
Registriert: 16.01.2017 17:38

Re: Struktur-Variable über Funktion per Zeiger kopieren

Beitrag von Beefi »

Hi,

@Sicro:
Danke, da muss man erstmal drauf kommen...das mit der Angabe von Map in den Parametern habe ich noch nirgends in der Hilfe gesehen. Oder besser gesagt, ich finde dieses Schlüsselwort nirgends in der Hilfe...immer nur NewMap.


@#NULL:
Mein letztes Beispiel trifft meinen Anwendungsfall recht gut (es geht aber nicht um Autos :D ). Die Map soll global im Programm zur Verfügung stehen und beinhaltet Profile mit sämtlichen Variablen. Die Funktion liest eigentlich eine XML-Datei ein und speichert die Inhalte kurzzeitig in der Struktur, um sie dann außerhalb (deswegen static) der Funktion der Map hinzuzufügen. Danach kann die Struktur ja wieder überschrieben werden. Diese ErzeugeFahrzeug-Funktion wird also beim Programmstart über eine Schleife mehrmals aufgerufen, bis alle vorhandenen Profile in die Map geladen sind.
Also grob beschrieben.
Oder hab ich jetzt einen Denkfehler?

Ich glaube ich muss da auch bei den Zeigern etwas umdenken. Ich kannte es von anderen Sprachen bisher so, dass ich eben einen Zeiger deklarieren kann, dem ich dann eine Adresse eines Speicherbereichs/Variable zuweise. In PureBasic ist es wohl normal, dass man direkt einen Zeiger deklariert und ihn dann sofort einen Wert zuweist (wo immer dieser auch gespeichert wird :mrgreen: ).
Oder ich steh grad total auf dem Schlauch :)

Also wenn ich das mal in C als Beispiel nehme:

Code: Alles auswählen

int a;
a = 5;
int *zeiger;
zeiger = &a;
...hier zeigt "*zeiger" jetzt auf die Variable "a" (also auf 5), bzw. "zeiger" beinhaltet die Adresse zu "a".


Es würde auch gehen (wie in PureBasic):

Code: Alles auswählen

int *zeiger;
*zeiger = 5;
Aber meines Wissens ist der Speicher dann ja nicht reserviert und es führt unter Umständen zu nem Programm-Crash.
Ist das in PureBasic nicht so?
Antworten