Autor Beitrag
Danillson
Hält's aus hier
Beiträge: 3



BeitragVerfasst: Mi 14.09.11 21:13 
Hallo Zusammen,
ich frage mich gerade, wie ich eine verkettete Liste speichere und dann wieder öffnen kann. Am Freitag schreibe ich eine Arbeit über Pointer. Einfügen am Anfang, in der Mitte und am Ende kann ich. Auch das Löschen an bestimmten Stelle funktioniert. Wie ich allerdings speichere und öffne (mit Open- und Savedialog) ist mir ein Rätstel.
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:
procedure TForm1.Speichern1Click(Sender: TObject);
begin
savedialog1.Execute;
assignfile(vocdb, savedialog1.FileName);
rewrite(vocdb);
zhilf:=zkopf;
while zhilf<>nil do begin
write (vocdb, zhilf);
zhilf:=zhilf^.next;
end;
end;

procedure TForm1.ffnen1Click(Sender: TObject);
begin
opendialog1.Execute;
assignfile(vocdb, opendialog1.FileName);
if fileexists (opendialog1.FileName)
then begin
      reset(vocdb);
while zkopf<>nil do begin
read (vocdb, zhilf);
zkopf:=zhilf;
end
end
else showmessage('Noch keine Datei vorhanden');

Das ist der Quelltext. Dass das Öffnen völlig falsch ist, ist mir klar. Ich würde mich über Lösungsvorschläge freuen...

Moderiert von user profile iconNarses: I- durch Delphi-Tags ersetzt
bole
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 107
Erhaltene Danke: 15

win 10

BeitragVerfasst: Mi 14.09.11 21:25 
Hallo im Forum :welcome:

Die Pointer musst Du nicht speichern. In das File werden nur die Daten geschrieben.

Beim Lesen musst Du die Liste neu aufbauen. (Datenstatz lesen, einfügen, nächsten Datensatz lesen...)

Gruss

Bole

_________________
ein programm macht nicht das was du willst sondern was du schreibst!
Danillson Threadstarter
Hält's aus hier
Beiträge: 3



BeitragVerfasst: Mi 14.09.11 21:32 
Wie genau stelle ich das an? Könnte mir einer ein Beispiel in Form eines Quelltextes schicken?
Die Deklaration sieht übrigens so aus:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
type
  tzeiger=^tknoten;
  tknoten=record
            de:string[15];
            en:string[15];
            next:tzeiger;
          end;


Moderiert von user profile iconNarses: Delphi-Tags hinzugefügt
Mitmischer 1703
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 754
Erhaltene Danke: 19

Win 7, Debian
Delphi Prism, Delphi 7, RAD Studio 2009 Academic, C#, C++, Java, HTML, PHP
BeitragVerfasst: Mi 14.09.11 21:37 
Hi!

Ich hab grad wenig Zeit aber du musst (ich denke, du hast ein Array von tzeigern) über dieses iterieren, den Pointer dereferenzieren und in ein file of tknoten schreiben (das ist am einfachsten), einfach writeln(f, knoten). Beim Lesen dasselbe, nur dass du hier in eine Variable liest:
ausblenden Delphi-Quelltext
1:
2:
var knoten : tknoten;
Readln(knoten);


Hoffe, das hat erstmal geholfen, wenn nicht schreib ich es dir morgen nochmal genauer.

_________________
Die Lösung ist nicht siebzehn.
Danillson Threadstarter
Hält's aus hier
Beiträge: 3



BeitragVerfasst: Mi 14.09.11 21:45 
Moderiert von user profile iconNarses: Komplett-Zitat des letzten Beitrags entfernt.

Nope, ich habe kein Array von TZeiger. Ich dachte man kann mit einem Hilfszeiger sich entlang hangeln und das dann in die Datei schreiben.
Wir haben Pointer bisher nur theoretisch besprochen und noch nichts dazu programmiert. Das ist auch der Grund, warum ich nicht weiß, wie ich in diesem Fall arbeiten muss.
Das ist der ganze Quelltext:
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:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
type
  tzeiger=^tknoten;
  tknoten=record
            de:string[15];
            en:string[15];
            next:tzeiger;
          end;

var
  Form1: TForm1;
  zkopf, zneu, zaktuell,zhilf:tzeiger;
  vocdb: file of tzeiger;

implementation

{$R *.dfm}


procedure TForm1.Button1Click(Sender: TObject);
begin
new(zneu);
zneu^.de:=edit1.Text;
zneu^.en:=edit2.Text;
zneu^.next:=nil;

if zkopf=nil then zkopf:=zneu
              else begin
                    zaktuell:=zkopf;
                    while zaktuell^.next<>nil do zaktuell:=zaktuell^.next;
                    zaktuell^.next:=zneu;
                   end;
edit1.Text:='';
edit2.Text:='';
end;



procedure TForm1.FormCreate(Sender: TObject);
begin
zkopf:=nil;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
//if zkopf=nil then showmessage('Liste ist leer')
//             else
                zaktuell:=zkopf;
                while zaktuell<>nil do
                                    begin
                                      listbox1.Items.add(zaktuell^.de +' = '+ zaktuell^.en);
                                      zaktuell:=zaktuell^.next;
                                    end;
end;

procedure TForm1.Speichern1Click(Sender: TObject);
begin
savedialog1.Execute;
assignfile(datei, savedialog1.FileName);
rewrite(datei);
if zkopf=nil then showmessage('Noch keine Vokabeln vorhanden!')
else
zhilf:=zkopf;
while zhilf <> nil do
begin
write(datei,zhilf^.inhalt);
zhilf:=zhilf^.next;
end;
closefile(datei);
end;


end;

procedure TForm1.ffnen1Click(Sender: TObject);
begin
opendialog1.Execute;
assignfile(vocdb, opendialog1.FileName);
if fileexists (opendialog1.FileName)
then begin
      reset(vocdb);
while zkopf<>nil do begin
read (vocdb, zhilf);
zkopf:=zhilf;
end
end
else showmessage('noch keine Datei vorhanden');

end;

end.

Moderiert von user profile iconNarses: Quote- durch Delphi-Tags ersetzt
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Do 15.09.11 00:26 
Moin und :welcome: in der Entwickler-Ecke!

user profile iconDanillson hat folgendes geschrieben Zum zitierten Posting springen:
Wir haben Pointer bisher nur theoretisch besprochen und noch nichts dazu programmiert. Das ist auch der Grund, warum ich nicht weiß, wie ich in diesem Fall arbeiten muss.
user profile iconDanillson hat folgendes geschrieben Zum zitierten Posting springen:
Am Freitag schreibe ich eine Arbeit über Pointer.
Sollte dein Lehrer tatsächlich etwas in einer Klausur abfragen, was er nachweislich vorher nicht erklärt hat, dann hätte er sich eine ziemlich tiefe Grube gegraben, in die er beabsichtigt zu fallen - was ich mal so pauschal nicht glaube. :nixweiss: Warum auch immer du also diese Begründung verwendet, Sinn macht sie nicht. :suspect: Wenn du einfach nur den Quelltext absaugen willst, weil du gepennt hast, sag´s doch gleich, kommt eh irgendwann raus... :mrgreen:

user profile iconbole hat folgendes geschrieben Zum zitierten Posting springen:
Die Pointer musst Du nicht speichern. In das File werden nur die Daten geschrieben.

Beim Lesen musst Du die Liste neu aufbauen. (Datenstatz lesen, einfügen, nächsten Datensatz lesen...)
Das ist der entscheidende Tipp! :idea:

user profile iconMitmischer 1703 hat folgendes geschrieben Zum zitierten Posting springen:
in ein file of tknoten schreiben (das ist am einfachsten), einfach writeln(f, knoten). Beim Lesen dasselbe, nur dass du hier in eine Variable liest:
ausblenden Delphi-Quelltext
1:
2:
var knoten : tknoten;
Readln(knoten);
Das ist leider nicht richtig, denn in dem Record ist ja auch der Pointer enthalten - der hat aber in der Datei nix zu suchen (ist eh unbrauchbar). ;)

