Autor Beitrag
JayEff
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2971

Windows Vista Ultimate
D7 Enterprise
BeitragVerfasst: Di 23.12.08 00:35 
Hallo Leute! Heute hab ich ausnahmsweise mal 2 Probleme ;) (nicht in diesem einen Thema, keine Sorge :mrgreen: )
In der folgenden Prozedur wird der Inhalt der Listbox1 in eine TStringList gepackt, dort per Bubblesort sortiert (die Einträge sind Zahl:String und sollen nach Zahl sortiert sein, darum sortiere ich das selber), und dann wieder zurück in die Listbox gießt. Leider erhalte ich in manchen Fällen beim Freigeben der stringlist eine Zugriffsverletzung, nach einer solchen kann beim Beenden auch ein Runtime-Error auftreten. Ein eigentlich triviales Problem, sollte man meinen :???:

ausblenden volle Höhe 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:
procedure TForm1.SortTheBox;
var
  sl: TStringList;
  changed: Boolean;
  i, tempint: Integer;
  arr: array of Integer; //bezueglich diesem wird sortiert
  temp: string;
begin
  sl := TStringList.Create;
  sl.AddStrings(Listbox1.Items);
  changed := true;

  SetLength(arr, sl.Count - 1);

  for i := 0 to sl.Count - 1 do //Füllt den Array mit den Zahlen vor dem ':'
    arr[i] := StrToInt(copy(sl[i], 1, pos(':', sl[i]) - 1));

  while changed do //typische Bubblesortimplementierung
  begin
    changed := false;
    for i := 0 to sl.Count - 2 do
    begin
      if arr[i] > arr[i + 1then
      begin
        temp := sl[i];
        sl[i] := sl[i + 1];
        sl[i + 1] := temp;
        tempint := arr[i];
        arr[i] := arr[i + 1];
        arr[i + 1] := tempint;
        changed := true;
      end;
    end;
  end;

  ListBox1.Items.Clear;
  ListBox1.Items.AddStrings(sl);
  sl.Free; //BLAM! Exception.
end;


Sehr zuverlässig crasht es hier:
ausblenden volle Höhe 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:
44:
45:
46:
47:
48:
49:
50:
procedure TForm1.Button12Click(Sender: TObject);
var
  line: string;
  ms: Integer;
begin
  if ListBox1.ItemIndex >= 0 then
  begin
    line := Listbox1.Items[Listbox1.ItemIndex];
    Form2.Shape5.Visible := (line[pos(':', line) + 1] = '1');
    Form2.Shape6.Visible := (line[pos(':', line) + 2] = '1');
    Form2.Shape7.Visible := (line[pos(':', line) + 3] = '1');
    Form2.Shape8.Visible := (line[pos(':', line) + 4] = '1');
    ms := StrToInt(copy(line, 1, pos(':', line) - 1));
    Form2.SpinEdit1.Value := ms;
  end;

  if Form2.ShowModal = mrOK then
  begin
    line := '10:----';

    if Form2.Shape5.Visible then
      line[pos(':', line) + 1] := '1'
    else
      line[pos(':', line) + 1] := '-';

    if Form2.Shape6.Visible then
      line[pos(':', line) + 2] := '1'
    else
      line[pos(':', line) + 2] := '-';

    if Form2.Shape7.Visible then
      line[pos(':', line) + 3] := '1'
    else
      line[pos(':', line) + 3] := '-';

    if Form2.Shape8.Visible then
      line[pos(':', line) + 4] := '1'
    else
      line[pos(':', line) + 4] := '-';

    ms := Form2.SpinEdit1.Value;

    Delete(line, 1, pos(':', line) - 1);
    Insert(IntToStr(ms), line, 1);

    ListBox1.Items.Add(line);
    SortTheBox; //<--
    UpdateOneLine(line);
  end;
end;

Aber auch bei mehrmaligem drücken eines Buttons in dem nur SortTheBox; steht, tritt der fehler auf. Interessanterweise scheint es vom Inhalt der Listbox abängig zu sein, ich hänge mal eine Datei an bei der es crasht. Bei dieser Datei erhalte ich auch gern mal eine AV mit aufpoppen des CPU fensters, welches vermutlich in einer Schleife angezeigt wird, da es immer wieder an der gleichen Stelle erscheint, wenn ich per F9 weiterlaufen lasse.
Schlussendlich bekomme ich einen schönen
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
---------------------------
Error
---------------------------
Runtime error 216 at 00403276
---------------------------
OK   
---------------------------

Was mach ich denn nur falsch? :!?!:

edit: grml. Als eingefleischter DF user immernoch in der falschen Kategorie gepostet :oops:
Moderiert von user profile iconNarses: Topic aus Algorithmen, Optimierung und Assembler verschoben am Mo 22.12.2008 um 23:41
Einloggen, um Attachments anzusehen!
_________________
>+++[>+++[>++++++++<-]<-]<++++[>++++[>>>+++++++<<<-]<-]<<++
[>++[>++[>>++++<<-]<-]<-]>>>>>++++++++++++++++++.+++++++.>++.-.<<.>>--.<+++++..<+.
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Di 23.12.08 00:44 
Moin!

user profile iconJayEff hat folgendes geschrieben Zum zitierten Posting springen:
In der folgenden Prozedur wird der Inhalt der Listbox1 in eine TStringList gepackt, dort per Bubblesort sortiert (die Einträge sind Zahl:String und sollen nach Zahl sortiert sein, darum sortiere ich das selber), und dann wieder zurück in die Listbox gießt. Leider erhalte ich in manchen Fällen beim Freigeben der stringlist eine Zugriffsverletzung, nach einer solchen kann beim Beenden auch ein Runtime-Error auftreten.
Das Verhalten, gerade im Zusammenhang mit lokalen, dynamischen Arrays, ist häufig ein Zeichen dafür, dass eine Bereichsüberschreitung auftritt - du schreibst in Speicher, der dir nicht gehört. :idea:

user profile iconJayEff hat folgendes geschrieben Zum zitierten Posting springen:
ausblenden Delphi-Quelltext
1:
2:
3:
procedure TForm1.SortTheBox;
//...
  SetLength(arr, sl.Count - 1);
Dein Array scheint mir ein Element zu kurz zu sein? :nixweiss:

Tipp: wozu das Array? Du kannst den Wert des Eintrags (=die Zahl) doch auch gleich im .Objects[] der Stringliste ablegen. ;)

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19326
Erhaltene Danke: 1749

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Di 23.12.08 00:49 
Schalte am besten einfach zum Debuggen mal in den Compileroptionen (Projekt --> Optionen --> Compiler) die Bereichsprüfung (ganz rechts oben) ein.

