Zugriffsverletzungs Fehler bei doppelt verketteter Liste
spacer
Autor Nachricht
PrismaX
Hält's aus hier
Beiträge: 10


Embacadero RAD Studio 2010
BeitragVerfasst: Di 29.11.11 18:59 
Bei meinem Folgenden Quelltext zur Erstellung einer Doppeltverketteten Liste tritt ein AccessError auf

ausblenden Delphi-Quelltext markieren
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
 inherited Create;
new(Knoten);
new(test);
new(test2);
Stringlist := TStringlist.Create;
for I := 1 to 44 do
begin
knoten^ := TKnoten.Create('',i,can);
knoten^.SetNext(test);
if (i+1)< 45 then
begin
test2 := knoten;
knoten := test;
knoten^.Previous := test2;
new(test);
new(test2);
end
else knoten^.Previous := test2;
end;
while (Knoten^.Previous <> nil) do // Hier tritt der Fehler auf
Knoten := Knoten^.Previous;


Fehler tritt wahrscheinlich tritt am Anfang des zweiten(!!) Durchlaufs auf. Meine Vermutung ist dass Knoten nicht initialisiert ist aber Warum? Kann einer weiterhelfen?

LG PrismaX


Zuletzt bearbeitet von PrismaX am Di 29.11.11 19:40, insgesamt 1-mal bearbeitet
 
Antworten mit Zitat Beitrag melden
Private Nachricht sendenPosting in privater Nachricht zitieren
Werbung ausblenden? Dann registriere Dich kostenlos. Weitere Gründe für eine Registrierung.


Werbung ausblenden? Dann registriere Dich kostenlos. Weitere Gründe für eine Registrierung.
Yogu
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starhalf offtopic star
Beiträge: 2544
Erhaltene Danke: 137

Windows 7 Home Premium
Visual C# 2010 Express
BeitragVerfasst: Di 29.11.11 19:21 
ausblenden Delphi-Quelltext markieren
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
 inherited Create;
new(Knoten);
new(test); // test^ = nil
new(test2);
Stringlist := TStringlist.Create;
for I := 1 to 44 do
begin
knoten^ := TKnoten.Create('',i,can);
//knoten^ := knoten^.create('Test',i,can);
knoten^.SetNext(test);
if (i+1)< 45 then
begin
test2 := knoten;
knoten := test; // knoten = test => knoten^ = test^ = nil (s.o.)
knoten^.Previous := test2;
new(test);
new(test2);
end
else knoten^.Previous := test2;
end;
while (Knoten^.Previous <> nil) do // koten^ = nil // Hier tritt der Fehler auf
Knoten := Knoten^.Previous;


Soweit ich das sehe ist test^ = nil, an der Stelle knoten := test;, also ist knoten^ in der while-Bedingung auch nil, oder?
 
Antworten mit Zitat Beitrag melden
Private Nachricht sendenPosting in privater Nachricht zitieren
PrismaX Threadstarter
Hält's aus hier
Beiträge: 10


Embacadero RAD Studio 2010
BeitragVerfasst: Di 29.11.11 19:39 
ausblenden Delphi-Quelltext markieren
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
1:
inherited Create;
new(Knoten);
new(test); // test^ = nil
new(test2);
Stringlist := TStringlist.Create;
for I := 1 to 44 do
begin
knoten^ := TKnoten.Create('',i,can); //Knoten^ wird erstellt => nicht mehr nil
knoten^.SetNext(test);
if (i+1)< 45 then
begin
test2 := knoten;
knoten := test; // knoten = test => knoten^ = test^ = nil (s.o.)
knoten^.Previous := test2;
new(test);
new(test2);
end
else knoten^.Previous := test2;
end;
while (Knoten^.Previous <> nil) do // koten^ = nil // Hier tritt der Fehler auf
Knoten := Knoten^.Previous;


Allerdings erstelle ich den Knoten bei TKnoten.Create ==> theoretisch und praktisch ist er dann nicht mehr nil...
Außerdem ist es merkwürdig dass der Fehler erst beim zweiten Durchlauf der while-Schleife Auftritt..

LG PrismaX
 
Antworten mit Zitat Beitrag melden
Private Nachricht sendenPosting in privater Nachricht zitieren
Yogu
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starhalf offtopic star
Beiträge: 2544
Erhaltene Danke: 137

Windows 7 Home Premium
Visual C# 2010 Express
BeitragVerfasst: Di 29.11.11 20:05 
Hups, ich habe deinen Code wohl nicht aufmerksam genug gelesen. Also, erstmal einrücken:

ausblenden Delphi-Quelltext markieren
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
inherited Create;
new(Knoten);
new(test);
new(test2);
Stringlist := TStringlist.Create;
for I := 1 to 44 do
begin
knoten^ := TKnoten.Create('',i,can);
knoten^.SetNext(test);
if (i+1)< 45 then
begin
test2 := knoten;
knoten := test;
knoten^.Previous := test2;
new(test);

