Delphi-PRAXiS
Seite 1 von 4  1 23     Letzte »    

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Array mit verschiedenen Records (https://www.delphipraxis.net/95275-array-mit-verschiedenen-records.html)

Scrutor 4. Jul 2007 13:39


Array mit verschiedenen Records
 
Hallo zusammen,

ich hab mal wieder ein Problemchen, bei dem ich nicht weiterkomme und ich denke mal hier wird mir die Frage schnell beantwortet.

Ich möchte eigentlich nur wissen, ob es möglich ist ein Array zu erstellen, in dem 5 verschiedene Records drin sind.

also ungefähr so:
Delphi-Quellcode:
type
  Rec1 = record
   a : char;
   b : char;
  end;

type
  Rec2 = record
   c: char;
   d: char;
  end;

...
 
RecArray:Array[0..4]of record;

RecArray[0]:=Rec1;
RecArray[1]:=Rec2;
...
RecArray[4]:=Rec5;
Geht das so wie ich mir das wünsche ? oder muss ich mir was anderes einfallen lassen ?

Bisher hab ich das nicht hinbekommen. :wall:

Vielen Dank für jede Hilfe.


mfg
Scrutor

sirius 4. Jul 2007 13:53

Re: Array mit verschiedenen Records
 
Geht, aber nur mit Tricks.
Einfacher machst du dir es hier mit Klassen.
Vielleicht nimmst du dann auch gleich eine TObjectList als Container statt eines Arrays.

Scrutor 4. Jul 2007 13:57

Re: Array mit verschiedenen Records
 
hmm,
hast du da irgendwo ein brauchbares Beispiel für ?

Hab mich mit Klassen und Containern noch nicht so befasst.


mfg
Scrutor

Der_Unwissende 4. Jul 2007 14:02

Re: Array mit verschiedenen Records
 
Hi,
so geht das nicht. Ein Array ist eine sehr einfache Art von Speicherstruktur, die nur dazu bestimmt ist einfach (und schnell) auf eine bestimmte (feste) Menge von gleichen Daten zugreifen zu können. Legst Du ein Array an, so wird einfach die Größe eines Elements mit der Anzahl der Elemente multitpliziert und der entsprechend Wert wird als Menge an Speicher alloziert. Anders gesagt, hast Du ein Array, dass aus 10 Integer Werten besteht (egal ob dynamisch oder statisch), dann wird hier einfach 10 * 4 Byte (sizeOf(Integer) = 4) alloziert. Nun merkt sich Delphi noch die Adresse des ersten Elements im Array. Möchtest Du nun auf das 7te Element zugreifen, so weiß Delphi hier, dass es einfach an 4 Byte an der Adresse (StartadresseDesArrays + 7 * 4) zugreifen muss.
Das ist gerade der Vorteil eines solchen Array, die Daten liegen alle am Stück im Speicher, da greifen einerseits Caching-Techniken recht gut und er wahlfreie Zugriff (Element an Stelle x) ist möglich.

Unterschiedliche Typen können eben genau diese Art von Zugriff nicht garantieren, das gilt auch für gleich große Elemente (z.B. Cardinal und Integer). Schließlich sind das unterschiedliche Typen, die könnten also (theoretisch) auch die Größe unabhängig voneinander ändern!

Was Du benutzen kannst ist immer etwas gleiches. Da gibt es schon mal die Möglichkeit, dass Du ein Array von Zeigern verwaltest und die speicherst. Die Records kannst Du dann (wenn Du die dyn. erzeugen willst) mit new erzeugen und die Adresse im Array speichern. Sind die Records statisch, musst Du darauf achten, dass die adresse nur lokal gültig ist, alles was Du in einer Methode als lokale Parameter deklarierst landet nur auf dem Stack und wird beim verlassen der Methode dort auch abgeräumt. Globale Variablen, Instanz- und Klassenvariablen, Instanzen von Klassen und eben mittels new erzeugte Typen unterliegen nicht der Einschränkung (Daten landen im Heap).

Das Problem dass Du beim arbeiten mit Zeigern hast (kannst hier auch auf eine TList statt einem Record of Pointerzurückgreifen) ist, dass Du nicht weißt was für einen Typ sich hinter dem Zeiger verbirgt. Der speichert nur eine Adresse, was sich an der Adresse befindet musst Du schon selbst wissen. Hier ist also die Frage, wie Du das ganze dann erkennen möchtest, eine Möglichkeit ist natürlich ein Record aus dem Typ und dem Zeiger.

Ansonsten kannst Du das ganze auch über Klassen realisieren. Die erben immer von der Basisklasse TObject. Details zu Klassen und OOP kannst Du in vielen Tutorials nachlesen, die meisten behandeln sicherlich auch Vererbung (und vergessen dafür häufiger mal die wichtigen Ideen der OOP).
Jedenfalls kannst Du jede Instanz einer Klasse immer wie eine TObject Instanz behandeln. Dabei siehst Du dann nur dass, was eben ein TObject anbietet (z.B. die Methode Free zum Freigeben der Instanz).
Hier kannst Du also auf ein Object of TObject oder eine TObjectList zurückgreifen. Ob eine Instanz nun vom Typ Klasse1 oder Klasse2 ist, kannst Du mittels dem Operator is (if Variable is TKlasse1 then ...) testen.

Gruß Der Unwissende

christian.noeding 4. Jul 2007 14:04

Re: Array mit verschiedenen Records
 
Hi - ich mache das immer so:

Delphi-Quellcode:
type
  Rec1 = record
   a : byte;
   b : string[255];
  end;

  Rec2 = record
   c: integer;
   d: word;
  end;

  RecComplete = record
   RecPart1 : Rec1;
   RecPart2 : Rec2;
  end;

RecArray : Array[0..4] of RecComplete;
Somit kann man in ein Array die unterschiedlichsten Sachen packen. :)

Der_Unwissende 4. Jul 2007 14:09

Re: Array mit verschiedenen Records
 
Zitat:

Zitat von christian.noeding
Hi - ich mache das immer so:

...

Somit kann man in ein Array die unterschiedlichsten Sachen packen. :)

Auf Kosten des Speicherverbrauchs. Du speicherst hier eben immer zwei Records in einem Datensatz. Je mehr unterschiedliche Records Du hast, desto schlimmer die Verschwendung!
Bei solchen unterschiedlichen Typen kannst Du dann auch ein varianten Record (einfach mal in die OH schauen) verwenden.

Scrutor 4. Jul 2007 14:10

Re: Array mit verschiedenen Records
 
hui, danke für die umfangreiche Info Der_Unwissende.
Nun weiss ich zumindest schonmal, dass die Lösung über Records in meinem Fall nicht (nie) funktionieren kann.

Ich werde mich dann nun mal den Klassen und Objecten widmen.


@christian.noeding
das wäre eine möglichkeit, aber ist für meinen Fall auch leider nicht brauchbar. trotzdem vielen dank.


ich beschreibe mal mein problem, vielleicht hat ja einer eine gute lösung:
Also, ich hab eine Text-Datei in der Datensätze gespeichert sind.
Diese muss ich laden.
Zeile 1 hat zum Beispiel 14 Datensätze, die bis auf den ersten Datensatz alle 8 Zeichen lang sind. Der erste Datensatz hat 10 Zeichen.
Nun kann es aber sein, dass bei einem alten Datenformat der erste Datensatz nur 9 Zeichen lang ist.
Also prüfe ich das Datei-Erstellungsdatum und entscheide danach, welchen Record ich benutze, um den Datensatz der ersten Zeile korrekt zu laden.