Dann wird dir eine Bereichsüberschreitung (die user profile iconNarses ja angesprochen hat) direkt angezeigt und beim schrittweise Debuggen dann auch direkt dort angehalten.
JayEff Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2971

Windows Vista Ultimate
D7 Enterprise
BeitragVerfasst: Di 23.12.08 02:33 
Es war ziemlich sicher der zu kleine dynamische Array (ihr kennts ja, schleifen gehen schließlich auch von 0 bis count - 1 ;) ), aber das mit der Bereichsprüfung...: da ist mir kein unterschied aufgefallen, nachdem ich die option aktiviert hatte

Es wundert mich, dass es nicht sofort eine Zugriffsverletzung hagelt, aber das hat potential für witzige effekte auf das programm :D schätze man schreibt munter auf seinem eigenen Speicher rum. Bestimmt sehr amüsant :mrgreen:

Danke für eure Hilfe!

_________________
>+++[>+++[>++++++++<-]<-]<++++[>++++[>>>+++++++<<<-]<-]<<++
[>++[>++[>>++++<<-]<-]<-]>>>>>++++++++++++++++++.+++++++.>++.-.<<.>>--.<+++++..<+.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19326
Erhaltene Danke: 1749

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Di 23.12.08 03:04 
Titel: Re: Freigabe von TStringList nach Bubblesort schlägt mit AV
user profile iconJayEff hat folgendes geschrieben Zum zitierten Posting springen:
Es war ziemlich sicher der zu kleine dynamische Array (ihr kennts ja, schleifen gehen schließlich auch von 0 bis count - 1 ;) ), aber das mit der Bereichsprüfung...: da ist mir kein unterschied aufgefallen, nachdem ich die option aktiviert hatte
Komisch, wenn die aktiviert ist, hätte eigentlich (wie user profile iconNarses bereits sagte) an dieser Stelle eine entsprechende Meldung kommen müssen. Bei Records wurde in einem anderen Beitrag hier im Forum bereits festgestellt, dass die Prüfung bei einem Array von bestimmten Records nicht klappt. Wie ich festgestellt habe wurde schlicht kein Prüfcode hinzugefügt. In diesem Fall hier sollte das aber klappen.

