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 :

Cast en (int(*)[])


Sujet :

C

  1. #1
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 496
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 496
    Billets dans le blog
    1
    Par défaut Cast en (int(*)[])
    Bonjour,

    J'ai fait une fonction récursive, pour travailler sur un tableau. Un warning de type m'a fait mettre un cast avec (int(*)[]). Voici un code minimaliste :

    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
    #include <stdio.h>
     
    void recursive(int (*ptab)[], unsigned int length)
    {
        if(length>=3)
            recursive(  (int(*)[]) ((*ptab)+1), length-1 );
    }
     
    // Main
    int main(void)
    {
        int tableau[]={0,1,2,3}; // tableau de int
        int (*pTabInt)[] = &tableau; // pointeur sur  "tableau de int"
        recursive( pTabInt, 4);
        return 0;
    }
    Si j'enlève le cast avec (int(*)[]), j'obtient le warning suivant:
    Ligne 6 = warning: passing argument 1 of 'recursive' from incompatible pointer type|
    Ligne 3 = note: expected 'int (*)[]' but argument is of type 'int *'|
    int (*)[] n'est pas plutôt équivalent à un **int qu'à *int ? Si oui, j'ai du mal à comprendre comment ma fonction peut marcher.

    Si quelqu'un a une explication, je suis preneur

  2. #2
    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
    int (*)[] n'est pas plutôt équivalent à un **int qu'à *int ?
    Je suppose que tu veux dire int ** ou int *. De toute façon la réponse est non.

    int (*)[] est un type "adresse d'un tableau de...int
    int ** est un type "adresse d'un pointeur sur int"
    int * est un type "adresse de int"

    Dans la fonction, *ptab est donc un tableau de int. Alors, dans le contexte (ligne 6) de l'expression (*ptab)+1, *ptab est l'adresse du premier élément de ce tableau et donc de type int *. Alors que la fonction attend, lors de l'appel récursif, comme type un int (*)[]

  3. #3
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 398
    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 398
    Par défaut
    C'est légal, ça, int(*)[] sans taille de tableau?
    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
    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
    pTabInt ou ptab sont des pointeurs sur un type incomplet (tableau de taille indéfini), ce qui est légal.
    Dans le code présenté, il n'y a pas nécessité de connaitre la taille du tableau et le code passe.
    Par contre, cela interdit d'écrire quelque chose comme pTabInt++ ou ptab++;

  5. #5
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 496
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 496
    Billets dans le blog
    1
    Par défaut
    Hop hop ! Remontée de topic !

    J'avais pas franchement compris à l'époque, j'y ai repensé souvent depuis, et hier je me suis enfin décidé à m'y replonger. Je crois que je ne comprends pas plus... Déjà, je me suis aperçu que pour ré-agencer les éléments d'un tableau, je n'avais pas besoin de l'adresse du tableau, mais juste du tableau. Un paramètre de type int[] ou int* suffit. Mais j'aimerai quand même comprendre cette histoire.

    pTabInt ou ptab sont des pointeurs sur un type incomplet (tableau de taille indéfini), ce qui est légal. [...] Par contre, cela interdit d'écrire quelque chose comme pTabInt++ ou ptab++;
    OK pour ça. On ne connait pas la taille de l’élément pointé, on ne peut donc pas décaler le pointeur de la taille de cet élément.

    Dans la fonction, *ptab est donc un tableau de int. Alors, dans le contexte (ligne 6) de l'expression (*ptab)+1, *ptab est l'adresse du premier élément de ce tableau et donc de type int *. Alors que la fonction attend, lors de l'appel récursif, comme type un int (*)[]
    OK pour ça. La fonction attend l'adresse d'un tableau, je lui passe simplement un tableau. Le cast permet juste de faire taire le warning, mais ne règle pas le problème du type.

    Je suppose que tu veux dire int ** ou int *. De toute façon la réponse est non.

    int (*)[] est un type "adresse d'un tableau de...int
    int ** est un type "adresse d'un pointeur sur int"
    int * est un type "adresse de int"
    En revanche, je bloque là dessus. Un tableau de int est de type int[] ; on peut "faire un tableau" avec un int*. Donc un pointeur sur tableau ressemble à un int** (d'où ma question de départ).

    J'ai du mal à concevoir qu'une fonction attendant l'adresse d'un tableau et qui reçoit un tableau puisse fonctionner. Voici le programme :
    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
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    #include <stdio.h>
     
    // Fonctions
    unsigned int position_of_min(char tableau[], unsigned int length, unsigned int position)
    {
        unsigned int tpos=position;
     
        for( ; position<length; position++)
        {
            if(tableau[position] < tableau[tpos])
            {
                tpos=position;
            }
        }
        return tpos;
    }
     
    void recursive_sort(char (*tableau)[], unsigned int length)
    {
         // Recuperation du min
        unsigned int mpos = position_of_min( (*tableau), length, 0 );
        char min = (*tableau)[mpos];
     
        // Echange
        (*tableau)[mpos] = (*tableau)[0];
        (*tableau)[0] = min;
     
        // Trier le reste du tableau
        if(length>=3)
            recursive_sort( (*tableau+1), length-1 );
    }
     
    void display_tableau(char tableau[], unsigned int length)
    {
        unsigned int i=0;
        for(printf("|"), i=0; i<length; printf(" %4d |", tableau[i++]))
            ;
        printf("\n\n");
    }
     
    // Main
    int main(void)
    {
        char tab[]={100,90,15,78,9,-66,5,10,94};
        unsigned int len = sizeof(tab)/sizeof(tab[0]);
     
        display_tableau(tab, len);
        recursive_sort(tab, len);
        //recursive_sort(&tab, len);
        display_tableau(tab, len);
     
        return 0;
    }
    Dans le main, que j'appelle avec tab ou avecv &tab, le résultat en console est le même et Dr Memory ne m'indique pas d'erreur. Pourtant, tab et &tab ne devraient pas être la même chose.

    Encore merci

  6. #6
    screetch
    Invité(e)
    Par défaut
    int* est equivalent avec int[]
    mains int* et int[] ne sont pas equivalent avec int[6] par exemple.

    int[] est un pointeur sur int, tout comme int*
    int[6] est un tableau d'entiers

    par equivalent, je veux dire qu'il est possible de caster de l'un a l'autre.

    Il est possible de caster de int[6] a int* mais pas de int* a int[6]


    pour ton probleme, tu prends l'adresse d'un pointeur donc un int** (equivalent a un (int*)[])
    puis tu fais ((*ptab)+1)
    ptab est int**
    (*ptab) est int*
    ((*ptab)+1) est int*


    ca ne fonctionne donc pas; si ca marche, c'est un coup de bol.
    j'ai essaye de compiler ton code et j'ai obtenu:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    main.cc:18:59: error: parameter 'tableau' includes pointer to array of unknown bound 'char []'
    main.cc: In function 'void recursive_sort(char (*)[], unsigned int)':
    main.cc:30:48: error: cannot convert 'char*' to 'char (*)[]' for argument '1' to 'void recursive_sort(char (*)[], unsigned int)'
    main.cc: In function 'int main()':
    main.cc:48:28: error: cannot convert 'char*' to 'char (*)[]' for argument '1' to 'void recursive_sort(char (*)[], unsigned int)'
    donc je ne comprends pas ou est le probleme; ca ne marche pas, ca n'est pas cense marcher et le compilateur refuse de le faire marcher. Il y a quelque chose que je n'ai pas suivi?

  7. #7
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 398
    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 398
    Par défaut
    Citation Envoyé par screetch Voir le message
    par equivalent, je veux dire qu'il est possible de caster de l'un a l'autre.
    C'est pourquoi je conseille le terme "implicitement convertible en" plutôt que "équivalent à".

    tab et &tab ne devraient pas être la même chose.
    tab est directement converti en &tab[0]: Ce n'est pas la même chose, mais les deux sont à la même adresse.
    C'est comme pour &maStructure et &maStructure.premierChamp: Types différents, retours de sizeof différents, adresse égale.
    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.

  8. #8
    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
    @Bktero
    En revanche, je bloque là dessus. Un tableau de int est de type int[] ;
    Oui
    on peut "faire un tableau" avec un int*.
    Là, les "..." montre que cet énoncé n'est pas précis et ambigu .
    Il faut toujours être précis dans ce genre de choses : le C obéit à une logique qu'il faut appliquer, pas approximer.
    J'ai déjà fait de nombreuses fois cet énoncé fondamental dans ce forum (car c'est la seule difficulté des tableaux), mais je le répèterai jusqu'à saouler les lecteurs si il le faut :
    Si X est une expression dont le résultat de l'évaluation désigne un tableau d'éléments de type T, alors le résultat de cette évaluation est en fait l'adresse du premier élément de ce tableau et est donc de type T*, sauf dans deux cas :
    1- L'expression X est opérande de l'opérateur unaire sizeof : sizeof X
    ou
    2- L'expression X est opérande de l'opérateur unaire & (adresse de) : &X
    Dans ces deux cas, le résultat de l'évaluation de l'expression X est le tableau lui-même et est du type T[].

    Note : on peut, si on veut, ajouter à ces deux cas l'expression primaire (X) puisque le résultat de l'évaluation de (X) est, quel que soit d'ailleurs le type de X, le même que celui de l'évaluation de X
    Donc, on peut dire que dans la plupart des contextes (tous en fait sauf les 3 cités plus haut) une expression dont l'évaluation désigne un tableau de int est du type int * et sa valeur est l'adresse du premier int du tableau

    Donc un pointeur sur tableau ressemble à un int** (d'où ma question de départ).
    Et non, car on est dans le cas d'exception 2 : un pointeur sur tableau de int doit contenir l'adresse d'un tableau de int donc quelque chose comme &X. Il est du type "adresse du tableau de int" int (*)[]

    Dans le main, que j'appelle avec tab ou avecv &tab, le résultat en console est le même et Dr Memory ne m'indique pas d'erreur. Pourtant, tab et &tab ne devraient pas être la même chose.
    Ce n'est pas les mêmes choses et ils ne sont pas interchangeables (il suffit de considérer l'arithmétique sur les adresses pour s'en convaincre). Ce n'est pas parce que les valeurs d'adresses transmises à la fonction sont les mêmes (et rien ne le garantit d'ailleurs) que les deux sont identiques.
    ----------
    @screetch
    int* est equivalent avec int[]
    Ce n'est vrai que lors de la déclaration d'un paramètre d'une fonction. Les deux notations sont alors permises et équivalentes
    donc un int** (equivalent a un (int*)[])
    On ne peut pas dire cela. C'est une source de confusion qui conduit à ne pas comprendre les relations entre adresse et tableau
    ----------
    @Médinoc
    C'est comme pour &maStructure et &maStructure.premierChamp: Types différents, retours de sizeof différents, adresse égale.
    Sauf que tu dois ajouter pour être complet (et tu le sais très bien), qu'il est légal de caster l'adresse d'une structure en celle de son premier champ ou réciproquement et que là, la norme garantit le comportement de ces opérations.

  9. #9
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 496
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 496
    Billets dans le blog
    1
    Par défaut
    Les vacances m'ont sans doute fait du bien car j'ai enfin compris !

    Les messages de diogene et de Jean-Marc ici m'ont fait revenir à ce sujet et j'ai compris les nuances entre tableaux et pointeurs, et aussi pourquoi ça marche dans mon dernier code exemple. Ce qu'il fallait retenir et mettre en regard c'est que
    *ptab est donc un tableau de int
    et
    tab est directement converti en &tab[0]: Ce n'est pas la même chose, mais les deux sont à la même adresse.
    Donc tableauet &tableau (avec un tableau un objet de type tableau de char) ont la même valeur, ce qui explique qu'appeler la fonction avec l'un ou l'autre des paramètres fonctionne.

  10. #10
    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
    Donc tableauet &tableau (avec un tableau un objet de type tableau de char) ont la même valeur, ce qui explique qu'appeler la fonction avec l'un ou l'autre des paramètres fonctionne.
    Tu devrais malgré tout avoir un warning du compilateur.

  11. #11
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 496
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 496
    Billets dans le blog
    1
    Par défaut
    Ah oui oui ! recursive_sort(&tab, len); ne produit pas de warning alors que recursive_sort(tab, len); en produit un, ce qui est très logique. Je parlais uniquement "à l'exécution".

    Merci à toi pour ta patience et tes explications !

  12. #12
    Membre éprouvé
    Inscrit en
    Juin 2008
    Messages
    91
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 91
    Par défaut
    Bonjour,

    Citation Envoyé par screetch Voir le message
    int* est equivalent avec int[]
    mains int* et int[] ne sont pas equivalent avec int[6] par exemple.

    int[] est un pointeur sur int, tout comme int*
    int[6] est un tableau d'entiers
    on sent de la confusion dans tout ça, pourtant une bonne réponse a été formulée par diogene.

    Bref, int[] est un type incomplet, sauf comme argument de fonction, où il n'est ni plus ni moins q'un int*.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void foo(int p[]);
    void foo(int p[4]);
    void foo(int p[10]);
    void foo(int * p);
    les 4 prototypes sont strictement et inconditionnellement identiques, malgré l'écriture trompeuse, dans les 4 cas p est un pointeur sur int.

    Pour un tableau de tableau :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void foo(int p[][3]);
    void foo(int p[4][3]);
    void foo(int p[10][3]);
    void foo(int (*p)[3]);
    Dans les 4 cas p est un pointeur sur tableau de 3 ints.

    La règle d'or :

    - Si E est une expression dont l'évaluation désigne un tableau d'élements T, alors le résultat de l'évaluation de l'expression E est le tableau seulement dans deux cas
    -- E est opérande de sizeof
    -- E est opérande de l'opérateur (unaire) & (adresse de)
    - Dans tous les autres cas, le résultat de l'évaluation de l'expression E est l'adresse du premier élément du tableau et est donc du type T*
    Ceci incluant les tableaux de tableaux évidemment.

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

Discussions similaires

  1. Cannot cast from int to Integer
    Par flotho dans le forum Jasper
    Réponses: 2
    Dernier message: 11/11/2009, 20h39
  2. Cast unsigned int en chaine de caractere
    Par MeWaa dans le forum C
    Réponses: 5
    Dernier message: 06/05/2009, 09h58
  3. cast Integer / int
    Par zaineb.z dans le forum Langage
    Réponses: 8
    Dernier message: 18/07/2007, 15h28
  4. [débutant] cast string->int
    Par gigigao dans le forum Visual C++
    Réponses: 8
    Dernier message: 23/08/2006, 11h47
  5. [Language]Cast de int en Object ?
    Par BouB dans le forum Langage
    Réponses: 5
    Dernier message: 22/12/2005, 17h41

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