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 :

Fonction qui renvoie un tableau?


Sujet :

C

  1. #1
    elm
    elm est déconnecté
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2005
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Décembre 2005
    Messages : 20
    Points : 11
    Points
    11
    Par défaut Fonction qui renvoie un tableau?
    Bonjour à nouveau, encore quelques petites questions de débutant:

    Je n'arrive pas à créer une fonction qui renvoie un tableau d'entiers de sorte que je puisse attribuer à un tableau dans ma fonction principale le tableau renvoyé par cette fonction auxilliaire:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    int main()
    {
    int a[32];
    a=sendTab();
    return 1;
    }
     
    int[] sendTab()
    {
    int b[32];
    return b;
    }
    Je souhaiterais assigner à mon a[32] les valeurs de b[32].

    Je suppose que d'une part, contrairement à JAVA, int[] fonction n'est pas une fonction qui renvoie un tableau...
    D'autre part, j'ai remarqué que ceci renvoie une erreur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    int a[32];
    int b[32];
    a=b;
    Même pour des tableaux de même taille on ne peut pas les égaliser? Peut-être faut-il passer par l'usage des pointeurs, mais venant de JAVA je ne suis pas encore très aisé avec leur utilisation (et quand les utiliser).

    Des idées?

  2. #2
    Expert éminent
    Avatar de PRomu@ld
    Homme Profil pro
    Ingénieur de Recherche
    Inscrit en
    Avril 2005
    Messages
    4 155
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Vienne (Poitou Charente)

    Informations professionnelles :
    Activité : Ingénieur de Recherche
    Secteur : Enseignement

    Informations forums :
    Inscription : Avril 2005
    Messages : 4 155
    Points : 6 486
    Points
    6 486
    Par défaut
    En fait, un tableau en C est un pointeur ainsi :

    Peut être un pointeur d'entier et un tableau d'entier. Dans ce deuxième cas, les tableaux sont dits dynamiques, c'est à dire que la taille n'est pas allouée dès le départ(Il faudra donc passer par les pointeurs). Ceci est donc à opposer aux tableaux statiques tels que tu les as fait :

    Ceci est un tableau statique avec une taille bien définie (taille allouée à la compilation). En C, il n'est pas possible (en tout cas je ne l'ai jamais fait) de renvoyer un tableau statique dans une fonction. (On ne pouvait pas au tout début retourner une structure). Tu peux seulement renvoyer un pointeur comme valeur de retour si tu veux renvoyer un tableau.

    Cependant tu ne peux pas faire une égalité entre deux pointeurs et penser que tu fais une copie. En fait tu ne feras une copie que du pointeur. C'est à dire que tu auras deux pointeurs qui pointeront sur le même espace mémoire. Il faut donc dans ton cas copier les éléments uns à uns pour effectuer une copie. Voici un exemple de ce qui est réalisable :

    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
     
    int * copie(int tab[],int taille)
    {
    int * res,i;
     
    /* On alloue une taille au tableau de retour */
    res = (int *) malloc (taille * sizeof(int));
     
    /* On regarde si le tableau a bien été crée */
    if(res == NULL)
    {
         fprintf(stderr,"Allocation impossible");
         exit(1);
    }
     
    /* On copie un à un les élements */
    for( i = 0 ; i <taille ; i++)
    {
         res[i] = tab[i];
    }
     
    return res;
    }
     
    int * a;
    int b[10];
     
    /* On considère que b est rempli
         on effectue la copie */
    a = copie(b,10);

  3. #3
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut Re: Fonction qui renvoie un tableau?
    Citation Envoyé par elm
    Je n'arrive pas à créer une fonction qui renvoie un tableau d'entiers de sorte que je puisse attribuer à un tableau dans ma fonction principale le tableau renvoyé par cette fonction auxilliaire:
    Normal. Tu ne peux renvoyer qu'une adresse, et celle-ci doit être valide après l'éxécution de la fonction. Comme le tableau est défini localement, son adresse est évidemment invalide après le 'return'.

    Il y a deux façons sérieuses de traiter ce problème :
    • Passer l'adresse du premier élément d'un tableau (et sa taille) défini par l'appelant (et éventuellement retourner cette adresse, mais c'est peu intéressant)
    • Retourner l'adresse d'un tableau alloué dynamiquement (qu'il faudra bien sûr libérer après usage).

  4. #4
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par PRomu@ld
    En fait, un tableau en C est un pointeur ainsi :

    Argh ! Non ! Ceci est un pointeur. Un tableau n'est pas un pointeur. C'est une séquence d'objets typés identiques. Point.
    Ceci est un tableau statique avec une taille bien définie (taille allouée à la compilation).
    Statique (càd appartenent à la mémoire statique), on en sait rien. de taille fixe, oui.
    En C, il n'est pas possible (en tout cas je ne l'ai jamais fait) de renvoyer un tableau statique dans une fonction. (On ne pouvait pas au tout début retourner une structure). Tu peux seulement renvoyer un pointeur comme valeur de retour si tu veux renvoyer un tableau.
    En réalité, on renvoit l'adresse du premier élement du tableau. Le type retourné est un type pointeur sur le type en question (ou void *)
    Cependant tu ne peux pas faire une égalité entre deux pointeurs et penser que tu fais une copie.
    Re-argh ! Quelle égalité ? '=' est l'opérateur d'affectation. Rien à voir avec '==' qui est l'opérateur de comparaison. Le C, comme le Pascal et la plupart des langagess sérieux sait faire la différence. Il n'y a que des langages jouets comme le BASIC pour tout mélanger et laisser les gens dans l'ignorance...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    int * copie(int tab[],int taille)
    {
    int * res,i;
     
    /* On alloue une taille au tableau de retour */
    res = (int *) malloc (taille * sizeof(int));
    A quoi sert ce cast ?

    http://emmanuel-delahaye.developpez....tes.htm#malloc

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    /* On copie un à un les élements */
    for( i = 0 ; i <taille ; i++)
    {
         res[i] = tab[i];
    }
    Ok pour l'aspect pédagogique, mais en pratique, on utilise memcpy()...

  5. #5
    elm
    elm est déconnecté
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2005
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Décembre 2005
    Messages : 20
    Points : 11
    Points
    11
    Par défaut
    Merci, ça marche !

    J'ai cependant utilisé la seconde méthode de Emmanuel Delahaye, et après avoir un peu galéré (pas l'habitude de déclarer les fonctions que j'utilise sous le main() ) ce nouveau test simple compile:

    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
    int * sendTab();
     
    int main()
    {
    int a[32];
    int * b;
    b = (int *) sendTab();
    int i;
    for(i=0; i<=32; i++)
    a[i]=b[i];
    return 1;
    }
     
    int * sendTab()
    {
    int * b;
    b = (int*) malloc( 32*sizeof(int));
    return b;
    }

  6. #6
    Expert éminent
    Avatar de PRomu@ld
    Homme Profil pro
    Ingénieur de Recherche
    Inscrit en
    Avril 2005
    Messages
    4 155
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Vienne (Poitou Charente)

    Informations professionnelles :
    Activité : Ingénieur de Recherche
    Secteur : Enseignement

    Informations forums :
    Inscription : Avril 2005
    Messages : 4 155
    Points : 6 486
    Points
    6 486
    Par défaut
    A quoi sert ce cast ?
    Celà sert à visiblement vous énerver mon cher ...

    En fait, comme vous avez l'air pointilleux (ou alors vous me cherchez, ce dont je doute), j'effectue toujours un cast pour la cohérence entre les lvalues et les rvalues.

    malloc retourne un pointeur générique il me semble (ou alors on m'arrait menti ...) et la lvalue est un pointeur sur un entier, par simple soucis de cohérence je le rajoute, et puis cela me parait plus clair. (enfin c'est un point de vue). Mais plus anecdotiquement, à la fac, on nous enlève des points quand nous ne les mettons pas ...

    Pour ce qui est des autres commentaires, je comprends vos points de vue et je suis tout à fait d'accord, en fait, la plupart du temps je me suis mal exprimé (en tout cas pas comme vous l'attendiez). En revanche sur l'assertion suivante, je ne suis pas d'accord :

    Il n'y a que des langages jouets comme le BASIC pour tout mélanger et laisser les gens dans l'ignorance...
    Les gens sont dans l'ignorance s'ils ne savent pas ce qu'ils font, un bon programmeur (il me semble) sais s'il fait une affectation ou s'il fait une comparaison.

  7. #7
    elm
    elm est déconnecté
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2005
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Décembre 2005
    Messages : 20
    Points : 11
    Points
    11
    Par défaut
    Pour le cast, il me semble avoir eu un warning lorsque je ne le mettais pas...

    Ceci est un détail évidemment, ça ne signifie en aucun cas que ça n'aurait pas marché, mais j'ai fait le cast par sécurité, après avoir vu ainsi dans le code plus haut et dans d'autres malloc en général.

    (pour info je compile avec GCC sous Linux-Ubuntu)

    [edit]: Je n'ai rien dit, à présent que ça compile, aucun des 2 casts ne semble indispensable... Corrigez-moi si je me trompe

  8. #8
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par elm
    Pour le cast, il me semble avoir eu un warning lorsque je ne le mettais pas...
    Dans ce cas le bon reflexe est de se demander pourquoi. Un cast est rarement la bonne réponse. En l'occurence, il s'agissant probablement d'un oubli de <stdlib.h> contre lequel le cast ne résout rien (comportement indéfini).
    Ceci est un détail évidemment,
    Un warning n'est pas un détail, et il mérite attention et analyse. On ne programme pas au hasard.
    ça ne signifie en aucun cas que ça n'aurait pas marché, mais j'ai fait le cast par sécurité, après avoir vu ainsi dans le code plus haut et dans d'autres malloc en général.
    Le cast n'est en aucun cas une sécurité. au contraire. As-tu lu le lien que j'ai posté plus haut ?

  9. #9
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par PRomu@ld
    En fait, comme vous avez l'air pointilleux
    Disons plutôt rigoureux.
    (ou alors vous me cherchez, ce dont je doute),
    La seule chose que je cherche, c'est la clarification.
    j'effectue toujours un cast pour la cohérence entre les lvalues et les rvalues.
    C'est totalement inutile en C. Le type void * est déjà parfaitement cohérent et compatible avec tout type de pointeurs sur objet. C'est garanti par la définition du langage.
    malloc retourne un pointeur générique il me semble (ou alors on m'arrait menti ...)
    Il retourne une adresse de type void*.
    et la lvalue est un pointeur sur un entier, par simple soucis de cohérence je le rajoute,
    C'est techniquement faisable, mais ne sert à rien. De plus ca peut masquer l'oubli du prototype (voir le post d'elm).
    et puis cela me parait plus clair. (enfin c'est un point de vue). Mais plus anecdotiquement, à la fac, on nous enlève des points quand nous ne les mettons pas ...
    Mauvais enseignement. Changer d'enseignement.
    Il n'y a que des langages jouets comme le BASIC pour tout mélanger et laisser les gens dans l'ignorance...
    Les gens sont dans l'ignorance s'ils ne savent pas ce qu'ils font, un bon programmeur (il me semble) sais s'il fait une affectation ou s'il fait une comparaison.
    Qui a dit
    Cependant tu ne peux pas faire une égalité entre deux pointeurs et penser que tu fais une copie
    à propos de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    int a[32];
    int b[32];
    a=b;

  10. #10
    elm
    elm est déconnecté
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2005
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Décembre 2005
    Messages : 20
    Points : 11
    Points
    11
    Par défaut
    Oui, en effet comme j'ai édité les warnings ont disparu depuis que ça compile, et ce pour les 2 casts. Ils venaient de l'oubli de déclarer la fonction définie après le main. Merci pour le lien, j'ai aussi noté comment déterminer la taille sans type au passage, c'est plus propre ainsi

    Ceci dit je viens de remarquer que j'ai oublié de libérer la mémoire. En faisant free(b) dans le main(), cela supprimera-t-il bien la mémoire allouée dans la fonction auxilliaire?

  11. #11
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par elm
    Oui, en effet comme j'ai édité les warnings ont disparu depuis que ça compile, et ce pour les 2 casts. Ils venaient de l'oubli de déclarer la fonction définie après le main. Merci pour le lien, j'ai aussi noté comment déterminer la taille sans type au passage, c'est plus propre ainsi

    Ceci dit je viens de remarquer que j'ai oublié de libérer la mémoire. En faisant free(b) dans le main(), cela supprimera-t-il bien la mémoire allouée dans la fonction auxilliaire?
    Oui. N'oublie pas non plus de tester la valeur retournée par malloc() avant de l'utiliser.
    <pseudo-code>
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    T *p = malloc(...)
     
    if (p != NULL)
    {
       /* OK */
    }
    </>

  12. #12
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par elm
    ce nouveau test simple compile:
    Ca ne passe pas !
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    Compiling: main.c
    main.c:6: warning: function declaration isn't a prototype
    main.c:20: warning: function declaration isn't a prototype
    main.c: In function `sendTab':
    main.c:22: error: implicit declaration of function `malloc'
    main.c:22: warning: nested extern declaration of `malloc'
    <internal>:0: warning: redundant redeclaration of 'malloc'
    main.c:24:2: warning: no newline at end of file
    Process terminated with status 1 (0 minutes, 0 seconds)
    1 errors, 4 warnings
    et heureusement, car il y a pas mal de problèmes dans ce code...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    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
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
     
    /* -ed-
    int * sendTab();
     
    il est inutile de creer une declaration separee. Il suffit d'organiser 
    le code selon le principe 'Definir avant d'utiliser'. 
     
    Suppression, reorganisation.
     
    La fonction n'étant pas exportee, on peut la definir static. 
    (Portee limitee a l'unite de compilation)
     
    Il est souhaitable que le fonction soit definie sous sa forme 'prototype', 
    c'est à dire avec les parametres formels ou void si il n'y en a pas.
    */
     
    #include <stdlib.h>
     
    static int * sendTab(void)
    {
       int * b;
     
       /* -ed-
       b = (int*) malloc( 32*sizeof(int));
        
       Cast inutile. Suppression. Manque une prototype visible (inclure <stdlib.h>)
        
       */
       b = malloc( 32 * sizeof(int));
       return b;
    }
     
    int main()
    {
       int a[32];
       int * b;
       /* -ed-
          b = (int *) sendTab();
          
          cast inutile. SUppression.
          */
     
       b = sendTab();
     
       /* sendTab() aurait pu retourner NULL... */
     
       if (b != NULL)
       {
          int i;
     
          /* -ed-
          for (i = 0; i <= 32; i++)
     
          Comportement indefini (debordement de tableau).
     
          Rappel : Les indices d'un tableau de taille N vont de 0 a N-1.
          */
          for (i = 0; i < 32; i++)
     
          /* -ed- preferer les {} ca facilite lecture et maintenance... */
          {
             a[i] = b[i];
          }
          /* -ed- manque la liberation ... */
          free (b), b = NULL;
       }
       return 1;
    }
    Beaucoup de réponses à tes futures questions sur mon site...

  13. #13
    elm
    elm est déconnecté
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2005
    Messages
    20
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Décembre 2005
    Messages : 20
    Points : 11
    Points
    11
    Par défaut
    En effet, j'ai oublié de préciser que j'ai copié les includes du programme plus important que j'écris à côté en haut de ce fichier test...
    Pour les fonctions, elles sont réutilisées dans d'autres classes (tout comme des sémaphores) que nous avons donc déclarées dans un fichier fonctions.h inclus dans chaque classe...

    Les casts étaient déja supprimés dans la dernière version, par contre j'ai complètement omis le débordement de tableau (tellement courant quand on passe d'un langage à un autre pourtant, ça devient impardonnable). Votre correction m'a encouragé à aller chercher de plus amples informations sur votre site pour les pointeurs invalides, merci !

  14. #14
    Expert éminent
    Avatar de PRomu@ld
    Homme Profil pro
    Ingénieur de Recherche
    Inscrit en
    Avril 2005
    Messages
    4 155
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Vienne (Poitou Charente)

    Informations professionnelles :
    Activité : Ingénieur de Recherche
    Secteur : Enseignement

    Informations forums :
    Inscription : Avril 2005
    Messages : 4 155
    Points : 6 486
    Points
    6 486
    Par défaut
    Mauvais enseignement. Changer d'enseignement.
    Oui c'est vrai c'est bien ce que je pense aussi, mais j'avais pensé ( à tord surement) que la licence informatique était un bon enseignement de base.

    Si vous acceptez de devenir un de nos professeur, je ne vois rien contre. Au moins on aurait un peu plus d'exactitide dans nos cours ...

    Mais je m'excuse d'insister, mais il me semblait plus logique d'effectuer un cast (ce n'est pas une question de C ou de warnong). D'ailleur, je viens de regarder ce matin le bouquin de Kernighan et Ritchie ("le langage C norme ANSI 2ème edition"),et bien toutes les allocations avec malloc sont castées.

    D'ailleur, si je peux me permettre de citer une ligne du bouquin :

    Le type à déclarer pour une fonction comme malloc pose un problème délicat dans n'importe quel langage qui prend au sérieux la vérification des types. En C, la méthode correcte consiste à déclarer que malloc retourne un pointeur de type void, puis de forcer explicitement le type de ce pointeur à l'aide d'un "cast".
    Bien que je conçoit tout à fait que ne pas mettre de cast explicite entraine un cast implicite (d'ailleur en regardant les sources de certain de des programmes de mon professeur, il n'y a pas de cast). Mais si les créateurs du langage le préconisent je leur fait donc confiance et puis, ça ne coute rien...

  15. #15
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par PRomu@ld
    Si vous acceptez de devenir un de nos professeur, je ne vois rien contre. Au moins on aurait un peu plus d'exactitide dans nos cours ...
    Bah, quelques livres/sites de références et quelques bons forums suffisent.
    Mais je m'excuse d'insister, mais il me semblait plus logique d'effectuer un cast (ce n'est pas une question de C ou de warning). D'ailleur, je viens de regarder ce matin le bouquin de Kernighan et Ritchie ("le langage C norme ANSI 2ème edition"),et bien toutes les allocations avec malloc sont castées.
    Pour bien comprendre, il faut connaître l'historique. C'est une réminiscence des habitudes prises du temps où malloc() renvoyait char*, c'est à dire avant la normalisation de 1989/90 qui a introduit 'void' et donc void *, dont a bénéficié malloc() en toute logique.
    D'ailleur, si je peux me permettre de citer une ligne du bouquin :
    Le type à déclarer pour une fonction comme malloc pose un problème délicat dans n'importe quel langage qui prend au sérieux la vérification des types. En C, la méthode correcte consiste à déclarer que malloc retourne un pointeur de type void, puis de forcer explicitement le type de ce pointeur à l'aide d'un "cast".
    L'expérience et la reflexion ont démontré que c'était inutile et même dangereux. Ne pas oublier que K&R ont certes créé le langage C, mais qu'ils se sont en quelque sorte faits 'déposséder' par le comité de normalisation, lorsque ce langage a été normalisé (ANSI-89, ISO-90). Certains aspects nouveau (void) ont pu leur echappé et ils ont pu commetrre des erreurs dans l'édition 2.
    Bien que je conçoit tout à fait que ne pas mettre de cast explicite entraine un cast implicite (d'ailleur en regardant les sources de certain de des programmes de mon professeur, il n'y a pas de cast). Mais si les créateurs du langage le préconisent je leur fait donc confiance et puis, ça ne coute rien...
    Si, j'ai déjà expliqué et démontré que ça pouvait coûter. D'autre part, il faut aussi lire l'errata du K&R2, comme indiqué sur mon site :

    http://emmanuel-delahaye.developpez.com/init_c.htm
    http://cm.bell-labs.com/cm/cs/cbook/2ediffs.html

  16. #16
    Expert éminent
    Avatar de PRomu@ld
    Homme Profil pro
    Ingénieur de Recherche
    Inscrit en
    Avril 2005
    Messages
    4 155
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Vienne (Poitou Charente)

    Informations professionnelles :
    Activité : Ingénieur de Recherche
    Secteur : Enseignement

    Informations forums :
    Inscription : Avril 2005
    Messages : 4 155
    Points : 6 486
    Points
    6 486
    Par défaut
    142(§6.5, toward the end): The remark about casting the return value of malloc ("the proper method is to declare ... then explicitly coerce") needs to be rewritten. The example is correct and works, but the advice is debatable in the context of the 1988-1989 ANSI/ISO standards. It's not necessary (given that coercion of void * to ALMOSTANYTYPE * is automatic), and possibly harmful if malloc, or a proxy for it, fails to be declared as returning void *. The explicit cast can cover up an unintended error. On the other hand, pre-ANSI, the cast was necessary, and it is in C++ also.
    Je m'incline... Si on ne peux plus faire confiance aux "références". Par contre, je ne vois pas ce qui peut arriver de mal, un pointeur NULL est le même quelque soit le pointeur (c'est ce que je crois mais vous me mettez un doute).

    J'avais cru comprendre que :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    (void *) NULL == ( int *) NULL
    Mais je me suis peut être trompé.

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 379
    Points : 41 573
    Points
    41 573
    Par défaut
    Tiens, j'ai trouvé le paragraphe correspondant de l'Errata:
    Citation Envoyé par Errata for The C Programming Language, Second Edition
    142(§6.5, toward the end): The remark about casting the return value of malloc ("the proper method is to declare ... then explicitly coerce") needs to be rewritten. The example is correct and works, but the advice is debatable in the context of the 1988-1989 ANSI/ISO standards. It's not necessary (given that coercion of void * to ALMOSTANYTYPE * is automatic), and possibly harmful if malloc, or a proxy for it, fails to be declared as returning void *. The explicit cast can cover up an unintended error. On the other hand, pre-ANSI, the cast was necessary, and it is in C++ also.
    Tu fais une fonction qui retourne un void *, mais prend des paramètres sous une certaine forme (dans le pire des cas, un long long, histoire de faire un beau décalage) et tu oublies de déclarer: déjà, tu peux causer un beau bordel lors de l'appel à la fonction.
    De plus, ça peut aussi causer des problèmes si tu appelles la fonction avec des paramètres incorrects... (Imagine que tu oublies un paramètre à calloc(), par exemple...

  18. #18
    Expert éminent
    Avatar de PRomu@ld
    Homme Profil pro
    Ingénieur de Recherche
    Inscrit en
    Avril 2005
    Messages
    4 155
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Vienne (Poitou Charente)

    Informations professionnelles :
    Activité : Ingénieur de Recherche
    Secteur : Enseignement

    Informations forums :
    Inscription : Avril 2005
    Messages : 4 155
    Points : 6 486
    Points
    6 486
    Par défaut
    Oui mais ce genre de problème se voit à la compilation (oublie d'un certain nombre de paramètre, paramètres hors de plage)

    De plus, si on teste le retour de malloc, il n'y a aucun soucis (c'est ce que j'ai dis dans mon précédent message). Si la fonction renvoie NULL, ça vaut aussi bien pour un void * qu'un int* , non ?

  19. #19
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par PRomu@ld
    Je m'incline... Si on ne peux plus faire confiance aux "références".
    La référence, c'est la norme. Le K&R2 n'est qu'un livre parmi d'autres.
    Par contre, je ne vois pas ce qui peut arriver de mal, un pointeur NULL est le même quelque soit le pointeur (c'est ce que je crois mais vous me mettez un doute).

    J'avais cru comprendre que :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    (void *) NULL == ( int *) NULL
    Oui, mais quel intérêt de caster NULL ?

    Le langage C admet 2 définitions pour la macro NULL :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    #define NULL 0
    #define NULL ((void*)0)
    J'aurais préféré que la 2ème fut imposée, mais ce n'est pas le cas. Un problème peut donc se poser avec les fonctions variadics, car le contexte 'pointeur' n'est pas affirmé. Dans ce cas, il faut un cast explicite en fonction du paramètre attendu. (void*) étant compatible avec tous les types pointeur sur obkjet, il couvre tous les cas concernés.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
       int my_list (int, ...);
     
       my_list (0, "hello", "world", (char*) NULL);
    etc.

  20. #20
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par PRomu@ld
    Oui mais ce genre de problème se voit à la compilation (oublie d'un certain nombre de paramètre, paramètres hors de plage)
    Ca dépend de la version du langage et des reglages du compilateur.
    De plus, si on teste le retour de malloc, il n'y a aucun soucis (c'est ce que j'ai dis dans mon précédent message). Si la fonction renvoie NULL, ça vaut aussi bien pour un void * qu'un int* , non ?
    Tu n'as pas compris le problème.

    Si une fonction est définie sans prototype, elle renvoi int (et non int *).

    Or un int n'est pas forcément suffisant pour recevoir une adresse valide.

    Exemple : i86 mode réel modèle de mémoire large:

    int : 16-bit
    void * : 32-bit (SEG:OFS)

    ca va pas le faire...

Discussions similaires

  1. appel d'une fonction qui renvoie un tableau
    Par yokou dans le forum VB.NET
    Réponses: 1
    Dernier message: 08/01/2008, 21h52
  2. fonction qui renvoie un tableau
    Par deubelte dans le forum C++
    Réponses: 24
    Dernier message: 26/05/2007, 01h51
  3. fonction qui renvoie un tableau
    Par GLSpirit dans le forum C++
    Réponses: 9
    Dernier message: 12/05/2007, 14h05
  4. fonction qui renvoie un tableau
    Par toto2022 dans le forum VB 6 et antérieur
    Réponses: 2
    Dernier message: 22/01/2007, 16h11
  5. Comment faire une fonction qui renvoi un tableau.
    Par poly128 dans le forum Delphi
    Réponses: 2
    Dernier message: 01/06/2006, 01h04

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