Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - EAccessViolation bei Zugriff auf dynamisches Array
morvister - Di 05.08.08 19:56
Titel: EAccessViolation bei Zugriff auf dynamisches Array
Hallo liebe Leutz!
Ich plage mich derzeit mit einem Problem beim Füllen eines dyn. Arrays. Möglicherweise ein typischer OOP-Falsch-DenkFehler (bin neu in der OOP, hab beruflich hauptsächlich mit Cobol zu tun - hey, hier wird nicht gelacht! ;-) )
Nun zum Code:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75:
| unit Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, Unit2;
type TSpiel = class(TObject) Owner: String[20]; Port: Integer; AnzSpielerGes: Byte; AnzSpielerFrei: Byte; private public end;
TForStart = class(TForm) Panel1: TPanel; Button1: TButton; Button2: TButton; Panel2: TPanel; Label1: TLabel; Panel3: TPanel; Button3: TButton; Button4: TButton; procedure Button4Click(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure FormActivate(Sender: TObject); procedure Button1Click(Sender: TObject); procedure Button3Click(Sender: TObject); private public Port: Integer; AnzSpieler: Integer; Spielername: String[20]; arrSpiele: array of TSpiel; end;
var ForStart: TForStart; Spiel: TSpiel;
implementation
{$R *.dfm}
procedure TForStart.Button1Click(Sender: TObject); var i: Integer; begin Form2.ShowModal; if (Spielername <> '') then begin Spiel := TSpiel.Create; Spiel.Port := Port; Spiel.AnzSpielerGes := AnzSpieler; Spiel.Owner := Spielername;
i := High(arrSpiele); if i < 0 then i := 0; arrSpiele[i] := Spiel; Spiel.Free; end;
end; |
An der markierten Zeile bricht mir das PGM mit einer EAccessViolation ab. Sehr ärgerlich ;-) Hat das mit dem handling von i, oder dem handling des arrays, oder der definition desselbigen zu tun?
Die Variablen ForStart.Port, -.AnzSpieler und -.Spielername werden aus Form2 heraus gefüllt. Hier Form2:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56:
| unit Unit2;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls;
type TForm2 = class(TForm) Button1: TButton; Button2: TButton; Edit1: TEdit; Panel1: TPanel; Label1: TLabel; Label2: TLabel; ComboBox1: TComboBox; Label4: TLabel; Edit2: TEdit; procedure Edit2KeyPress(Sender: TObject; var Key: Char); procedure Button2Click(Sender: TObject); procedure Button1Click(Sender: TObject); private public function PortAdressePruefen: Boolean; function SpielernamePruefen: Boolean; end;
var Form2: TForm2;
implementation
uses Unit1; {$R *.dfm}
procedure TForm2.Button1Click(Sender: TObject); var ok: boolean; begin ok := SpielerNamePruefen;
if ok then PortAdressePruefen;
if ok then begin ForStart.Port := StrToInt(Edit1.Text); ForStArt.AnzSpieler := StrToInt(ComboBox1.Text); ForStart.Spielername := Edit2.Text; end;
Close; end; |
Ich wäre für eure Hilfe wahnsinnig dankbar. Ich möchte möglichst schnell fit werden in Delphi um dem Forum auch mal als Berater und nicht nur als Fragender zu neuen Beiträgen zu verhelfen ;-)
Vielen Dank schon mal
morvi
Marc. - Di 05.08.08 20:08
Momentan hat Dein dyn. Array eine Länge von Null. Mit Setlength(); kannst Du die Anzahl der Elemente festlegen.
cu
Marc.
wirbeldelphi - Di 05.08.08 20:09
Dein Array hat wohl die Größe Null solange du die nicht mit SetLength geändert hast. Zugriffe auf das erste Element werden da wohl nix.
SetLength(arrSpiele, neueArrayGröße);
morvister - Di 05.08.08 20:11
Nachtrag:
Mir ist noch aufgefallen, dass ich Spiel.AnzSpielerFrei noch gar nicht gefüllt hatte und hab das bereinigt. Außerdem hab ich mal versucht, die Felder einzeln von Spiel ins arrSpiele zu packen. Bringt auch nix. Hier der aktuelle Code:
(nur die procedure, in der das Array versorgt wird, denn nur die hab ich geändert):
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24:
| procedure TForStart.Button1Click(Sender: TObject); var i: Integer; begin Form2.ShowModal; if (Spielername <> '') then begin Spiel := TSpiel.Create; Spiel.Port := Port; Spiel.AnzSpielerGes := AnzSpieler; Spiel.AnzSpielerFrei := AnzSpieler; Spiel.Owner := Spielername;
i := High(arrSpiele); if i < 0 then i := 0; arrSpiele[i].Owner := Spiel.Owner; arrSpiele[i].Port := Spiel.Port; arrSpiele[i].AnzSpielerGes := Spiel.AnzSpielerGes; arrSpiele[i].AnzSpielerFrei := Spiel.AnzSpielerFrei; Spiel.Free; end;
end; |
Boldar - Di 05.08.08 20:11
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73:
| unit Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, Unit2;
type TSpiel = class(TObject) Owner: String[20]; Port: Integer; AnzSpielerGes: Byte; AnzSpielerFrei: Byte; private public end;
TForStart = class(TForm) Panel1: TPanel; Button1: TButton; Button2: TButton; Panel2: TPanel; Label1: TLabel; Panel3: TPanel; Button3: TButton; Button4: TButton; procedure Button4Click(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure FormActivate(Sender: TObject); procedure Button1Click(Sender: TObject); procedure Button3Click(Sender: TObject); private public Port: Integer; AnzSpieler: Integer; Spielername: String[20]; arrSpiele: array of TSpiel; end;
var ForStart: TForStart; Spiel: TSpiel;
implementation
{$R *.dfm}
procedure TForStart.Button1Click(Sender: TObject); var i: Integer; begin Form2.ShowModal; if (Spielername <> '') then begin Spiel := TSpiel.Create; Spiel.Port := Port; Spiel.AnzSpielerGes := AnzSpieler; Spiel.Owner := Spielername;
i := lenght(arrSpiele); if i < 0 then i := 0; arrSpiele[i-1] := Spiel; Spiel.Free; end;
end; |
Allerdings musst du für dass array auch irgendwo speicher reservieren:
Delphi-Quelltext
1:
| setlength (array, laenge); |
______________________________________________
morvister - Di 05.08.08 20:33
Hallo bolder, danke für die antwort! :-)
Ich habe mich nun nach deinem hinweis richten wollen und in die FormCreate-Prozedur den SetLEngth reingepackt:
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| procedure TForStart.FormCreate(Sender: TObject); begin
SetLength(arrSpiele, 100);
end; |
Die EAccessViolation-Exception krieg ich aber immer noch. Ist FormCreate der falsche Ort dafür?
danke und gruß
morvi
FinnO - Di 05.08.08 22:12
wenn du die länge eh fest machen willst reicht auch
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| procedure bla(); var arrSpiele: Array[1..100] of String begin end; |
morvister - Di 05.08.08 22:31
Hallo, habe die anderen Helfer vorhin glatt überlesen...sorry :oops:
Danke euch allen!
Ich bin nun ein kleines Stück weiter. Der SetLength war ein Problem, ein weiteres war aber anscheinend, dass ich, bevor ich die Array-Felder füllen kann, erst mal zu dem jeweils neuen Element (anzSpiele -1) mit TSpiel.Create eine Instanz erzeugen muss...Versteh ich zwar nicht, aber nachdem ich das getan habe, konnte ich zumindst 3 Spiele öffnen...just in diesem Augenblick fällt mir auf, dass mein ganzes Vorhaben blödsinnig ist, weil ich nur 1 ServerSocket-Komponente haben werde, und somit das öffnen von n Spielen keinen Sinn macht.
Nichts desto trotz liegt mir sehr viel daran, das Problem zu erkennen. Was derzeit passiert ist, dass ich 2-3 mal Form2 aufrufen kann und 2 - 3 mal das Array befüllt wird und DANN kommt die EAccessViolation :eyecrazy:
Ich denke nicht, dass man mir helfen kann, ohne das Projekt zur Verfügung zu haben, deshalb lade ich mal ein .rar mit allen Dateien außer der .exe hoch.
Ich bin mit meinem Latein echt am Ende...Hilfe!
P.S: Wie bereits geschrieben, bin ich OOP-Anfänger und das hier soll auch mein erstes kleines Spielchen werden...also bitte nicht zu doll schimpfen über meinen Code *fleh*
Danke :)
Lossy eX - Do 07.08.08 13:45
Kleine Anmerkung.
Delphi-Quelltext
1: 2: 3:
| Spiel := TSpiel.Create; arrSpiele[i-1] := Spiel; Spiel.Free; |
Das da ist falsch. Das Objekt wird sehr wohl noch benötigt.
Du erzeugst eine Instanz einer Klasse und merkst dir in dem Array lediglich den Pointer der Instanz. Wenn du die Instanz danach wegschmeißt zeigt der Pointer in dem Array noch auf den Speicherbereich an dem sich die Klasse befunden hatte. Allerdings ist dieser Speicherbereich wieder frei verfügbar. Beim 2ten oder 3ten Aufruf wird er scheinbar überschrieben und dann knallt es. Es kann aber jederzeit knallen sobald nur jemand auf den Speicherbereich zugreifen möchte.
Objekte dürfen erst freigegeben werden, wenn sie wirklich nicht mehr benötigt werden.
morvister - Do 07.08.08 16:19
Ich verstehe...das bedeutet wohl, dass ich die Instanzen der Klasse TSpiel direkt im Array erzeugen müsste, wenn ich gleichzeitig mehrere Spiele verwalten will, oder? In der Objektvariable 'Spiel' ist ja nur Platz für 1 Spiel, nicht für n Spiele. Und da ich die Instanz nicht wegschmeißen darf, so wie es im Moment ist, darf ich in der Variablen sicher auch keine neue Instanz erzeugen, da die alte dann genauso weg wäre, richtig?
Tilman - Do 07.08.08 17:00
Entweder du erzeugst für jedes feld im Array direkt die Spiele, wie du ja schon selbst gesagt hast
Delphi-Quelltext
1:
| arrSpiele[0] := tSpiel.Create |
oder du machst es wie bisher, ohne aber spiel.free aufzurufen. Das Funktioniert auch. Beispiel:
Delphi-Quelltext
1: 2: 3: 4: 5:
| spiel := TSpiel.Create; arrSpiele[0] := spiel; spiel := tSpiel.create; arrSpiele[1] := spiel; spiel.free; |
Lossy eX - Do 07.08.08 20:00
Um das evtl. noch etwas weiter auszuholen. Wenn du eine Klasse anlegst, dann bekommst du einen Zeiger auf die Instanz zurück. Den kannst du beliebig oft kopieren. Dadurch veränderst du aber keine Instanz und erstellst auch keine Kopie davon. Da du bei allem lediglich die Adresse kopiert hast.
Evtl mal ein Beispiel ohne das Array. Mag sein, dass das evtl. verwirrt.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| var Spiel_1, Spiel_2, Spiel_3: TSpiel; begin Spiel_1 := TSpiel; Spiel_2 := Spiel_1; Spiel_3 := Spiel_2; end; |
Bei diesem Code zeigen alle Spiel_X auf die selbe Instanz. Wenn du jetzt eine eninzige davon frei gibst sind alle weg. Es mag sein, dass sie evtl. noch kurzzeitig funktionieren aber der Speicher kann jederzeit mit irgendwas anderem überschrieben werden. Und dann kracht es.
morvister - Do 07.08.08 20:48
Danke für die Erläuterung,ich habe verstanden :-)
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!