Autor Beitrag
Georg08
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 155
Erhaltene Danke: 6

Win XP
Delphi 7.0 Personal
BeitragVerfasst: Di 30.11.10 20:25 
Hallo Community,

ich habe ein Programm geschreiben, dass ein dynamisches Array besitzt, und in dises Array auch gut schreiben kann. Auch das Auslesen funktioniert reibungslos, aber wenn ich versuche ein Element zu löschen bekomme ich ein paar probleme :D

Ich habe gegoogelt und hier einen Artikel gefunden. Diesen habe ich dann auf mein Programm angewandt. Aber mein Problem ist, dass wenn ich bestimmte Elemente lösche irgenwas nicht mehr stimmt.

Die ersten paar Einträge (Einträge "weit vorne" wie Array[2]) kann ich ohne Probleme löschen, aber wenn ich versuche z.B. den vorletzen Eintrag zu löschen werden mir in meinem StringGrid (in das ich die Werte zuzeit noch auslese) beim "neuen" letzen Eintrag seltsame Zeichen angezeigt. Den letzen Eintrag jedoch kann ich wieder problemlos löschen...

Das Array ist als eine von mir ein angelegte Klasse definiert.

ausblenden 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:
// Array und Typ für Array
[...]
type
  TBenutzer = record // bin gerade nicht am Rechner auf dem das org. Prg ist, aber das ist das selbe
    Name: String;    // Sinngemäß "übersetzt"
    Nachname: String;
end;
[...]
type
  TKartei = class
    private
      Benutzer: Array of TBenutzer
    public
      USerCount: Integer;  // Anzahl der Karten
      [...]
      procedure Delete(Index: Integer);
[...]
procedure TKartei.Delete(Index: Integer);
begin
  if Index < UserCount then begin
    Move(Benutzer[Index+1], Benutzer[Index], (Length(Benutzer)-Index-1));
    // Dahinterliegende Daten aufrücken
    SetLength(Benutzer, Length(Benutzer)-1); // Länge kürzen
    dec(UserCount);
  end
  else
    raise Exception.CreateFmt('Fehler! Eingabe ''%d'' überschreitet Maximum ''%d''', [KartenIndex, KartenCount]);
end;


Original vom Link oben:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
procedure DeleteArrayElement(var AArray: TIntArray; const AIndex: Integer);
var
  i: Integer;
begin
  Move(AArray[AIndex + 1], AArray[AIndex], SizeOf(AArray[0]) * (Length(AArray) - AIndex - 1)); //Dahinterliegende Daten aufrücken
  SetLength(AArray, Length(AArray) - 1); // Länge kürzen
end;
Jakob_Ullmann
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1747
Erhaltene Danke: 15

Win 7, *Ubuntu GNU/Linux*
*Anjuta* (C, C++, Python), Geany (Vala), Lazarus (Pascal), Eclipse (Java)
BeitragVerfasst: Di 30.11.10 20:34 
Vielleicht hilft es, Name als string[...] mit festgelegter Zeichenanzahl zu deklarieren?

Zumindest muss da am Ende irgendwas sein, was noch mit eingelesen wird, aber kein String ist (könnte ich mir vorstellen, vor allem mit Lazarus hatte ich in letzter Zeit solche Probleme).

EDIT: Jedenfalls glaube ich nicht, dass Move etwas anderes als memmove() macht (auch, wenn ich es noch nie verwendet habe). Vor allem, wenn man die Deklaration anschaut:

ausblenden Quelltext
1:
void *memmove(void *dest, const void *src, size_t n);					


Zuletzt bearbeitet von Jakob_Ullmann am Di 30.11.10 20:41, insgesamt 2-mal bearbeitet
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Di 30.11.10 20:38 
Gibt es einen Grund, dass du keine Liste benutzt? :gruebel:

Ab Delphi 2009 kannst du mit Generics sogar direkt eine Liste mit dem konkreten Typ erstellen.

Am einfachsten geht das natürlich, wenn du statt des Records eine Klasse benutzt. Dann musst du nicht umständlich selbst mit Pointern spielen, sondern hast direkt welche. Das gilt auch für deine jetzige Situation.

Was durch das Move vermutlich passiert ist, dass die Referenzzählung der Strings durcheinanderkommt. Und dadurch werden die Strings evtl. schon zu früh freigegeben oder sowas. Was genau passiert, müsste ich mir anschauen, aber es gibt wie gesagt deutlich einfachere Lösungen.
Georg08 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 155
Erhaltene Danke: 6