new(test2);
end
else
knoten^.Previous := test2;
end;

while (Knoten^.Previous <> nil) do // Hier tritt der Fehler auf
Knoten := Knoten^.Previous;

Der Fehler tritt also gar nicht im oberen Teil auf, sondern in der einzelnen while-Schleife, in der du schlicht und einfach den ersten Knoten auswählst. Vorneweg, wenn ich das so richtig verstanden habe: Warum merkst du dir den nicht einfach zu Beginn?

Da der Fehler im zweiten Durchlauf der while-Schleife auftritt, ist voher folgendes passiert:

  • Knoten := Knoten^.Previous
  • Aufgrund der ersten Bedingungsabfrage wissen wir, dass jetzt gilt: Knoten != nil.
  • Allerdings ist nicht gesichert, ob Knoten^ != nil ist. Aufgrund der Exception ist also anzunehmen, dass irgend ein Element dieser Liste zwar Previous gesetzt hat, aber Previous^ nicht gesetzt ist.


Umgekehrter Ansatz: Im vorletzten Durchlauf der for-Schleife haben wir am Ende ein neues, leeres test2. Im letzten Durchlauf weisen wir dieses nun einem knoten^.Previous zu. Dadurch ergibt sich, dass knoten^.Previous^ nil ist. Also genau das, was wir oben festgestellt haben.

Hoffe, ich hab den Code jetzt richtig gelesen.

Edit: Dein Ansatz ist aber insgesamt ziemlich seltsam. Beispielsweise weist du die Eigenschaft Previous zu, bevor du den Konstruktur aufrufst: Die Zuweisung in Zeile 15 bezieht sich ja schon auf das Objekt, das sich vorher hinter test verborgen hatte, und noch gar nicht initialisiert war.

Edit2: Ist das hier vielleicht so in etwa, was du suchst?

ausblenden volle Höhe Delphi-Quelltext markieren
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:
type
TKnoten = record
Prevoius: TKnoten;
Next: TKnoten;
end;

PKnoten = ^TKnoten;

var
First, Current, Prevoius: PKnoten;
i: Integer
begin
Previous := nil;
First := nil;

for i := 1 to 44 do
begin
new(Current);
Current^ := new TKnoten();

Current^.Previous := Previous; // Previous ist nil bei i = 1

if First = nil then
First := Current;

// Next wird immer im nächsten Durchlauf zugewiesen; für den letzten Knoten daher nicht mehr.
if Previous <> nil then
Previous^.Next := Current;

// Diese letzte Zeile hat gefehlt, danke, PrismaX.
Previous = Current;
end;
end;


Zuletzt bearbeitet von Yogu am Di 29.11.11 21:40, insgesamt 1-mal bearbeitet
 
Antworten mit Zitat Beitrag melden
Private Nachricht sendenPosting in privater Nachricht zitieren
PrismaX Threadstarter
Hält's aus hier
Beiträge: 10


Embacadero RAD Studio 2010
BeitragVerfasst: Di 29.11.11 21:32 
Also das Problem hast du jetzt richtig erkannt und dein Quelltext schaut auch erstmal gut aus.

Zu meinem Ansatz: Ja er ist z.T. merkwürdig (ich glaube meine erste implementation von Liste aus Delphi 7 von Doberenz/Gewinnus zu haben) aber für test und test2 wird schon am Anfang Speicher freigegeben d.h. eigentlich dürfte sie immer benutzbar sein.

Zu deinem Quelltext hätte ich eine Frage: Ist dann Previous nicht immer nil?

ausblenden Delphi-Quelltext markieren
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:
type
PKnoten = ^TKnoten;
TKnoten = record
Previous: PKnoten;
Next: PKnoten;
end;

var
First, Current, Previous: PKnoten;
i: Integer
begin
Previous := nil;
First := nil;

for i := 1 to 44 do
begin
new(Current);
Current^ := new TKnoten();

Current^.Previous := Previous; // Previous ist nil bei i = 1

if First = nil then
First := Current;

// Next wird immer im nächsten Durchlauf zugewiesen; für den letzten Knoten daher nicht mehr.
if Previous <> nil then
Previous^.Next := Current;

Previous := Current;
end;
end;


So stell ich mir das vor damit wäre das Problem mit dem Previous := nil gelöst (hoffentlich nicht der gleiche Fehler wie in Post 1).

LG PrismaX
 
Antworten mit Zitat Beitrag melden
Private Nachricht sendenPosting in privater Nachricht zitieren
Yogu
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starhalf offtopic star
Beiträge: 2544
Erhaltene Danke: 137

