Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Problem mit Pointern + Fragen


Distemix - Do 13.11.08 19:51
Titel: Problem mit Pointern + Fragen
Hi,

Ich hab mich grade ein wenig mit Pointern in Delphi beschäftigt. Und ein kleines Program geschrieben, wo ich Speicher im Heap für eine Integer Variabel reserviere diese Speicherstelle in einem Pointer speicher. Ich habe der Integer Variabel noch den Wert 10 zugewiesen und mir den Wert 10 anzeigen lassen. So weit ging alles. Nun habe ich noch einen zweiten Pointer gemacht und wollte nicht den Wert sondern die Speicherstelle übergeben. Das hat nun dazu geführt, dass ich das Programm nicht mehr ausführen kann nicht mal wenn ich alle Zeilen auskommatier die dazu gekommen sind. Ich habe das ganze so versucht, wie ich auch in C++ mit Pointern gearbeitet habe.


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

uses
  SysUtils;
var
pointer1 : ^integer;
//pointer2 : ^integer;
begin
    new(pointer1);
    //new(pointer2);
    pointer1^ := 10;
  //  pointer2 :=   @pointer1;  Geht nicht?
    write(inttostr(pointer1^));
    //write(inttostr(pointer2^));
    readln;


end.


Thread-Start: Thread-ID: 3220. Prozess Project2.exe (2156)
Prozessstart: C:\Documents and Settings\jytf\My Documents\Borland Studio-Projekte\Project2.exe. Basisadresse: $00400000. Prozess Project2.exe (2156)
Modul laden: Project2.exe. Enthält Debug-Infos. Basisadresse: $00400000. Prozess Project2.exe (2156)
Modul laden: ntdll.dll. Ohne Debug-Infos. Basisadresse: $7C900000. Prozess Project2.exe (2156)
Modul laden: KERNEL32.dll. Ohne Debug-Infos. Basisadresse: $7C800000. Prozess Project2.exe (2156)
Modul laden: OLEAUT32.dll. Ohne Debug-Infos. Basisadresse: $77120000. Prozess Project2.exe (2156)
Modul laden: ADVAPI32.dll. Ohne Debug-Infos. Basisadresse: $77DD0000. Prozess Project2.exe (2156)
Modul laden: RPCRT4.dll. Ohne Debug-Infos. Basisadresse: $77E70000. Prozess Project2.exe (2156)
Modul laden: Secur32.dll. Ohne Debug-Infos. Basisadresse: $77FE0000. Prozess Project2.exe (2156)
Modul laden: GDI32.dll. Ohne Debug-Infos. Basisadresse: $77F10000. Prozess Project2.exe (2156)
Modul laden: USER32.dll. Ohne Debug-Infos. Basisadresse: $7E410000. Prozess Project2.exe (2156)
Modul laden: msvcrt.dll. Ohne Debug-Infos. Basisadresse: $77C10000. Prozess Project2.exe (2156)
Modul laden: ole32.dll. Ohne Debug-Infos. Basisadresse: $774E0000. Prozess Project2.exe (2156)
Modul laden: ShimEng.dll. Ohne Debug-Infos. Basisadresse: $5CB70000. Prozess Project2.exe (2156)
Modul laden: IMM32.dll. Ohne Debug-Infos. Basisadresse: $76390000. Prozess Project2.exe (2156)
Modul entladen: ShimEng.dll. Prozess Project2.exe (2156)
Modul laden: UxTheme.dll. Ohne Debug-Infos. Basisadresse: $5AD70000. Prozess Project2.exe (2156)
Quelltexthaltepunkt bei $00409159: C:\Documents and Settings\jytf\My Documents\Borland Studio-Projekte\Project2.dpr Zeile 9. Prozess Project2.exe (2156)
Erste Gelegenheit für Exception bei $7C812AEB. Exception-Klasse EInOutError mit Meldung 'E/A-Fehler 105'. Prozess Project2.exe (2156)

Das ist die Fehlerausgabe. Ich habe wohl nen ziemlichen Fehler gemacht glaub ich.. Würde mich über Hilfe freuen ;)


Delete - Do 13.11.08 20:08

Versuch es mal so:

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

{$APPTYPE CONSOLE}

uses
  SysUtils;

var
    pointer1 : Pinteger;
    pointer2 : Pinteger;
begin
    new(pointer1);
    new(pointer2);
    pointer1^ := 10;
    pointer2 := @pointer1;
    writeln(inttostr(pointer1^));
    writeln(inttostr(integer(pointer2))); //so sollte es stimmen
    readln;
    Dispose(pointer1);
    Dispose(pointer2);
end.


[edit] Code korrigiert [/edit]


Distemix - Do 13.11.08 20:10

Könntest du oder jemand anders vieleicht auch eine kleine erklärung geben, was bei mir der Fehler war und was bei deinem Beispiel jetzt besser ist damit ich auch was lerne?

Wäre nett ;)