Ich schlage mal vor, einfach eine Textdatei als Kontainer zu verwenden, jeweils zwei Zeilen ergeben einen Datensatz, zuerst kommt der deutsche Text. :idea: Und weil ich eh grad noch auf was warten muss, hier mal dein Quelltext etwas überarbeitet: ;)
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:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
type
  TZeiger = ^TKnoten;
  TKnoten = record
              de: String;
              en: String;
              next: TZeiger;
            end;

  TForm1 = class(TForm)
    btnAdd: TButton;
    Edit1: TEdit;
    Edit2: TEdit;
    ListBox1: TListBox;
    btnList: TButton;
    btnClear: TButton;
    OpenDialog1: TOpenDialog;
    SaveDialog1: TSaveDialog;
    btnSave: TButton;
    btnLoad: TButton;
    procedure btnAddClick(Sender: TObject);
    procedure btnListClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure btnClearClick(Sender: TObject);
    procedure btnSaveClick(Sender: TObject);
    procedure btnLoadClick(Sender: TObject);
  public
    zKopf: TZeiger; // Variablen dieses Formulars gehören auch hier hin
  end;

var
  Form1: TForm1;

implementation

// Neuen Eintrag anlegen
procedure TForm1.btnAddClick(Sender: TObject);
  var
    zNeu, zAktuell: TZeiger; // diese Variablen brauchen wir nur hier
begin
  New(zNeu); // Speicher anfordern
  zNeu^.de := Edit1.Text; // deutscher Text
  zNeu^.en := Edit2.Text; // englischer Text
  zNeu^.next := nil// kein Nachfolger
  if zKopf = nil then // Liste leer?
    zKopf := zNeu // dann ist das aktuelle das erste Element
  else begin // Liste ist nicht leer, letztes Element suchen
    zAktuell := zKopf; // dazu "Vorne" anfangen
    while zAktuell^.next <> nil do // hat Element einen Nachfolger?
      zAktuell := zAktuell^.next; // dann im nächsten Schritt diesen untersuchen
    zAktuell^.next := zNeu; // das aktuelle Element ist das letzte, neues anhängen
  end;
  Edit1.Clear; // Eingabefelder löschen
  Edit2.Clear;
end;

// Liste in ListBox ausgeben
procedure TForm1.btnListClick(Sender: TObject);
  var
    zAktuell: TZeiger;
begin
  ListBox1.Clear; // ListBox leeren
  zAktuell := zKopf; // "Vorne" anfangen
  while zAktuell <> nil do begin // ist das aktuelle gültig?
    ListBox1.Items.Add(zAktuell^.de + ' = ' + zAktuell^.en); // dann ausgeben
    zAktuell := zAktuell^.next; // und im nächsten Schritt den Nachfolger untersuchen
  end;
end;

// Liste rekursiv löschen - was hier passiert, ist deine Hausaufgabe... ;-)
procedure TForm1.btnClearClick(Sender: TObject);

  procedure KillEntry(const zAktuell: TZeiger);
  begin
    if zAktuell <> nil then begin
      KillEntry(zAktuell^.next);
      Dispose(zAktuell);
    end;
  end;

begin
  ListBox1.Clear;
  KillEntry(zKopf);
  zKopf := nil// Liste ist gelöscht
end;

// Liste als Textdatei speichern
procedure TForm1.btnSaveClick(Sender: TObject);
  var
    Datei: TStringList;
    zAktuell: TZeiger;
begin
  if SaveDialog1.Execute then begin // Der Benutzer hat eine Datei ausgewählt
    Datei := TStringList.Create;
    try
      zAktuell := zKopf; // "Vorne" anfangen
      while zAktuell <> nil do begin // aktuelles Element gültig?
        Datei.Add(zAktuell^.de); // beide Texte als Zeilen in die Datei
        Datei.Add(zAktuell^.en);
        zAktuell := zAktuell^.next; // nächstes Element
      end;
      Datei.SaveToFile(SaveDialog1.FileName); // auf Platte schreiben
    finally
      Datei.Free;
    end;
  end;
