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 C++ Discussion :

[Langage] question de notations


Sujet :

Langage C++

  1. #1
    Membre éprouvé
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Par défaut [Langage] question de notations
    je sais que c'est qu'une question de notations, mais est il plus logique d'écrire:

    que
    car *t signifie que *t est en fait un double et que t point vers un double.

    double* n'est pas un type de C++.


    En revanche, la notation:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    double **tab=new double*[10000];
    signifie que *tab est un tableau de pointeurs.
    par contre, comment comprendre : double*[10000]

  2. #2
    Membre chevronné
    Profil pro
    Inscrit en
    Novembre 2005
    Messages
    349
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : Suisse

    Informations forums :
    Inscription : Novembre 2005
    Messages : 349
    Par défaut
    A mon avis c'est personnel. Moi je préfère:
    J'ai une variable qui s'appelle "t", et son type est "pointeur vers double".


    J'ai une variable qui s'appelle "tab", et son type est "pointeur vers pointeur vers double".


    J'ai un tableau de taille 10000 qui s'appelle "tab", et qui contient des "pointeur vers double".


    Dans la pratique, depuis que j'ai découvert les conteneurs de la STL, je me rappel pas d'avoir écrit un programme avec un tableau, sauf quand j'utilise une bibliothèque dont les fonctions prennent des tableaux en paramètre. Dans ce cas je travail avec la STL et convertit en tableau au dernier moment.

    Edit: Pour moi *t c'est ça:

    Encore une fois, c'est personnel.

  3. #3
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 392
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 392
    Par défaut
    C'est compliqué, mais il ne faut pas oublier que:
    ne déclare pas b en tant que pointeur sur double, mais en tant que double.
    Par contre, ceci le fait:
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    typedef double *pdouble;
    pdouble a, b;
    De nos, jours, j'ai tendance à mette un espace des deux côtés de l'étoile.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  4. #4
    Alp
    Alp est déconnecté
    Expert confirmé

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Par défaut
    Citation Envoyé par deubelte Voir le message
    je sais que c'est qu'une question de notations, mais est il plus logique d'écrire:

    que
    car *t signifie que *t est en fait un double et que t point vers un double.

    double* n'est pas un type de C++.
    C'est comme ça je le vois en tout cas


    Citation Envoyé par deubelte Voir le message
    En revanche, la notation:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    double **tab=new double*[10000];
    signifie que *tab est un tableau de pointeurs.
    par contre, comment comprendre : double*[10000]
    Un tableau de 10 000 pointeurs vers double ?

  5. #5
    Membre éprouvé
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Par défaut
    bien sur que c'est un tableau de 1000 points, mais ce qui me gène c'est:

    et même plutot l'écriture:

  6. #6
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 634
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 634
    Par défaut
    Salut,

    Il faut bien comprendre que le pointeur est, quelque part, un "type" en lui-même.

    En effet, ca permet de déclarer une variable qui va contenir... l'adresse à laquelle on trouvera (normalement) effectivement la valeur souhaitée.

    Ce "type", bien que ce n'en soit pas réellement un, dispose d'une taille précise et connue qui correspond à un nombre de bits suffisant pour représenter l'ensemble des adresses mémoire accessibles.

    Que tu place, dans la déclaration d'une variable de type "pointeur vers..." ou de type "pointeur de pointeur vers...", l'étoile (les étoiles) juste à coté du type en question ou juste à coté de l'identifiant de la variable n'a en définitive aucune importance et tient de l'habitude personnelle.

    Ce qui importe, c'est que, quand tu déclare une variable sous la forme
    tu déclare tab comme étant une variable représentant l'adresse mémoire à laquelle l'ordinateur trouvera(normalement)... l'adresse mémoire où il trouvera un double.

    Tu peux donc demander à l'ordinateur d'allouer dynamiquement de la mémoire pour représenter un nombre (sensiblement) quelconque de... pointeurs sur des double, sous la forme de
    Ensuite, tu pourra demander à l'ordinateur d'allouer, pour chaque pointeur sur des double, la mémoire suffisante pour y placer un (autre) nombre (sensiblement) quelconque de double sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    for(int i = 0;i<X;++i)
        tab[i] = new double[Y];
    où y représente le nombre, éventuellement calculé, de double dont tu veux disposer de manière contigue

    Maintenant, si tu sais très bien qu'il te faudra disposer de X pointeurs vers double, et que ce nombre est "ferme et définitif" (que tu ne devra jamais décider d'en avoir X+1), tu peux demander à ce que l'ordinateur réserve la mémoire suffisante de manière non dynamique, sous la forme de
    ce qui revient à lui demander de "créer un tableau dans lequel je trouverai X pointeur sur des double contigus en mémoire", tableau que tu pourra ensuite initialiser avec... les adresses auxquels trouver des... tableaux de double sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    for(int i = 0;i<X;++i)
        tab[i] = new double[Y];
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  7. #7
    Membre éprouvé
    Inscrit en
    Novembre 2006
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 073
    Par défaut
    merci pour ta rep

    Toujours dans les pointeurs/adresses, quand je lis la valeurs d'un tableau dans la fenetre variable locale, je lis par ex:
    0x00284cb0

    je sais que c'est de l'hexa, mais si on le transforme en entier normal, cela contient quoi comme information?
    est-ce que 0x00284cb1 sera la case suivante?

  8. #8
    Membre chevronné
    Profil pro
    Inscrit en
    Novembre 2005
    Messages
    349
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : Suisse

    Informations forums :
    Inscription : Novembre 2005
    Messages : 349
    Par défaut
    Citation Envoyé par deubelte Voir le message
    merci pour ta rep

    Toujours dans les pointeurs/adresses, quand je lis la valeurs d'un tableau dans la fenetre variable locale, je lis par ex:
    0x00284cb0

    je sais que c'est de l'hexa, mais si on le transforme en entier normal, cela contient quoi comme information?
    est-ce que 0x00284cb1 sera la case suivante?
    C'est l'adresse en mémoire du pointeur. Dans le cas d'un tableau, les éléments sont stockés dans un espace contigu de la mémoire, donc oui si 0x00284cb0 est la n-ième case alors 0x00284cb1 sera la (n+1)-ième case.

    C'est ce qui fait qu'un accès aléatoire dans un tableau a un coût constant, si tu veux le 35ème élément il suffit de rajouter 34 à l'adresse du premier. Il y a une arithmétique des pointeurs qui te permet diverses opérations, intéressant pour travailler sur des tableaux.

  9. #9
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 634
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 634
    Par défaut
    Citation Envoyé par Cheps Voir le message
    C'est l'adresse en mémoire du pointeur. Dans le cas d'un tableau, les éléments sont stockés dans un espace contigu de la mémoire, donc oui si 0x00284cb0 est la n-ième case alors 0x00284cb1 sera la (n+1)-ième case.
    A vrai dire, c'est un peu plus compliqué que cela...

    L'arithmétique des pointeurs assure que, si tu incrémente un pointeur, selon un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    int main()
    {
        int tab[4]; /* tab est un pointeur sur des entiers */
        /* évitons de perdre le pointeur sur le premier élément */
        int *ptrtab=tab;
        ptrtab++;
        /* ...*/
        return 0;
    }
    tu arrivera à la case contigue à celle qui est pointée par le pointeur qui permet de contenir l'élément en question.

    Le problème, c'est que tous les types n'ont pas la même taille...

    C'est à dire que tu a de fortes chances de te rendre compte que l'adresse d'un pointeur sur caractères que tu aurait incrémenté soit effectivement l'adresse de départ +1, mais, à coté de cela, si ton pointeur pointe sur... des entiers, et que l'on considère (pour l'exemple) qu'un entier tient sur 4 bytes, l'incrémentation portera l'adresse à... l'adresse de départ +4.

    Il ne faut donc pas confondre la "case contigue d'un tableau" avec l'adresse à laquelle cette case contigue peut se trouver

    Mais, ceci dit, tu peux être rassuré: quel que soit le type de donnée que tu gère avec un pointeur, le fait d'incrémenter le pointeur t'amenera toujours au début de la variable suivante dans le tableau
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  10. #10
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Par défaut
    Quand tu déclares une variable comme ceci :
    Le type de foo est double[1000]; du moins c'est comme celà qu'on le note à part. (si tu veux faire un typedef, il faut utiliser la même syntaxe que pour les déclarations de variables)

    Pourquoi alors on écrit pas
    C'est tout simplement parce que la syntaxe de C en a décidé autrement. C'est moche, mais c'est comme ça.

    À noter qu'il faut pouvoir distinguer les tableaux de pointeurs, double*[1000], des pointeurs vers des tableaux, double(*)[1000] :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    double* foo[1000];
    double (*bar)[1000];
    Avec ça, tu devrais être convaincu que la syntaxe pour définir des types en C ou C++ est tout simplement horrible.
    Quoiqu'on pourrait aussi écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    array< pointer<double>, 1000 > foo;
    pointer< array<double, 1000> > bar;
    Finalement c'est pas si mal...

  11. #11
    Membre chevronné
    Profil pro
    Inscrit en
    Novembre 2005
    Messages
    349
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : Suisse

    Informations forums :
    Inscription : Novembre 2005
    Messages : 349
    Par défaut
    Oui koala a raison, je me suis un peu emmêlé les pinceaux. En fait si tu incrémentes ton pointeur (ptr++ ou ptr = ptr+1) tu auras bien le prochain élément, mais l'incrément réel de l'adresse dépend de la taille de l'élément, donc ton adresse sera incrémentée de sizeof(ton type).

  12. #12
    Membre éprouvé
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    1 537
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Juillet 2006
    Messages : 1 537
    Par défaut
    Et encore, cela dépend de comment ton compilo fait joujou avec les alignements. Mais de base, c'est vrai.

  13. #13
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Par défaut
    Non, ça ne dépend pas.
    T* ptr; ptr += i; est toujours équivalent à (char*)ptr += i*sizeof(T);

  14. #14
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 392
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 392
    Par défaut
    Citation Envoyé par loufoque Voir le message
    (char*)ptr += i*sizeof(T);
    Ça compile, ça ?
    Peut-être que oui, mais dans tous les cas c'est illisible. Je suis pour restreindre les += aux endroits où la signification est évidente.

    Par contre, ça équivaut bel et bien à ptr = (T*)( ((char*)ptr) + i*sizeof(T) ); donc sur le fond ton argument tient parfaitement.

    Quant au coup des alignements, on ne le voit jamais sur un pointeur de type simple. Mais pour des structures, c'est le sizeof de la structure qui prend en compte les alignements : par exemple, sizeof (struct { int i, char c }) a de grandes chances d'être égal à 8 et non 5, sur une machine 32 bits.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  15. #15
    Rédacteur
    Avatar de Bakura
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2005
    Messages
    1 386
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 386
    Par défaut
    Puisque l'on parle de choses très laides ici, je me suis toujours posé une question. Lorsque l'on souhaite passer un tableau de type C de taille fixe par exemple (alors je sais qu'il existe std::tr1::array, mais je trouve son usage vraiment lourd à l'écriture, et puis tant bien même qu'il ne soit pas supporté), on passe le pointeur vers le premier élément. Mais y a t-il une différence au niveau du compilateur de faire ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    float myTab[4] = {...};
     
    MyFunc (myTab);
    MyFunc (&myTab[0]);
    Le code généré est-il le même ?

  16. #16
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 634
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 634
    Par défaut
    Cela risque fort de dépendre des optimisations du compilateur, mais le code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void func(float* f)
    {
        f[0]=0.0f;
    }
    void foo()
    {
        float f[3];
        func(f);
        func(&f[0]);
    }
    est, chez moi, transformé, version assembleur, en
    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
    	.file	"main.cpp"
    	.text
    .globl __Z4funcPf
    	.def	__Z4funcPf;	.scl	2;	.type	32;	.endef
    __Z4funcPf:
    LFB2:
    	pushl	%ebp
    LCFI0:
    	movl	%esp, %ebp
    LCFI1:
    	movl	8(%ebp), %edx
    	movl	$0x00000000, %eax
    	movl	%eax, (%edx)
    	leave
    	ret
    LFE2:
    .globl __Z3foov
    	.def	__Z3foov;	.scl	2;	.type	32;	.endef
    __Z3foov:  /* ce qui suit est la fonction foo() */
    LFB3:
    	pushl	%ebp
    LCFI2:
    	movl	%esp, %ebp
    LCFI3:
    	subl	$16, %esp
    LCFI4:
    	leal	-12(%ebp), %eax
    	pushl	%eax
    LCFI5:
    	call	__Z4funcPf    /* premier appel de la fonction */
    	addl	$4, %esp
    	leal	-12(%ebp), %eax
    	pushl	%eax
    	call	__Z4funcPf  /* deuxieme appel de la fonction */
    	addl	$4, %esp
    	leave
    	ret
    LFE3:
    Cela semble pour le moins identique, si l'on excepte le fait que l'on quitte foo apres le deuxième appel

    [EDIT] ceci dit, seul l'utilisation de &tab[0] est susceptible de fonctionner si tu travaille avec un std::vector (tab.begin() renvoyant un... itérateur (constant ou non, selon le cas)
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  17. #17
    Membre chevronné
    Profil pro
    Inscrit en
    Novembre 2005
    Messages
    349
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : Suisse

    Informations forums :
    Inscription : Novembre 2005
    Messages : 349
    Par défaut
    Ou alors &(tab.front())

  18. #18
    Membre éprouvé
    Avatar de NiamorH
    Inscrit en
    Juin 2002
    Messages
    1 309
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 1 309
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    De nos, jours, j'ai tendance à mette un espace des deux côtés de l'étoile.
    Pareil, et le const entre les deux premiers.

  19. #19
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Citation Envoyé par Bakura Voir le message
    Mais y a t-il une différence au niveau du compilateur de faire ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    float myTab[4] = {...};
     
    MyFunc (myTab);
    MyFunc (&myTab[0]);
    Le code généré est-il le même ?
    Si MyFunc prend en paramètre un float*, probablement. Un pointeur est aisément castable en pointeur sur son premier élément.

    Par contre, si par exemple MyFunc est déclaré ainsi (elle pourrait alors se nommer size...) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    template<size_t N>
    size_t MyFunc(float (&array)[N])
    {
      return N;
    }
    Le premier appel retourne 4, le second est illégal.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

Discussions similaires

  1. [Langage] question bête a propos des enum
    Par gronaze dans le forum Langage
    Réponses: 7
    Dernier message: 06/10/2008, 19h38
  2. [langage] question sur tableau
    Par vince2005 dans le forum Langage
    Réponses: 1
    Dernier message: 24/10/2006, 14h12
  3. [langage]question expression reguliere
    Par Fabouney dans le forum Langage
    Réponses: 13
    Dernier message: 27/06/2005, 01h48
  4. [langage] Question débutant compilation PERL
    Par sebbyoguard dans le forum Langage
    Réponses: 5
    Dernier message: 04/09/2004, 19h39
  5. [langage] pb de question reponse
    Par And_the_problem_is dans le forum Langage
    Réponses: 2
    Dernier message: 29/11/2002, 11h59

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