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

 C Discussion :

signification de * lorsqu'il est placé après le terme


Sujet :

C

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    15
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 15
    Par défaut signification de * lorsqu'il est placé après le terme
    Bonjour, voila je suis débutant en C et je souhaiterais connaître la signification de l'opérateur * lorsqu'il est placé après le terme. Pour info je sais qu'il peut soit représenter l'opérateur arithmétique multiplié ou il peut désigner un pointeur.

    Opérateur multiplier: X * Y = XY (jusqu'ici tout va bien!)
    pointeur : *ptr => désigne le contenu de la mémoire située à l'adresse de ptr (la ça va)
    Par contre dans le cas suivant extrait de mon code:

    sourceInfo = &((SourceInstance*)sgInstanceTable.itemTable[index])->sourceInfo;

    dans ce dernier cas à quoi correspond *???

    Merci beaucoup pour vos eclaircissements!

  2. #2
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 499
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 499
    Par défaut
    Bonjour,

    Citation Envoyé par Seb_33 Voir le message
    sourceInfo = &((SourceInstance*)sgInstanceTable.itemTable[index])->sourceInfo;

    dans ce dernier cas à quoi correspond *???
    C'est bien un pointeur. Il faut en fait lire « (SourceInstance*) ». Les parenthèses forment un transtypage (cast) vers le type « pointeur sur un SourceInstance ».

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    15
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 15
    Par défaut
    Merci beaucoup pour ta réponse!!

    sinon comme je suis un véritable débutant peux tu également me donner des informations sur la syntaxe du reste de la phrase?

    sourceInfo = &((SourceInstance*)sgInstanceTable.itemTable[index])->sourceInfo;

    De ce que je comprends:

    & => adresse de la variable entre parenthèse? c'est à dire de "((SourceInstance*)sgInstanceTable.itemTable[index])"

    Est ce que (SourceInstance*)sgInstanceTable.itemTable[index] se lit:
    (SourceInstance*) X sgInstanceTable.itemTable[index]

    Enfin le caractère -> signifie paraît il : variable pointée donc

    sourceInfo est égale à l'adresse de la variable (SourceInstance*)sgInstanceTable.itemTable[index] qui pointe sur source info??

    Enfin comme tu peux le voir j'y comprends pas grand chose, est ce récupérable?? help please!

  4. #4
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    sourceInfo = &((SourceInstance*)sgInstanceTable.itemTable[index])->sourceInfo;
    Tu es confronté à plusieurs notions:
    • les tableaux avec [] (mais ca ne te pose pas de probleme ici)
    • les pointeurs avec "&" et "*"
    • les structures, avec "."
    • les pointeurs de structures, reconnaissables à l'emploi de "->"


    Ici, SourceInstance est un type (que je devine être une structure)
    J'imagine que le type SourceInfo est celui du champ sourceInfo des structures SourceInstance.

    Supposons que la variable si soit un SourceInstance.

    Alors "si.sourceInfo" est un SourceInfo (celui contenu dans si)

    SourceInstance* est un pointeur sur un SourceInstance
    &si est une valeur de ce type.

    sgInstanceTable.itemTable[index] est d'un type arbitraire (celui d'un élément du tableau nommé itemTable, contenu dans la structure sgInstanceTable
    (SourceInstance*)sgInstanceTable.itemTable[index] est cette même valeur, lu comme un SourceInstance* (on dit "convertie en", ou "casté en").
    Les règles de priorité disent en effet que la conversion intervient après l'accès par . et par []

    p->m est l'opérateur "accès au membre m de la structure pointée par p:
    p->m équivaut à (*p).m
    Les priorités sont aussi telles que l'adressage (&a) est moins prioritaire que ->, donc &a->b est en réalité &(a->b) c'est à dire l'adresse du membre b de la structure pointée par a.

    Dans ton cas, on a donc, après parenthésage complet:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    sourceInfo =
    &(
        (
            (SourceInstance*) (sgInstanceTable.itemTable[index])
        )
        ->
        sourceInfo
    );
    J'en déduis que le type de sourceInfo est (const?) SourceInfo* (ou void*, peut-être, mais il manquerait une conversion)

  5. #5
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    caractère -> signifie paraît il : variable pointée donc
    a->b : a est un pointeur sur une structure qui contient un champ b
    et a->b permet d'accéder au champ b via l'adresse de la structure.
    Cette expression est équivalente à (*a).b (parenthèses obligatoires) mais plus simple à lire.

    On peut tirer pas mal d'informations avec l'expression sourceInfo = &((SourceInstance*)sgInstanceTable.itemTable[index])->sourceInfo;.
    1-
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    sourceInfo = &((SourceInstance*)sgInstanceTable.itemTable[index])->sourceInfo;
    // est de la forme
    sourceInfo = &(x)->sourceInfo
    // équivalente à
    sourceInfo  = &(x->sourceInfo)
    //ou
    sourceInfo  = &x->sourceInfo
    2-
    Alors x est un pointeur sur une structure contenant un champ sourceInfo et x == (SourceInstance*)sgInstanceTable.itemTable[index] .
    A cause du cast, ce pointeur x est du type SourceInstance* donc SourceInstance comporte un champ sourceInfo (d'un type T1 inconnu)

    3-
    Ce cast fait que sgInstanceTable.itemTable[index] est d'un type inconnu, mais probablement un pointeur sur T2 (peut être un void*) ou un entier (j'espère que non, ce serait de la bidouille)
    sgInstanceTable.itemTable est donc un tableau de pointeurs sur T2
    sgInstanceTableest donc une structure (appelons la InstanceTable) comportant un tableau de pointeurs sur T2

    Un exemple qui résume ce que cette expression nous apprend :
    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
    #include <stdio.h>
    typedef int T1 ;  // par exemple
    typedef void T2 ; // par exemple
    typedef struct
    {
       T1 sourceInfo;
       //.....
    } SourceInstance;
     
    typedef struct
    {
       T2 * itemTable[3]; //Il y a aussi la possibilité T2** itemTable;
       //....
    }InstanceTable;
     
    // En global pour initialiser les données de l'exemple
    SourceInstance s1 ={1};
    SourceInstance s2 ={2};
    SourceInstance s3 ={3};
     
    int main(void)
    {
      InstanceTable sgInstanceTable = {&s1, &s2,&s3};
      T1 * sourceInfo ;
      int index = 1 ;
     
      sourceInfo = &((SourceInstance*)sgInstanceTable.itemTable[index])->sourceInfo;
      printf("%d", *sourceInfo);
      return 0;
    }
    qui affiche '2'

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    15
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 15
    Par défaut
    Merci beaucoup d'avoir pris le temps de me répondre et pas à l'arrache en plus! ça fait vraiment plaisir! Bon j'ai quelques notions de bases (je sais ce qu'est un pointeur depuis peu de temps) donc n'ayant pas l'habitude de manipuler ces notions c'est pas hyper simple, en gros je comprends chaque phrase indépendammentn maintenant faut que je fasse le lien entre elles, ça va le faire! après je pense revenir avec des questions

  7. #7
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    15
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 15
    Par défaut
    Citation Envoyé par leternel Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    sourceInfo = &((SourceInstance*)sgInstanceTable.itemTable[index])->sourceInfo;
    Si j'ai bien compris pour chacun des membres:
    Source instance est une structure contenant le champ sourceInfo
    SourceInstance* est un pointeur de type sourceInstance donc un type structure
    sgInstanceTable est une structure contenant le champ itemTable
    itemTable est un champ de type inconnu contenant lavariable index qui est icic un tableau

    Cependant j'ai du mal à comprendre la notion de type que vous manipulez avec dextérité! Pour moi un type est soit (int ou float ou double ou const ou char). Après une rapide recherche j'ai découvert qu'on pouvait créer des type à sa guise avec "Typedef" c'est ça?

    Vous dites que a -> b signifie que a est un pointeur sur une structure qui contient un champ b, ramener à mon expression cela signifie que:

    SourceInstance* est le pointeur sur la structure sgInstanceTable.item[index] qui contient le champ sourceInfo? si j'ai bien compris se sont les structures qui contiennent des champs, le . signifiant qu'il s'agit d'une structure, je comprends que c'est la structure sgInstanceTable.item[index] qui contient le champ sourceInfo et que cette structure est de type SourceInstance défini par un "Typedef" quelquepart...c'est donc la que je ne suis plus... Et en plus aprèstout ça on rajoute un & devant donc la variable locale sourceinfo reçoit au final une adresse????

    NB: Je pense être perdu dans l'espace intergalactique

  8. #8
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    En gros, oui.

    Citation Envoyé par Seb_33 Voir le message
    NB: Je pense être perdu dans l'espace intergalactique
    Dans ce cas, tu as peut-être besoin d'informations complémentaires.

    Toute valeur a un type. Par exemple, 12 est un int, et '\0' un char.
    Chaque variable possède un type qui indique quelles valeurs peuvent y être mises. (et comment le compilateur doit gérer le bout de mémoire qu'elle désigne...)

    Un type peut être un type de base: int, long, float, void...
    Ce peut aussi être une structure, une union ou une énumération.
    Les tableaux et les pointeurs sont des types construits sur un autre: int*, double[]. (j'en profite pour signaler que l'instruction int * i; se compile en *i est un int, ce qui signifie que int * i, j; déclare *i et j sont deux int, j ne sera pas un pointeur de int, alors que (int*) i,j; devrait déclarer i et j sont deux int*)
    Enfin, une signature de fonction est un type, par exemple int ()(int, int) est une fonction prenant deux entiers et retournant un entier.

    une énumération prend ses valeurs parmi un nombre fini (et généralement petit) de valeurs
    une union entasse plusieurs champs à la meme adresse
    une structure regroupe dans un meme "sac" plusieurs variables
    un pointeur est une variable contenant l'adresse d'une autre. le type des valeurs pointées fait partie du type des pointeurs.


    Un type peut être complété par quelques propriétés:
    • const rend le type à sa gauche non modifiable, ou à défaut, celui de droite
      const int* == (const int)* == (int const)* == int const * sont des syntaxes du type d'un "pointeur (variable) vers un entier constant"
      int * const == (int*) const sont des syntaxes du type "pointeur constant vers un entier (variable)"
    • volatile signifie qu'il existe peut-être un moyen externe de modifier cette variable

    [*]static rend la variable visible uniquement à l'unité de compilation (en gros, le .c et ses en-têtes et leurs en-têtes, récursivement). Cela n'est utile que pour cacher des détails d'implémentations. Il ne faut normalement pas utiliser static dans un en-tête.

    Enfin, certains types sont convertibles vers d'autres, par exemple:
    • int* vers void*
    • void* vers char*
    • int vers long


    Dans le cas d'une structure, beaucoup de chose sont faisables:
    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
    /* création d'un type struct */
    struct type_structure {
        int champ1;
        int champ2;
    };/* point virgule important */
    
    /* déclaration d'une variable */
    struct type_structure structure;
    /* écriture dans la variable */
    structure.champ1 = 2;
    /* déclaration-initialisation */
    struct type_structure structure2={3, 5};
    
    /* structure anonyme (rarement utile) */
    struct {int champ1; int champ2};
    
    /* combinaison création de type et déclaration de variable */
    struct autre_type_structure{int champ1; int champ2} autre_structure={3, 5};
    /* ici, struct autre_type_structure est un type utilisable par la suite... */
    
    struct {int champ1; int champ2} autre_structure_anonyme={3, 5};
    /* ici, le type reste anonyme */
    
    /* utilisation de typedef pour définir un type: */
    typedef struct autre_type_structure autre_structure_t;
    autre_structure_t autre_structure2 = {4, 5};/* pas de mot-clé struct */
    Pour plus de clarté, et pour une meilleur réutilisabilité, les types peuvent et devraient être défini dans des en-têtes, qui seront inclus par les codes les utilisant (comme c'est le cas de time_t dans <time.h>)

    Tu dois avoir plus haut dans ton code des définitions de ce genre, ou des #include "..."

    Une partie du "jeu" de la programmation est de concevoir le bon ensemble de données, et la bonne manière de les représenter, pour simplifier l'écriture du programme.

    Comprendre la manipulation des types est important, et permet souvent de clarifier les codes. Ce en quoi, la ligne que tu nous indique est mal faite, parce que le parenthésage n'est pas assez explicite.

    PS: Quand on devient malchanceux, on peut rencontrer des déclarations amusantes/tordues
    une fonction "function_factory" qui prend
    un pointeur d'entier (une taille modifiable),
    un pointeur de tableau de pointeurs de fonction prenant en argument un pointeur de chaine de caractere, une entier, une chaines de caractere, et un nombre variable d'argument et retournant un entier,
    et retournant un code d'erreur personnalisé, représenté par une structure déclarée pour l'occasion donne:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    struct function_factory_error{int code; char const * message;}
    function_factory(
       int *nbfunctions,
       ( ( int ()(char**, int, char const*, ...) )[]) *functions
    );
    Et celui-là, je l'ai vraiment rencontré.

    Le pointeur donné en argument de functions recevait un tableau alloué par function_factory et contenant entre autre snprintf, mais aussi des fonctions que je devais tester.
    Avec quelques typedefs, ont peut arriver à:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    typedef struct {int code; char const * message;} fferror_t;
    typedef int (*test_fp_t)(char**, int, char const*, ...);
    fferror_t function_factory( int *nbfunctions, (test_fp_t[]) *functions);

  9. #9
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    15
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 15
    Par défaut
    Citation Envoyé par leternel Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    typedef struct {int code; char const * message;} fferror_t;
    typedef int (*test_fp_t)(char**, int, char const*, ...);
    fferror_t function_factory( int *nbfunctions, (test_fp_t[]) *functions);
    Merci pour la longue explication et pour ta patience!!

    Donc d'après ce que tu écris là et ce que je comprends:

    On utilise typedef quand on veut typer un éléments que l'on créer comme une structure si l'on souhaite réutiliser le type créer sinon c'est pas nécessaire?

    De ce que j'ai compris de ton dernier code(en gros je mets les commentaires):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    ligne1 : /* Définition de la structure fferror_t et de son type MAIS pas d'initialisation, ici le type est une structure contenant 2 champ 1 entier int et un pointeur de type char constant (qui ne varie pas) */
    ligne2 : /* Définition du tableau test_fp_t et de son type int (c'est à dire qu'il renvoie un entier) */
    ligne3 : /* Appel de la fonction function_factory (qui doit être défini ailleurs dansle code) et qui prend comme arguments le pointeur d'entier (une taille modifiable car pas de présence de const) ainsi que le tableau défini précédemment.*/
    Good ou pas good?

    Question en plus (tant que tu m'envoies pas sur les roses je reste!! lol):

    Je ne comprends pas bien la déclaration suivante:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    typedef int (*test_fp_t)(char**, int, char const*, ...);
    En lisant juste cette ligne un programmeur identifie tout de suite qu'il s'agit d'un tableau? si oui cela provient du fait du dernier parenthésage?

    Concernant la ligne3:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    fferror_t function_factory( int *nbfunctions, (test_fp_t[]) *functions);
    tu juxtaposes le code d'erreur fferror_t et la fonction function_factory => le compilateur identifie tout de suite que fferror_t est le code d'erreur associé à la fonction function_factory?

    => Je retourne sur ma ligne de départ pour vraiment bien la comprendre....

    Encore merci!

  10. #10
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 499
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 499
    Par défaut
    Hello et bravo pour ta persévérance.

    Citation Envoyé par Seb_33 Voir le message
    On utilise typedef quand on veut typer un éléments que l'on créer comme une structure si l'on souhaite réutiliser le type créer sinon c'est pas nécessaire?
    Non, c'est plus simple que ça : typedef signifie « Type Definition » mais sert en fait à créer un alias sur un type existant. Par exemple :


    … te permet de déclarer indistinctement des variables de type « int » ou « entier ». Elles seront de même nature. Dans cet exemple-ci, ça n'a pas beaucoup d'intérêt. Par contre, lorsque ton type est très long ou très compliqué, par exemple, dans le cas d'un pointeur de fonction, ça devient vite très utile, surtout quand cela permet de s'affranchir des subtilités syntaxiques. Par exemple, si je veux définir un pointeur sur une fonction qui elle-même attend en paramètre un pointeur vers une fonction de type « void * fnct (void *) » et qui m'en renvoie un autre en retour, il faudrait écrire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
        void * (*(*ptr)(void *(*)(void*)))(void *)
    … ce qui est parfaitement imbuvable. Par contre, tu peux spécifier deux typedef. Le premier pour simplifier « void * fnct (void *) », qui est une fonction recevant un pointeur void et en renvoyant un autre, et le second pour écrire le type de la fonction qui reçoit un pointeur vers ce genre de fonction et qui en renvoie un autre également :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
        typedef void *         (VoidFunction)    (void *);
        typedef VoidFunction * (SpecialFunction) (VoidFunction *);
    
        SpecialFunction *ptr,
    … ce qui est déjà plus clair.

    Question en plus (tant que tu m'envoies pas sur les roses je reste!! lol):

    Je ne comprends pas bien la déclaration suivante:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    typedef int (*test_fp_t)(char**, int, char const*, ...);
    En lisant juste cette ligne un programmeur identifie tout de suite qu'il s'agit d'un tableau? si oui cela provient du fait du dernier parenthésage?
    Non, ce n'est pas un tableau, mais un pointeur de fonction. En C, les tableaux sont toujours représentés avec des crochets « [ ] ».

    « test_fp_t » est le nom du pointeur. Il pointe en mémoire une fonction variadique (ie: au nombre variable d'arguments) mais renvoyant toujours un int.

    Concernant la ligne3:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    fferror_t function_factory( int *nbfunctions, (test_fp_t[]) *functions);
    tu juxtaposes le code d'erreur fferror_t et la fonction function_factory => le compilateur identifie tout de suite que fferror_t est le code d'erreur associé à la fonction function_factory?
    Non plus. Il s'agit là d'une déclaration de fonction ordinaire. « fferror_t » est donc un nom de type, défini là encore avec « typedef ». La convention veut que les symboles se finissant en « _t » soient des noms de types pour qu'on les reconnaissent, même si le compilateur ne t'oblige en rien à suivre cette règle.

    La plupart du temps, ces types correspondront tous à de simples « int » ou « unsigned int ». Le fait de leur donner un nom explicite a deux avantages :

    • Cela réintroduit un peu de sémantique : ça permet de savoir à l'avance si le numéro qu'on va lire est une taille, un code d'erreur, un booléen, une position quelconque, ou autre chose encore ;
    • Ça permet d'adapter automatiquement le format de l'entier utilisé à l'architecture sur laquelle on travaille.


    Par exemple, strlen(), qui te donne la taille d'une chaîne de caractères, te renvoie un « size_t ». C'est un nom explicite et comme la seule limite d'une chaîne de caractère est l'espace mémoire qui la contient, c'est tout naturellement que l'on va choisir un entier capable de représenter sa capacité. On peut raisonnablement penser que le fichier « types.h » ou l'un de ses dérivés va donc faire un « typedef unsigned int size_t » sur une machine 32 bits et un « typedef unsigned long int size_t » sur une machine 64 bits.


    Pour finir, décortiquons une fois de plus ton expression initiale :

    1. « sgInstanceTable » est un nom de variable, et plus précisément une instance d'une structure. Son nom et son contenu sont définis ailleurs dans ton code. Nous, on ne les connaît pas, mais ça ne nous empêche pas de poursuivre ;

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    sourceInfo = &((SourceInstance*)sgInstanceTable.itemTable[index])->sourceInfo;

    2. « itemTable » est l'un des champs de cette structure. Puisque l'on y met des crochets, c'est vraisemblablement un tableau ;

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    sourceInfo = &((SourceInstance*)sgInstanceTable.itemTable[index])->sourceInfo;

    3. « index » est un nom de variable. Le type de cette variable est un entier. La variable elle-même est définie, elle aussi, quelque part dans le code et est complètement indépendante, en elle-même, de l'expression qui nous intéresse ou de la structure examinée ici. C'est juste qu'elle contient le numéro de la « case » du tableau qui nous intéresse ;

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    sourceInfo = &((SourceInstance*)sgInstanceTable.itemTable[index])->sourceInfo;

    4. Cette expression nous permet donc de récupérer l'élément en question. Il s'agit vraissemblablement d'un pointeur. Ce pointeur est probablement de type « void * », idée confortée par le fait qu'une « table d'items » doit pouvoir contenir des éléments de différentes natures ;

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    sourceInfo = &((SourceInstance*)sgInstanceTable.itemTable[index])->sourceInfo;

    5. Un nom de type seul (fût-ce un pointeur) entouré de parenthèses et précédant une valeur ou une variable quelconque est un transtypage ou cast. Ça sert à demander au compilateur de convertir la valeur en question dans le type de destination. En l'occurrence, on va convertir un pointeur supposé « void » vers un « SourceInstance * » explicite. Au niveau de sa valeur, ça ne change rien du tout : son adresse en mémoire reste rigoureusement identique. Par contre, ça permet d'indiquer ce que l'on pointe au compilateur ;

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    sourceInfo = &((SourceInstance*)sgInstanceTable.itemTable[index])->sourceInfo;

    6.Cette expression entière retourne donc un pointeur vers une instance de la structure SourceInstance :

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    sourceInfo = &((SourceInstance*)sgInstanceTable.itemTable[index])->sourceInfo;

    7. On déréférence ce pointeur pour aller directement pour se référer, dans la structure qu'il pointe, au champ « sourceinfo » ;

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    sourceInfo = &((SourceInstance*)sgInstanceTable.itemTable[index])->sourceInfo;

    8. On récupère l'adresse en mémoire du champ en question, dans cette instance en particulier ;

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    sourceInfo = &((SourceInstance*)sgInstanceTable.itemTable[index])->sourceInfo;

    9. On affecte cette valeur à une variable locale nommée également « sourceinfo » mais qui n'a rien à voir avec notre structure. Cette variable est autonome. Elle n'est pas non plus membre d'une autre structure. Faire cela nous permettra de mettre directement ce champ à jour sans avoir à re-spécifier l'expression entière. C'est utile si le code qui va exploiter cette adresse est utilisé pour mettre à jour d'autres structures construites de la même façon.

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    sourceInfo = &((SourceInstance*)sgInstanceTable.itemTable[index])->sourceInfo;

    À noter enfin la priorité des opérateurs utilisés. Dans l'ordre :

    — Les crochets : « [ ] », puis
    — L'opérateur de sélection d'un membre « . », puis
    — L'opérateur de sélection d'un membre avec déréférencement « -> », puis
    — L'opérateur d'adresse « & », puis
    — L'opérateur de transtypage « (…) », et enfin
    — L'opérateur d'affectation « = ».

    Lorsque ces priorités correspondent bien à l'ordre des opérations que tu veux effectuer, pas de problème. Sinon, il faut mettre des parenthèses, comme en algèbre.

    Comme « -> » est prioritaire par rapport à « & » et que tout le reste est entre parenthèses, le « & » est la dernière chose évaluée avant l'affectation et tu es sûr que c'est bien l'adresse du membre « sourceInfo » que tu récupères, et pas celle d'autre chose.

  11. #11
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    15
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 15
    Par défaut
    Re-bonjour à tous, c'est vraiment bien d'avoir des réponses quotidiennes sans quoi j'aurais certainement laché l'affaire!

    J'ai encore et toujours quelques questions:

    1. quelle est la différence entre les deux typages ci dessous:
    Pour info dans la phrase suivante itemTable est de type void**
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    sourceInfo = &((SourceInstance*)sgInstanceTable.itemTable[index])->sourceInfo;
    2.Dans cette même phrase et concernant SourceInstance, j'ai trouvé sa déclaration dans mon code et il est de type structure, Il n'y a que ici qu'on utilise SourcInstance* en fait c'est comme si on écrivait int* si SourceInstance était un int?

    3.Je n'ai pas bien compris le point 7 du dernier message. Qu'entends tu par déréférence??
    7. On déréférence ce pointeur pour aller directement pour se référer, dans la structure qu'il pointe, au champ « sourceinfo » ;

    Code C :Sélectionner tout - Visualiser dans une fenêtre à part
    sourceInfo = &((SourceInstance*)sgInstanceTable.itemTable[index])->sourceInfo;
    De ce que je comprends:
    1. Dans la structure sgInstanceTable on récupère le pointeur itemTable contenant l'adresse de la variable pointé (soit index).
    2. On déplace le contenu de itemTable dans le champ SourceInfo lui même contenu dans la structure SourceInstance.
    3. On récupère une adresse (mais la je ne sais pas laquelle? celle de souceInfo? de itemTable? et c'est la ou c'est confus pour moi. Ou alors c'est celle de sgInstance.itemTable[index] si on considère qu'il s'agit ni plus ni moins d'une déclaration de variable....??
    4. La valeur itemTable étant de type void** on a une incompatibililité avec le champ de destination donc on converti son type en SourceInstance.
    5. On range l'adresse de sgInstanceTable.item[index] transtypée (si c ça...) dans la variable locale SourceInfo???

      De plus, le typedef de SourceInstance étant une struct alors itemTable placé dans sourceInfo devient une structure lors du transtypage. juste?

      Je vais vraiment finir par kiffer l'info!!

  12. #12
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 499
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 499
    Par défaut
    Citation Envoyé par Seb_33 Voir le message
    Re-bonjour à tous, c'est vraiment bien d'avoir des réponses quotidiennes sans quoi j'aurais certainement laché l'affaire!

    J'ai encore et toujours quelques questions:

    1. quelle est la différence entre les deux typages ci dessous:
    « void * » est un pointeur vers un type inconnu ;
    « void ** » est un pointeur vers un pointeur vers un type inconnu ;

    Dans le cas qui te concerne, toutefois, itemTable est défini de la sorte car il s'agit d'un « tableau de pointeurs void ». Plus précisément, il s'agit d'une liste d'éléments tous différents entre eux et, donc, référencés chacun par leur adresse en mémoire plutôt que directement contenus dans la liste. La liste elle-même est indépendante de la structure parce que sa taille peut varier et qu'elle doit être allouée dynamiquement avec malloc().

    Donc, « itemTable » est un pointeur vers un tableau qui contient lui-même des pointeurs vers les différents objets. C'est extrêmement courant en C.


    2.Dans cette même phrase et concernant SourceInstance, j'ai trouvé sa déclaration dans mon code et il est de type structure, Il n'y a que ici qu'on utilise SourcInstance* en fait c'est comme si on écrivait int* si SourceInstance était un int?
    C'est encore un tour de ton ami typedef ! :-)

    « struct » n'est pas un soi un type unique : c'est par définition un agrégat de plusieurs sous-variables. « struct » n'a donc de sens qu'avec le bloc qui le suit. C'est d'ailleurs pour cela que tu es obligé d'ajouter un point-virgule : le compilo considère le mot-clé struct, le nom éventuel que tu vas lui donner et sa définition comme un type :

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    int                                  x;
    struct { int a; int b; float c; }    y;

    Lorsque tu définis une structure, c'est en général pour y rassembler toutes les caractéristiques d'un entité bien identifiée. Par exemple, si je veux coder toutes les caractéristiques d'un pixel, je peux écrire :

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    struct Pixel 
    {
        int x;  /* Abscisse du pixel */
        int y;  /* Ordonnée du pixel */
        int c;  /* Couleur du pixel */
    };

    J'ai donné le nom « Pixel » à ma structure dans sa définition, ce qui me permet de m'y référer et d'en déclarer des instances facilement :

    Seulement les programmeurs ont pris assez vite l'habitude d'utiliser « typedef » sur une définition de structure pour déclarer un alias éponyme, mais permettant de s'affranchir du mot-clé « struct » explicite :

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    typedef struct _Pixel 
    {
        int x;  /* Abscisse du pixel */
        int y;  /* Ordonnée du pixel */
        int c;  /* Couleur du pixel */
    } Pixel;

    … ce qui permet ensuite de faire directement :


    … comme s'il s'agissait de types natifs. Depuis, en C++, ce procédé est devenu automatique lorsque tu déclares une « struct » ou une « class ».

    3.Je n'ai pas bien compris le point 7 du dernier message. Qu'entends tu par déréférence??
    C'est le terme employé pour exprimer le fait de « suivre » le pointeur, et que celui-ci s'éclipse pour faire place à ce qu'il pointe. Donc :

    « ptr » se réfère au pointeur proprement dit ;
    « *ptr » se réfère à ce qui est pointé par le pointeur ;

    De ce que je comprends:
    1. Dans la structure sgInstanceTable on récupère le pointeur itemTable contenant l'adresse de la variable pointé (soit index).
    2. On déplace le contenu de itemTable dans le champ SourceInfo lui même contenu dans la structure SourceInstance.
    3. On récupère une adresse (mais la je ne sais pas laquelle? celle de souceInfo? de itemTable? et c'est la ou c'est confus pour moi. Ou alors c'est celle de sgInstance.itemTable[index] si on considère qu'il s'agit ni plus ni moins d'une déclaration de variable....??
    4. La valeur itemTable étant de type void** on a une incompatibililité avec le champ de destination donc on converti son type en SourceInstance.
    5. On range l'adresse de sgInstanceTable.item[index] transtypée (si c ça...) dans la variable locale SourceInfo???


    De plus, le typedef de SourceInstance étant une struct alors itemTable placé dans sourceInfo devient une structure lors du transtypage. juste?
    Hélas, non. Pas tout-à-fait. Tu t'égares encore mais c'est parce qu'il te fallait les informations ci-dessus. Il faut aussi que tu ailles voir en détails comment fonctionne un tableau (c'est fort simple). En réalité :

    1. On accède bien au champ « ItemTable » de « sgInstanceTable » (ça, c'est bon) mais ce champ est un pointeur qui indique l'emplacement en mémoire d'un tableau. « index » n'a rien à voir avec la structure ou le reste, mais contient simplement un entier qui va nous servir à indiquer le numéro de l'entrée qui nous intéresse dans ce tableau (d'où son nom). Note bien qu'on a passé ici une variable mais qu'on aurait aussi pu l'écrire directement en chiffres ;
    2. On sait à l'avance que cette entrée elle-même un pointeur vers l'élément qui nous intéresse et que cet élément est une SourceInstance (qui est elle-même une structure). On transtype donc notre pointeur en « SourceInstance * » ;
    3. Maintenant que le compilateur sait ce qu'il pointe, il peut en récupérer le champ « sourceInfo » ;
    4. On copie le contenu de ce champ « sourceinfo » vers une variable locale à notre fonction, qui porte le même nom mais qui est complètement indépendante de toutes les autres variables et structures que l'on a manipulé pour arriver jusqu'ici.


    Je vais vraiment finir par kiffer l'info!!
    Ça, oui ! Et ce n'est que le début !

  13. #13
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Je n'ai rien à ajouter, sauf un petit compliment.
    Citation Envoyé par Seb_33 Voir le message
    Je vais vraiment finir par kiffer l'info!!
    Ca fait plaisir de voir quelqu'un d'assez curieux pour s'acharner à comprendre. Tu iras loin, et bientôt, comme nous, tu expliqueras tout ca au prochain qui posera la question.

    L'info est un paradis de questions plus tordues et intéressantes les unes que les autres, et en partager les explications est un bonheur.

    Je te promets que tu vas un jour te creuser la tête avec le magique 1.0 + 0.1 != 1.1, mais c'est une autre histoire …

  14. #14
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    15
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 15
    Par défaut
    Merci pour vos encouragements! même si le brouillard reste épais, j'aperçois des formes et à chaque fois que j'en distingue de nouvelles ça fait plaisir!! et sans vous ça serais bien plus difficile et beaucoup moins plaisant!!

    Pour revenir à nos moutons!

    1-
    « ptr » se réfère au pointeur proprement dit ;
    « *ptr » se réfère à ce qui est pointé par le pointeur ;
    Si je comprends bien, "ptr" se réfère à l'adresse de la variable pointée (valeur gauche) et "*ptr" se réfère au contenu de la variable pointée (valeur droite). Si c'est ça, je peux écrire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    int* ptr;
    int X=2;
    int Y;
    ptr=&X; /* donc ptr = adresse de X en mémoire */
    Y=*ptr; /* donc Y=X=2 */
    Juste?

    2- J'ai repris le raisonnement en imaginant l'organisation de l'ensemble de ces variables dans le PC. Je sais qu'une valeur en mémoire est définie par son type son adresse (valeur gauche) et son contenu (valeur droite). Mais comment ça marche pour les structures, les énumérations, les unions et même les tableaux. Par exemple, si on revient à itemTable, ce pointeur pointe vers un tableau. Un tableau ayant plusieurs valeurs, il vient la question suivante: est ce que chacune des cases du tableau à une adresse propre? ok Obsidian, comme tu dis :
    Il faut aussi que tu ailles voir en détails comment fonctionne un tableau (c'est fort simple)
    ...Faut peut être que j'aille voir comment fonctionne un tableau.

    3-Enfin, on reprend l'expression complète:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    sourceInfo = &((SourceInstance*)sgInstanceTable.itemTable[index])->sourceInfo;
    En la simplifiant ça donne ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    sourceInfo1 = &((SourceInstance*) X )->sourceInfo2;
    Ici,
    X prend l'adresse mémoire de sourceInfo2 => juste?
    sourceInfo1 reçoit l'adresse de X => juste?

    et pourtant sourceInfo1 est déclaré comme un pointeur simple (*) et pas un pointeur de pointeur (**)....

  15. #15
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 499
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 499
    Par défaut
    Bonsoir,

    Citation Envoyé par Seb_33 Voir le message
    1-
    Si je comprends bien, "ptr" se réfère à l'adresse de la variable pointée (valeur gauche) et "*ptr" se réfère au contenu de la variable pointée (valeur droite). Si c'est ça, je peux écrire:
    Ton code est juste ! Félicitations.

    Cependant, ta phrase est très légèrement incorrecte : comme dit plus haut, « ptr » se réfère au pointeur lui-même, et « *ptr » à ce qu'il pointe. Il est important que ce soit clair pour éviter d'être perdu lorsque ces termes sont impliqués dans des expressions plus complexes. En outre, si je fais « ptr = NULL », par exemple, j'affecte une valeur complètement nouvelle à « ptr » et l'ancienne adresse qu'il contenait est perdue. Cependant, la variable qu'il pointait jusqu'ici reste inaffectée.

    2- J'ai repris le raisonnement en imaginant l'organisation de l'ensemble de ces variables dans le PC. Je sais qu'une valeur en mémoire est définie par son type son adresse (valeur gauche) et son contenu (valeur droite).
    Pas tout-à-fait. Peut-être as-tu rencontré les termes «lvalue » et « rvalue ». On dit généralement qu'une « lvalue » est une valeur qui a une adresse en mémoire. Mais dans le cas présent, ça va rendre les choses encore plus confuses.

    Mais comment ça marche pour les structures, les énumérations, les unions et même les tableaux. Par exemple, si on revient à itemTable, ce pointeur pointe vers un tableau. Un tableau ayant plusieurs valeurs, il vient la question suivante: est ce que chacune des cases du tableau à une adresse propre? ok Obsidian, comme tu dis :
    ...Faut peut être que j'aille voir comment fonctionne un tableau.
    Oui, chaque élément a sa propre adresse.

    Ok. Je m'y colle.

    Un « tableau » est une suite consécutive et ordonnée en mémoire de plusieurs variables du même type.

    Admettons que tu aies besoin de mémoriser dix entiers, par exemple, pour stocker les notes des examens que tu auras passés tout au long d'un trimestre. Tu peux toujours déclarer dix variables de cette façon :

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
        int a1,a2,a3,a4,a5,a6,a7,a8,a9,a10;

    … seulement c'est un peu fastidieux. Et surtout :
    • Si tu veux calculer ta moyenne, tu vas être obligé de toutes les spécifier dans ton expression : « (a1+a2+a3+a4+a5+a6+a7+a8+a9+a10)/10 » ;
    • Si ce n'est pas dix variables que tu veux déclarer, mais 1500, ça n'est plus humainement faisable.


    La bonne méthode consiste donc à déclarer un tableau de cette façon :


    Le compilateur réserve donc dans la pile la place pour 1500 « int ». Or, le langage C te garantit que ces entiers seront consécutifs en mémoire, et dans l'ordre.

    Puisque le bloc alloué est en un seul morceau, c'est déjà une bonne façon de réserver de la mémoire. Mais surtout, puisqu'il est composé d'éléments de même taille et dans l'ordre, alors si tu connais l'emplacement du début du tableau, tu peux facilement déduire celui de n'importe quel élément : il suffit d'y ajouter le rang multiplié par la taille de l'élément.

    Dès lors, lorsque tu as un simple pointeur, tu peux quand même l'indexer comme s'il s'agissait d'un tableau. C'est pratique lorsque tu alloues de la mémoire avec malloc(), par exemple.

    En outre, à partir du moment où l'on sait que le numéro entre crochets est le numéro du rang de l'élément auquel on se réfère, donc un index, alors on peut utiliser n'importe quelle expression pour le spécifier. Si je reprend l'exemple de ma moyenne, je peux toujours écrire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
        int moyenne = (a[0] + a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8] + a[9])/10,
    … mais je peux aussi écrire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
        int i,moyenne=0;
     
        for (i=0;i<10;i++) moyenne += a[i];
        moyenne /= 10;
    3-Enfin, on reprend l'expression complète:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    sourceInfo = &((SourceInstance*)sgInstanceTable.itemTable[index])->sourceInfo;
    En la simplifiant ça donne ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    sourceInfo1 = &((SourceInstance*) X )->sourceInfo2;
    Ici,
    X prend l'adresse mémoire de sourceInfo2 => juste?
    sourceInfo1 reçoit l'adresse de X => juste?
    Non. Ici, tu transtypes la valeur de X en type « SourceInstance * ». C'est-à-dire que tu convertit un pointeur void en pointeur sur une structure « SourceInstance ». Une fois que le compilateur le sait, il peut accéder au membre « sourceInfo » de cette structure. Donc :

    • X est évalué mais ne change pas ;
    • C'est sourceInfo1 qui prend comme valeur l'adresse de sourceInfo2.


    As-tu bien compris ce qu'est une structure, ou est-ce utile d'y revenir ?

  16. #16
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    pour t'aider à comprendre la barbare sourceInfo1 = &((SourceInstance*) X )->sourceInfo2;, il faut la diviser encore une fois

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    SourceInstance *Y=(SourceInstance*) X;
    sourceInfo1 = &(Y)->sourceInfo2;
    La premiere instruction est du meme type que la derniere du code suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    int entier;
    float flottant = 2.0;
    entier = (int)flottant;
    Il s'agit d'un transtypage, qui dit lit l'expression (ici "flottant") comme un "int". Dans le cas de nombre, il y a une conversion numérique, qui donnera 2.
    Pour les pointeurs, l'adresse contenue dans l'expression reste identique, mais sa signification change.
    ici, X était un pointeur vers void, et Y recoit un pointeur vers SourceInstance.
    Donc *Y est un SourceInstance, tandis que *X n'est pas.

    J'en profite pour toucher deux mots de void*.
    void* est le type des pointeurs vers "n'importe quoi, mais on ne sait pas quoi"
    Les pointeurs ne sont pas convertibles les uns vers les autres.
    Par contre, ils sont tous convertibles vers et depuis void*.

    Si p est un pointeur vers un type donné, *p est une valeur de ce type.
    mais si p est un void*, p serait une valeur de type void. Tu n'en connais pas? le compilateur non plus, et il te hurlera dessus si tu essayes quand même.

  17. #17
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 853
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 853
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Seb_33 Voir le message
    Un tableau ayant plusieurs valeurs, il vient la question suivante: est ce que chacune des cases du tableau à une adresse propre?
    Salut

    Tout à fait. Et chaque case possède l'adresse se situant juste après celle de la case précédente.

    Exemple int tab[5];.
    Si ce tableau commence à l'adresse 0x10 (qui est alors l'adresse de tab[0]), alors tab[1] sera 4 octets plus loin donc aura l'adresse 0x14. Et tab[2] sera à 0x18 et tab[3] sera à 0x1c. Et tab[4] sera à 0x20

    De plus, si tu déclares un pointeur ayant le même type que le tableau, toute incrémentation ou décrémentation se fera de façon à ce que les adresse coïncident toujours avec les éléments tu tableau
    Exemple int *pt=tab; // Ou int *pt=&tab[0].
    Ici pt aura alors pour valeur 0x10 mais si on écrit pt=pt+1 alors pt prendra la valeur 0x14. C'est ce qu'on nomme "arithmétique des pointeurs". "Ajouter x" est converti en "Ajouter (x * taille d'un élément)"...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  18. #18
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    15
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 15
    Par défaut
    Hello à tous! Non j'ai pas laché l'affaire, j'étais en vac! lol à bientôt je risque de revenir avec des questions encore......

  19. #19
    Nouveau candidat au Club
    Profil pro
    Développeur informatique
    Inscrit en
    Août 2012
    Messages
    3
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2012
    Messages : 3
    Par défaut
    Citation Envoyé par leternel Voir le message
    j'en profite pour signaler que l'instruction int * i; se compile en *i est un int, ce qui signifie que int * i, j; déclare *i et j sont deux int, j ne sera pas un pointeur de int, alors que (int*) i,j; devrait déclarer i et j sont deux int*
    (int*)i,j; n'est pas une déclaration, c'est une instruction. Elle est constituée de la conversion de la valeur i en type int*, puis de l'opérateur virgule, puis de la valeur j.

  20. #20
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Citation Envoyé par Marc Mongenet Voir le message
    (int*)i,j; n'est pas une déclaration, c'est une instruction. Elle est constituée de la conversion de la valeur i en type int*, puis de l'opérateur virgule, puis de la valeur j.
    Après vérification, c'est effectivement une erreur de ma part.
    Je devais m'en douter inconsciemment, vu que j'avais écrit "devrait déclarer" au lieu "déclare".

Discussions similaires

  1. page blanche apres submit lorsque password est vide
    Par monlou dans le forum Langage
    Réponses: 11
    Dernier message: 21/08/2010, 19h32
  2. Réponses: 9
    Dernier message: 19/12/2005, 16h41
  3. Remplacer une ressource du réseau lorsqu'elle est utilisée
    Par Charette dans le forum Web & réseau
    Réponses: 6
    Dernier message: 22/06/2005, 11h46
  4. Réponses: 3
    Dernier message: 26/02/2005, 09h33

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