Wie zu erwarten war ... überall Speicherlecks.
Aber erstmal egal
@arB
= ein Zeiger auf die Variable
@arB[0]
= ein Zeiger auf die Daten
Denn ein dynamisches Array ist intern ein Zeiger und die Daten stecken nicht direkt in der Variable.
Bei einem statischen Array entspicht @arB zwar einem @arB[Low(arB)], aber besser immer mit Index ... nicht daß man es mal vergißt und es dann bei einem Dynamischen knallt.
bis hier ist alles wie es sein soll
falsch gedacht
Delphi-Quellcode:
D.OutPut(P);
SetLength(arB,D._RealSize);
arB := TArByte(P^); //bis hier ist alles wie es sein soll
P gibt einen Speicherbereich (Pointer) zurück
arB ist aber kein billiger Zeiger (
Pointer), sondern ein
array of byte
Dann reservierst du Speicher für das dyn. array (SetLength),
welchen du dann wieder verwirfst (
:=
) und versuchst den Pointer als
array of byte
zu interpretieren,
was natürlich niemals funktionieren kann, da es vollkommen unterschiedliche Typen sind und sie ihren speicher unterschiedlich verwalten.
Du mußt also den speicher von P
in das Array kopieren.
Praktisch so ähnlich, wie du schonmal den Text in das Array reinkopiert hast. (Edit1.Text ist der Inhalt von P)
Delphi-Quellcode:
for I := 0 to len - 1 do
arB[I] := ord(Edit1.Text[I+1]);
(statt solcher Schleifen kann man natürlich auch
Move verwenden)
P köntest du dir dafür nach PStaticBytes casten.
Delphi-Quellcode:
type
TStaticBytes = array[0..0] of Byte;
PStaticBytes = ^TStaticBytes;
PS: 0..0 ist ein sonderfall, denn dort macht Delphi niemals eine Bereichsprüfung für den Index.
Man könnte auch
[0..666]
nehmen (666 = irgendein Wert, welcher groß genug ist ... also mindestens so groß, wie der maximal zu erwartende Indexwert ... da ist [0..0] natürlich einfacher
)
Und am Ende vergißt du auch noch P wieder freizugeben, welches in OutPut reserviert wurde.
Darum macht man sowas eigentlich auch besser nicht ... Speicher sollte möglichst immer in der Ebene freigeben werden, wo er reserviert wurde.
Mach Output genauso wie input (Pointer+Len) und laß' die Daten vom Output direkt in @arB[0] reinschreiben.
(Len ist dann die Länge von arB, also die maximale Größe der daten, welche in arb reinpassen würde, was man in Output prüfen sollte, bevor man was reinschreibt)
Delphi-Quellcode:
TBytes = array of Byte; // in neueren Delphis kann man das dann weglassen, da es diesen Typ dort schon gibt
TDataType = (dtNone, dtBool, dtByte, dtChar, dtString, dtInteger, dtReal); // ein Enumerator
TData = class
private
_Data : Pointer;
_MaxSize, _RealSize: Integer;
_DataType : TDataType;
public
procedure Init(MaxSize : Integer; DataType : TDataType); // wäre als Constructor bestimmt besser geeignet
destructor Destroy; override;
procedure Input(Data : Pointer; DataSize : Integer);
property MaxSize: Integer read _MaxSize;
property RealSize: Integer read _RealSize;
property DataType: TDataType read _DataType;
procedure Output(Data : Pointer; MaxSize: Integer);
end;
implementation
procedure TData.Init(MaxSize, DataType : Integer);
begin
_MaxSize := MaxSize;
_DataType := DataType;
GetMem(_Data, _MaxSize);
end;
destructor TData.Destroy;
begin
FreeMem(_Data);
end;
procedure TData.Input(Data : Pointer; DataSize : Integer);
begin
if RealSize <= _MaxSize then
begin
_RealSize := DataSize;
Move(Data, _Data, DataSize);
end
else
ShowMessage('Speicherplatz überschritten!');
end;
procedure TData.Output(Data : Pointer; MaxSize: Integer);
begin
if MaxSize >= _RealSize then
Move(_Data, Data, _RealSize)
else
ShowMessage('Data zu klein!');
end;
Zitat:
Delphi-Quellcode:
D := TData.Create;
D.Init(500,1);
Mit Init als Constructor, würde dann
D := TData.Create(500, 1);
gehn.
Delphi-Quellcode:
procedure TForm1.Button2Click(Sender: TObject);
var
arB : array of Byte;
I,Len : Integer;
begin
len := length(Edit1.Text);
SetLength(arB, len);
for I := 0 to len - 1 do
arB[I] := ord(Edit1.Text[I+1]);
D.Input(@arB[0], len);
end;
procedure TForm1.Button3Click(Sender: TObject);
var
arB : TArByte;
I : Integer;
begin
SetLength(arB, D.RealSize); // D._RealSize ist PRIVAT ... sowas verwendet man nicht extern
D.OutPut(@arB[0], Length(arB));
for I := 0 to High(arB) do
Caption := Caption + chr(arB[I]);
end;
Enumeratoren sind toll, erstmal ist somit alles logisch und physisch zusammen, was zusammen gehört
und die Quelltextvervollständigung verrät einem was man an soeine Variable/Parameter übergeben kann, da der Compiler nun auch weiß was zusammengehört.