Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi Zugriffsverletzung? (https://www.delphipraxis.net/178240-zugriffsverletzung.html)

Wulli12 26. Dez 2013 00:11

Zugriffsverletzung?
 
Ich habe in meinem Programm eine function, welche mir einen gegebenen string sortieren soll.

z.B. : '7,3,11,5,1' --> '1,3,5,7,11'

Dazu gebe ich meiner function einen string in solch einer Form, also durch Kommas abgetrennte Zahlen. Daraufhin soll es die einzelnen Zahlen separieren und in einem Array aufteilen. Daraufhin durch meinen Such-Algorithmus die einzelnen Glieder jeweils vergleichen und in ein anderes Array in geordneter Reihenfolge kopieren. Und als Ausgabe diese einfach wieder durch Kommas getrennt als einzelnen string ausgeben.

Ich denke vom Verfahren her ist mein Code in Ordnung, jedoch bekomme ich immer den folgenden Error:

Zugriffsverletzung bei Adresse 00403EBC in Modul 'psort.exe'. Lesen von Adresse 00000004.

Hier noch einmal mein Delphi-Code:

Delphi-Quellcode:
unit msort;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    procedure Edit1Change(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

function sortString(input: string): string;
  var i, j, x: integer;
      output, rest: string;
      unsorted, sorted: array of string;
begin

  rest:= input;
  i:= 1;

  repeat

  if pos(',', rest) <> 0 then
  begin

    unsorted[i]:= copy(rest, i, pos(',', rest) - 1);
    rest:= copy(rest, pos(',', rest) + 1, length(rest));
    i:= i + 1;

  end;

  if pos(',', rest) = 0 then
  begin

    unsorted[i]:= copy(rest, 1, length(rest));
    rest:= '';

  end;

  until rest = '';

  for i:= 1 to length(unsorted) do
  begin

  x:= i;

  for j:= 1 to length(unsorted) do
  begin

      if (j <> i) and (unsorted[j] <> '') then
      begin

        if strtofloat(unsorted[x]) < strtofloat(unsorted[j]) then
        begin

          x:= j;

        end;

      end;

    end;

    sorted[i]:= unsorted[x];

  end;

  output:= sorted[1];

  for i:= 2 to length(sorted) do
  begin

  output:= output + ',' + sorted[i];

  end;

  result:= output;

end;

{$R *.dfm}

procedure TForm1.Edit1Change(Sender: TObject);
begin

  Edit2.Text:= sortString(Edit1.Text);

end;

end.
Ich hoffe mir kann jemand sagen, worin genau mein Fehler liegt, denn ich habe keine Ahnung was ich falsch gemacht haben könnte. Und schon einmal Danke im vorraus.
:lol:

Dalai 26. Dez 2013 00:23

AW: Zugriffsverletzung?
 
Du benutzt ein dynamisches Array of String, setzt aber nirgendwo dessen Größe. Entweder mit SetLength die Größe setzen oder ein statisches Array of String verwenden (das dann immer die angegebene Anzahl von Elementen hat).

Übrigens: Wenn du mit dem Debugger durchsteppst (F7 bzw. F8), wirst du sehen, wo der Fehler auftritt. Allerdings muss die dann markierte Zeile nicht die eigentliche Ursache sein.

MfG Dalai

Wulli12 26. Dez 2013 01:00

AW: Zugriffsverletzung?
 
Danke für deine schnelle Hilfe, ich habe nun probiert die Längen meiner Arrays nach einer anderen function zu setzen, welche mir die nötige Länge ermittelt, bekomme jedoch nun immer einen Error von einer ungültigen Zeigeroperation, aber was ist damit gemeint?

Habe meinen Code um folgendes erweitert:

Delphi-Quellcode:
function testLength(input: string): integer;
  var rest: string;
      counter: integer;
begin

  input:= rest;
  counter:= 0;

  repeat

  if pos(',', rest) <> 0 then
  begin

    rest:= copy(rest, pos(',', rest) + 1, length(rest));
    counter:= counter + 1;

  end;

  if pos(',', rest) = 0 then
  begin

    rest:= '';
    counter:= counter + 1;

  end;

  until rest = '';

  result:= counter;

end;
Delphi-Quellcode:
  setLength(unsorted, testLength(input));
  setLength(sorted, testLength(input));

Dalai 26. Dez 2013 01:07

AW: Zugriffsverletzung?
 
Nun, schrumpfen wir's mal auf das Wesentliche zusammen:
Delphi-Quellcode:
function testLength(input: string): integer;
  var rest: string;
      counter: integer;
begin

  input:= rest;
  counter:= 0;

  result:= counter;

end;
Fällt dir was auf?

MfG Dalai

nuclearping 26. Dez 2013 01:11

AW: Zugriffsverletzung?
 
Statt einem Array of String kannst du auch eine TStringList nehmen.

Setze doch auch mal einen Breakpoint in function sortString bei
Delphi-Quellcode:
rest:= input;
(in die Zeile gehen und F5 drücken).

Wenn du das Programm dann mit F9 startest, hält der Debugger an der Stelle an und du kannst mit F8 durch die Funktion steppen, bzw. mit F7 in eine Funktion reinsteppen. Wenn du mit der Maus dann über Variablen gehst, siehst du auch deren Werte bzw Inhalte.

Dadurch kannst du besser nachvollziehen, warum dein Code Probleme macht.

Wulli12 26. Dez 2013 01:20

AW: Zugriffsverletzung?
 
Tut mir Leid, ich bin damit noch nicht so vertraut:)

Aber was genau ist den nun die Ursache für die 'Ungültige Zeigeroperation', ich verstehe es einfach nicht, für mich ergibt das alles Sinn, leider.^^

Ich weiß nicht einmal was mit einer Zeigeroperation gemeint ist :(

Sir Rufo 26. Dez 2013 01:22

AW: Zugriffsverletzung?
 
Teile deinen Code auf, dann wird der übersichtlicher, leichter zum Umsetzen und kommt eigentlich ohne Dokumentation aus.
Delphi-Quellcode:
type
  TDynIntArray = array of integer;

function StrToIntArray( const AStr : string; const ADelimiter : Char ) : TDynIntArray;
begin

end;

procedure SortIntArray( var AArray : TDynIntArray );
begin

end;

function IntArrayToStr( const AArray : TDynIntArray; const ADelimiter : Char ) : string;
begin

end;

function SortIntArrayStr( const AStr : string ) : string;
var
  LIntArray : TDynIntArray;
begin
  LIntArray := StrToIntArray( AValue, ',' );
  SortIntArray( LIntArray );
  Result := IntArrayToStr( LIntArray, ',' );
end;

himitsu 26. Dez 2013 02:07

AW: Zugriffsverletzung?
 
Und für die Zukunft schalldest du in den Projektoptionen die Bereichsprüfung an
und lernst wie man den Debugger verwendet.

Perlsau 26. Dez 2013 05:09

AW: Zugriffsverletzung?
 
Zitat:

Zitat von Wulli12 (Beitrag 1241044)
Ich habe in meinem Programm eine function, welche mir einen gegebenen string sortieren soll.

z.B. : '7,3,11,5,1' --> '1,3,5,7,11'

Dazu gebe ich meiner function einen string in solch einer Form, also durch Kommas abgetrennte Zahlen. Daraufhin soll es die einzelnen Zahlen separieren und in einem Array aufteilen. Daraufhin durch meinen Such-Algorithmus die einzelnen Glieder jeweils vergleichen und in ein anderes Array in geordneter Reihenfolge kopieren. Und als Ausgabe diese einfach wieder durch Kommas getrennt als einzelnen string ausgeben.

Die einfachste Möglichkeit, diese Aufgabe zu lösen, bestünde wohl darin, eine TStringList zu verwenden, mittels DelimitedText einlesen, den Delimiter auf Komma stellen und StrictDelimiter auf True. Danach setzt du das Sort-Property auf True und gibst als Result den DelimitedText aus:
Delphi-Quellcode:
Function SortiereZahlen(Eingabe : String) : String;
Var
  MyList : TSTringList;
Begin
  Result := '';                    // setzt Result auf Leerstring; Fehler kannst dann daran erkennen
  MyList := TStringList.Create;    // erzeugen einer Stringliste
  MyList.Delimiter := ',';         // Trennzeichen = Komma
  MyList.StrictDelimiter := True;  // sorgt dafür, daß nur das Komma als Trennzeichen verwendet wird

  Try
    MyList.DelimitedText := Eingabe; // hier wird dein String automatisch in einzelne Items zerlegt
    MyList.Sorted := True;          // schaltet die Sortierung der Stringliste ein
    Result := MyList.DelimitedText; // weist der Rückgabe-Variablen den sortierten String zu
  Finally
    MyList.Free;
  End;
End;

Sir Rufo 26. Dez 2013 07:54

AW: Zugriffsverletzung?
 
@Perlsau

Das Ergebnis ist dann aber
Delphi-Quellcode:
'1,11,3,5,7'
statt
Delphi-Quellcode:
'1,3,5,7,11'
;)

Perlsau 26. Dez 2013 08:14

AW: Zugriffsverletzung?
 
Da hast du auch wieder recht :oops:
Man kann das aber umgehen, indem man einfach alle Strings vor dem Setzen des Sorted-Properties mit der entsprechenden Anzahl von '0' ergänzt :stupid:
Delphi-Quellcode:
Function FillString(Quelle : String; Zeichen : Char; Anzahl : Integer; Anfang : Boolean) : String;
Var
  Fuellung : String;

begin
  Result := '';
  IF Quelle = '' THEN Exit;
  Anzahl := Anzahl - Length(Quelle);
  IF Anzahl < 1 THEN Exit;

  Fuellung := '' + Zeichen;
  Fuellung := StrUtils.DupeString(Fuellung,Anzahl);
  IF Anfang THEN
     Result := Fuellung + Quelle ELSE
     Result := Quelle + Fuellung;
end;

Function SortiereZahlen(Eingabe : String) : String;
Var
  MyList : TSTringList;
  i : Integer;

Begin
  Result := '';
  MyList := TStringList.Create;
  MyList.Delimiter := ',';
  MyList.StrictDelimiter := True;

  Try
    MyList.DelimitedText := Eingabe;

    For i := 0 to MyList.Count -1 DO MyList[i] := FillString(MyList,'0',10,True);

    MyList.Sorted := True;
    Result := MyList.DelimitedText;
  Finally
    MyList.Free;
  End;
Benötigt man die im Rückgabe-String enthaltenen Zahlen danach als Integer-Werte, kann man ohne Probleme die mit voranstehenden Nullen ergänzten Strings zum Umwandeln in Integer verwenden, andernfalls müßte man die Nullen wieder entfernen.

Sir Rufo 26. Dez 2013 09:36

AW: Zugriffsverletzung?
 
Ich hätte da eher an so etwas gedacht
Delphi-Quellcode:
program dp_178240;

{$APPTYPE CONSOLE}
{$R *.res}
{.$DEFINE USE_TYPES}

uses
{$IFDEF USE_TYPES}
  Types, // Gibt es ab Delphi XE ???
{$ENDIF}
  Classes,
  SysUtils;

{$IFNDEF USE_TYPES}

type
  TIntegerDynArray = array of Integer;
{$ENDIF}

function StrToIntArray( const AStr : string; const ADelimiter : Char ) : TIntegerDynArray;
  var
    LStrings : TStrings;
    LIdx    : Integer;
  begin
    LStrings := TStringList.Create;
    try
      LStrings.Delimiter    := ADelimiter;
      LStrings.DelimitedText := AStr;
      SetLength( Result, LStrings.Count );

      for LIdx := 0 to LStrings.Count - 1 do
        begin
          Result[LIdx] := StrToInt( LStrings[LIdx] );
        end;
    finally
      LStrings.Free;
    end;
  end;

function IntArrayToStr( const AIntArray : TIntegerDynArray; const ADelimiter : Char ) : string;
  var
    LStrings : TStrings;
    LIdx    : Integer;
  begin
    LStrings := TStringList.Create;
    try
      LStrings.Delimiter := ADelimiter;

      for LIdx := low( AIntArray ) to high( AIntArray ) do
        begin
          LStrings.Add( IntToStr( AIntArray[LIdx] ) );
        end;

      Result := LStrings.DelimitedText;
    finally
      LStrings.Free;
    end;
  end;

procedure SortIntArray( var AIntArray : TIntegerDynArray );
  var
    LCurrent : Integer;
    LCompare : Integer;
    LTemp   : Integer;
  begin
    // Simple Bubble-Sort algo
    for LCurrent := low( AIntArray ) to high( AIntArray ) - 1 do
      begin
        for LCompare := LCurrent + 1 to high( AIntArray ) do
          begin
            if AIntArray[LCurrent] > AIntArray[LCompare]
            then
              begin
                LTemp              := AIntArray[LCurrent];
                AIntArray[LCurrent] := AIntArray[LCompare];
                AIntArray[LCompare] := LTemp;
              end;
          end;
      end;
  end;

function SortIntArrayStr( const AStr : string; const ADelimiter : Char = ',' ) : string;
  var
    LIntArray : TIntegerDynArray;
  begin
    LIntArray := StrToIntArray( AStr, ADelimiter );
    SortIntArray( LIntArray );
    Result := IntArrayToStr( LIntArray, ADelimiter );
  end;

procedure Test;
  var
    LTest : string;
  begin
    LTest := '7,3,11,5,1';
    Writeln( LTest, ' => ', SortIntArrayStr( LTest ) );
  end;

begin
  try
    Test;
  except
    on E : Exception do
      Writeln( E.ClassName, ': ', E.Message );
  end;

  ReadLn;

end.
Jede Funktion/Prozedur erledigt genau eine Aufgabe. Dadurch bleiben diese übersichtlich, wiederverwend-, test- und wartbar.

Sir Rufo 26. Dez 2013 09:53

AW: Zugriffsverletzung?
 
Zitat:

Zitat von Perlsau (Beitrag 1241062)
Da hast du auch wieder recht :oops:
Man kann das aber umgehen, indem man einfach alle Strings vor dem Setzen des Sorted-Properties mit der entsprechenden Anzahl von '0' ergänzt :stupid:

Das geht doch aber auch erheblich einfacher (mit TStringList) auch ohne durch die Brust ins Auge und zurück ;)
Delphi-Quellcode:
// Nur mit TStringList

function StringListIntSort( List : TStringList; Index1, Index2 : Integer ) : Integer;
  begin
    Result := StrToInt( List[Index1] ) - StrToInt( List[Index2] );
  end;

function SortIntArrayStr( const AStr : string; const ADelimiter : Char = ',' ) : string;
  var
    LStrings : TStringList;
  begin
    LStrings := TStringList.Create;
    try
      LStrings.Delimiter    := ADelimiter;
      LStrings.DelimitedText := AStr;

      LStrings.CustomSort( StringListIntSort );

      Result := LStrings.DelimitedText;
    finally
      LStrings.Free;
    end;
  end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:27 Uhr.

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