Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Stack-Overflow, Endloschleife?


Juniorsatan - Mo 22.03.10 17:43
Titel: Stack-Overflow, Endloschleife?
Ich probiere mich gerade an einer RLE-Kompression für dynamische Arrays.

Bisher funktionierte die Prozedur mit allen Testarrays, die ich manuell erstellt habe. Generiere ich jedoch ein größeres (wo bspw. die Farbwerte eines Bildes gespeichert sind), kommt es zu einem Stackoverflow.

Die sieht wie folgt aus:

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:
37:
38:
39:
40:
41:
42:
43:
procedure RLE(kanal_array: Array of Byte);
var
new_array: Array of Byte;
k, count: integer;
output:string;
begin
setlength(new_array, 0);  //Initialisierung
k:=0;                     //Initialisierung
While ( k <= length(kanal_array)) DO
  Begin
    count:= countrep(kanal_array, k);
    if (kanal_array[k] = 255then // Ist das Zeichen der Codeflag?
          Begin
            setlength(new_array, (length(new_array) + 2));
            new_array[(high(new_array)-1)]:= 255// Codeflag speichern
            new_array[(high(new_array))]:= 0;   // No Code Flag speichern
            inc(k)
          End
    else if (count > 3then  // mind. 4 redundante Zeichen nebeneinander
          Begin
            setlength(new_array, (length(new_array) + 3)); //neues Array wird um drei Elemente erhöht
            new_array[(high(new_array)-2)]:= 255// Codeflag im neuen Array an vorvorletzte Stelle
            new_array[(high(new_array)-1)]:= count;    // Anzahl der Wiederholungen des Zeichen  an vorletzte Stelle
            new_array[(high(new_array))]:= kanal_array[k]; // Zeichen selbst an letzte Stelle
            k:=(k + count); // neue Stelle, bei der Kompressionsversuch gestartet wird
          End
    Else
      Begin
        setlength(new_array, (length(new_array) + 1)); // Array um ein Element vergrößern
        new_array[(high(new_array))]:= kanal_array[k]; // Wert an letzte Stelle schreiben
        inc (k);
      End;
  End;
setlength(new_array, (length(new_array) - 1)); // Produziertes Array ist immer ein Index zu groß, wird hier behoben

{Test}
For k:=0 to high(new_array) DO
  begin
  output:= output + inttostr(new_array[k]) + '; ';
  end;

showmessage(output);
end;


Die Funktion countrep sucht redundante Einträge und sieht so aus:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
function countrep(arr: Array of Byte; k:Integer): Integer;
var
n:integer;
Begin
n:=0;
While ( ( (k+n) < high(arr) ) AND (arr[(k+n)] = arr[(k+n)+1]) AND (n < 253)) Do  // Solange weder Ende der Schleife + gleichheit der benachbarten Elemente + Maxcount nicht überschritten
  Begin
  inc(n);
  End;
countrep:=n +1 ;
End;


Mich verwirrt wie gesagt der Fakt, dass es für kleine Arrays bisher tadellos funktionierte, Endlosschleifen o.ä. sehe ich auch nirgends. Habt ihr eine Idee?


elundril - Mo 22.03.10 17:52

kann es sein das er sich in der markierten zeile aufhängt weil du mit <= length anstatt mit < length bzw <= high arbeitest?


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:
37:
38:
39:
40:
41:
42:
43:
procedure RLE(kanal_array: Array of Byte);
var
new_array: Array of Byte;
k, count: integer;
output:string;
begin
setlength(new_array, 0);  //Initialisierung
k:=0;                     //Initialisierung
While ( k <= length(kanal_array)) DO
  Begin
    count:= countrep(kanal_array, k);
    if (kanal_array[k] = 255then // Ist das Zeichen der Codeflag?
          Begin
            setlength(new_array, (length(new_array) + 2));
            new_array[(high(new_array)-1)]:= 255// Codeflag speichern
            new_array[(high(new_array))]:= 0;   // No Code Flag speichern
            inc(k)
          End
    else if (count > 3then  // mind. 4 redundante Zeichen nebeneinander
          Begin
            setlength(new_array, (length(new_array) + 3)); //neues Array wird um drei Elemente erhöht
            new_array[(high(new_array)-2)]:= 255// Codeflag im neuen Array an vorvorletzte Stelle
            new_array[(high(new_array)-1)]:= count;    // Anzahl der Wiederholungen des Zeichen  an vorletzte Stelle
            new_array[(high(new_array))]:= kanal_array[k]; // Zeichen selbst an letzte Stelle
            k:=(k + count); // neue Stelle, bei der Kompressionsversuch gestartet wird
          End
    Else
      Begin
        setlength(new_array, (length(new_array) + 1)); // Array um ein Element vergrößern
        new_array[(high(new_array))]:= kanal_array[k]; // Wert an letzte Stelle schreiben
        inc (k);
      End;
  End;
setlength(new_array, (length(new_array) - 1)); // Produziertes Array ist immer ein Index zu groß, wird hier behoben

{Test}
For k:=0 to high(new_array) DO
  begin
  output:= output + inttostr(new_array[k]) + '; ';
  end;

showmessage(output);
end;


lg elundril


Juniorsatan - Mo 22.03.10 18:09

Daran habe ich auch schon gedacht, deswegen prüfe ich in der darauffolgenden Funktion sofort, ob ich mich noch im Rahmen des Arrays bewege.


Delphi-Quelltext
1:
While ( ( (k+n) < high(arr) ) AND ....) Do                    


Mir wurde schulischerseits beigebracht, dass es bei solchen Prüfungen wichtig ist, dass diese "vorne" in der Bedingung stehen, sodass bei einem etwaigen Überschreiten die hinteren Expressions nicht mehr angesprochen wird, da es sofort zum Abbruch kommt.


BenBE - Mo 22.03.10 18:40

Dennoch läuft deine äußere Schleife in einen Fall rein, der ohne Behandlung un der inneren Schleife bleibt und damit nie verlassen wird. Schau Dir das doch einmal im Single-Step-Modus (F7/F8) im Debugger an und beobachte die verschiedenen Werte.


Juniorsatan - Mo 22.03.10 18:43

Kann ich das in irgendeiner Weise zumindest ein wenig automatisieren? Das Array ist um die 4000000 Einheiten groß und ich kriege den Fehler bisher nicht anders reproduziert, als das ich das besagte Bild als Ausgangsmaterial verwende.

Nichtsdestotrotz werd ichs mir nochmal angucken.


BenBE - Mo 22.03.10 19:24

Haltepunkt setzen, links auf das rote Mumpel klicken --> Halötepunkt-Eigenschaften und da ne Bedingung eingeben.