Autor Beitrag
morvister
Hält's aus hier
Beiträge: 15

XP
Delphi 2005 Prof.
BeitragVerfasst: Di 05.08.08 19:56 
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:
ausblenden volle Höhe 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
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
    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;      //Formular zwecks Eingabe d. Server-Parms modal öffnen

   if (Spielername <> '') then begin   //Anwender hat Form2 mit OK verlassen
      Spiel := TSpiel.Create;          //neues Object 'Spiel' anlegen
      Spiel.Port := Port;              // füllen...
      Spiel.AnzSpielerGes := AnzSpieler;
      Spiel.Owner := Spielername;

      i := High(arrSpiele);            // letzten Eintrag ermitteln
      if i < 0 then i := 0;            // leeres Array abfangen
      arrSpiele[i] := Spiel;           // Spiel ins Array für offene Spiele

      Spiel.Free;                      //Objekt wird nicht mehr benötigt
   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:
ausblenden volle Höhe 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
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
    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.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1876
Erhaltene Danke: 129

Win 8.1, Xubuntu 15.10

BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 29



BeitragVerfasst: 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);

_________________
Ich bin keine Signatur - ich putz hier nur.
morvister Threadstarter
Hält's aus hier
Beiträge: 15

XP
Delphi 2005 Prof.
BeitragVerfasst: 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):
ausblenden 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;      //Formular zwecks Eingabe d. Server-Parms modal öffnen

   if (Spielername <> '') then begin   //Anwender hat Form2 mit OK verlassen
      Spiel := TSpiel.Create;          //neues Object 'Spiel' anlegen
      Spiel.Port := Port;              // füllen...
      Spiel.AnzSpielerGes := AnzSpieler;
      Spiel.AnzSpielerFrei := AnzSpieler;
      Spiel.Owner := Spielername;

      i := High(arrSpiele);            // letzten Eintrag ermitteln
      if i < 0 then i := 0;            // leeres Array abfangen
//      arrSpiele[i] := Spiel;           // Spiel ins Array für offene Spiele

      arrSpiele[i].Owner := Spiel.Owner;
      arrSpiele[i].Port := Spiel.Port;
      arrSpiele[i].AnzSpielerGes := Spiel.AnzSpielerGes;
      arrSpiele[i].AnzSpielerFrei := Spiel.AnzSpielerFrei;
      Spiel.Free;                      //Objekt wird nicht mehr benötigt
   end;

end;
Boldar
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 1555
Erhaltene Danke: 70

Win7 Enterprise 64bit, Win XP SP2
Turbo Delphi
BeitragVerfasst: Di 05.08.08 20:11 
ausblenden volle Höhe 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
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
    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;      //Formular zwecks Eingabe d. Server-Parms modal öffnen
   if (Spielername <> '') then begin   //Anwender hat Form2 mit OK verlassen
      Spiel := TSpiel.Create;          //neues Object 'Spiel' anlegen
      Spiel.Port := Port;              // füllen...
      Spiel.AnzSpielerGes := AnzSpieler;
      Spiel.Owner := Spielername;

      i := lenght(arrSpiele);            // letzten Eintrag ermitteln
      if i < 0 then i := 0;            // leeres Array abfangen
      arrSpiele[i-1] := Spiel;           // Spiel ins Array für offene Spiele
      Spiel.Free;                      //Objekt wird nicht mehr benötigt
   end;

end;



Allerdings musst du für dass array auch irgendwo speicher reservieren:
ausblenden Delphi-Quelltext
1:
setlength (array, laenge);					




______________________________________________
morvister Threadstarter
Hält's aus hier
Beiträge: 15

XP
Delphi 2005 Prof.
BeitragVerfasst: 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:
ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1331
Erhaltene Danke: 123

Mac OSX, Arch
TypeScript (Webstorm), Kotlin, Clojure (IDEA), Golang (VSCode)
BeitragVerfasst: Di 05.08.08 22:12 
wenn du die länge eh fest machen willst reicht auch

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
procedure bla();
var
  arrSpiele: Array[1..100] of String // was auch immer fürn Typ;
begin
  
end;
morvister Threadstarter
Hält's aus hier
Beiträge: 15

XP
Delphi 2005 Prof.
BeitragVerfasst: 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 :)
Einloggen, um Attachments anzusehen!
Lossy eX
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1048
Erhaltene Danke: 4



BeitragVerfasst: Do 07.08.08 13:45 
Kleine Anmerkung.
ausblenden Delphi-Quelltext
1:
2:
3:
  Spiel := TSpiel.Create;
  arrSpiele[i-1] := Spiel;
  Spiel.Free;                      //Objekt wird nicht mehr benötigt

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.

_________________
Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.
morvister Threadstarter
Hält's aus hier
Beiträge: 15

XP
Delphi 2005 Prof.
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1405
Erhaltene Danke: 51

Win 7, Android
Turbo Delphi, Eclipse
BeitragVerfasst: 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

ausblenden Delphi-Quelltext
1:
arrSpiele[0] := tSpiel.Create					


oder du machst es wie bisher, ohne aber spiel.free aufzurufen. Das Funktioniert auch. Beispiel:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
spiel := TSpiel.Create;    // neues Spiel erzeugt, nennen wir es Spiel1
arrSpiele[0] := spiel;     // auch arrSpiele[0] zeigt nun auf Spiel1
spiel := tSpiel.create;    // neues Spiel erzuegen, nennen wir es Spiel2 - arrSpiele[0] zeigt immer noch auf Spiel1 !!!
arrSpiele[1] := spiel;     // arrSpiele[1] zeigt nun auf Spiel2, arrSpiele[0] nach wie vor auf Spiel1
spiel.free;                // weder Spiel noch arrSpiele[1] sind jetzt definiert - arrSpiele[0] zeigt aber auch jetzt noch auf Spiel1

_________________
Bringe einen Menschen zum grübeln, dann kannst du heimlich seinen Reis essen.
(Koreanisches Sprichwort)
Lossy eX
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1048
Erhaltene Danke: 4



BeitragVerfasst: 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.
ausblenden 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.

_________________
Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.
morvister Threadstarter
Hält's aus hier
Beiträge: 15

XP
Delphi 2005 Prof.
BeitragVerfasst: Do 07.08.08 20:48 
Danke für die Erläuterung,ich habe verstanden :-)