Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Variableninhalt ist "weg"


D. Annies - Mi 04.03.09 19:15
Titel: Variableninhalt ist "weg"
Hi, Delpher,

ich habe das folgende Problem:
In Form1 bestimme ich in einer Schleife die Größe eines Arrays.
In Form2 rufe ich diese Proc auf.
Der Wert von Anz_Kla ist dann aber leider 0 und nicht 34, wie vorher bestimmt.

CodeSchnipsel:


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:
.......

Var Form1 : TForm1;
    Anz_Kla : integer;  // also global

.....

procedure TForm1.machwas(sender:tobject);
begin
  Anz_Kla := 0;
  setlength(Kla_Bez,     Anz_Kla +1);
  Kla_Bez[Anz_Kla] := TbAusleihsatz.fieldbyname('KLASSE').asstring;
  setLength(Kla_Bez_Anz, Anz_Kla +1);
  QSchueler.first;    // Wieviele Schüler in welcher Klasse?  TbSchueler ???
  while not QSchueler.eof do
  begin
    if (QSchueler.fieldbyname('KLASSE').asstring <> ''and
       (QSchueler.fieldbyname('KLASSE').asstring = Kla_Bez[Anz_Kla]) then
          inc(Kla_Bez_Anz[Anz_Kla]);
        QSchueler.next;
  end;
  showmessage(inttostr(Anz_Kla));   // das sind 34
end;

.....

// in Form2:
form1.machwas(self);
showmessage(inttostr(Kla_Anz));  // das sind 0 
for n := 0 to Kla_Anz do ...


Wer hat da eine Idee??

Danke, Detlef


Delete - Mi 04.03.09 19:24

Du änderst den Wert von Anz_Kla ja auch nirgends.


jaenicke - Mi 04.03.09 19:28

Doch, das schon, aber:
user profile iconD. Annies hat folgendes geschrieben Zum zitierten Posting springen:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
Var Form1 : TForm1;
    Anz_Kla : integer;  // also global

.....

procedure TForm1.machwas(sender:tobject);
begin
  ...
  showmessage(inttostr(Anz_Kla));   // das sind 34
end;

.....

// in Form2:
form1.machwas(self);
showmessage(inttostr(Kla_Anz));  // das sind 0 
for n := 0 to Kla_Anz do ...
War das jetzt ein Schreibfehler oder hast du tatsächlich eine zweite Variable Kla_Anz irgendwo...

Und zum Zugriff solltest du wenn dann Unit1.Anz_Kla benutzen, am besten deklarierst du die Variable aber in TForm1.


Delete - Mi 04.03.09 19:33

Zitat:

Delphi-Quelltext
1:
Anz_Kla := 0;                    

Das ist die einzige Zuweisung von Anz_Kla, die ich entdeckt habe, oder bin ich erblindet?


D. Annies - Mi 04.03.09 19:33

Hi, Sebastian,

leider tatsächlich ein Schreibfehler!
Im Code steht also auch in Form2 richtigerweise: showmessage(inttostr(Anz_Kla));


jaenicke - Mi 04.03.09 19:39

user profile iconDeddyH hat folgendes geschrieben Zum zitierten Posting springen:
Zitat:

Delphi-Quelltext
1:
Anz_Kla := 0;                    

Das ist die einzige Zuweisung von Anz_Kla, die ich entdeckt habe, oder bin ich erblindet?
Stimmt, da habe ich gar nicht weiter nachgeschaut, ich hatte mich auf den Kommentar verlassen, dass das da richtig ausgegeben wird...

Delphi-Quelltext
1:
  showmessage(inttostr(Anz_Kla));   // das sind 34                    


D. Annies - Mi 04.03.09 19:48

Hi, Deddy und Sebastian,

nein, keiner ist erblindet - mein Fehler, ich habe oben vergessen, eine Schleife anzugeben, aber diese Schleife wird durchlaufen, so dass Anz_Kla (!) den Wert 34 hat.


Delete - Mi 04.03.09 19:54

Dann zeig doch am Besten nochmal den ganzen Code. Unabhängig davon würde ich Dir aber trotzdem empfehlen, keine globale Variable, sondern ein Feld oder gleich eine Property von Form1 zu deklarieren.


D. Annies - Mi 04.03.09 20:08

Hi,

der Code:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
procedure TForm1.machwas(sender:tobject);
begin
  Anz_Kla := 0;
  setlength(Kla_Bez,     Anz_Kla +1);
  TbAusleihsatz.first;
  while not eof(TbAusleihsatz do
  begin
    Kla_Bez[Anz_Kla] := TbAusleihsatz.fieldbyname('KLASSE').asstring;
    setLength(Kla_Bez_Anz, Anz_Kla +1);
    QSchueler.first;    // Wieviele Schüler in welcher Klasse?  TbSchueler ???
    while not QSchueler.eof do
    begin
      if (QSchueler.fieldbyname('KLASSE').asstring <> ''and
         (QSchueler.fieldbyname('KLASSE').asstring = Kla_Bez[Anz_Kla]) then
            inc(Kla_Bez_Anz[Anz_Kla]);
          QSchueler.next;
    end;
    TbAusleihsatz.next;
    inc(Anz_Kla);
  end;
  showmessage('Form1: ' + inttostr(Anz_Kla));   // Form1: 34
end;


man beachte die showmessage! Und wenn ich die Proc dann in Form2 aufrufe, steht da:

Form1: 0

Detlef :gruebel:


Delete - Mi 04.03.09 20:17

Da habe ich im Moment auch keine Erklärung dafür. Du hast nicht zufällig Anz_Kla noch einmal als lokale Variable definiert?


jaenicke - Mi 04.03.09 20:21

Deshalb sagte ich ja:
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Und zum Zugriff solltest du wenn dann Unit1.Anz_Kla benutzen
Dann lässt sich das ausschließen.

Trotzdem verursachen globale Variablen eben oft Unklarheiten, und in diesem Fall frage ich mich, warum das überhaupt nicht einfach eine Funktion ist...
Deren Rückgabewert könntest du dann direkt nutzen.

Ansonsten mach doch einfach was user profile iconDeddyH (und ich ganz oben) geschrieben hatte: Deklariere Anz_Kla innerhalb von TForm1, entweder als Feld oder als Property.


D. Annies - Mi 04.03.09 20:24

Ich danke euch beiden sehr, aber wie geht euer Vorschlag?

Danke für Erleuchtung, Detlef


Delete - Mi 04.03.09 20:30


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
type
  TForm1 = class(TForm)
  ...
  private 
    //private Variable anlegen
    FAnz: integer;
  ...
  public
    //eine ReadOnly-Property anlegen,
    //damit wird indirekt auf die private Variable zugegriffen
    property Anzahl: integer read FAnz;
  end;


jaenicke - Mi 04.03.09 20:31

Zunächst mal vorneweg:
Es ist in Delphi absolut nicht üblich Unterstriche für Bezeichner zu verwenden...
Halte dich besser an den Styleguide, dann ist der Code auch lesbarer.
http://dn.codegear.com/article/10280 (englisch)
http://www.delphi-treff.de/delphi-styleguide/ (deutsch)

Dann zum Thema:

Delphi-Quelltext
1:
2:
3:
4:
TForm1 = class(TForm)
public
  AnzKla: Integer;
end;
Innerhalb von Form1 immer nur AnzKla, außerhalb Form1.AnzKla zur Benutzung verwenden.

Oder eine richtige property:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
TForm1 = class(TForm)
private
  FAnzKla: Integer;
public
  property AnzKla: Integer read FAnzKla write FAnzKla;
end;
Wobei man hier dann auch einen Setter schreiben kann, der statt das direkt an FAnzKla weiterzuleiten den Wert vorher prüft oder eine Aktion daraufhin durchführt, dass der Wert geändert wurde:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
TForm1 = class(TForm)
private
  FAnzKla: Integer;
  procedure SetAnzKla(Value: Integer);
public
  property AnzKla: Integer read FAnzKla write SetAnzKla;
end;

...

procedure TForm1.SetAnzKla(Value: Integer);
begin
  FAnzKla := Value;
  ShowMessage('Neuer Wert gesetzt!');
end;


D. Annies - Mi 04.03.09 20:39

Danke, da hab ich was zum Nachdenken!

(Aufruf in Form2?)

Melde mich wieder, Gruß, Detlef


jaenicke - Mi 04.03.09 20:44

Außerhalb von TForm1 mit Form1.AnzKla, innerhalb von TForm1 entweder FAnzKla oder AnzKla, je nach Variante.


D. Annies - Do 05.03.09 18:25

Hi, Sebastian,

ich habe den Schnipsel "oder eine richtige Property" eingearbeitet, aber leider ist der Variableninhalt immer noch 0.

>Witzigerweise< funktionierte inc(AnzKla) nicht,ich musste Anzkla := anzkla + 1 schreiben. (nur so nebenbei)

Hängt es vielleicht irgendwie mit dem dynamischen Array zusammen??

Gruß, Detlef


Delete - Do 05.03.09 19:31

Kannst Du mal beide Units anhängen?


D. Annies - Do 05.03.09 20:51

Gute Idee, aber die Unit1 ist zu groß (ca 6000 Zeilen) - das kann ich keinem zumuten!

Nun, ich denke, das ist hier wohl ein Seiteneffekt, (nicht zum ersten Mal) da muss ich wohl wieder ein bisschen allein beißen - ich melde mich dann wieder.

Vielen Dank für deine (eure) Tipps,
Detlef :mrgreen: :lupe: :evil: :nixweiss: :hair: :eyecrazy: :les: :oops: :D


jaenicke - Do 05.03.09 21:12

user profile iconD. Annies hat folgendes geschrieben Zum zitierten Posting springen:
>Witzigerweise< funktionierte inc(AnzKla) nicht,ich musste Anzkla := anzkla + 1 schreiben. (nur so nebenbei)

Hängt es vielleicht irgendwie mit dem dynamischen Array zusammen??
Das hört sich dann allerdings wieder mal nach einem Speicherproblem an, ich glaube das Thema war bei dir schonmal gewesen, oder?

Denn Inc muss funktionieren, außer beim Debuggen, wo das schlicht eine Compileroptimierung sein kann, wenn es direkt bei der Auswertung in Delphi falsch angezeigt wird.

Zum Debuggen schalte am besten die Optimierung aus und die Bereichsprüfung an. ;-)


Delete - Do 05.03.09 21:16

Eine Integer-Property kann man nicht mit Inc erhöhen. Dazu müsste man direkt auf die private Variable zugreifen, da geht das dann wieder.


jaenicke - Do 05.03.09 21:21

Wenn AnzKla die Property ist, klar. Daran habe ich gar nicht mehr gedacht. Innerhalb der Klasse sollte man aber eher direkt auf die Variable (dann wohl FAnzKla?) zugreifen, weil die Property eigentlich Zugriffe von außen ggf. überwacht.


Delete - Do 05.03.09 21:24

Nur, sofern eine Setter-Methode implementiert wurde, ansonsten ist das Wumpe.


jaenicke - Do 05.03.09 22:09

Bis man einen Getter und Setter schreibt und sich über die seltsamen Ergebnisse in der Klasse wundert... :roll:


D. Annies - Fr 06.03.09 08:46

So, das Problem ist behoben, es war wohl ein Seiteneffekt, also ein Programmierfehler. Ich habe nur die Reihenfolge etwas verändert und jetzt geht es.

Also wohl kein Speicherleck (richtig, :zustimm: dass ich das schon mal hatte)

Nun ist meine Proggerwelt (erstmal) wieder in Ordnung ...

Danke für euer Interesse und eure Hilfe,
Detlef