Was du machst war ja:
user profile iconJayEff hat folgendes geschrieben Zum zitierten Posting springen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
  SetLength(arr, sl.Count - 1);

  for i := 0 to sl.Count - 1 do //Füllt den Array mit den Zahlen vor dem ':'
    arr[i] := StrToInt(copy(sl[i], 1, pos(':', sl[i]) - 1));
Beispiel: sl.Count sei 10
--> SetLength(arr, 9);
--> höchster Index 8 ( 0..8 )
for i := 0 to 9 do
--> arr[9] existiert aber nicht
Und genau da hätte eigentlich nach dem Aktivieren eine Bereichsüberschreitung entdeckt werden müssen.

Deshalb: Nimm bei Arrayzugriffen in Schleifen einfach for i := 0 to High(arr) ;-).

Aber wenn du diesen Fehler behoben hast ist ja alles in Ordnung, egal warum die Prüfung nicht funktionierte. :nixweiss:
DeddyH
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Di 23.12.08 03:13 
Oder aus Gründen der besseren Lesbarkeit
ausblenden Delphi-Quelltext
1:
for i := Low(arr) to High(arr)					


P.S.: Ich weiß, dass Low(arr) bei dynamischen Arrays immer 0 ist (steht ja auch so in der Hilfe), bitte nicht schon wieder Diskussionen darüber ;)
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19326
Erhaltene Danke: 1749

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Di 23.12.08 04:47 
Warum sollte darüber jemand diskutieren? Delphi macht aus dem Low(arr) ohnehin automatisch™ :mrgreen: eine 0 im Assemblercode, wenn es sich um ein dynamisches Array handelt.
Deshalb ist es ohnehin vollkommen egal was man schreibt, es kommt exakt der selbe Code heraus, man kann also das nehmen was man für schöner™ hält. :D
DeddyH
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Di 23.12.08 14:55 
Und dann definiert sich jemand ein Array[1..7] und wundert sich, wenn es knallt.
JayEff Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2971

Windows Vista Ultimate
D7 Enterprise
BeitragVerfasst: Mi 24.12.08 02:48 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
[...], wenn es sich um ein dynamisches Array handelt.

;)

Und keine Sorge, ich kann es auseinander halten, ob ich ein dynamisches oder statisches Array vor mir habe, da ich den code selbst geschrieben habe. Dass das schief ging, war ein Denkfehler von mir gepaart mit Abändern von altem code: Zunächst hatte ich auf die Strings bubblesort angewendet, wobei ich per copy/pos die ms zahl immer wieder neu rauskopiert hab, das war nicht performant also hab ich's geändert und die schleifengrenzen aber so gelassen wie sie vorher waren (sl.count) anstatt high(arr) zu nehmen. Ausserdem hatte ich den denkfehler mit SetLength: es setzt ja die *länge* wie aus dem Name hervorgeht, ich hatte aber an den höchsten Index gedacht.

Bei statischen Arrays hab ich's allerdings auch gerner, wenn ich die Array grenzen direkt sehe in der Schleife anstatt mit low/high zu arbeiten.

_________________
>+++[>+++[>++++++++<-]<-]<++++[>++++[>>>+++++++<<<-]<-]<<++
[>++[>++[>>++++<<-]<-]<-]>>>>>++++++++++++++++++.+++++++.>++.-.<<.>>--.<+++++..<+.