Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Auf dynamischen Speicher zugreifen


reimo - Fr 27.02.04 13:00
Titel: Auf dynamischen Speicher zugreifen
also, folgendes Problem:

ich empfange über IP ein telegram mit dynamischer Länge, also reserviere ich den dafür nötigen Speicher auch dynamisch:


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:
Cnt : Integer;
pBuffer : ^Byte;
bRec: Byte;

Cnt := Socket.ReceiveLength;
GetMem( pBuffer, Cnt );

Socket.ReceiveBuf( pBuffer^, Cnt );

// so, jetzt möchte ich den buffer byteweise auslesen, aber wie???
// 1. Versuch

for i := 0 to Cnt-1 do begin
   bRec := pBuffer[i];      // schön wärs, geht leider nicht
end;

// 2. Versuch
bRec: ^Byte;

bRec := pBuffer;      // geht auch nicht, obwohl beide gleichen Typs, schreit der Compiler, dagegen bRec := @pBuffer funktioniert -> will ich aber nicht
for i := 0 to Cnt-1 do begin
   ...
   Inc(bRec);
end;

wie kann ich auf die einzelnen Bytes des reservierten Speichers zugreifen??
wieso kann ich einen Pointer nicht inkrementieren?

mfg
reimo

Moderiert von user profile iconTino: Titel geändert.


ErnestoChe - Fr 27.02.04 13:27

Hallo,

ich nehme mal an, dass du versuchst es wie in C zu machen. Was Pointer und Arrays angeht unterscheidet sich Delphi von C. In deinem Fall würde ich einfach einen Pointer auf ein Byte-Arry machen:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
type
  TByteArr = array of Byte;
  PByteArr = ^TByteArr;

var
  pBuffer: PByteArr;

//..............................................

  pBuffer := New(PByteArr);
  SetLength(pBuffer^, Cnt);


MFG

- Ernesto -


Phantom1 - Fr 27.02.04 13:30

oder wenn du kein PByteArray verwenden möchtest, so hier:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
Cnt: Integer; 
pBuffer, 
bRec: PByte; 

Cnt := Socket.ReceiveLength; 
GetMem(pBuffer, Cnt); 

Socket.ReceiveBuf(pBuffer^, Cnt); 

bRec := pBuffer;         
for i := 0 to Cnt-1 do begin 
   ... 
   Inc(bRec); 
end;


reimo - Fr 27.02.04 13:41

cool, danke für die Antworten

wusste garnicht, dass man die Länge eines arrays dynamisch ändern kann.

in diesem Fall kann ich gleich die Funktion SetLength verwenden und mir den Zugriff über Pointer ersparen (falls ichs richtig verstanden habe)


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
Buffer : array of Byte;

Cnt := Socket....

SetLenght( Buffer, Cnt);               
Socket.Receive( Buffer, Cnt );

for i := 0 to Cnt do begin
   xx := Buffer[i]
end;


@Phantom1
was wäre bei deinem Vorschlag der Unterschied zu meinem 2ten Versuch?
du hast bRec als PByte deklariert, ich dagegen als ^Byte, ist das nicht das selbe?

mfg
reimo


Motzi - Fr 27.02.04 13:41

ErnestoChe hat folgendes geschrieben:
Hallo,

ich nehme mal an, dass du versuchst es wie in C zu machen. Was Pointer und Arrays angeht unterscheidet sich Delphi von C. In deinem Fall würde ich einfach einen Pointer auf ein Byte-Arry machen:


Delphi-Quelltext
1:
2:
3:
type
  TByteArr = array of Byte;
  PByteArr = ^TByteArr;

Aber was du hier deklarierst ist ein Zeiger auf ein dynamisches Array und das kann ganz schnell Probleme machen..!

In der Unit SysUtils ist bereits ein Type TByteArray bzw PByteArray deklariert:

