Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Pointerproblem


Janus - Do 06.03.03 22:09
Titel: Pointerproblem
Hi
Ich bin ein absoluter Neuling, was die Programmierung unter Object-Pascal angeht, doch ich habe fundierte Kenntnisse von C/C++;
Nun, der folgende Code ist aus mir unverständlichen Gründen nicht konpilierbar:


Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
program research;

{$APPTYPE CONSOLE}

uses
  SysUtils;

var
 arr: array[0..9] of Integer;
 p: ^Integer = nil;
 pp: ^Integer = nil;

begin
  arr[0] := 7;
  arr[5] := 13;
  p := @arr[5];
  pp := p; // bei dieser Zeile erscheint der Fehler "inkompatible Typen"
  WriteLn(IntToStr(pp^));
  ReadLn;
end.


P.S.
Mit ^Variable kann ich ja einen Typisierten Pointer machen, doch wie mache ich einen Pointer auf einen Pointer mit ^^Variable war es nicht möglich ?

Gruss Janus


AndyB - Do 06.03.03 22:35

Pascal ist sehr Typorientiert.
Ein ^Integer ist nicht gleich ein ^Integer.

Jedoch gilt nach

Quelltext
1:
2:
3:
4:
PInteger = ^Integer;
var
  a: PInteger;
  b: PInteger;

dass Typ von a = Typ von b ist.

Kurzum: Du musst einen neuen Typ deklarieren und diesen dann verwenden. Oder du Typecastest auf Teufel komm raus.


Janus - Do 06.03.03 22:39

Hi Andy
Also das verstehe ich nun nicht ganz: ^Integer ist nicht gleich ^Integer ?! :?

Integer ist doch gleich Integer oder etwa nicht, wo ist denn da der Unterschied ??? :shock:


AndyB - Do 06.03.03 22:43

Object Pascal macht daraus 2 Typen. Du musst OP dazu zwingen einen Typen daraus zu machen.


Noch was:
var a, b: ^Integer;Hierbei haben a und b den selben Typ.

Hingegen bei

Quelltext
1:
2:
3:
var
  a: ^Integer;
  b: ^Integer;

Macht der Compiler 2 nicht kompatible Typen daraus.


Janus - Do 06.03.03 22:50

OK, ich kann mir zwar beim besten Willen nicht vorstellen, wieso der Compiler das macht, aber das muss ich wohl akzepieren...
Mein eigentliches Problem liegt allerdings in folgendem Code, welcher zur Laufzeit eine Speicherschutzverletzung verursacht:


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:
unit Lib;

interface

uses
 StdCtrls, Classes, Grids;

function listStrings(ListSelection: TComboBox; TopicList: array of TStringList; DataTable: TStringGrid): Boolean;

implementation
 function listStrings(ListSelection: TComboBox; TopicList: array of TStringList; DataTable: TStringGrid): Boolean;
 var
  i: Integer;
  sl: ^TStringList;

 begin
  sl := @TopicList[ListSelection.ItemIndex];

  if ListSelection.Items.Count = sl^.Count then begin
   sl^.LoadFromFile(ListSelection.Text+'.txt');
   for i:=0 to sl.Count do DataTable.Cells[0,i] := sl^.Strings[i];
   Result := true;
  end else
   Result:= false;
 end;
end.


AndyB - Do 06.03.03 22:59

Mit ^TStringList hast du einen Zeiger auf einen Zeiger. Jede class ist automatisch ein Zeiger.



Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
procedure listStrings(ListSelection: TComboBox; TopicList: array of TStringList; DataTable: TStringGrid); 
var 
  i: Integer; 
  sl: TStringList; 

begin 
  sl := TopicList[ListSelection.ItemIndex]; 
  sl.LoadFromFile(ListSelection.Text+'.txt'); // hier stürzt das Programm ab 

  for i:=0 to sl.Count do DataTable.Cells[0,i] := sl.Strings[i]; 
end;


Hast du mit TStringList.Create auch jedem Element von TopicList[] eine Referenz auf eine Instanz zugewießen.


Janus - Do 06.03.03 23:11

Was meinst du mit Create ? Nein ich habe nirgens ein Create gemacht ! :oops:

Muss ich zuerst jedes Element mit Create erstellen und mit Destroy zerstören, wenn ich es nicht mehr benötige ?

Ach ja, wie gebe ich anschliessen den Speicher wieder frei ??
I habe da x Varianten gesehen:

a := nil;
FreeMem(a);
Dispose(a);

???

Ach ja, gibt es eine Möglichkeit die Grösse eines dynamischen Arrays herauszufinden ? In C/C++ ist das nicht möglich... :(


AndyB - Do 06.03.03 23:54

Length(dynArray)



Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
var
  a: array of TStringList;
  i: Integer;
begin
  SetLength(a, 3);
  for i := 0 to Length(a) - 1 do
    a[i] := TStringList.Create; // Instanzen erzeugen

  ...
  for i := 0 to Length(a) - 1 do
    a[i].Free; // Speicher freigeben

  SetLength(a, 0);
end;


Ein Dynamisch Array wird von Delphi normalerweise automatisch freigegeben, wenn es den Gültigkeitsraum verlässt. Globale Arrays sollte man dann schon selbst freigeben, wenn man nicht den Speicher bis zum Programmeende belegen will.

Freigeben von dyn. Arrays

Quelltext
1:
2:
3:
SetLength(a, 0); 
bzw:
a := nil;

Freigeben von Instanzen (Objekte)

Quelltext
1:
obj.Free                    

Freigeben von Speicjer, der mit New reserviert wurde

Quelltext
1:
Dispose(typptr);                    

Freigeben von Speicher, der mit GetMem/AllocMem reserviert wurde

Quelltext
1:
FreeMem(ptr);                    


Udontknow - Fr 07.03.03 14:31

Hallo!

Zitat:
Was meinst du mit Create ? Nein ich habe nirgens ein Create gemacht !


In C++ erstellst du doch Objekte, indem du z.B. schreibst:

Quelltext
1:
classmyobject myobject=new classmyobject();                    

Aufgebröselt könntest du das auch in zwei Schritten machen:

Variable deklarieren:

Quelltext
1:
classmyobject myobject;                    

Instanz der Klasse erstellen und der Variable zuweisen

Quelltext
1:
myobject=new classmyobject();                    


Das gleiche musst du für Objekte auch in Delphi machen. Es reicht nicht, eine Variable vom Typ Tstringlist zu deklarieren:

Quelltext
1:
var StrL:TStringlist;                    

Du musst nun auch eine Instanz von TStringlist erstellen und einen Zeiger auf diese Instanz in dieser Variable ablegen:

Quelltext
1:
StrL:=TStringlist.Create;                    


Delphi verfügt über keine Garbage-Collection, daher musst du sämtliche Objekte auch manuell freigeben (siehe Beitrag über diesem, Stichwort Free).

Cu,
Udontknow


Janus - Fr 07.03.03 21:31

Hei ich danke euch vielmals für die vielen Antworten, ich denke nun habe ich es begriffen !!! :D

Gruss Jnaus