Windows 7 Home Premium
Visual C# 2010 Express
BeitragVerfasst: Di 29.11.11 21:49 
user profile iconPrismaX hat folgendes geschrieben Zum zitierten Posting springen:
für test und test2 wird schon am Anfang Speicher freigegeben d.h. eigentlich dürfte sie immer benutzbar sein.

Ist denn TKnoten eine Klasse oder ein Record? Wenn's eine Klasse ist, musst du die ja erstmal initialisieren, so war meine Logik. Aber wenn du einen Record genommen hast, musst du das natürlich gar nicht machen; dann liegt der Fehler wohl doch wieder wo ganz anders.

Aber ich würde dir so oder so empfehlen, nochmal von vorne anzufangen (:mrgreen:). Überleg nochmal genau, was ein Schleifendurchlauf machen soll: Was der erste Durchlauf tun soll, der zweite, ..., der letzte. Wo genau do Speicher reservierst (in deinem Code passiert das zweimal pro Schleifendurchlauf). Wann welche Variable welchen Inhalt hat (und nenn sie nicht test und test2). Was am Ende tatsächlich rauskommen soll.
 
Antworten mit Zitat Beitrag melden
Private Nachricht sendenPosting in privater Nachricht zitieren
PrismaX Threadstarter
Hält's aus hier
Beiträge: 10


Embacadero RAD Studio 2010
BeitragVerfasst: Di 29.11.11 22:08 
Ja, TKnoten ist eine Klasse und bisher war ich davon ausgegangen dass zum erstellen von einem Objekt dieser Klasse die Construktor-Anweisung Create ausgereicht hätte --> dem ist anscheinend nicht so^^. Daher muss ich mich wohl nochmal stärker damit beschäftigen.

Zum anderen Thema (neuer Quelltext, neues Glück):

ausblenden Delphi-Quelltext markieren
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
var previous,first,current : PKnoten;         //Hilfsvariablen PKnoten = ^TKnoten, TKnoten ist eine class
I: Integer;
begin
previous := nil;
first := nil;

for I := 1 to 44 do
begin
new(Knoten);

knoten^ := TKnoten.Create('',i,can); // erstellen eines Objektes und der Pointer bekommt die Adresse zugewiesen --> falsch?
knoten^.Previous := previous;

if first = nil then
first := knoten;

if previous <> nil then
previous^.SetNext(Knoten);

previous := Knoten;

end;

Knoten := first;


Tut mir leid dass ich deine Zeit genutzt habe ich I***t hätte mir auch einfach den ersten Knoten merken können --> Problem gelöst^^.
 
Antworten mit Zitat Beitrag melden
Private Nachricht sendenPosting in privater Nachricht zitieren
Yogu
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starhalf offtopic star
Beiträge: 2544
Erhaltene Danke: 137

Windows 7 Home Premium
Visual C# 2010 Express
BeitragVerfasst: Di 29.11.11 22:24 
user profile iconPrismaX hat folgendes geschrieben Zum zitierten Posting springen:
Ja, TKnoten ist eine Klasse und bisher war ich davon ausgegangen dass zum erstellen von einem Objekt dieser Klasse die Construktor-Anweisung Create ausgereicht hätte --> dem ist anscheinend nicht so^^.

Doch, Create erzeugt ein Objekt einer Klasse. Das Problem ist nur, dass der Konstruktur in deinem Quelltext in einem bestimmten Fall nicht augerufen wurde: Und zwar im letzten Durchgang für test. Das wurde nur mit New initialisiert - was Platz für den Zeiger auf das Objekt schafft - aber nicht mit dem Konstruktur - was Platz für die eigentlichen Daten des Objekts freimacht.

Eigentlich ist es auch nicht unbedingt sinnvoll, einen Zeiger auf ein Objekt einer Klasse zu verwenden, dann hast du nämlich einen Zeiger auf einen Zeiger, und das macht alles so kompliziert. Entweder du lässt die Zeiger ganz sein und verwendest normale OOP, oder du machst's wie ich in meinem Beispiel und verwendest einen Record für TKnoten.

Zu dem Quelltext: Das funktioniert auch mit einer Klasse, allerdings brauchst du dann keine Zeiger mehr:


ausblenden Delphi-Quelltext markieren
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:
type TKnoten = class
Previous: TKnoten;
Next: TKnoten;
end;

var
previous, first, current : TKnoten;
I: Integer;
begin
previous := nil;
first := nil;

for I := 1 to 44 do
begin
current := TKnoten.Create();
current.Previous := previous;

if first = nil then
first := current;

if previous <> nil then
previous.Next = current;

previous := current;
end;
end;

Gefällt mir eigentlich auch besser. Die ganzen ^-Zeichen sind weg, und es ist reine Objektorientierung. Ich könnte jetzt spontan nichtmal einen Performancevorteil der Pointer-Lösung zeigen.
 
Antworten mit Zitat Beitrag melden
Private Nachricht sendenPosting in privater Nachricht zitieren
home home