Datei von 2002 sieht so aus:
Delphi-Quellcode:
type
  TDaten_Zeile_1_altesFormat = record
    Auftr  : array[0..8]of char;  //Auftragsnummer
    Dum1    : array[0..7]of char;  //Dummy
    ProgNr : array[0..7]of char;  //Programmnummer
    ZeichNr : array[0..7]of char;  //Zeichnungsnummer
    LineNr : array[0..7]of char;  //Lineelement
    IdBohr : array[0..7]of char;  //Ident Bohren
    IdVorr : array[0..7]of char;  //Ident Vorrichtung
    Dum2    : array[0..7]of char;  //Dummy
    AVO    : array[0..7]of char;  //AVO
    Mach   : array[0..7]of char;  //Maschine
    Durchm : array[0..7]of char;  //Raddurchmesser
    AusWink : array[0..7]of char;  //Austrittswinkel
    AnzScha : array[0..7]of char;  //Anzahl Schaufeln
    SchaHohe: array[0..7]of char;  //Schaufelhöhe
    LineFeed: array[0..1]of char;
  end;
Datei von 2004 sieht so aus:
Delphi-Quellcode:
type
  TDaten_Zeile_1_neuesFormat = record
    Auftr  : array[0..9]of char;  //Auftragsnummer
    Dum1    : array[0..7]of char;  //Dummy
    ProgNr : array[0..7]of char;  //Programmnummer
    ZeichNr : array[0..7]of char;  //Zeichnungsnummer
    LineNr : array[0..7]of char;  //Lineelement
    IdBohr : array[0..7]of char;  //Ident Bohren
    IdVorr : array[0..7]of char;  //Ident Vorrichtung
    Dum2    : array[0..7]of char;  //Dummy
    AVO    : array[0..7]of char;  //AVO
    Mach   : array[0..7]of char;  //Maschine
    Durchm : array[0..7]of char;  //Raddurchmesser
    AusWink : array[0..7]of char;  //Austrittswinkel
    AnzScha : array[0..7]of char;  //Anzahl Schaufeln
    SchaHohe: array[0..7]of char;  //Schaufelhöhe
    LineFeed: array[0..1]of char;
  end;
so, davon gibt es also mehrere unterschiedliche Datensätze zu unterschiedlichen Datumsangaben.

Ich hab 5 Zeilen-Records und für jeden Zeilen Record kann es sein, dass ich 6 verschiedene Zeit-Records erstellen muss.
(Hab nämlich noch nicht alle Format unterschiede mir angeschaut)

ich hoffe jemand versteht mein Porblem wenigstens ansatzweise :)

sirius 4. Jul 2007 14:26

Re: Array mit verschiedenen Records
 
Iim einfachsten Fall:
Delphi-Quellcode:
type TClass1=class
       x,y:integer;
end;

type TClass2=class
       b:string;
       c:char;
end;

...
var Liste:TObjectList
    Class1:Tclass1;
    Class2:Tclass2;

//irgendwo Liste erstellen
Liste:=Tobjectlist.create;
Liste.ownsobjects:=true; //damit verwaltet die Liste ihre Elemente selber

//Object einfügen
Class1:=Tclass1.create;
Liste.add(Class1);
Class1.x:=5;

//usw..
Class2:=Tclass2.create;
...


//Zugriff über
list.Items[0]
list.items[1]
//also
Class1:=list.items[0];
ergebnis:=Class1.x
//oder
ergebnis:=TClass1(list.items[0]).x;
Soweit erstmal.
Hier geht aber noch viel mehr.

marabu 4. Jul 2007 16:28

Re: Array mit verschiedenen Records
 
Hallo Scrutor,

bei Textdateien gibt es zwei Basis-Formate: Fixed-Field und Comma-Separated. Die Bezeichnungen sagen aus, dass im ersten Fall die einzelnen Felder über ihren Offset und im letzteren Fall durch Abzählen der Trennzeichen lokalisiert werden. Deine Textdaten gehören in die erste Kategorie.

Für deine beiden Datensatztypen kommt man leicht zu folgenden Strukturen:

