Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Arrays wie in C++


Andreas Pfau - So 19.01.03 13:23
Titel: Arrays wie in C++
Hallo liebe Experten,

ich kenne mich eigentlich nicht mit C++ aus, aber ich habe da mal einen sourcecode gelesen:

Quelltext
1:
2:
3:
4:
5:
6:
7:
typedef struct
{
    WORD           idReserved;
    WORD           idType;
    WORD           idCount;
    ICONDIRENTRY   idEntries[1];of 'em)
} ICONDIR;


idEntries ist ein dynamischer Array. Wenn man die Struktur (den Record) mit einem Stream einliest, und idEntries 3 Elemente hat, werden auch 3 Elemente gelesen.

In Delphiy müsste das dann so aussehen:

Quelltext
1:
2:
3:
4:
5:
6:
7:
type
 IconDir = record
  idReserved: DWord;
  idType: DWord;
  idCount: DWord;
  idEntries: Array Of IcondirEntry;
 end;


OK, aber wenn ich das mit 'nem Stream einlese, wird der Array nicht eingelesen (da es sich hier ja nur um Pointer handelt). Aber Dynamische Arrays lasesn sich eben nur mit Pointern realisieren (Ich will keinen Statischen Array).

Jetzt müsste ich die ersten 3 Elemente als Record einlesen, und dann jedes Element des Arrays manuell. Aber gibt es auch einen anderen Weg, oder ist das eine Sache, in der uns C++ vorraus ist?


AndyB - So 19.01.03 17:21

Wie würdest du denn die obige Structur in C++ einlesen? Das geht auch nur über vorheriges einlesen von Count, denn das Array besitzt im Grunde nur 1 Element.


Andreas Pfau - So 19.01.03 19:15

Äh, sorry, schreiben meine ich :oops:

Mit C++ kann man die Länge des Arrays festlegen, und dann werden so viele Elemente geschreiben, wie der Array hat. Mit Delphi wird nur der Zeiger geschreiben (also 4 Byte), und damit kann man nix anfangen.


tommie-lie - So 19.01.03 20:24

Würde sich damit nicht das Array im Stream statisch?
Ich würde zuerst das Record schreiben, und dann für jeden Eintrag im Array (for i := 0 to High(array) -1 usw) hinten dranhängen. Dsa geht aber nur so llange, wie nur ein Record im Stream ist. Für den Fall, daß da mehrere im Stream sind, würde ich die momentane Länge des Array speichern (als Integer, also immer 4 Byte) und dann dannach den Inhalt des Arrays. Das auslesen geht dann genauso. Erst das Record auslesen, dann schauen, wie lang das Array ist (nächsten 4 Byte auslesen, da steht's drin) und dann die eben ausgelesene Anzahl an Bytes zurückauslesen und in das Array zurückspeichern.
Dann weißt du automatisch, daß hinter dem Array (also nach der Anzahl an Bytes, die du nach dem Record ausgelesen hast) das nächste Record anfängt, wieder gefolgt von einer Array-Länge und dem Array-Inhalt, wieder gefolgt von einem Record usw.


Andreas Pfau - So 19.01.03 21:08

Ja, schon kalr, so mache ich das ja auch immer. Ich wollte nur wissen, ob das auch so geht wie in C++, also Länge festlegen und den gesamten Record auf einmal schreiben, und nicht Element für Element.


Andreas Pfau - So 19.01.03 21:58

Juhu, ich habe es geschafft. Ich habe grade einen code zum Erstellen einer Palette geschreiben, da fiel mir auf, dass das ja genau das ist, was ich suche. So gehts:


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:
type
 TTestRecord = packed record
  S: Integer;
  A: Array[0..0] Of Char;
 end;

procedure TMain.Button1Click(Sender: TObject);
var
  T: ^TTestRecord;
  S: TFileStream;
  I: Integer;
begin
  GetMem(T, SizeOf(TTestRecord) + 4 * SizeOf(Char));
  T.S := 5;
  I := 0; T.A[I] := 'H';
  I := 1; T.A[I] := 'e';
  I := 2; T.A[I] := 'l';
  I := 3; T.A[I] := 'l';
  I := 4; T.A[I] := 'o';

  S := TFileStream.Create('Test.hex', fmCreate);
  S.Write(T^, SizeOf(TTestRecord) + 4 * SizeOf(Char));
  S.Free;
  FreeMem(T);
end;

procedure TMain.Button1Click(Sender: TObject);
var
  T: ^TTestRecord;
  S: TFileStream;
  I, L: Integer;
  E: String;
begin
  S := TFileStream.Create('Test.hex', fmOpenRead);

  GetMem(T, SizeOf(TTestRecord));
  S.Read(T^, SizeOf(Integer));
  L := T.S;
  GetMem(T, SizeOf(TTestRecord) + (L - 1) * SizeOf(Char));

  S.Read(T^.A, SizeOf(Char) * L);

  S.Free;

  E := '';
  For I := 0 To L - 1 Do
   E := E + T.A[I];

  ShowMessage(E);
 
  FreeMem(T);
end;


Funktioniert aber leider nur mit einem Array, und der muss am Ende sein (weil ja sonst die Absolute Adresse der folgenden Variablen nicht mehr stimmen würde).