end;

// Liste aus Textdatei laden
procedure TForm1.btnLoadClick(Sender: TObject);
  var
    Datei: TStringList;
    zNeu, zAktuell: TZeiger;
begin
  if OpenDialog1.Execute then begin // Benutzer hat eine Datei ausgewählt
    btnClearClick(Self); // aktuelle Liste löschen
    Datei := TStringList.Create;
    try
      Datei.LoadFromFile(SaveDialog1.FileName); // Datei laden
      zAktuell := nil// aktuelle Einfügeposition = Anfang
      while Datei.Count > 1 do begin // noch min. 2 Zeilen in der Datei vorhanden?
        New(zNeu); // neues Listenelement anlegen
        zNeu^.de := Datei.Strings[0]; // Texte übernehmen
        zNeu^.en := Datei.Strings[1];
        zNeu^.next := nil// hat (aktuell) keinen Nachfolger
        if zAktuell = nil then // erstes Element?
          zKopf := zNeu // dann als Kopf merken
        else
          zAktuell^.next := zNeu; // sonst beim letzten Element anhängen
        zAktuell := zNeu; // das aktuelle Element ist in der nächsten Runde das zum Anhängen
        Datei.Delete(0); // die ersten beiden Zeilen aus der Datei entfernen
        Datei.Delete(0);
      end;
    finally
      Datei.Free;
    end;
    btnListClick(Self); // geladene Liste ausgeben
  end;
end;

// Beim Programmende evtl. vorhandene Liste wieder freigeben
procedure TForm1.FormDestroy(Sender: TObject);
begin
  btnClearClick(Self); // per Programm den Button zum Löschen anklicken
end;
Bei Fragen - Fragen! :P

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Do 15.09.11 00:43 
Und weil wir hier grad so schön am Nörgeln sind, mal etwas zum Style Guide:

Pointer-Typen sollten in Delphi mit einem P beginnen, gefolgt von dem Namen des Typen, auf den sie zeigen, ohne das typische T.

Konkret also:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
type
    PKnoten = ^TKnoten;
    TKnoten = record
        de: string;
        en: string;
        next: PKnoten;
    end;


Die nächste Sache ist eher eine Formsache, erleichtert aber die Strukturierung etwas: Jede Gruppe von zusammengehörigen Typen sollte in einem eigenen Type-Block stehen. Vor TForm1 also noch ein Type schreiben. Hat auch was mit der Gültigkeit von Forward-Deklarationen zu tun, aber das ist eine andere Geschichte.

Ach ja: In Sachen Einrückung: Bitte keine Hängenden Gärten der Semiramis veranstalten, wenn man pro Syntax/Block-Ebene jeweils 2 (Borland/Inprise/CodeGear/Embarcadero) oder 4 (im DF häufig anzutreffen) verwendet, dann reicht das. Einrückung nach = oder anderen Trennzeichen verschwendet oft nur unnötig Platz auf der Zeile, ohne dass es die Lesbarkeit steigert.

@user profile iconNarses: Für user profile iconMitmischer 1703 wäre ich für die Einführung eines Oink!!!-Buttons.

Ach ja, abschließend noch was: Trennung von Code und GUI ;-)

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Mitmischer 1703
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 754
Erhaltene Danke: 19

Win 7, Debian
Delphi Prism, Delphi 7, RAD Studio 2009 Academic, C#, C++, Java, HTML, PHP
BeitragVerfasst: So 25.09.11 22:04 
user profile iconBenBE hat folgendes geschrieben:
@user profile iconNarses: Für user profile iconMitmischer 1703 wäre ich für die Einführung eines Oink!!!-Buttons.

Ein Oink? Wieso das :P?

Moderiert von user profile iconNarses: ZItat repariert.

_________________
Die Lösung ist nicht siebzehn.
Knulli
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 116
Erhaltene Danke: 2

Win2k, Win7, Win10
D5, D2005, D2006, D2007, D10.4.2
BeitragVerfasst: Fr 21.10.11 17:44 
Kann mir mal einer erklären, was ein Oink ist? :P