Delete - Do 13.11.08 20:16

Wenn Du 2 mal einen Zeiger mit ^Typ deklarierst, sind das für Delphi 2 verschiedene Typen. Du kannst also entweder einen vordefinierten Typen verwenden wie ich oder Dir selbst einen definieren. Die Variablen müssen dann von diesem Typ sein, um als kompatibel erkannt zu werden.

Delphi-Quelltext
1:
2:
3:
4:
type PMyTyp = ^TMyTyp;

var var1: PMyTyp;
    var2: PMyTyp;


Distemix - Do 13.11.08 20:27

Okey Danke schon mal für die Antwort. Hätte da aber noch zwei fragen.

type MyType = ^TInteger; Ist das Richtig so? Muss ich also für TMyTyp den Datentyp angeben für den ich den Typen erstellen möchte?
writeln(inttostr(integer(pointer2))); //so sollte es stimmen Wieso muss ich da nochmal integer(pointer2) schreiben und kann nicht einfach pointer2^ in einen integer umwandeln?


Delete - Do 13.11.08 20:31


Delphi-Quelltext
1:
2:
type PMyTyp = ^TMyTyp; //PMyTyp wird als Zeiger auf TMyTyp deklariert
     PInteger = ^integer; //ist bereits definiert, daher unnötige Typisierung


Was wolltest Du mit pointer2 denn ausgeben? Die Adresse von pointer1 oder die von pointer2 selbst? Hier mal mein Beispiel etwas erweitert, das sollte klarer sein:

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:
program Project2;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type PInteger = ^Integer;

var
    pointer1 : PInteger;
    pointer2 : PInteger;
begin
    new(pointer1);
    new(pointer2);
    pointer1^ := 10;
    pointer2 := @pointer1;
    writeln('Inhalt von Pointer1: '+inttostr(pointer1^));
    writeln('Adresse von Pointer1 mittels Cast: '+inttostr(Integer(pointer1)));
    writeln('Adresse von Pointer1 mittels Pointer2: '+inttostr(pointer2^));
    writeln('Adresse von Pointer2 mittels Cast: '+inttostr(Integer(pointer2)));
    readln;
    Dispose(pointer1);
    Dispose(pointer2);
end.


Distemix - Do 13.11.08 20:41

Ahh jetzt glaube ich verstehe ich auch, was der Quelltext hier bewirkt:

writeln(inttostr(integer(pointer2))); Ich glkaube hier wird jetzt die Speicher Addresse in einen Integer umgewandelt damit man sie mit der Funktion inttostr in einen String umwandeln kann richtig?


type PMyTyp = ^TMyTyp; //PMyTyp wird als Zeiger auf TMyTyp deklariert
Und hier ist es völlig egal was für Namen ich vergebe? Kann ich auch einfach Tblub = ^Pblub schreiben? Und ist es notwendig das P und T mitzuschreiben?


Delete - Do 13.11.08 20:42

Ich habe meinen vorherigen Beitrag nochmal editiert. Und es hat sich allgemein eingebürgert, Typen mit dem Präfix T (für Type) und Zeiger mit dem Präfix P (für Pointer) zu benennen, so sieht man gleich, worum es sich handelt.


Distemix - Do 13.11.08 20:49

Also bekommt man durch Integer(pointer1) einfach die Speicheraddresse in einen Integerwert umgewandelt?


Delete - Do 13.11.08 20:50

Richtig, ein Pointer ist ja im Grunde nichts anderes als ein Integerwert mit "Sonderstatus".


Distemix - Do 13.11.08 22:43

Okey mich würde jetzt noch interesieren, wie Zeiger in Delphi in der Praxis eingesetzt werden. Also in C++ habe ich Zeiger meistens dafür eingesetzt um beispielsweise Klassen an Funktionen zu übergeben, weil es nicht so viel Rechenaufwand ist nur die Addressen zu übergeben. Oder ich hab Zeiger bei Singleton klassen eingesetzt.

Ich bin mir jetzt noch überhaupt nicht sicher wann und wie man Zeiger bei Delphi einsetzten kann und würde mich freuen, wenn hierauf mal jemand eingehen könnte :)


Boldar - Do 13.11.08 22:52

Naja, Zeiger in Delphi werden z.B. für verkettete Listen eingesetzt, oder zum dynamischen reservieren von Speicher ala

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
var p1: pointer;
begin
getmem (p1, 1000);
byte(p1^):=$111;
p1 := p1 +1;
integer(p1^):=$262;
freemem(p1, 100);
end;


Da wird 1000 byte reserviert, es wird ins erste byte $111 als byte geschrieben und in bytes 2 bis 5 der Wert $262 als integer.
Man sieht auch of in API-Funktionen die Argumente

Delphi-Quelltext
1:
2:
Buffer: pointer,
var length: integer

, Wobei buffer ein Pointer auf einen (vorher reservierten!) Speicherbereich sein muss und length die Länge.