Autor Beitrag
Master_of_Magic
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 56

Win 98, Win XP
D6 Pers, D2005 Arch
BeitragVerfasst: Mo 17.04.06 15:31 
Ich bin gerade dabei mir eine kleine Datenbankanwendung zu basteln ('Datenbank' ist etwas übertrieben :wink: ). Die Datensätze bestehen dabei aus dem Record:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
type
  TUser = record
    id:word;
    name:string;
    gala:byte;
    mail:string;
    pdate:word;
    paccount:byte;
    pamount:word;
    state:byte;
    hddsn:cardinal;
    winsn:cardinal;
    lansn:cardinal;
    cpusn:cardinal;
    comment:string;
  end;

var
  user: array of TUser;


Die Daten werden in den Stringgrid db dargestellt. Um einen Datensatz zu löschen hab ich mir folgende Prozedur gebastelt (Teile im Forum gefunden):

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
procedure TForm1.deleteClick(Sender: TObject);
var index,i:integer;
begin
  index:=db.Selection.Top-1;

  Finalize(user[index]);
  Move(user[index + 1], user[index], SizeOf(TUser) * (High(user) - index));
  FillChar(user[High(user)], SizeOf(TUser), 0);
  SetLength(user, High(user));

  db.Row := index+1;
  if (db.Row = db.RowCount -1then
    db.RowCount := db.RowCount - 1
  else
    begin
      for i := index+1 to db.RowCount-1 do db.Rows[i] := db.Rows[i+1];
      db.RowCount := db.RowCount - 1;
    end;

  displayrecord(index);
end;


Das funktioniert soweit - trotzdem bleiben stellen sich mir 3 Fragen:
1. Welche Bedeutung hat Finalize in diesem Zusammenhang?
2. Warum kann ich die Daten einfach mit move verschieben, obwohl der Record dynamische(!) Strings enthält?
3. Weshalb liefert SizeOf(TUser) immer den Wert 44 und wie setzt sich dieser zusammen?

Nun zu meinem eigentlichen Problem.
Zum Einfügen eines neuen Datensatzes verwende ich folgende Prozedur:

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:
procedure TForm1.insertClick(Sender: TObject);
var index,i:integer;
begin
  index:=db.Selection.Top-1;

  SetLength(user, Length(user)+1);
  Move(user[index], user[index+1], SizeOf(TUser) * (High(user) - index));

  with user[index] do
  begin
    if index=0 then id:=1
    else id:=user[index-1].id;
    name:='';
    gala:=0;
    mail:='';
    pdate:=38353;
    pamount:=0;
    paccount:=0;
    state:=5;
    hddsn:=0;
    winsn:=0;
    lansn:=0;
    cpusn:=0;
    comment:='';
  end;

  displaydbentry(index+1,index);
  displayrecord(index);

  db.RowCount:=db.RowCount+1;
  for i := db.RowCount-2 downto index+1 do
    db.Rows[i+1] := db.Rows[i];
end;


Da scheint jetzt irgendein Fehler (ich tipp im move-Teil) zu sein, da nachfolgende Datensätze (bzw. deren Strings) zerhackstückt werden. Außerdem erhalte ich beim Speichern des user-Arrays eine Zugriffsverletzung ...

Weiß einer, woran das liegt?
Master_of_Magic Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 56

Win 98, Win XP
D6 Pers, D2005 Arch
BeitragVerfasst: Sa 22.04.06 15:57 
hmm, da anscheinend niemand eine Antwort auf meine Frage(n) weiß, will ich sie mal umformulieren:

Kann mir einer sagen, wie ich Record-Elemente in ein (dyn.) Array einfügen bzw. zwei Records vertauschen kann?

Der obige Code ist nur mein bisheriges Ergebnis - der muss also nicht beibehalten werden ... :wink:
alias5000
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 2145

WinXP Prof SP2, Ubuntu 9.04
C/C++(Code::Blocks, VS.NET),A51(Keil),Object Pascal(D2005PE, Turbo Delphi Explorer) C# (VS 2008 Express)
BeitragVerfasst: Sa 22.04.06 16:14 
Vertauschen (allgemein formuliert):
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
Procedure Exchange(index1, index2: integer);
var Rec: TMyRecord;
begin
Rec := RecArray[index1];
RecArray[index1] := RecArray[index2];
RecArray[index2] := Rec;
end;


Hilft das weiter?

_________________
Programmers never die, they just GOSUB without RETURN
Master_of_Magic Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 56

Win 98, Win XP
D6 Pers, D2005 Arch
BeitragVerfasst: So 23.04.06 14:52 
Ok, auf das Vertauschen hätt ich auch selber kommen können - ist ja quasi BubbleSort ...

Aber kann ich einfach so zwei Datensätze vertauschen? Weil die haben ja durch den String eine verschiedene Größe, oder?
Horst_H
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1654
Erhaltene Danke: 244

WIN10,PuppyLinux
FreePascal,Lazarus
BeitragVerfasst: So 23.04.06 15:14 
Hallo,

der String ist ja ein Zeiger auf eine String-Struktur, deshalb klappt es.
Die Strings selber stehen also nicht im record sondern woanders.
Diese werden also nie verschoben, wenn Du dein array user vergroesserst oder verkleinerst.

Beim nach oben schieben muesste:
Move(Von,Nach,Anzahl)
ausblenden Delphi-Quelltext
1:
Move(user[index + 1], user[index], SizeOf(TUser) * (High(user) - index));					

wohl
ausblenden Delphi-Quelltext
1:
Move(user[index], user[index+1], SizeOf(TUser) * (High(user) - index));					

sein.
Aber bei Dir haette trotzdem kein Muell auftreten duerfen, sondern der letzt Datensatz waer doppelt vorhanden und der an der Position Index einfach ueberschrieben.

Gruss Horst
Master_of_Magic Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 56

Win 98, Win XP
D6 Pers, D2005 Arch
BeitragVerfasst: Mo 24.04.06 18:34 
@Horst_H
Das heißt also, ich kann meine Records beliebig verschieben und vertauschen, da die Daten selbst nicht verändert werden, oder? Das macht die Sach einfacher ... *freu*

Deine Code-Schnipsel blick ich nicht ganz: was meinst du mit 'nach oben schieben'? Meine zwei Code-Teile oben sind nur zum löschen und einfügen eines Records:
Beim Löschen werden die user[index+1] nach user[index] verschoben und beim einfügen andersrum - von daher stimmt das doch.

Was mein Problem angeht: Ich habe herausgefunden, dass das Array passt, jedoch nur die Anzeige Müll liefert. Liegt von an den letzten Zeilen der Procedure, die falsch herum waren. Meine Procedure sieht nun so aus:

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.insertClick(Sender: TObject);
var index,i:integer;
begin
  index:=db.Selection.Top-1;

  SetLength(user, Length(user)+1);
  {For i:=High(user)-1 downto index do
  begin
  user[i+1]:=user[i];
  end;}


  Move(user[index], user[index+1], SizeOf(TUser) * (High(user) - index));

  with user[index] do
  begin
    if index=0 then id:=1
    else id:=user[index-1].id;
    name:='Name';
    gala:=0;
    mail:='Mail';
    pdate:=38353;
    pamount:=0;
    paccount:=0;
    state:=5;
    hddsn:=0;
    winsn:=0;
    lansn:=0;
    cpusn:=0;
    comment:='';
  end;

  db.RowCount:=db.RowCount+1;
  for i := db.RowCount-2 downto index+1 do
    db.Rows[i+1] := db.Rows[i];

  displaydbentry(index+1,index);  //die beiden Aufrufe waren anfangs vor der Schleife...
  displayrecord(index);

end;


Nun passt die Anzeige und das Einfügen klappt auch - meistens. Manchmal (v.a. beim Beenden) erhalte ich jedoch eine 'Invalid Pointer Operation', eine 'AccessViolation' oder in seltenen Fällen sogar eine Zugriffsverletzung auf die Kernel.dll ... :shock:

Verwende ich jedoch eine For Schleife (die die im Code oben auskommentiert ist) klappt alles wunderbar ohne Fehler.

Im Prinzip ist mein Problem damit gelöst, jedoch wurde ich doch gerne die Ursache der move-Fehler wissen ... kann mir da einer helfen?
Horst_H
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1654
Erhaltene Danke: 244

WIN10,PuppyLinux
FreePascal,Lazarus
BeitragVerfasst: Mo 24.04.06 19:29 
Hallo,
Du bewegst ein record zu wenig (auch beim Loeschen) also,
ausblenden Delphi-Quelltext
1:
Move(user[index], user[index+1], SizeOf(TUser) * (High(user) - index +1));					

denn 1..10 nach 2..11 verschieben sind 10 Elemente aber 10-1=9.
Deshalb hat deine Variable Comment (=string= Zeiger auf eine Delphi-StringStruktur) eine Zuordnung in die unendlichen Weiten des Hauptspeichers(, in die noch nie ein Bit vorgedrungen ist, oder total verbotene Bereiche access violation).
Dies kann also zu Mist fuehren.

Gruss Horst
Master_of_Magic Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 56

Win 98, Win XP
D6 Pers, D2005 Arch
BeitragVerfasst: Di 25.04.06 18:58 
Nein, das hast du was vergessen:
Bevor ich move anwende, wird ja das Array bereits um 1 vergrößert (beim
Einfügen)! High(user) liefert also bereits 11 zurück (um bei deinem Beispiel zu bleiben). Somit passt das wieder (11-1=10 Elemente zu verschieben).

Dein Quellcode liefert daher eine Zugriffsverletzung (bzw. eine 'Debugger Fault Notification '...)