Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - AV bei SetLength
Silas - Di 17.07.07 14:18
Titel: AV bei SetLength
Hallo :wave:
Ich hab' da ein Problem :)
Mein Code sieht (gekürzt) so 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: 44: 45: 46: 47: 48:
| ...
type TFIniValue = record ... end;
TFIniSection = record ... Values: array of TFIniValue; ValuesLength: Cardinal; ... end;
TFIniFile = class private Sections: array of TFIniSection; SectionsLength: Cardinal; ... CurrentSection: Integer; ... public constructor Create(FileName: String); ... end;
...
implementation
constructor TFIniFile.Create(FileName: String); var Buf, Buf1, Buf2: String; begin ... SetLength(Sections, SectionsLength+1); inc(SectionsLength); ... CurrentSection := SectionsLength-1; ... with Sections[CurrentSection] do begin SetLength(Values, ValuesLength+1); inc(ValuesLength); ... end; ... end;
... |
Nun bekomme ich in der markierten Zeile eine AV:
Access violation at adress 0045B13A in module 'test.exe'. Read of address 00000008
Was hab' ich falsch gemacht?
BenBE - Di 17.07.07 21:14
Du hast grad genau die Zeilen rausgelassen, die für die Fehlerdiagnose interessant gewesen wären. Poste mal bitte den Gesamten Constructor.
Delete - Di 17.07.07 21:52
SetLength löst keine AccessViolation aus. Ist die Instanz von Sections gültig?
Silas - Mi 18.07.07 15:20
Hier mal der Komplette Constructor inkl. den zwei Funktionen, die er noch verwendet:
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: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67:
| constructor TFIniFile.Create(FileName: String); var Buf, Buf1, Buf2: String; begin AssignFile(IniFile, FileName); Reset(IniFile); while not EOF(IniFile) do begin readln(IniFile, Buf); DeleteSpaces(Buf); if (Pos('[', Buf) <> -1 ) and (Buf[Length(Buf)-1] = ']') then begin SetLength(Sections, SectionsLength+1); inc(SectionsLength); Sections[SectionsLength-1].Deleted := false; Sections[SectionsLength-1].Name := Copy(Buf, 1, Length(Buf)-3); CurrentSection := SectionsLength-1; end else begin if Pos('=', Buf) = -1 then continue; SplitAt(Buf, Buf1, Buf2, '='); DeleteSpaces(Buf1); DeleteSpaces(Buf2); with Sections[CurrentSection] do begin SetLength(Values, ValuesLength+1); inc(ValuesLength); Values[ValuesLength-1].Name := Buf1; Values[ValuesLength-1].Value := Buf2; Values[ValuesLength-1].Deleted := false; end; end; end; CurrentSection := -1; end;
procedure SplitAt(const Str: String; var Sub1, Sub2: String; const Chr: Char); var ChrPos: Integer; begin ChrPos := Pos(Chr, Str); if ChrPos = -1 then begin Sub1 := Str; Sub2 := ''; end else begin Sub1 := Copy(Str, 0, ChrPos-1); Sub2 := Copy(Str, ChrPos+1, Length(Str)-ChrPos); end; end;
procedure DeleteSpaces(var Str: String); var LStrPos, i: Cardinal; LastNSpc, FirstNSpc: Integer; begin if (Pos(' ', Str) = -1) or (Length(Str) = 0) then exit; LStrPos := Length(Str)-1; FirstNSpc := -1; for i := 0 to LStrPos do begin if Str[i] <> ' ' then begin FirstNSpc := i; break; end; end; LastNSpc := -1; for i := LStrPos downto 0 do if Str[i] <> ' ' then begin LastNSpc := i; break; end; Str := Copy(Str, FirstNSpc, LastNSpc-FirstNSpc+1); end; |
Zum leichteren verständnis:
Create liest eine Zeile aus einer Ini-Datei entweder in einen Sektionen- oder einen Wertepuffer ein;
SplitAt teilt einen String an einem Char (der dabei wegfällt) und
DeleteSpaces löscht Leerzeichen, die am Anfang und am Ende eines Strings stehen.
alzaimar - Mi 18.07.07 15:26
Wo wird Sectionslength und ValuesLength initialisiert? Schalte mal deine Compilerwarnungen EIN! Dann siehst Du solche Schusseligkeitsfehler schneller.
Silas - Mi 18.07.07 15:35
Ich hab's mal mit Initialisierung versucht, die einzige Veränderung ist, dass die AV jetzt
Read of Address FFFFFFF8 heißt.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| constructor TFIniFile.Create(FileName: String); var Buf, Buf1, Buf2: String; begin AssignFile(IniFile, FileName); Reset(IniFile); SectionsLength := 0; CurrentSection := -1; while not EOF(IniFile) do begin ... inc(SectionsLength); Sections[SectionsLength-1].ValuesLength := 0; Sections[SectionsLength-1].Deleted := false; Sections[SectionsLength-1].Name := Copy(Buf, 1, Length(Buf)-3); ... end; CurrentSection := -1; end; |
Meine Compilerwarnungen waren eingeschaltet, eine Meldung (außer der Erfolgsmeldung) hab ich nicht bekommen.
alzaimar - Mi 18.07.07 15:52
Silas hat folgendes geschrieben: |
Ich hab's mal mit Initialisierung versucht, die einzige Veränderung ist, dass die AV jetzt Read of Address FFFFFFF8 heißt. |
Ein Indiz dafür, das das auch gefehlt hat... Und zwar initialisierst Du 'CurrentSection' auf -1.. Wenn nun CurrentSection vorher nicht gesetzt wird, dann geht dieser Aufruf in die Pampa ('FFFFFF8') vorher war CurrentSection mangels Initialisierung bei 0 (schätze ich) und dann könnte das passen.
Delphi-Quelltext
1: 2: 3: 4:
| ... with Sections[CurrentSection] do begin SetLength(Values, ValuesLength+1); ... |
BenBE - Mi 18.07.07 19:53
Silas hat folgendes geschrieben: |
Hier mal der Komplette Constructor inkl. den zwei Funktionen, die er noch verwendet:
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: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72:
| constructor TFIniFile.Create(FileName: String); var Buf, Buf1, Buf2: String; begin AssignFile(IniFile, FileName); Reset(IniFile); SectionsLength := 0; while not EOF(IniFile) do begin readln(IniFile, Buf); Buf := Trim(Buf); if (Pos('[', Buf) <> -1 ) and (Buf[Length(Buf)-1] = ']') then begin SetLength(Sections, SectionsLength+1); inc(SectionsLength); Sections[SectionsLength-1].Deleted := false; Sections[SectionsLength-1].Name := Copy(Buf, 1, Length(Buf)-3); CurrentSection := SectionsLength-1; Sections[CurrentSection] := TINISection.Create(Self); ValuesLength := 0; end else begin if Pos('=', Buf) = -1 then continue; SplitAt(Buf, Buf1, Buf2, '='); Buf1 := Trim(Buf1); Buf2 := Trim(Buf2); with Sections[CurrentSection] do begin SetLength(Values, ValuesLength+1); inc(ValuesLength); Values[ValuesLength-1] := TINIValue.Create; Values[ValuesLength-1].Name := Buf1; Values[ValuesLength-1].Value := Buf2; Values[ValuesLength-1].Deleted := false; end; end; end; CurrentSection := -1; end;
procedure SplitAt(const Str: String; var Sub1, Sub2: String; const Chr: Char); var ChrPos: Integer; begin ChrPos := Pos(Chr, Str); if ChrPos = -1 then begin Sub1 := Str; Sub2 := ''; end else begin Sub1 := Copy(Str, 0, ChrPos-1); Sub2 := Copy(Str, ChrPos+1, Length(Str)-ChrPos); end; end;
procedure DeleteSpaces(var Str: String); var LStrPos, i: Cardinal; LastNSpc, FirstNSpc: Integer; begin if (Pos(' ', Str) = -1) or (Length(Str) = 0) then exit; LStrPos := Length(Str)-1; FirstNSpc := -1; for i := 0 to LStrPos do begin if Str[i] <> ' ' then begin FirstNSpc := i; break; end; end; LastNSpc := -1; for i := LStrPos downto 0 do if Str[i] <> ' ' then begin LastNSpc := i; break; end; Str := Copy(Str, FirstNSpc, LastNSpc-FirstNSpc+1); end; |
Zum leichteren verständnis: Create liest eine Zeile aus einer Ini-Datei entweder in einen Sektionen- oder einen Wertepuffer ein; SplitAt teilt einen String an einem Char (der dabei wegfällt) und DeleteSpaces löscht Leerzeichen, die am Anfang und am Ende eines Strings stehen. |
Hab mal ein wenig rumgebastelt ... im Kopf ... Sollte so funzen ... Ggf. die Aufrufe der Konstruktoren mal anpassen :P
alzaimar - Do 19.07.07 10:51
... und wenn der else-Teil zuerst angesprungen wird, passiert das Gleiche (weil 'CurrentSection' undefiniert ist).
BenBE - Do 19.07.07 12:45
So viel Denken trau ich ihm zu, dass er die dafür benötigte Denkleistung alleine aufbringt ...
Silas - Do 19.07.07 15:39
Danke Dir, BenBE! Funzt jetzt wunderbar. :)
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!