Delphi-Quelltext
1:
2:
  PByteArray = ^TByteArray;
  TByteArray = array[0..32767of Byte;

Und mit so einer Deklaration funktioniert dann auch der gewünschte Zugriff...


ErnestoChe - Fr 27.02.04 14:40

Hallo,

Zitat:
Aber was du hier deklarierst ist ein Zeiger auf ein dynamisches Array und das kann ganz schnell Probleme machen..!


Hast du eine weitere Begründung, außer kann ganz schnell Probleme machen?

Es war nur ein Beispiel, um einen Denkanstoß zu geben. Er muss selber wissen ob das Array dynamisch oder statisch sein muss. Wenn man mit dem dynamischen Array sauber umgeht, kann auch nichts passieren.

MFG

- Ernesto -


Motzi - Fr 27.02.04 16:29

Ein dynamischer Array ist in Delphi (genauso wie auch Strings) nur ein Pointer der implizit dereferenziert wird. Mit einem Pointer auf einen dyn. Array hast du also praktisch einen Pointer auf einen Pointer und daher in diesem Fall unbrauchbar...


ErnestoChe - Fr 27.02.04 17:49

Hallo,

Zitat:
Mit einem Pointer auf einen dyn. Array hast du also praktisch einen Pointer auf einen Pointer und daher in diesem Fall unbrauchbar


Stimmt, dynamische Arrays sind implizit Zeiger. Daher ist es zwar nicht unbrauchbar aber wohl unnötig.

Apropos Zeiger auf Zeiger. Wieso machst du eigentlich in deinem Pointer-Tutorial [http://www.delphi-forum.de/viewtopic.php?t=10926] sowas:

Zitat:
type PMultipleForm = ^TMultipleForm;


MFG

- Ernesto -


Motzi - Fr 27.02.04 18:16

ErnestoChe hat folgendes geschrieben:
Stimmt, dynamische Arrays sind implizit Zeiger. Daher ist es zwar nicht unbrauchbar aber wohl unnötig.

In diesem Fall ist es schon unbrauchbar..! Probier mal diesen Code aus, dann siehst du auch warum:

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:
const
  MAX_COUNT = 255;

type
  PDynByteArray = ^TDynByteArray;
  TDynByteArray = array of Byte;

  PStatByteArray = ^TStatByteArray;
  TStatByteArray = array [1..MAX_COUNT] of Byte;


procedure TForm1.Button1Click(Sender: TObject);
var
  szArray: array [1..MAX_COUNT] of Byte;
  pDynArray: PDynByteArray;
  pStatArray: PStatByteArray;
  i: Integer;
begin
  Listbox1.Clear;
  Listbox2.Clear;

  // den Array füllen
  for i := 1 to MAX_COUNT do
    szArray[i] := i;

  pDynArray := @szArray[1]; // dem Zeiger auf den dyn. Array die Adresse des Arrays zuweisen
  pStatArray := @szArray[1]; // dem Zeiger auf den stat. Array die Adresse des Arrays zuweisen

  // Listbox1 mit den Werten des Zeigers auf den stat. Array füllen
  for i := 1 to MAX_COUNT do
    Listbox1.Items.Add(IntToStr(pStatArray^[i]));

  // Listbox2 mit den Werten des Zeigers auf den dyn. Array füllen
  for i := 1 to MAX_COUNT do
    Listbox2.Items.Add(IntToStr(pDynArray^[i]));
end;

Bei der zweiten Schleife (in der eigentlich die Werte in die Listbox2 eingetragen werden sollten) wirst du nämlich mit einer wunderschönen EAccessViolation Exception begüßt.... Warum? Weil ein Zeiger auf einen dyn. Array eben ein Zeiger auf einen Zeiger ist welcher implizit nochmal dereferenziert wird. Dh die ersten 4 Bytes des Arrays auf das der Zeiger zeigt werden nochmal dereferenziert womit du an der Adresse $01020304 landest an der dann versucht wird auf den eigentlichen Array zuzugreifen...

Zitat:
Apropos Zeiger auf Zeiger. Wieso machst du eigentlich in deinem Pointer-Tutorial [http://www.delphi-forum.de/viewtopic.php?t=10926] sowas:

Zitat:
type PMultipleForm = ^TMultipleForm;

Weil ich hier den Einsatz von Pointern und dyn. Speicherallozierung zeigen wollte.. du hast recht es sind im Prinzip auch wieder Zeiger auf Zeiger, aber wenn ich mich recht erinnere hab ich ganz am Schluss auch extra geschrieben, dass man das ganze auch ohne extra Zeiger machen kann da Objekte ohnehin nur Zeiger sind... Ich weiß das Beispiel ist nicht unbedingt gut gewählt, aber es ist schon sehr lang her dass ich das Tutorial damals geschrieben hab und ich in der zwischenzeit auch viel neues dazu gelernt, aber ich war bis jetzt zu faul das Tutorial zu überarbeiten... ;)


ErnestoChe - Sa 28.02.04 23:25

Hallo,

@Motzi
Du hast Recht. Naja, meine Muttersprache ist nun mal C/C++.

Motzi hat folgendes geschrieben:
Ich weiß das Beispiel ist nicht unbedingt gut gewählt, aber es ist schon sehr lang her dass ich das Tutorial damals geschrieben hab und ich in der zwischenzeit auch viel neues dazu gelernt, aber ich war bis jetzt zu faul das Tutorial zu überarbeiten...:wink:


OK, kann man verstehen :wink:

MFG

- Ernesto -