Delphi-Quellcode:
type
  TAuftragDaten = record
    Dum1    : array[0..7]of char;  //Dummy
    ProgNr : array[0..7]of char;  //Programmnummer
    ZeichNr : array[0..7]of char;  //Zeichnungsnummer
    LineNr : array[0..7]of char;  //Lineelement
    IdBohr : array[0..7]of char;  //Ident Bohren
    IdVorr : array[0..7]of char;  //Ident Vorrichtung
    Dum2    : array[0..7]of char;  //Dummy
    AVO    : array[0..7]of char;  //AVO
    Mach   : array[0..7]of char;  //Maschine
    Durchm : array[0..7]of char;  //Raddurchmesser
    AusWink : array[0..7]of char;  //Austrittswinkel
    AnzScha : array[0..7]of char;  //Anzahl Schaufeln
    SchaHohe: array[0..7]of char;  //Schaufelhöhe
  end;

  TAuftrag2002 = record
    Nr : array[0..8]of char;  //Auftragsnummer
    Spec: TAuftragDaten;
  end;

  TAuftrag2004 = record
    Nr : array[0..9]of char;  //Auftragsnummer
    Spec: TAuftragDaten;
  end;
Einlesen kannst du diese Daten wahlweise über die alten Pascal Standardroutinen ReadLn (ohne vorherige Kenntnis der Satzlänge) und BlockRead (mit vorheriger Kenntnis der Satzlänge) oder über einen FileStream.

Wenn nur diese beiden Datensatztypen existieren, dann kannst du auch einfach den größeren Typ verwenden und beim Einlesen die erste Stelle mit einem Leerzeichen oder einer Null initialisieren, wenn die kurzen Sätze verarbeitet werden.

Grüße vom marabu

Scrutor 5. Jul 2007 06:57

Re: Array mit verschiedenen Records
 
Hallo marabu,

diese Lösung hört sich sehr gut an.
Da ja mehr als nur diese 2 datensätze existieren, ist diese Möglichkeit brauchbar.

Ich hab das mal wie folgt angefangen:
Delphi-Quellcode:
type
  TZeile_1 = record
    Dum1    : array[0..7]of char;  //Dummy
    ProgNr : array[0..7]of char;  //Programmnummer
    ZeichNr : array[0..7]of char;  //Zeichnungsnummer
    LineNr : array[0..7]of char;  //Lineelement
    IdBohr : array[0..7]of char;  //Ident Bohren
    IdVorr : array[0..7]of char;  //Ident Vorrichtung
    Dum2    : array[0..7]of char;  //Dummy
    AVO    : array[0..7]of char;  //AVO
    Mach   : array[0..7]of char;  //Maschine
    Durchm : array[0..7]of char;  //Raddurchmesser
    AusWink : array[0..7]of char;  //Austrittswinkel
    AnzScha : array[0..7]of char;  //Anzahl Schaufeln
    SchaHohe: array[0..7]of char;  //Schaufelhöhe
    LineFeed: array[0..1]of char;
  end;

type
  TZeile_1_vor04 = record
    Auftr  : array[0..8]of char;  //Auftragsnummer
    Spec   : TZeile_1;
  end;

type
  TZeile_1_nach04 = record
    Auftr  : array[0..9]of char;  //Auftragsnummer
    Spec   : TZeile_1;
  end;

type
  TZeile_2 = record
    MesDurch: array[0..8]of char;  
    EinDur : array[0..7]of char;  
    FLAS   : array[0..4]of char;  
    Wkstoff : array[0..7]of char;  
    Stueck : array[0..7]of char;  
    Dum4    : array[0..7]of char;  
  end;

type
  TZeile_2_vor03 = record
    Spec   : TZeile_2;
    SchaHoSi: array[0..7]of char;  
    ZwShaSi : array[0..7]of char;  
    LineFeed: array[0..1]of char;
  end;

type
  TZeile_2_nach03 = record
    Spec   : TZeile_2;
    SchaHoSi: array[0..7]of char;  
    ZwShaSi : array[0..7]of char;  
    MaxType : array[0..7]of char;  
    LineFeed: array[0..1]of char;
  end;
so, nun lese ich aber ja in einer procedure die Datei mit Filestream aus und übergebe die ausgelesenen records an eine weitere procedure, die die einzelenen Daten dann in Editfelder, etc. einträgt.

wie deklariere ich in der ersten procedure am besten die verschiedenen records ?
und wie übergebe ich die an die nächste procedure ?
alle global deklarieren ?


mfg
Scrutor


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:12 Uhr.
Seite 1 von 4  1 23     Letzte »    

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz