Autor |
Beitrag |
JayEff
      
Beiträge: 2971
Windows Vista Ultimate
D7 Enterprise
|
Verfasst: Di 23.12.08 00:35
Hallo Leute! Heute hab ich ausnahmsweise mal 2 Probleme  (nicht in diesem einen Thema, keine Sorge  )
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
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; 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 arr[i] := StrToInt(copy(sl[i], 1, pos(':', sl[i]) - 1));
while changed do begin changed := false; for i := 0 to sl.Count - 2 do begin if arr[i] > arr[i + 1] then 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; end; |
Sehr zuverlässig crasht es hier:
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
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
Moderiert von Narses: Topic aus Algorithmen, Optimierung und Assembler verschoben am Mo 22.12.2008 um 23:41
Einloggen, um Attachments anzusehen!
_________________ >+++[>+++[>++++++++<-]<-]<++++[>++++[>>>+++++++<<<-]<-]<<++
[>++[>++[>>++++<<-]<-]<-]>>>>>++++++++++++++++++.+++++++.>++.-.<<.>>--.<+++++..<+.
|
|
Narses
      

Beiträge: 10183
Erhaltene Danke: 1256
W10ent
TP3 .. D7pro .. D10.2CE
|
Verfasst: Di 23.12.08 00:44
Moin!
JayEff hat folgendes geschrieben : | 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.
JayEff hat folgendes geschrieben : | Delphi-Quelltext 1: 2: 3:
| procedure TForm1.SortTheBox; SetLength(arr, sl.Count - 1); | |
Dein Array scheint mir ein Element zu kurz zu sein?
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
      
Beiträge: 19326
Erhaltene Danke: 1749
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: 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 Narses ja angesprochen hat) direkt angezeigt und beim schrittweise Debuggen dann auch direkt dort angehalten.
|
|
JayEff 
      
Beiträge: 2971
Windows Vista Ultimate
D7 Enterprise
|
Verfasst: 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  schätze man schreibt munter auf seinem eigenen Speicher rum. Bestimmt sehr amüsant
Danke für eure Hilfe!
_________________ >+++[>+++[>++++++++<-]<-]<++++[>++++[>>>+++++++<<<-]<-]<<++
[>++[>++[>>++++<<-]<-]<-]>>>>>++++++++++++++++++.+++++++.>++.-.<<.>>--.<+++++..<+.
|
|
jaenicke
      
Beiträge: 19326
Erhaltene Danke: 1749
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Di 23.12.08 03:04
Titel: Re: Freigabe von TStringList nach Bubblesort schlägt mit AV
JayEff hat folgendes geschrieben : | 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 Narses 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: JayEff hat folgendes geschrieben : | Delphi-Quelltext 1: 2: 3: 4:
| SetLength(arr, sl.Count - 1);
for i := 0 to sl.Count - 1 do 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. 
|
|
DeddyH
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Di 23.12.08 03:13
Oder aus Gründen der besseren Lesbarkeit
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
      
Beiträge: 19326
Erhaltene Danke: 1749
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Di 23.12.08 04:47
Warum sollte darüber jemand diskutieren? Delphi macht aus dem Low(arr) ohnehin automatisch™  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. 
|
|
DeddyH
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Di 23.12.08 14:55
Und dann definiert sich jemand ein Array[1..7] und wundert sich, wenn es knallt.
|
|
JayEff 
      
Beiträge: 2971
Windows Vista Ultimate
D7 Enterprise
|
Verfasst: Mi 24.12.08 02:48
jaenicke hat folgendes geschrieben : | [...], 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.
_________________ >+++[>+++[>++++++++<-]<-]<++++[>++++[>>>+++++++<<<-]<-]<<++
[>++[>++[>>++++<<-]<-]<-]>>>>>++++++++++++++++++.+++++++.>++.-.<<.>>--.<+++++..<+.
|
|
|