Win XP
Delphi 7.0 Personal
BeitragVerfasst: Di 30.11.10 20:43 
Ich habe leider nur Delphi7 PE...

Das mit den Listen naja...
Ich persönlich mag Listen nicht so, besonders wenn man mehrere Werte speichern muss, wie in meinem Beispiel "Name" und "Nachname"
oder wie meinst du das jetzt?
Horst_H
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1654
Erhaltene Danke: 244

WIN10,PuppyLinux
FreePascal,Lazarus
BeitragVerfasst: Di 30.11.10 20:49 
Hallo,

fehlt der Groessenberechnung nicht etwas?
ausblenden Delphi-Quelltext
1:
Move(Benutzer[Index+1], Benutzer[Index], SIZEOF[Benutzer)*(Length(Benutzer)-Index-1));					

Natuerlich muesste man selbst vorher die Strings löschen

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
procedure TKartei.Delete(Index: Integer);
begin
  if Index < UserCount then 
    begin
    With Benutzer[Index] do
      Name := '';
      Nachname := '';
      end;
    //bei Loeschung des letzen nicht schieben
    IF (Index+1)< UserCount then
       // Dahinterliegende Daten aufrücken
       Move(Benutzer[Index+1], Benutzer[Index], SIZEOF[TBenutzer) *(Length(Benutzer)-Index-1));
    SetLength(Benutzer, Length(Benutzer)-1); // Länge kürzen
    dec(UserCount);
    end
  else
    raise Exception.CreateFmt('Fehler! Eingabe ''%d'' überschreitet Maximum ''%d''', [KartenIndex, KartenCount]);
end;



Gruß Horst
bummi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1248
Erhaltene Danke: 187

XP - Server 2008R2
D2 - Delphi XE
BeitragVerfasst: Di 30.11.10 20:55 
Ich würde von dem fehlerträchtigen UserCount absehen und statt dessen
High(Benutzer) + 1 nehmen und beim Löschen das Array redimensionieren, beim Einfügen tust Du dies ja (wahrscheinlich) eh schon.

_________________
Das Problem liegt üblicherweise zwischen den Ohren H₂♂
DRY DRY KISS
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Di 30.11.10 21:37 
user profile iconGeorg08 hat folgendes geschrieben Zum zitierten Posting springen:
Ich persönlich mag Listen nicht so, besonders wenn man mehrere Werte speichern muss, wie in meinem Beispiel "Name" und "Nachname"
Genau dafür ist es doch ideal. :gruebel:

Beispiel:
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:
51:
52:
53:
54:
55:
56:
57:
58:
59:
type
  TUserInfo = class
  private
    FFirstName: string;
    FLastName: string;
  public
    property FirstName: string read FFirstName write FFirstName;
    property LastName: string read FLastName write FLastName;
  end;

  TForm272 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    FUserList: TObjectList;
  public
  end;

var
  Form272: TForm272;

implementation

{$R *.dfm}

procedure TForm272.Button1Click(Sender: TObject);
var
  NewUser: TUserInfo;
begin
  // zwei neue Benutzer hinzufügen
  NewUser := TUserInfo.Create;
  NewUser.FirstName := 'Thomas';
  NewUser.LastName := 'Mustermann';
  FUserList.Add(NewUser);

  NewUser := TUserInfo.Create;
  NewUser.FirstName := 'Miriam';
  NewUser.LastName := 'Musterfrau';
  FUserList.Add(NewUser);

  // ersten Benutzer löschen
  FUserList.Delete(0);

  // jetzt ersten Benutzer auslesen
  ShowMessage(TUserInfo(FUserList[0]).FirstName + ' '
    + TUserInfo(FUserList[0]).LastName);
end;

procedure TForm272.FormCreate(Sender: TObject);
begin
  FUserList := TObjectList.Create(True);
end;

procedure TForm272.FormDestroy(Sender: TObject);
begin
  FUserList.Free;
end;
Georg08 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 155
Erhaltene Danke: 6

Win XP
Delphi 7.0 Personal
BeitragVerfasst: Di 30.11.10 21:45 
Danke
ich denke ich wers jetzt so machen wie jaenicke beschrieben hat. (Danke jaenicke)

Hat übrigens jetzt geklappt, wenn ich beim record dem String eine feste länge gegeben habe... (Danke Jakob_Ullmann)