Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Problem mit Pointer auf dyn. Array (https://www.delphipraxis.net/116395-problem-mit-pointer-auf-dyn-array.html)

nEmai 28. Jun 2008 03:39


Problem mit Pointer auf dyn. Array
 
Hallo,

es handelt sich hier um eine Methode, die einen String in eine Bitmap schreiben soll.
Funktioniert soweit ganz gut, mich stört aber, dass ich es nicht hinkrieg MyLine der Größe einer Zeile der Bitmap anzupassen. Wenn mans auf 32768 setzt reichts garantiert, ist dann aber wenn man ein 100x100 Bitmap verwendet wenig sinnvoll. Daher hätte ich das gern ein wenig adaptiver.

Zum Gedanken:
MyLine:^TDynRGB is ein Zeiger auf ein Dynamisches Array, eine Adresse.
Wenn ich sie auflös, sollte ich mit SetLength doch eine Länge hinbringen können. Warum geht das nicht?

Und noch ne Frage: Kann man die Methode noch 'effizienter' gestalten? (Speicher/Laufzeit/whatever..)

Delphi-Quellcode:
type
  TRGBTripleArray = Array[0..3999] of TRGBTriple;
  TDynRGB = Array of TRGBTriple;

function MergeTextToBitmap(aBitmap: TBitmap; aString: String): TBitmap;
var
  iHeight,
  iWidth,
  iBitCount: Integer;
  MyLine: ^TRGBTripleArray;//^TDynRGB;
begin
  iBitCount:= 0;
  //SetLength(MyLine^, aBitmap.Width);
  aString:= IntToStr(Length(aString)) + '/' + aString;
  aBitmap.PixelFormat:= pf24Bit;
  for iHeight:= 0 to aBitmap.Height - 1 do
  begin
    MyLine:= aBitmap.ScanLine[iHeight];
    for iWidth:= 0 to aBitmap.Width - 1 do
    begin
      if not ((iBitCount + 1) > (Length(aString) * 8)) then
        MyLine[iWidth].rgbtRed:= (MyLine[iWidth].rgbtRed and $FE)
          or ((Ord(aString[(iBitCount div 8) + 1])
          shr (iBitCount mod 8)) and $01);
      Inc(iBitCount);
    end;
  end;
  Result:= aBitmap;
end;
MfG nEmai

Dax 28. Jun 2008 04:38

Re: Problem mit Pointer auf dyn. Array
 
Ein Pointer kostet vier Byte, demnach kostet dich MyLine auch nur vier Byte. Und der Grund, warum du SetLength nicht anwenden kannst: du hast keinen Speicher für das Array reserviert, das müsstest du erst mit New(MyLine) tun. Dann würde aber der Zugriff auf ScanLine nicht mehr richtig funktionieren. In solchen Fällen benutzt man aber meist keine Arrays, sondern typisierte Pointer:
Delphi-Quellcode:
function MergeTextToBitmap(aBitmap: TBitmap; aString: String): TBitmap;
var
  iHeight,
  iWidth,
  iBitCount: Integer;
  MyLine: ^TRGBTriple;
begin
  iBitCount:= 0;
  aString:= IntToStr(Length(aString)) + '/' + aString;
  aBitmap.PixelFormat:= pf24Bit;
  for iHeight:= 0 to aBitmap.Height - 1 do
  begin
    MyLine:= aBitmap.ScanLine[iHeight];
    for iWidth:= 0 to aBitmap.Width - 1 do
    begin
      if not ((iBitCount + 1) > (Length(aString) * 8)) then
        MyLine^.rgbtRed:= (MyLine^.rgbtRed and $FE)
          or ((Ord(aString[(iBitCount div 8) + 1])
          shr (iBitCount mod 8)) and $01);
      Inc(iBitCount);
      Inc(MyLine);
    end;
  end;
  Result:= aBitmap;
end;

nEmai 28. Jun 2008 11:51

Re: Problem mit Pointer auf dyn. Array
 
Ich würde das aus meiner relativ bescheidenen Erfahrung nicht empfehlen, weil ich mit exakt diesem Sourcecode ziemlich auf die Nase gefallen bin. (Auch was die 1. Präsentation des Ganzen anging..)
Auf meinem PC funktioniert es anstandslos, auf 3 von 4 weiteren Access Violations ohne Ende.
Auf Grund dieses 'schockierenden' Erlebnisses stufe ich es jetzt als gefährlich ein, Pointer zu inkrementieren. :mrgreen:

Kann man das gar nich dynamisch machen? Zur Not lass ich es halt doch so.

MfG nEmai

marabu 28. Jun 2008 12:08

Re: Problem mit Pointer auf dyn. Array
 
Hallo,

es gibt zwei grundsätzliche Wege zur Lösung deines Problems. Den einen mit der expliziten Pointer-Arithmetik hat dir Dax gezeigt. Die Alternative ist eine implizite Pointer-Arithmetik. Dabei musst du aber immer noch mit Zeigern arbeiten, da der von ScanLine gelieferte Speicherbereich ja nicht von dir kontrolliert wird.

Bei ausgeschaltetem Range-Checking kannst du über dieses Pseudo-Array zugreifen
Delphi-Quellcode:
type
  TRGBTripleArray = Array[0..0] of TRGBTriple;
  PRGBTripleArray = ^TRGBTripleArray;
var
  myLine: PRGBTripleArray;
Freundliche Grüße

nEmai 28. Jun 2008 13:06

Re: Problem mit Pointer auf dyn. Array
 
Interessant, das funktioniert.
Und lässt sich leicht auf konstant trimmen, sollte ich wieder AV-Probleme kriegen.

Noch ne Frage zum Schluss: Was bedeutet ausgeschaltetes Range-Checking? Eben diese [0..0] Grenzangabe?

MfG&Danke nEmai

marabu 28. Jun 2008 13:11

Re: Problem mit Pointer auf dyn. Array
 
Mit dem Compiler-Switch {$R+} kannst du Delphi zur Erzeugung von Prüfroutinen anweisen, die dir zur Laufzeit z.B. Bereichsüberschreitungen für Indexwerte melden. Der einzig gültige Indexwert im obigen Beispiel wäre dann 0, was dich nicht glücklich machen dürfte.


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:44 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz