Pointer auf Arrays als Prozedur-Rückgabewert

Für allgemeine Fragen zur Programmierung mit PureBasic.
Salafat
Beiträge: 30
Registriert: 05.01.2012 07:40
Computerausstattung: AMD FX-8350 Eight-Core-Prozessor 4,00 GHz
8 GB RAM
Windows 7 64-Bit
Wohnort: Berlin

Pointer auf Arrays als Prozedur-Rückgabewert

Beitrag von Salafat »

Hallo,

ich habe eine Prozedur Lff geschrieben, die die Erstellung von Fenstern mit Listenfeldern (ListView) automatisieren soll. Genauer: Die Prozedur erstellt ein Fenster mit einem Listenfeld , befüllt es und plaziert Bildschaltflächen darunter, was dann in etwa so aussieht: https://www.dropbox.com/s/c31ozj4nt4pg9 ... nhalte.jpg

Die Nummern für Fenster, Listenfeld und Bildschaltflächen werden in der Prozedur mit #PB_Any generiert und in einem Array (zur späteren Verwendung in der Repeat-Ereignisschleife) abgelegt.

Nun kann eine Prozedur bedauerlicherweise keine Arrays zurückliefern. Ich konnte mich aber noch dunkel an eine Bemerkung in Gary Willoughbys Buch erinnern, daß man diese Einschränkung umgehen kann:
It is however possible to get around these limitations, by returning a pointer.
(S. 92 unten). Meine Prozedur gibt also kein Array, sondern den Zeiger auf das Array mit den Nummern zurück: ProcedureReturn @K(). Der Aufruf der Prozedur sieht dann so aus:

Code: Alles auswählen

Define *K=Lff("Lerninhalte", 375, "Helios", 10, 20, I(), BuHt(), 1)
*K ist ein Zeiger auf ein Array mit insgesamt 10 Elementen. Es ist problemlos möglich, die Werte der Element explizit Variablen zuzuordnen (so wie es Willoughby auf S. 278 beschreibt):

Code: Alles auswählen

Define Fe_H=PeekI(*K), Zs_Lf=PeekI(*K+8), Lf_Li=PeekI(*K+16)
usw., oder auch einem Array des Main-Quellkodes:

Code: Alles auswählen

Dim K(9)
K(0)=PeekI(*K)
K(1)=PeekI(*K+8)
K(2)=PeekI(*K+16)
K(3)=PeekI(*K+24)
K(4)=PeekI(*K+32)
K(5)=PeekI(*K+40)
K(6)=PeekI(*K+48)
K(7)=PeekI(*K+56)
K(8)=PeekI(*K+64)
K(9)=PeekI(*K+72)
Der Offset ist ein Vielfaches von 8 (und nicht wie bei Willoughby von 4), weil ich auf einem 64-Bit-System programmiere. Sowohl die Zuweisung an die Variablen als auch an das Array funktioniert problemlos. Die Verfolgung im Beobachtungsfenster des Debuggers zeigt, daß die von #PB_Any in der Prozedur generierten 8stelligen Nummern dieselben sind, wie die von PeekI den Variablen/Array-Elementen zugewiesenen.

Und nun ein Effekt, den ich mir nicht erklären kann. Wenn ich diese umständliche explizite Wertezuweisung durch eine For-Next-Schleife automatisieren will (zumal ja auch die Gefahr besteht, sich bei längeren Arrays beim Offset zu verrechnen):

Code: Alles auswählen

Dim K(9)
For Ix=0 To ArraySize(K())
  K(Ix)=PeekI(*K+Ix*8)
Next
so funktioniert das nicht mehr, die von PeekI in der For-Next-Schleife zugewiesen Werte stimmen nicht mehr mit denen in der Prozedur Lff überein.

Hat von Euch jemand eine Idee, woran das liegt?

Vielen Dank
PureBasic v5.11 x64
Windows 7 64-Bit
AMD FX-8350 Eight-Core Processor 4 GHz, 8 GB Arbeitsspeicher
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7032
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Pointer auf Arrays als Prozedur-Rückgabewert

Beitrag von STARGÅTE »

Das mit den Pointer ist wie du selbst sieht umständlich.

Übergib das Array welches zu befüllen willst lieber als Parameter mit der Procedure Lff()
Arrays, Listen und Maps die übergeben werden, werden als Referenz übergeben, somit kann der Wert innerhalb der Procedure geändert werden, was sich dann auf das übergebene Array auswirkt:

Code: Alles auswählen

Procedure Fill(Array Test.i(1), Length)
	Dim Test(Length)
	For N = 0 To Length
		Test(N) = N
	Next
EndProcedure


Dim Example.i(0)
Debug "Größe vorher: "+ArraySize(Example())

Fill(Example(), 10)

Debug "Größe danach: "+ArraySize(Example())
Debug "---"
For N = 0 To ArraySize(Example())
	Debug Example(N)
Next
Tu deinem Effekt kann ich nichts sagen, sehe in letzten Code eigentlich kein Fehler, und das Auslesen von Arrays über Pointer ist durchaus erlaubt, solange das Quell-Array existiert.
Wenn das Quell-Array nachtürlich Protected ist in der Prozedur, dann darfst du den Pointer nicht nutzen, da das Array nach dem verlassen der Prozedur ungültig wird. Daher u.u. das Array in der Prozedur als Static definieren, oder den Code von mir oben verweden.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Salafat
Beiträge: 30
Registriert: 05.01.2012 07:40
Computerausstattung: AMD FX-8350 Eight-Core-Prozessor 4,00 GHz
8 GB RAM
Windows 7 64-Bit
Wohnort: Berlin

Re: Pointer auf Arrays als Prozedur-Rückgabewert

Beitrag von Salafat »

Hallo Stargate,

stimmt, das Arrays und LinkedLists byRef übergeben werden war mir entfallen.

Trotzdem würde ich gern wissen, was der Grund für diesen seltsamen Effekt ist. Es scheint fast so, daß die For-Next-Schleife irgendetwas im Speicher manipuliert, so daß die von Lff in K() abgelegten Werte verändert werden.

Danke
PureBasic v5.11 x64
Windows 7 64-Bit
AMD FX-8350 Eight-Core Processor 4 GHz, 8 GB Arbeitsspeicher
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8812
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: Pointer auf Arrays als Prozedur-Rückgabewert

Beitrag von NicTheQuick »

Salafat hat geschrieben:Und nun ein Effekt, den ich mir nicht erklären kann. Wenn ich diese umständliche explizite Wertezuweisung durch eine For-Next-Schleife automatisieren will (zumal ja auch die Gefahr besteht, sich bei längeren Arrays beim Offset zu verrechnen):

Code: Alles auswählen

Dim K(9)
For Ix=0 To ArraySize(K())
  K(Ix)=PeekI(*K+Ix*8)
Next
so funktioniert das nicht mehr, die von PeekI in der For-Next-Schleife zugewiesen Werte stimmen nicht mehr mit denen in der Prozedur Lff überein.

Hat von Euch jemand eine Idee, woran das liegt?

Vielen Dank
Das ist leicht.
Das Array, das du innerhalb deiner Prozedur erstellst und benutzt, existiert nach Beenden der Prozedur nicht mehr. Das heißt du gibst im Grunde einen Pointer zu einem nicht mehr existierenden Array zurück. Am Anfang kannst du die Werte aus dem Array noch auslesen, aber dass das problemlos funktioniert ist reiner Zufall. Denn jederzeit kann der frei gewordene Speicherbereich wieder durch anderen Kram überschrieben werden und somit ganz andere Werte enthalten.
Wahrscheinlich würde der Purifier dich auch darauf aufmerksam machen, wenn du ihn aktivierst.

Edit:
Und um alles etwas verständlicher und dynamischer zu machen, würde ich statt eines Arrays auch eine Struktur nehmen.

Code: Alles auswählen

Structure Dialog
	idWindows.i
	idListe.i
	idButton1.i
	;...
EndStructure

Procedure oeffneDialog(*werte.Dialog)
	With *werte
		\idWindows = 1
		\idListe = 2
		\idButton1 = 3
	EndWith
EndProcedure

Define dialog1.Dialog

oeffneDialog(dialog1)

Debug dialog1\idWindows
Debug dialog1\idListe
Debug dialog1\idButton1
Salafat
Beiträge: 30
Registriert: 05.01.2012 07:40
Computerausstattung: AMD FX-8350 Eight-Core-Prozessor 4,00 GHz
8 GB RAM
Windows 7 64-Bit
Wohnort: Berlin

Re: Pointer auf Arrays als Prozedur-Rückgabewert

Beitrag von Salafat »

Das ist leicht.
Das Array, das du innerhalb deiner Prozedur erstellst und benutzt, existiert nach Beenden der Prozedur nicht mehr. Das heißt du gibst im Grunde einen Pointer zu einem nicht mehr existierenden Array zurück.
Na schön, nur stellt sich dann die Frage, welchen Sinn es überhaupt machen soll, Pointer auf Arrays (gemäß Willoughbys Vorschlag) zurückzugeben. Denn diese Arrays sind ja immer lokal zur Prozedur, in der sie deklariert wurden. Und wenn man sie global deklariert, braucht man gar keinen Rückgabewert mehr. Dieser "Kniff" ist damit völlig wertlos.
Wahrscheinlich würde der Purifier dich auch darauf aufmerksam machen, wenn du ihn aktivierst.
Dieses Werkzeug ist in der Hilfe derart defizitär erklärt, daß niemand, der sich die Sprache gerade erst zu erschließen beginnt, damit etwas anfangen kann. Er scheint mir eher etwas für Assembler- oder erfahrene C-Programmierer zu sein. Trotzdem danke für den Hinweis.
PureBasic v5.11 x64
Windows 7 64-Bit
AMD FX-8350 Eight-Core Processor 4 GHz, 8 GB Arbeitsspeicher
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8812
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: Pointer auf Arrays als Prozedur-Rückgabewert

Beitrag von NicTheQuick »

Salafat hat geschrieben:
Das Array, das du innerhalb deiner Prozedur erstellst und benutzt, existiert nach Beenden der Prozedur nicht mehr. Das heißt du gibst im Grunde einen Pointer zu einem nicht mehr existierenden Array zurück.
Na schön, nur stellt sich dann die Frage, welchen Sinn es überhaupt machen soll, Pointer auf Arrays (gemäß Willoughbys Vorschlag) zurückzugeben. Denn diese Arrays sind ja immer lokal zur Prozedur, in der sie deklariert wurden. Und wenn man sie global deklariert, braucht man gar keinen Rückgabewert mehr. Dieser "Kniff" ist damit völlig wertlos.
Genau so ist es. Das heißt in dem Buch steht an der Stelle Schwachfug. Ich kenne das Buch nicht mal, deswegen weiß ich auch nicht, was sonst noch falsches drin stehen könnte.
Salafat
Beiträge: 30
Registriert: 05.01.2012 07:40
Computerausstattung: AMD FX-8350 Eight-Core-Prozessor 4,00 GHz
8 GB RAM
Windows 7 64-Bit
Wohnort: Berlin

Re: Pointer auf Arrays als Prozedur-Rückgabewert

Beitrag von Salafat »

Das heißt in dem Buch steht an der Stelle Schwachfug. Ich kenne das Buch nicht mal, deswegen weiß ich auch nicht, was sonst noch falsches drin stehen könnte.
Ist in der PureArea frei herunterladbar: http://www.purearea.net/pb/download/PureBasicBook.pdf

Die Stelle, auf die ich mich beziehe, ist S. 92 unten (was Du als Schwachfug bezeichnest). Bedauerlicherweise kenne ich neben der Hilfe kaum andere Literatur, mit der man sich autodidaktisch weiterbilden könnte.
PureBasic v5.11 x64
Windows 7 64-Bit
AMD FX-8350 Eight-Core Processor 4 GHz, 8 GB Arbeitsspeicher
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7032
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Pointer auf Arrays als Prozedur-Rückgabewert

Beitrag von STARGÅTE »

Ei jei jei, das Buch ist ja von 2006, also die Zeiten von PB 4.0
Vor 4.0 waren alle Arrays und Liste immer global, daher ist das Problem mit Protected Arrays garnicht bekannt.
Diese kamen erst mit Version 4.0.

Ohne den Autor zu kränken, behaupte ich mal, das der Inhalt an einigen Stellen längst überholt oder sogar Falsch ist (in Hinblick auf die neuste PB version).
PB ist eine sich (auch wenn einige das anders sehen, weil Updates immer so lange brauchen ^^) schnell entwickelnde Sprache, bei der jederzeit sich u.U. grundlegende Sachen im Kern ändern.
Seit 2006 kamen halt viele Wichtige Sachen dazu wie:
  • 64-Bit Kompiler und die Integers (Long oder Quad, je nach Prozessor)
  • Maps
  • Arrays, Lists, Maps in Strukturen
  • u.v.m
Ja es ist schade das es kaum "richtige" Literatur zu PB gibt, es müsste sich halt jemand finden der sie schreibt.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8812
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: Pointer auf Arrays als Prozedur-Rückgabewert

Beitrag von NicTheQuick »

Salafat hat geschrieben:Bedauerlicherweise kenne ich neben der Hilfe kaum andere Literatur, mit der man sich autodidaktisch weiterbilden könnte.
Keine Sorge. Ich hab das auch so gelernt wie du gerade. Herum probieren, Fehler produzieren, versuchen sie zu lösen, notfalls im Forum fragen, schlauer werden. :mrgreen:
Antworten