IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Delphi Discussion :

Record avec champ "variable"


Sujet :

Langage Delphi

  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    707
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 707
    Points : 777
    Points
    777
    Par défaut Record avec champ "variable"
    Bonjour,

    J'ai un petit problème de débutant mais je pense que cette section convient mieux pour mon cas...

    J'ai une procédure qui déclare et utilise localement un record dont une partie est "variable"; ce code fonctionne:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    procedure Test;
    const
      NbMax = 10;
    type
      TMonRecord = record
        Tableau: array[0..NbMax - 1] of Integer;
      end;
    var
      UnRecord: TMonRecord;
      i1: Integer;
    begin
     //
    end;
    mais je voudrais passer la partie variable en paramètre de ma fonction, et là ça ne marche plus:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    procedure Test(const NbMax: Integer);
    type
      TMonRecord = record
        Tableau: array[0..NbMax - 1] of Integer;
      end;
    var
      UnRecord: TMonRecord;
      i1: Integer;
    begin
     //
    end;
    Comment faire pour rendre mon record "dynamique", selon le paramètre passé à la procédure ?

    (Je sais, c'est niveau raz-de-la-moquette, mais j'ai toujours eu du mal avec les subtilités du langage)

    Merci

  2. #2
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 448
    Points
    28 448
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    procedure Test(const NbMax: Integer);
    type
      TMonRecord =  array of Integer;
    var
      UnRecord: TMonRecord;
      i1: Integer;
    begin
      SetLength(UnRecord, NbMax);
     //
    end;

  3. #3
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 577
    Points : 25 225
    Points
    25 225
    Par défaut
    Attention au terme "variable" en Delphi, il existe Partie variable des enregistrements, voir plus bas dans ma réponse, c'est plus tordu !

    @Paul Toth, TMonRecord n'est plus un record mais un type équivalent à TIntegerDynArray

    GoustiFruit, pour ton cas que Paul Toth a un peu trop simplifié, c'est la même chose avec le type string

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    const
      NbMax = 10;
     
    type
      TMonRecord = record 
        Tableau: Types.TIntegerDynArray; // Dès D6, sinon "array of Integer"
        Chaine: string;
        ChaineFixe: ShortString;
        ChaineDix: string[10];
      end;
     
    var
      UnRecord: TMonRecord;
      i: Integer;
    begin
      SetLength(UnRecord.Tableau, NbMax);
      for i := Low(UnRecord.Tableau) do High(UnRecord.Tableau) do
        UnRecord.Tableau[i] := i; 
     
      Chaine := 'Une Phrase Longue c''est  dynamique';
      SetLength(UnRecord.Chaine, NbMax); // Tronque la chaine !
     
      ChaineFixe = 'Une Phrase Longue ce n''est pas dynamique ici car toujours 255 caractères';
      ChaineDix := 'Pas plus de Dix ! Oups !'; // tronque !
     
    end;

    Un démo de la Partie variable des enregistrements, tu noteras que c'est différent mais aussi très intéressants !


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    procedure Test;
    const
      NbMax = 10;
    type
      TMonRecord = record
        case integer of
          0: (
               Tableau: array[0..NbMax - 1] of Integer;
             );
     
         1: (
               I1: Integer;
               I2: Integer;
               I3: Integer;
               I4: Integer;
               I5: Integer;
               I6: Integer;
               I7: Integer;
               I8: Integer;
               I9: Integer;
               I10: Integer;
             );
     
      end;
    var
      UnRecord: TMonRecord;
      i: Integer;
    begin
    begin
      SetLength(UnRecord.Tableau, NbMax);
      for i := Low(UnRecord.Tableau) do High(UnRecord.Tableau) do
        UnRecord.Tableau[i] := i; 
     
      ShowMessage(IntToStr(UnRecord.i1)); // contient 0 car partage l'espace mémoire avec Tableau[0]
      ShowMessage(IntToStr(UnRecord.i2)); // contient 1 partage avec Tableau[1]
      ShowMessage(IntToStr(UnRecord.i3)); // contient 2 partage avec Tableau[2]
      ...
    end;

  4. #4
    Membre éclairé
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    707
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 707
    Points : 777
    Points
    777
    Par défaut
    @Paul Toth: mon exemple est hyper simplifié, en réalité mon enregistrement contient d'autres champs !

    @Paul Toth et @ ShaiLeTroll: je ne veux pas passer par SetLength car par la suite j'utilise un grand nombre d'enregistrements de type TMonRecord, je suis en D7 et ça ne me semble pas efficace de redimensionner pour chaque enregistrement !?

    Mais d'après vous il n'y a pas moyen de déclarer ce tableau dans mon record avec une taille dépendant d'un paramètre ? Vraiment obligé de passer par SetLength ?

  5. #5
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 577
    Points : 25 225
    Points
    25 225
    Par défaut
    Citation Envoyé par GoustiFruit Voir le message
    Mais d'après vous il n'y a pas moyen de déclarer ce tableau dans mon record avec une taille dépendant d'un paramètre ? Vraiment obligé de passer par SetLength ?
    C'est un simple tableau dynamique, c'est ultra standard comme pratique !


    Citation Envoyé par GoustiFruit Voir le message
    je suis en D7 et ça ne me semble pas efficace de redimensionner pour chaque enregistrement !?
    Si tu alloue le tableau qu'une seule fois, c'est tout à fait performant, regarde la String, cela passe son temps à faire ça !
    Par contre, si tu passe ton temps à changer de taille, cela devient discutable, il faudrait étudier une TList ou TObjectList,
    mais bon si tu utilises des Record, tu ne dois pas être familier de la POO en général

    Citation Envoyé par GoustiFruit Voir le message
    j'utilise un grand nombre d'enregistrements de type TMonRecord
    ?
    un Grand nombre ? 10 000 ? 100 000 ?
    Création de metaclass en dynamique
    Création d'objets "par lots"


    Deux méthodes,
    soit le SetLength pour le tableau dynamique
    soit une Partie variable des enregistrements, je pense que tu n'as pas envisagé cela avec ma démo :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    procedure Test;
    type
      TMonRecord = record
        case integer of
          10: (Tableau10: array[0..9] of Integer;); 
          20: (Tableau20: array[0..19] of Integer;);
          30: (Tableau30: array[0..29] of Integer;);
      end;
    var
      UnRecord: TMonRecord;
      i: Integer;
    begin
      for i := Low(UnRecord.Tableau10) do High(UnRecord.Tableau10) do
        UnRecord.Tableau10[i] := i; 
     
      for i := Low(UnRecord.Tableau20) do High(UnRecord.Tableau20) do
        ShowMessage(UnRecord.Tableau20[i]); 
     
      for i := Low(UnRecord.Tableau20) do High(UnRecord.Tableau20) do
        UnRecord.Tableau20[i] := -i; 
     
      for i := Low(UnRecord.Tableau10) do High(UnRecord.Tableau10) do
        ShowMessage(UnRecord.Tableau10[i]); 
     
      for i := Low(UnRecord.Tableau20) do High(UnRecord.Tableau20) do
        ShowMessage(UnRecord.Tableau20[i]); 
     
      for i := Low(UnRecord.Tableau30) do High(UnRecord.Tableau30) do
        ShowMessage(UnRecord.Tableau30[i]); 
    end;
    en pratique dans le code

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    procedure FaireChose(TableauType: Integer);
    begin
      case TableauType of 
        10 : FaireChoseTableau(UnRecord.Tableau10);
        20 : FaireChoseTableau(UnRecord.Tableau20);
        30 : FaireChoseTableau(UnRecord.Tableau30);
      end;
    end;
     
    procedure FaireChoseTableau(const Tableau : array of Integer);
    var
      i: Integer
    begin
      for i := Low(Tableau) do High(Tableau ) do
        ShowMessage(Tableau [i]); 
    end;

  6. #6
    Membre éclairé
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    707
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 707
    Points : 777
    Points
    777
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    ?
    un Grand nombre ? 10 000 ? 100 000 ?
    99% du temps ça serait quelques centaines, mais en théorie ça pourrait atteindre 5-10 millions dans certains cas.

    Deux méthodes,
    soit le SetLength pour le tableau dynamique
    soit une Partie variable des enregistrements, je pense que tu n'as pas envisagé cela avec ma démo :
    J'avais envisagé, mais les cas ne seront pas déterminés à l'avance, ils dépendront vraiment du paramètre.

    Bon, allons-y pour le SetLength...

  7. #7
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 577
    Points : 25 225
    Points
    25 225
    Par défaut
    Citation Envoyé par GoustiFruit Voir le message
    99% du temps ça serait quelques centaines
    tu te prends trop la tête alors !
    Citation Envoyé par GoustiFruit Voir le message
    mais en théorie ça pourrait atteindre 5-10 millions dans certains cas
    la théorie et la pratique ... imaginer charger 10 millions de record n'est même pas imaginable, pense que si ton record occupe 200 octets, tu arrives arrive à 2Go mémoire, le problème sature en Win32 !

    10 millions de record via pointeur, c'est déjà 40Mo rien que pour les pointeurs de record !
    Un tableau de 10 Integers, c'est déjà 32 octets, donc 320Mo !
    cela monte très vite !

  8. #8
    Membre émérite
    Avatar de ALWEBER
    Homme Profil pro
    Expert Delphi
    Inscrit en
    Mars 2006
    Messages
    1 504
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 69
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Expert Delphi

    Informations forums :
    Inscription : Mars 2006
    Messages : 1 504
    Points : 2 773
    Points
    2 773
    Billets dans le blog
    10
    Par défaut
    Tu peux faire un SetLength progressif du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     
    var
      i1 : integer ;
      ar1 :  array of integer ;
      pos1 : integer ;
      long1 : integer ;
     
    begin
      pos1 := 0 ;
      long1 := 10 ;
      setLength(ar1,long1) ;
      for i1 := 1 to 100 do
      begin
          if pos1 >= high(ar1)- 1 then
          begin
            long1 := long1 * 120 div 100 ;  // +20%
            setLength(ar1, long1);
          end ;
          ar1[pos1] := 10000 + i1 ; // juste pour avoir une valeur
          pos1 := pos1 + 1 ;
      end ;
    end;

  9. #9
    Membre éclairé
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    707
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 707
    Points : 777
    Points
    777
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    tu te prends trop la tête alors !

    la théorie et la pratique ... imaginer charger 10 millions de record n'est même pas imaginable, pense que si ton record occupe 200 octets, tu arrives arrive à 2Go mémoire, le problème sature en Win32 !
    10 millions x 200 octets, ça ne ferait pas plutôt 2 milliards d'octets, soit un peu en dessous de 2 Go (2147483648 o) ? Ça passe largement :-D

    Un tableau de 10 Integers, c'est déjà 32 octets, donc 320Mo !
    cela monte très vite !
    Hmm, les chiffres et toi... Ca ne serait pas plutôt 3,2 milliards d'octets ? 10*32*10000000...

    Bref, j'ai transformé mon code pour utiliser des SetLength à la place, pas de problème ça fonctionne mais gare à ne pas oublier une initialisation de la longueur quelque part !

    @ALWEBER: oui je sais, mais inutile dans mon cas, la taille du tableau de chaque enregistrement est définie une fois pour toute pour toute la procédure. C'était juste un problème d'initialisation.

  10. #10
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 577
    Points : 25 225
    Points
    25 225
    Par défaut
    Citation Envoyé par GoustiFruit Voir le message
    Hmm, les chiffres et toi...
    Tout dépend sur Go ou Gio !

    1 Go = 1 000 000 000 o
    1 Gio = 1 073 741 824 o

    Citation Envoyé par GoustiFruit Voir le message
    Citation Envoyé par ShaiLeTroll Voir le message
    Un tableau de 10 Integers, c'est déjà 32 octets, donc 320Mo !
    cela monte très vite !
    Hmm, les chiffres et toi... Ca ne serait pas plutôt 3,2 milliards d'octets ? 10*32*10000000...
    Mais d'où ai-je sorti ce 32 ??? c'était 40 !

    10 000 000 records
    1record = 1 tableau de 10 integer donc 10 x 4o donc 40o
    donc 40 x 10 000 000 = 400Mo !

    EDIT : je suis bête, 4o = 32bit, je me suit mis à compter en bit, et tu as raison 400 000 000o = 3 200 000 000 bit


    Citation Envoyé par GoustiFruit Voir le message
    gare à ne pas oublier une initialisation de la longueur quelque part !
    POO, Objet et Constructeur au lieu de Record !

  11. #11
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 755
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 755
    Points : 13 349
    Points
    13 349
    Par défaut
    Oui mais euhh... un integer c'est 4 octets (en 32 bits)

  12. #12
    Membre éclairé
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    707
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 707
    Points : 777
    Points
    777
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    POO, Objet et Constructeur au lieu de Record !
    Oui mébon, c'est un besoin très ponctuel sur une pitit' procédure

    Citation Envoyé par Andnotor
    Oui mais euhh... un integer c'est 4 octets (en 32 bits)
    C'est bon, tu nous a bien foutu la honte !

    Mais il me semblait bien que les chiffres de Shai étaient fantaisistes, dans mon appli je manipule des tableaux de millions d'entiers sans problème, et je n'ai pas d'explosion de la conso mémoire. Ça ne représente que quelques Mo, aujourd'hui toutes les applis utilisent bien plus que ça !

  13. #13
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 448
    Points
    28 448
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    C'est un simple tableau dynamique, c'est ultra standard comme pratique !
    tout à fait

    Citation Envoyé par ShaiLeTroll Voir le message
    ...
    Deux méthodes,
    soit le SetLength pour le tableau dynamique
    soit une Partie variable des enregistrements, je pense que tu n'as pas envisagé cela avec ma démo :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    procedure Test;
    type
      TMonRecord = record
        case integer of
          10: (Tableau10: array[0..9] of Integer;); 
          20: (Tableau20: array[0..19] of Integer;);
          30: (Tableau30: array[0..29] of Integer;);
      end;
    ?????!!!! tu me fais quoi là Shai ?????!!!

    tout cela pour utiliser Low() et High() ?! c'est assez horrible

  14. #14
    Membre éclairé
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    707
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 707
    Points : 777
    Points
    777
    Par défaut
    Certes pour le tableau dynamique, mais le truc était que tous les enregistrements devaient avoir un tableau de même longueur - longueur passée en paramètre à la procédure - donc je pensais qu'au lieu d'initialiser le tableau pour chaque nouvel enregistrement avec un SetLength, j'aurais pu l'initialiser dans la déclaration même du type record, une fois pour toute, en fonction du dit paramètre.

  15. #15
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 755
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 755
    Points : 13 349
    Points
    13 349
    Par défaut
    Delphi reste du code natif et ne peut gérer (optimiser) que ce qu'il connait au moment de la compilation

  16. #16
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 577
    Points : 25 225
    Points
    25 225
    Par défaut
    Citation Envoyé par Paul TOTH Voir le message
    ?! tu me fais quoi là Shai ?! c'est assez horrible
    Je te confirme, c'était juste pour montrer ce qui existait !
    Surtout que cela consomme toujours la taille du plus grand tableau, ce n'est pas économique, un SetLength ou une bonne TList c'est effectivement mieux !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Requête avec champ NULL simple quote
    Par tidou95220 dans le forum Requêtes
    Réponses: 2
    Dernier message: 13/07/2012, 13h15
  2. problème de Wshshell.run avec quotes & variable
    Par frenchlion dans le forum VBScript
    Réponses: 8
    Dernier message: 29/11/2011, 17h35

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo