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 :

Accès d'une valeur dans un tableau via son pointeur et le size_of de la valeur


Sujet :

Langage Delphi

  1. #1
    Candidat au Club
    Inscrit en
    Février 2014
    Messages
    4
    Détails du profil
    Informations forums :
    Inscription : Février 2014
    Messages : 4
    Points : 2
    Points
    2
    Par défaut Accès d'une valeur dans un tableau via son pointeur et le size_of de la valeur
    Bonjour à tous !

    Fervent lecteur des solutions de ce forum, je n'ai point trouvé de solution à mon problème.

    Je cherche à créer diverses fonctions "génériques" sous Delphi 5 (oula oui un ancêtre ^^') pour traiter des tableaux quelconques avec un unique algorithme.

    Par exemple un algorithme de tri, ou un de recherche ou quoi que ce soit qui pourrait avoir en commun une logique.

    Pour ce faire j'utilise des fonctions globales qui ont en paramètres des fonctions Templates

    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
     
     
    //ma fonction template de comparaison
    Fonction_De_Comparaison = function(Val1, Val2: Pointer): integer; 
     
    //ici une utilisé pour comparer deux integers.
    function Compare_Integer_ET_Integer(Val1, Val2: Pointer): integer;
     
    function Compare_Integer_ET_Integer(Val1, Val2: Pointer): integer;
    begin
      try
        result := PInteger(Val1)^ - PInteger(Val2)^;
      except
        result := 0;
      end;
    end;

    Ainsi je peux théoriquement créer un algorithme unique mais nuancé par une fonction de comparaison dédié au type de tableau qu'on lui passe

    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
    39
    40
     
     
    function Trouve_Element_Tab_Trie(Tab : Pointer;Val : pointer; SizeofRecord, SizeOfTab : integer; Fct_Cmp  : Fonction_De_Comparaison) : integer;
     
    //algo qui se base sur la dichotomie
    function Trouve_Element_Tab_Trie(Tab : Pointer; Val : pointer; SizeofRecord, SizeOfTab : integer; Fct_Cmp  : Fonction_De_Comparaison) : Integer;
    var
      Trouve        : boolean;
      inf, sup, Cur : integer;
      ptr_tmp       : Pointer;
    begin
      Trouve := false;
      try
        inf := 0;
        sup := SizeOfTab - 1;
     
        Cur := 0;
        if SizeOfTab = 0 then
        begin
          ptr_tmp := ptr(integer(Tab) + Cur * SizeofRecord);
          if Fct_Cmp(Val, ptr_tmp) > 0 then Cur := 1;
        end else
        begin
          while (inf <= sup) and not Trouve do
          begin
            Cur := (inf + sup) div 2;
            ptr_tmp := ptr(integer(Tab) + Cur * SizeofRecord);
            if      Fct_Cmp(Val, ptr_tmp) = 0  then Trouve := true
            else if Fct_Cmp(Val, ptr_tmp) > 0  then inf := Cur + 1
                                                 else sup := Cur - 1;
          end;
          ptr_tmp := ptr(integer(Tab) + Cur * SizeofRecord);
          if (Cur <= SizeOfTab - 1) and (Fct_Cmp(Val, ptr_tmp) < 0) then inc(Cur);
        end;
     
        result := Cur;
      except
        result := -1;
      end;
    end;

    D'après ma logique je pensais pouvoir utiliser la même fonction si dessus pour un tableau de Integer ou un tableau de String ou même avec des Records généraux en paramétrant uniquement la fonction de comparaison.

    Mon problème est au niveau de l’accès des éléments, Pour moi, ce qui suit permet d'avoir un pointer directement sur l'élément numéro 'Cur' dans mon tableau. Puis avec le bon Cast devant on récupère la valeur.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     ptr_tmp := ptr(integer(Tab) + Cur * SizeofRecord);

    Mais avec un simple exemple de tableau d'entier, ou je remarque bien qu'on passe d'une adresse $7000 à $7040 pour accéder au 10ème element, le cast PInteger($7040)^ me renvoie une valeur juste incohérente.

    Est ce que j'ai mal compris quelque chose? ou alors les tableaux dynamiques ne s'accèdent pas linéairement ?

    Merci d'avance pour vos lumières

  2. #2
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 560
    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 560
    Points : 25 156
    Points
    25 156
    Par défaut
    sur un tableau de string, la fonction Fct_Cmp ne sera pas évidente à écrire, cela va te donner l'adresse de la chaine, la prudence voudrait que tu exploites en PChar sur coup
    Normalement, un tableau d'entier se manipule très bien via un PInteger, peut faire une boucle et utiliser Inc() pour incrémenter

    Attention confusion 10eme élément en base zéro c'est l'indice 9
    l'indice 10 est le 11eme élément

    Code tab : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    0 - $7000
    1 - $7004
    2 - $7008
    3 - $7012
    4 - $7016 - Leeloo ... le 5ème élément 
    5 - $7020
    6 - $7024
    7 - $7028
    8 - $7032 
    9 - $7036 - 10ème 
    10 - $7040 - 11ème

  3. #3
    Candidat au Club
    Inscrit en
    Février 2014
    Messages
    4
    Détails du profil
    Informations forums :
    Inscription : Février 2014
    Messages : 4
    Points : 2
    Points
    2
    Par défaut
    Bonjour et merci pour la réponse extrêmement rapide ShaiLeTroll

    Effectivement j'ai été un peu étourdit sur mon exemple du 10ème élément du tableau ^^ Cependant dans mes tests je suis certain d'avoir été dans les bornes de mon tableau et d'inspecter un élément dont je connaissais la valeur.

    Si je refais un exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
     
    Tab_Integer = Array of Integer; // Tableau d'entier
    PTab_Integer = ^Tab_Integer; // pointer sur le Tableau D'entier
     
     
    Tab : PTab_Integer;
     
    setlength(Tab^, 100);
     
    //Normalement on devrait avoir la même valeur entre
     
    Tab^[i] = Pinteger(ptr(Integer(Tab) + i * SizeOf(Integer)))^ ?

    Parce que dans mes objectifs, le INTEGER qui définit le tableau pourrait très bien etre un record du type

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    MyRecord = record
    Val_1 : Integer;
    Val_2 : Double;
    Val_3 : string;
    End;
     
    PMyRecord = ^MyRecord;
    et ainsi dans mes fonctions de tri, je pourrais par exemple définir un état de comparaison suivant une des valeurs comme

    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
     
     
    function Compare_Integer_ET_MyRecord(Val1, Val2: Pointer): integer;
    begin
        result := PInteger(Val1)^ - PMyRecord(Val2)^.Val_1;
    end;
     
    function Compare_Real_ET_MyRecord(Val1, Val2: Pointer): integer;
    begin
        result := trunc(PDouble(Val1)^ - PMyRecord(Val2)^.Val_2);
    end;
     
    function Compare_Char_ET_MyRecord(Val1, Val2: Pointer): integer;
    begin
        result := CompareStr(PChar(Val1)^, PMyRecord(Val2)^.Val_3);
    end;
    et ainsi appeler ma fonction généraliste juste en précisant quel méthode de comparaison elle doit utiliser.
    ( J'ai écris ce code sans le compiler, il y a peut être des erreurs mais c'est pour la logique de mon énoncer et ce que j'essaye d'obtenir)



    NB : Oui je me méfie aussi des Strings, j'ai eu plusieurs soucis avec elle quand je faisais des copier de record et autre manipulation qui me renvoyait parfois des chaines vides...






    DECOUVERTE !

    Bon j'ai fait un bout de code tout simple et j'ai remarqué que ca marche dans ce cas la :

    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
     
    procedure TForm1.BTN1Click(Sender: TObject);
    var
      i : integer;
      Tab : PTab_Integer;
    begin
      Randomize();
      New(Tab);
      setlength(Tab^, 20);
     
      for i := 0 to High(Tab^) do Tab^[i] := random(50);
      mmo1.Lines.Clear;
      mmo2.Lines.Clear;
      //Normalement on devrait avoir la même valeur entre
      for i := 0 to Length(Tab^)  -1 do
      begin
        mmo1.Lines.Add(IntToStr(Tab^[i]));
        mmo2.Lines.Add(IntToStr(Pinteger(ptr(Integer(Tab) + i * SizeOf(Integer) + 20))^));
      end;
     
    end;
    Dans ce cas mes deux mémos contiennent les memes infos.

    Dans le cas de Double, c'est :

    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
     
    procedure TForm1.BTN1Click(Sender: TObject);
    var
      i : integer;
      Tab : PTab_double;
    begin
      Randomize();
      New(Tab);
      setlength(Tab^, 20);
     
      for i := 0 to High(Tab^) do Tab^[i] := random(50);
      mmo1.Lines.Clear;
      mmo2.Lines.Clear;
      //Normalement on devrait avoir la même valeur entre
      for i := 0 to Length(Tab^)  -1 do
      begin
        mmo1.Lines.Add(FloatToStr(Tab^[i]));
        mmo2.Lines.Add(FloatToStr(Pdouble(ptr(Integer(Tab) + i  * Sizeof(Double) + 20))^));
      end;
     
    end;
    Du coup j'ai trouvé comment obtenir mes informations via des pointers non typé *_* Mais j'ai aucune idée du pourquoi faut décaler de 20 octets ? Quelqu'un saurait à titre de culture ? Delphi code ses tableaux avec 20 octets ou il met des infos qui lui est utile ? elles sont récupérable via certains opérateurs, comme pour récupérer la taille, le type de données ou je ne sais quoi ?

  4. #4
    Candidat au Club
    Inscrit en
    Février 2014
    Messages
    4
    Détails du profil
    Informations forums :
    Inscription : Février 2014
    Messages : 4
    Points : 2
    Points
    2
    Par défaut
    J'ai trouvé mon erreur !!!!!!!!!!!!!!

    J'espère que ca aidera quelqu'un ! Donc mon problème ne venait pas du parcours du tableau mais bien de la façon dont je le passais en paramètre !

    Ceci est correct pour une raison que j'ignore :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Tab : PTab_Integer;
     PInteger(ptr(Integer(Tab) + i  * Sizeof(Integer) + 20))^
    La réelle solution qui marche, à tous les coups, avec n'importe quel tableau

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Tab : PTab_Integer;
    PInteger(ptr(Integer(Tab^) + i  * Sizeof(Integer)))^
    En fait j'ai l'impression qu'on récupère non pas l'adresse du tableau mais l'adresse de l'adresse du tableau dans le premier cas. D'ou le décalage de 20 (surement un coup de chance lors de la compilation)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    //dans ce cas Tab est lui meme un pointer donc pour acceder au pointer pas la peine de faire @tab comme je faisais.
    Tab : Array of Integer;
     
    PInteger(ptr(Integer(Tab) + i  * Sizeof(Integer)))^ //marche

    J'espère que ca aidera qqun qui aurait cherché aussi des infos la dessus ^^

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

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 753
    Points : 13 337
    Points
    13 337
    Par défaut
    Citation Envoyé par rogelja Voir le message
    Mais avec un simple exemple de tableau d'entier, ou je remarque bien qu'on passe d'une adresse $7000 à $7040 pour accéder au 10ème element, le cast PInteger($7040)^ me renvoie une valeur juste incohérente.
    Citation Envoyé par ShaiLeTroll Voir le message
    Code tab : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    0 - $7000
    1 - $7004
    2 - $7008
    3 - $7012
    4 - $7016 - Leeloo ... le 5ème élément 
    5 - $7020
    6 - $7024
    7 - $7028
    8 - $7032 
    9 - $7036 - 10ème 
    10 - $7040 - 11ème
    Oui mais non ! $7040 serait le 17ième élément

    0 - $7000
    1 - $7004
    2 - $7008
    3 - $700C
    4 - $7010
    5 - $7014
    6 - $7018
    7 - $701C
    8 - $7020
    9 - $7024
    10 - $7028
    11 - $702C
    12 - $7030
    13 - $7034
    14 - $7038
    15 - $703C
    16 - $7040

  6. #6
    Candidat au Club
    Inscrit en
    Février 2014
    Messages
    4
    Détails du profil
    Informations forums :
    Inscription : Février 2014
    Messages : 4
    Points : 2
    Points
    2
    Par défaut
    Ahah ouai bien joué Andnotor ^^, Double mistake sur mon exemple qui devait etre simple XD

  7. #7
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 560
    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 560
    Points : 25 156
    Points
    25 156
    Par défaut
    Et j'ai même oublié de compter en Hexadécimal !


  8. #8
    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 : 54
    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 rogelja Voir le message
    J'ai trouvé mon erreur !!!!!!!!!!!!!!

    J'espère que ca aidera quelqu'un ! Donc mon problème ne venait pas du parcours du tableau mais bien de la façon dont je le passais en paramètre !

    Ceci est correct pour une raison que j'ignore :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Tab : PTab_Integer;
     PInteger(ptr(Integer(Tab) + i  * Sizeof(Integer) + 20))^
    La réelle solution qui marche, à tous les coups, avec n'importe quel tableau

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Tab : PTab_Integer;
    PInteger(ptr(Integer(Tab^) + i  * Sizeof(Integer)))^
    En fait j'ai l'impression qu'on récupère non pas l'adresse du tableau mais l'adresse de l'adresse du tableau dans le premier cas. D'ou le décalage de 20 (surement un coup de chance lors de la compilation)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    //dans ce cas Tab est lui meme un pointer donc pour acceder au pointer pas la peine de faire @tab comme je faisais.
    Tab : Array of Integer;
     
    PInteger(ptr(Integer(Tab) + i  * Sizeof(Integer)))^ //marche

    J'espère que ca aidera qqun qui aurait cherché aussi des infos la dessus ^^
    Un "array of" est un pointeur dynamique, contrairement à une "array[x..y] of" qui est un type statique, donc

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Tab_Integer = Array of Integer; // (pointeur sur un) Tableau d'entier
    PTab_Integer = ^Tab_Integer; // pointer sur le (pointer d'un) Tableau D'entier
    du coup le code ci-dessous ne devrait pas fonctionner, sauf si par change le tableau se trouve à 20 octets de son pointeur
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Tab : PTab_Integer;
     PInteger(ptr(Integer(Tab) + i  * Sizeof(Integer) + 20))^
    le code ici est valide, Tab^ est bien l'adresse du tableau dynamique, on lui ajoute i éléments, c'est un PInteger dont on lit la valeur
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Tab : PTab_Integer;
    PInteger(ptr(Integer(Tab^) + i  * Sizeof(Integer)))^

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

Discussions similaires

  1. Réponses: 3
    Dernier message: 23/03/2015, 11h12
  2. Réponses: 5
    Dernier message: 10/11/2006, 11h00
  3. ecrire des valeurs dans un tableau via formulaire
    Par kenny49 dans le forum Général JavaScript
    Réponses: 3
    Dernier message: 07/07/2006, 10h23
  4. Rechercher une valeur dans un tableau
    Par pafi76 dans le forum Access
    Réponses: 2
    Dernier message: 29/06/2006, 14h23
  5. Réponses: 21
    Dernier message: 28/02/2006, 15h23

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