![]() |
wieder mal die Zeiger
hallo,
habe folgenden Record:
Delphi-Quellcode:
und den Zeiger, auf diesen Record.
type
TSettings = record FZa1 : String; FZa2 : String; iFk : Integer; iCo : Integer; end; type PSettings = ^TSettings; mit der folgenden Routine versuche ich den Record mit Daten aus einer Inidatei zu füllen
Delphi-Quellcode:
Leider bringt mir der Aufruf , immer eine Zugriffsverletzung.
procedure LoadSettings;
var Ini: TIniFile; xP : PSettings; begin GetMem(xP, sizeOf(TSettings)); Ini:= TIniFile.Create(ExtractFilePath(Paramstr(0)) + 'maxes.ini'); with Ini do Begin with xP^ do begin FZa1:= ini.ReadString('Zahlen', 'Zahl1', '10'); FZa2:= ini.ReadString('Zahlen', 'Zahl2', '10'); iFk := ini.ReadInteger('Funktionen', 'Funktion', 0); end; end; ini.free; end; Die Frage ist nun, was ist falsch an dieser Geschichte? Danke Raik edit : Die Schutzverletzung kommt beim Zugriff auf FZa2. |
Re: wieder mal die Zeiger
Hai kiar,
scheint wohl am Typ String liegen. Wenn Du z.B. ShortString verwendest geht es. Frage mich aber nicht warum :roll: |
Re: wieder mal die Zeiger
Hoi
Probier mal New anstatt GetMem. Gruss Shaman |
Re: wieder mal die Zeiger
für dynamische strings werden nur 4byte oder so reserviert
versuchs mal so
Delphi-Quellcode:
type
TSettings = record FZa1 : String[100]; //kann natürlich auch ne andere zahl ausser 100 sein FZa2 : String[100]; iFk : Integer; iCo : Integer; end; |
Re: wieder mal die Zeiger
hallo,
Habe ich schon gemacht und es klappt, leider ist der Zugriff von einer anderen Form auch nicht befriedigend. wenn ich jetzt
Delphi-Quellcode:
der Pointer stimmt, einmal in LoadSettings und in oben aufgeführter Procedure. Leider sind die Werte in FZa1 und Fza2 nicht nachvollziehbar und schwirren in den Weiten meines Rechners herum.
var
a:integer; xp:Psettings; begin LoadSettings; Edit1.Text :=xp^.FZa1; Edit2.Text :=xp^.FZa2; raik |
Re: wieder mal die Zeiger
Das Problem ist wie bereits angesprochen der String bzw. das interne String-Handling. GetMem initialisiert den reservierten Speicher nicht, d.h. es können irgendwelche zufälligen Daten drinnenstehen und die String-Felder enthalten daher willkürliche Adressen. Weißt du einem dieser Strings nun einen neuen Inhalt zu, so versucht das interne String-Handling den Referenzzähler des "alten" Strings zu dekrementieren, da aber der String ja nicht wirklich auf einen String zeigt sondern eben nur eine willkürliche Adresse enthält endet das in einer Zugriffsverletzung.
Lösungen: 1) New verwenden (Compiler-Magic nimmt alle nötigen Initialisierungen vor) 2) AllocMem verwenden (ruft GetMem auf und initialisiert den Speicher anschließend mit FillChar) 3) selber den Speicher mit ZeroMemory oder FillChar initialisieren 4) die procedure Initialize verwenden... |
Re: wieder mal die Zeiger
hallo,
mit diesem Quelltext:
Delphi-Quellcode:
trten erstmal kein Zugriffsverletzungen auf, leider ist der Zugriff auf die procedure von einen anderen form immer noch nicht definiert :pale:
procedure LoadSettings;
var Ini: TIniFile; xP : PSettings; begin new(xP); Ini:= TIniFile.Create(ExtractFilePath(Paramstr(0)) + 'maxes.ini'); with Ini, xP^ do Begin FZa1:= ReadString('Zahlen', 'Zahl1', '10'); FZa2:= ReadString('Zahlen', 'Zahl2', '10'); iFk := ReadInteger('Funktionen', 'Funktion', 0); end; ini.free; end; erstmal Danke an Alle |
Re: wieder mal die Zeiger
Zitat:
|
Re: wieder mal die Zeiger
hallo Sharky,
ich sehe ja den Zeiger, die Adresse ist in beiden Fällen die gleiche. zb: wird in FZa1 = '10' geschrieben. der Aufruf aus der anderen Form, zeigt mir aber, nur Datenmüll an? raik |
Re: wieder mal die Zeiger
Warum nimmst du überhaupt ein Record?
für was gibts Objecte? Beispiel:
Delphi-Quellcode:
So in der Art würd ich das machen...
Unit Unit1;
Interface Uses SysUtils, IniFiles; Type TSettings_Base = Class Private { Private-Deklarationen } FiCo: Integer; FiFk: Integer; FFZa1: String; FFZa2: String; Public { Public-Deklarationen } Function Load: Boolean; Virtual; Abstract; Property FZa1: String Read FFZa1; Property FZa2: String Read FFZa2; Property iFk: Integer Read FiFk; Property iCo: Integer Read FiCo; End; TSettings_Ini = Class( TSettings_Base ) Public { Public-Deklarationen } Function LoadSettings: Boolean; End; Implementation Function TSettings_Ini.LoadSettings: Boolean; Var InI: TIniFile; Begin Result := False; InI := Nil; Try Try Ini := TIniFile.Create( ExtractFilePath( Paramstr( 0 ) ) + 'maxes.ini' ); FFZa1 := InI.ReadString( 'Zahlen', 'Zahl1', '10' ); FFZa2 := InI.ReadString( 'Zahlen', 'Zahl2', '10' ); FiFk := InI.ReadInteger( 'Funktionen', 'Funktion1', 0 ); FiCo := InI.ReadInteger( 'Funktionen', 'Funktion2', 0 ); Result := True; Finally If Assigned( InI ) Then FreeAndNil( InI ); End; Except On Error: Exception Do Begin Error.Message := 'LoadSettings - Error:'#13#10 + Error.Message; Raise; End; End; End; End. :dancer2: Es lebe die Objectorientiertheit :zwinker: Bye |
Re: wieder mal die Zeiger
Zitat:
@Kiar : Man darf natürlich das xP, wenn es schon mit new nur lokal erzeugt wird auch nicht als Wert-Parameter sondern als Var-Parameter übergeben. Da hat einer sich nicht so richtig an das Prinzip der Datenkapselung gehalten. :mrgreen: |
Re: wieder mal die Zeiger
Hmpf.. warum wird mein Beitrag wiedermal komplett ignoriert? :?
Ich hab doch ![]() |
Re: wieder mal die Zeiger
Zitat:
Bye |
Re: wieder mal die Zeiger
Aber er hat doch new verwendet. Das ist nicht der Fehler. Leider eben nur für eine lokale Variable. Woher soll denn eine andere Form wissen, was in dem lokalen Xp drinsteht ?
|
Re: wieder mal die Zeiger
hallo,
@Kedariodakon - nette Variante werde ich mir mal näher anschauen, also mache dich auf Fragen gefasst :mrgreen: @Manuel - habe ich doch nicht, habe doch es mit new() gemacht :gruebel: Das richtige, in meinem Fall ist der Tip von Hansa gewesen , aber halt, er hatte einen anderen Kenntnisstand :mrgreen: ich habe die aufrufende Procedure geändert, das konntet Ihr nicht wissen.
Delphi-Quellcode:
aufgrund der neueren Variante hatte Hansa den Vorschlag gemacht, die LoadSettings mir Var Parameter zu deklarieren. also so:
var
xP: Psettings; begin LoadSettings; // alte Variante Loadsettings(xP); // neue Variante
Delphi-Quellcode:
dies hat erstmal zum Erfolg geführt.
Loadsettigs(var xP: Psettings);
danke an alle Raik |
Re: wieder mal die Zeiger
Um es noch einmal ganz klar zu sagen: die Gültigkeitsbereiche sind schon wichtig. Und das hat mit Pointer usw. absolut nichts zu tun. Solche Fehler können im Prinzip überall auftreten. Wird eine Variable lokal, also so wie hier innerhalb einer Prozedur deklariert, dann gilt sie nur da. Wird die Prozedur aufgerufen, so bekommt das aufrufende Programm davon nichts mit. Das new innerhalb der Prozedur war also hier auch für die Katz.
Auch der jetzt verwendete VAR-Parameter ist nicht ganz ohne. Dann wird nämlich immer etwas an die aufrufende Stelle zurückgeliefert. Das geht hier ja jetzt anscheinend. Aber wehe, wenn innerhalb der Prozedur der VAR-Parameter keinen Wert zugewiesen bekommt. Dann ist der Effekkt der selbe und auch dann wird nur ein Zufallswert an das Programm zurückgeliefert. Deshalb sollten Var-Parameter immer zuerst initialisiert werden. Auch wenn man sich ganz sicher ist, daß sie auf jeden Fall irgendwo einen Wert erhalten. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:48 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz