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 :

argv dans une fonction


Sujet :

C

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Mars 2012
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2012
    Messages : 23
    Par défaut argv dans une fonction
    bonjour,
    une de mes fonction a besoin des argument de argv[] pour fonctionner, comment je fais pour les récupérer ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    int *ma_fontion(char **argv);
     
    int main(int argc, char *argv[]){
    ma_fontion(argv); // ???? erreur N°1
    }
     
    int *ma_fontion(char **argv){
    int *mes_operations
    // .... 
    return(mes_operations);
    // mes_operations => un tableau qui contient les résultats souhaités
    }
    erreur
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    ligne 5: attention : assignment from incompatible pointer type [enabled by default]
    ligne 10: attention : return from incompatible pointer type [enabled by default]

  2. #2
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 152
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 152
    Par défaut
    Bonjour,

    Je suis débutant en C, donc je vais essayer de pas dire de bêtises, mais je pense que c'est tout simplement à prendre en compte comme un tableau de char.

    L'indice 0 de ton tableau représente le nom du fichier, et l'indice 1 le paramètre suivant, etc...

    argc représente le nombre d'arguments, tu peux l'utiliser pour vérifier que le nombre de paramètres est cohérent pour l'exécution de ton code.

    Voilà, j'espère pas avoir dis de bêtises

    Un code fonctionnel pour tester

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    int main(int argc, char *argv[])
    {
        if (argc == 2)
        {
            printf("Le nom de mon fichier est %s\n", argv[0]);
            printf("mon paramètre est %s\n", argv[1]);
            return 0;
        }
        return 1;
    }

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Mars 2012
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2012
    Messages : 23
    Par défaut
    "ma_fonction" réalise des opérations avec des arguments, de ce coté là il n'y a pas de problème, et le résultat est stocké dans un tableau "mes_operations"

    le problème se situe au niveau de l'appel de la fonction, et aussi dans le "return(mes_operations)"

  4. #4
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 152
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 152
    Par défaut
    Pour ta fonction "ma_fonction"

    devrait être correct, par contre je ne comprend pas les doubles pointeurs, peut-être ne suis-je pas assez avancé pour comprendre cela.

    Mais ça m'étonnerait pas que ton erreur soit une erreur de pointeur, vu ton message d'erreur

    Voilà un autre exemple

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    void ma_fonction(char *argv)
    {
        printf("Mon paramètre est %s\n", argv);
    }
     
    int main(int argc, char *argv[])
    {
        if (argc == 2)
        {
            ma_fonction(argv[1]);
            return 0;
        }
        return 1;
    }
    ou ceci est possible aussi

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    char *ma_fonction(char *argv)
    {
        return argv;
    }
     
    int main(int argc, char *argv[])
    {
        if (argc == 2)
        {
            printf("mon paramètre est %s\n", ma_fonction(argv[1]));
            return 0;
        }
        return 1;
    }

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Mars 2012
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2012
    Messages : 23
    Par défaut
    moi j'ai seulement écouté les avertissements lorsque je compile, on me dit qu'il faut un double pointeur.

    oui ton programme marche très bien, mais c'est pareil de mon coté, lorsque j'utilise un printf dans "ma_fonction", le résultat s'affiche normalement.

    Ce que je cherche à faire, c'est de stocker le résultat dans un tableau au lieu de l'afficher, ensuite le renvoyer vers ma fonction principal, et c'est là que sa se complique

  6. #6
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 152
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 152
    Par défaut
    Tu ne peux pas retourner un tableau

    Voir ci-dessus j'ai édité mon message précédent

  7. #7
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 497
    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 497
    Billets dans le blog
    1
    Par défaut
    Je ne suis pas sûr que les warnings que tu indiques soient causés par les passages d'argv en paramètres. J'ai fait une fonction pour tester :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    void test(char **arguments, int nbarg)
    {
        int c;
        puts("\n\n Fonction test\n");
        for(c=0;c<nbarg;c++)
        {
            printf("argv[%d] = [%s]\n", c, arguments[c]);
        }
    }
    que j'appelle dans le main() :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    int main(int argc, char *argv[])
    {
       test(argv, argc);
       return 0;
    }
    Je n'ai pas de warning à la compilation, en utilisant -Wall -Wextra de gcc.


    Une remarque sur ta fonction utilisant argv :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int *ma_fontion(char **argv);
    Il faut aussi que tu passes argc en paramètre, sinon impossible pour toi de savoir combien d'éléments contient le tableau. Que souhaites-tu faire dans cette fonction ?

  8. #8
    Membre averti
    Profil pro
    Inscrit en
    Mars 2012
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2012
    Messages : 23
    Par défaut
    un pointeur sur un tableau c'est possible

    j'essaie en ce moment de modifier un code qui fonctionnait, mais je l'ai pas encore fini, j'ai une erreur de segmentation, je repasserai tout à l'heure car je dois y aller
    merci pour le coup de main en tout cas

    voila un code un plus complet, la fonction ne fait pas grand chose, elle réalise juste une copie de argv, mais c'est juste un exemple dont je vais m'inspirer pour réaliser mon programme du même style.

    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
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
     
    /*  Prototype  */
    int * Function(int la_taille,char **argv);
     
    /*  Main  */
    int main(int argc, char *argv[])
    {
      char *tableau_final;
      int nombre_case = argc;
      int i;
      /* Allocation */
      printf("Affichage depuis la fonction Function:\n");
      tableau_final = Function(nombre_case,argv); // fonction
     
      printf("\n");
      printf("Affichage depuis la fonction main :\n");
      for(i=0;i<nombre_case;i++){
        printf("%s\n",tableau_final[i]);
      }
      printf("\n");
     
      return 0;
    }
     
    /*  Function  */
    int * Function(int la_taille, char **argv)
    {  
      char * tab_a_renvoyer;
      int i;
      /* Allocation */
      if( (tab_a_renvoyer = (char*) calloc (la_taille,sizeof(char))) == NULL)
        {
          perror("Echec");
          exit(0);
        }  
      for(i=0;i<la_taille;i++){
        tab_a_renvoyer[i]=argv[i];
      }
       for(i=1;i<la_taille;i++){
         printf("%s |",argv[i]);
      }
     
      return tab_a_renvoyer;
    }

  9. #9
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 152
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 152
    Par défaut
    Si tu veux jouer avec les doubles pointeurs, il faudra l'adresse de ton argument, je propose ceci, sans trop bien comprendre l'intérêt, je dois dire.

    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
    char *ma_fonction(char *argv)
    {
        return argv;
    }
     
    int main(int argc, char **argv)
    {
        if (argc == 2)
        {
            char **tab = &argv[1];
            printf("mon paramètre est %s\n", ma_fonction(*tab));
            return 0;
        }
        return 1;
    }

  10. #10
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 497
    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 497
    Billets dans le blog
    1
    Par défaut
    1) La fonction renvoie un int* d'après son prototype mais elle renvoie en fait un char*. A corriger.

    2)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    tab_a_renvoyer[i]=argv[i];
    On ne copie pas des tableaux de cette façon en C. On utilise strcpy() ou memcpy().

    3)Ce n'est qu'une chaîne de caractères et non un tableau de chaîne de caractères comme l'est argv.

    4) A quoi cela va t-il te servir de copier argv ? Normalement, quand tu utilises les arguments de ton main, tu les parses et les enregistre dans des variables adaptées.

  11. #11
    Membre averti
    Profil pro
    Inscrit en
    Mars 2012
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2012
    Messages : 23
    Par défaut
    tab_a_renvoyer est tableau dynamique

    la fonction que je cherche à faire ne copie pas argv, ce n'est pas le but, mais elle réalise plusieurs choses avant d'insérer les résultats dans tab_a_renvoyer et le renvoyer vers main, et elle a besoin des données qui se trouvent dans argv

    Ce n'est pas un très bon exemple celui que je vous ai donné, mais c'est juste pour faire court et ne pas compliqué la situation.

    J'ai appliqué les modifications, maintenant j'ai plusieurs messages d'avertissement, sans vraiment les comprendre, et lors de l'exécution j'ai une erreur de segmentaion

    Main
    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
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
     
    /*  Prototype  */
    char * Function(int la_taille, char **argv);
     
    /*  Main  */
    int main(int argc, char *argv[]){
      char *tableau_final;
      int nombre_case = argc;
      int i;
      /* Allocation */
      printf("Affichage depuis la fonction Function:\n");
      tableau_final = Function(nombre_case,argv); // fonction
      printf("\n");
      printf("Affichage depuis la fonction main :\n");
      for(i=0;i<nombre_case;i++){
        printf("%s\n",tableau_final[i]);
      }
      printf("\n");
      return 0;
    }
    Function
    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
    /*  Function  */
    char * Function(int la_taille, char **argv){  
      char * tab_a_renvoyer;
      int i;
      /* Allocation */
      if( (tab_a_renvoyer = (char*) calloc (la_taille,sizeof(char))) == NULL){
          perror("Echec");
          exit(0);
        }  
      strcpy (tab_a_renvoyer,argv);
      for(i=1;i<la_taille;i++){
        printf("%s |",argv[i]);
      }
      return tab_a_renvoyer;
    }

  12. #12
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 152
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 152
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    strcpy (tab_a_renvoyer, *argv); /* Pour l'argument 0 */
    Mais je n'arrive toujours pas à voir pourquoi utiliser un double pointeur?

    Tu ne peux pas retourner un tableau, je me répète, mais c'est une chose dont je suis sûr

    Si on part sur le principe qu'on ne retourne pas un tableau, on pourrait modifier ton code pour qu'il soit fonctionnel. Il te reste des erreurs de pointeurs.

    D'ailleurs je suis débutant aussi et je te conseille de jouer avec un seul pointeur pour commencer, tu joueras avec la "modification de pointeur" un peu plus tard

    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
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    /*  Function  */
    char *Function(int la_taille, char **argv){
      char *tab_a_renvoyer = malloc(80*sizeof(char));
      int i;
      /* Allocation */
      if(tab_a_renvoyer == NULL){
          perror("Echec");
          exit(0);
        }
      strcpy (tab_a_renvoyer, argv[1]);
      for(i=1;i<la_taille;i++){
        printf("%s |",argv[i]);
      }
      return tab_a_renvoyer;
    }
     
    /*  Main  */
    int main(int argc, char *argv[]){
      char *tableau_final;
      int nombre_case = argc;
      /* Allocation */
      printf("Affichage depuis la fonction Function:\n");
      tableau_final = Function(nombre_case,argv);
      printf("\n");
      printf("Affichage depuis la fonction main :\n");
      printf("%s\n", tableau_final);
      printf("\n");
      return 0;
    }

  13. #13
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    Février 2008
    Messages
    2 315
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : Février 2008
    Messages : 2 315
    Billets dans le blog
    5
    Par défaut
    Prenons un exemple simple : un tableau de 10 char. C'est à dire un tableau dont les éléments sont des octets.

    Si nous déclarons char tab[10] l'ordinateur va allouer en mémoire 10 octets qui seront les uns à côté des autres. Cette façon de faire est très importante à comprendre pour la suite.

    En partant de ce constat en C il est possible d'accéder aux données de ce tableau de deux manières :
    1. soit en utilisant l'écriture tab[x] avec 0<x<9,
    2. soit en utilisant le pointeur du premier élément du tableau.


    La première écriture est simple à comprendre, je ne m'étends pas plus. Regardons d'un peu plus prés la deuxième méthode.

    Pour accéder au pointeur du tableau il suffit d'enlever les [] lors de l'écriture. Ainsi tab équivaut à tab[0]. À partir de là il faut bien comprendre que tab est le pointeur du premier élément du tableau. Pour accéder à l'élément n il suffit de faire tab+n.

    Mais pourquoi parler de ca?

    Dés qu'on comprend comment fonctionne en mémoire un tableau on peut l'adresser un peu comme on veut. Si on revient au prototype de la fonction main(); on voit char *argv[]. Si on traduit cette écriture en pointeur, comme je viens de l'expliquer, on peut écrire : char **argv. Et au miracle nous voila avec deux *! Je reçois bien l'adresse d'un tableau.

    Si on pousse un peu plus loin, il est donc tout à fait possible de transmettre un tableau à une fonction (et c'est tant mieux parce que sinon on serait bien embêté ) mais on peut aussi "renvoyer" un tableau depuis une fonction. Je vois que les sourcils de fred1599 se froncent. Quoi, on m'aurait menti!

    Si je déclare par exemple cette fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void init_tab (char **tab);
    Je peux dans cette fonction initialiser le tableau tab[] avec une simple boucle par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    void init_tab (char **tab)
    {
      int i = 0;
     
      for (i = 0; i <10; i++)
        tab[i] = i;
    }
    En retour de cette fonction mon tableau est initialisé. Bien sûr, je n'ai pas "renvoyer" au sens propre du terme un tableau. J'ai simplement eu accès à son adresse et j'ai fait le reste.

    Pour finir, il est tout à fait possible de renvoyer un tableau au sens propre du terme cette fois en effectuant une allocation dans le tas. Mais c'est un autre sujet...

  14. #14
    Membre averti
    Profil pro
    Inscrit en
    Mars 2012
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2012
    Messages : 23
    Par défaut
    C'est une bonne chose de programmer avec des pointeur, mais j'ai jamais su m'en servir correctement

    J'ai réussi à obtenir ce que je voulais grâce à vous tous

    Merci

  15. #15
    Membre averti
    Profil pro
    Inscrit en
    Mars 2012
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2012
    Messages : 23
    Par défaut
    fred, voila pour toi un exemple de tableau renvoyé par une fonction, avec une bonne explication de diogene : http://www.developpez.net/forums/d12...eau-dynamique/

    Je vais devoir lire au moins 20x la réponse de gerald3d pour ne jamais l'oublier
    merci à tous

  16. #16
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 152
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 152
    Par défaut
    Bonsoir,

    Bien sûr, je n'ai pas "renvoyer" au sens propre du terme un tableau. J'ai simplement eu accès à son adresse et j'ai fait le reste
    On est bien d'accord, on ne peut retourner un tableau, on ne m'avait donc pas menti.

    Par contre rien n'empêche de retourner une structure, ça c'est cool !

    Dés qu'on comprend comment fonctionne en mémoire un tableau on peut l'adresser un peu comme on veut. Si on revient au prototype de la fonction main(); on voit char *argv[]. Si on traduit cette écriture en pointeur, comme je viens de l'expliquer, on peut écrire : char **argv. Et au miracle nous voila avec deux *! Je reçois bien l'adresse d'un tableau.
    Si tu regardes bien j'ai placé un argument de ce type dans mon code précédent, reste que je n'en vois pas l'intérêt, surtout dans ce type d'exercice.

    Souvent il est dit qu'on peut toujours se débrouiller sans ** et n'utiliser que *. Je pense que c'est pas faux, ai-je tort?

    D'ailleurs ton code exemple, je pourrais le représenter de cette manière

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    void init(char *tab)
    {
        int i = 0;
        while (tab[i] != '\0')
        {
            tab[i]= i;
            i++;
        }
    }
    Je trouve, dis moi si je me trompe que de renvoyer une structure est un bon compromis...

    Merci pour les explications, mais j'ai plus l'impression que tu confirmes ce qu'on m'avait déjà dis, que de me prouver le contraire, à moins que je n'ai pas tout pigé, dans ce cas "mea culpa"

  17. #17
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    Février 2008
    Messages
    2 315
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : Février 2008
    Messages : 2 315
    Billets dans le blog
    5
    Par défaut
    Le seul moyen pour renvoyer un tableau est de l'allouer dans le tas dans la dite fonction. Cette technique est intéressante, par exemple pour faire de la programmation orienté objet en C (il y a d'autres cas bien sûr).

    Oui tu as raison pour la fonction init();. L'adressage de pointeur est surtout utilisé lorsque tu ne connais pas la longueur du tableau que tu veux récupérer à la sortie.

    Je m'explique. Imagine une fonction de ce type :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int load (const char *filename, char **error);
    Cette fonction renvoie 0 si tout c'est bien passé, 1 dans le cas contraire. Dans ce dernier cas error contient alors un texte d'explication sur l'erreur survenue.

    Comme je ne connais pas à priori la longueur de error, je transmets à la fonction l'adresse du pointeur error. En interne le pointeur error est initialisé avec une allocation dans le tas. En retour je peux afficher l'erreur et ensuite faire un free(error); pour libérer le tout.

    Pour finir renvoyer une structure revient à renvoyer un type particulier. Ce qui est en définitif la même chose .

    Une dernière remarque : l'idée générale est d'éviter le plus possible de faire des allocations dynamiques. Simplement pour éviter l'oubli de la libération derrière. Utiliser le double adressage est souvent lié à une allocation dynamique (pas systématique). CFQD.

  18. #18
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 152
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 152
    Par défaut
    Comme je ne connais pas à priori la longueur de error, je transmets à la fonction l'adresse du pointeur error
    Je débute depuis 2 semaines, donc dis moi, est-ce une règle?

    Lorsque je ne connais pas la longueur d'un texte, je ne vois toujours pas l'intérêt du double pointeur, ou pourrais-tu continuer ta fonction load?

    En interne le pointeur error est initialisé avec une allocation dans le tas
    Allocation dans le tas? un malloc, tu veux dire?

    Pourquoi pas une utilisation de ce type?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char ma_chaine[] = "Vous avez fait une erreur"
    et dans ta fonction load

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int load (const char *filename, char *error);
    ?

    Une dernière remarque : l'idée générale est d'éviter le plus possible de faire des allocations dynamiques. Simplement pour éviter l'oubli de la libération derrière. Utiliser le double adressage est souvent lié à une allocation dynamique (pas systématique). CFQD.
    Donc si je comprend bien, tu es d'accord sur le fait qu'il n'est pas utile d'utiliser le double adressage, ou dans des cas assez restreints?

    Sinon valgrind permet d'éviter ces oublis, non?

  19. #19
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    Février 2008
    Messages
    2 315
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : Février 2008
    Messages : 2 315
    Billets dans le blog
    5
    Par défaut
    On va écrire un code un peu plus complet.

    reprenons la fonction int load (const char *filename, char *error); à ta façon. Lorsque tu appelles cette fonction le pointeur error que tu transmets, tu l'initialises comment?

    Par exemple si je fais :
    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
     
    #include <stdio.h>
    #include <stdlib.h>
     
     
    int load (const char *filename, char *error)
    {
      printf ("adresse de error dans load() : %u\n", error);
     
      return 0;
    }
     
    int main (int argc, char *argv[])
    {
      char *error = 0;
     
      printf ("adresse de error dans le main() : %u\n", error);
     
      if (load ("./essai.txt", error)==1)
        {
          fprintf (stderr, "%s\n", error);
        }
     
      return 0;
    }
    Le résultat à l'exécution donne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    adresse de error dans le main() : 0
    adresse de error dans load() : 0
    Pour l'instant tout va bien. On récupère bien le même pointeur dans la fonction load();.

    Maintenant reprenons notre exemple précédent mais cette fois en initialisant la variable error à l'interieur de load(); :
    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
     
    #include <stdio.h>
    #include <stdlib.h>
     
     
    int load (const char *filename, char *error)
    {
      error = "Erreur de lecture";
     
      printf ("adresse de error dans load() : %u\n", error);
     
      return 0;
    }
     
    int main (int argc, char *argv[])
    {
      char *error = 0;
     
      printf ("adresse de error dans le main() : %u\n", error);
     
      if (load ("./essai.txt", error)==1)
        {
          fprintf (stderr, "%s\n", error);
        }
     
     
      return 0;
    }
    Le résultat à l'exécution donne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    adresse de error dans le main() : 0
    adresse de error dans load() : 4197100
    Les adresses ne sont plus les mêmes. Le coupable est l'affectation de la chaîne de caractères. Une allocation mémoire implicite a été faite par le compilateur et l'adresse du premier octet de la chaîne a été affectée à error. En retour de la fonction tu n'as aucun moyen de récupérer cette adresse.

    Comment faire ?

    La solution est donc le double adressage. On transmet à la fonction load(); l'adresse du pointeur. Cette adresse ne change pas. Par contre on va pouvoir lui affecter comme valeur à l'intérieur l'adresse que nous renvoie l'affectation de la chaîne. En retour dans le main(); on retrouvera cette nouvelle adresse. CQFD.

    Voila l'exemple complet. La fonction load(); renvoie 1 pour montrer la gestion de la variable error :
    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
     
    #include <stdio.h>
    #include <stdlib.h>
     
     
    int load (const char *filename, char **error)
    {
      *error = "Erreur de lecture";
     
      printf ("adresse de error dans load() : %u\n", *error);
     
      return 1;
    }
     
    int main (int argc, char *argv[])
    {
      char *error = 0;
     
      printf ("adresse de error dans le main() : %u\n", error);
     
      if (load ("./essai.txt", &error)==1)
        {
          printf ("adresse de error en retour de load() dans le main() : %u\n", error);
          fprintf (stderr, "%s\n", error);
        }
     
     
      return 0;
    }
    En console on obtient :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Erreur de lecture
    adresse de error dans le main() : 0
    adresse de error dans load() : 4197132
    adresse de error en retour de load() dans le main() : 4197132
    on voit bien ici que l'on récupère l'adresse nouvellement affectée en retour de la fonction load();.

    Je pense qu'avec cet exemple on comprend mieux pourquoi le fait de transmettre simplement le pointeur de la variable ne suffit pas. Même si elle est allouée dans le tas (avec malloc) on ne la récupérera pas à la sortie. Il nous faut transmettre l'adresse du pointeur pour faire cette opération.

  20. #20
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 152
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 152
    Par défaut
    Merci pour ta réponse, ça devient un peu plus clair

    Ok c'est un peu complexe pour moi, dis moi si j'ai compris.

    En gros il est utile d'avoir un double adressage quand on veut récupérer l'adresse d'une variable se trouvant dans une fonction autre que main() ?

    Ainsi on peut récupérer (presque comme une variable globale) la valeur de error se trouvant dans la fonction load() pour l'utiliser dans notre main?

    C'est un peu le flou artistique, peut-on à l'aide du double adressage, faire une fonction echange?

    J'ai testé en essayant de rester cohérent dans ma syntaxe.

    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
    void echange(int **a, int **b)
    {
        int *temp = *a;
        *a = *b;
        *b = temp;
    }
     
    int main(void)
    {
        int *c, *d;
        int e = 12;
        int f = 25;
        c = &e;
        d = &f;
        echange(&c, &d);
        printf("e vaut %d et f vaut %d", *c, *d);
        return 0;
    }
    J'ai bien pigé la syntaxe je pense, mais il me semble que l'on ne peut pas modifier une adresse ?

    Tu vois encore beaucoup de questions

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Recuperation de formulaire dans une fonction
    Par arsgunner dans le forum ASP
    Réponses: 5
    Dernier message: 23/06/2004, 15h04
  2. Transmission d'un objet crée dans une fonction
    Par EvilAngel dans le forum ASP
    Réponses: 2
    Dernier message: 10/05/2004, 20h19
  3. Utilisez MinimizeName() dans une fonction
    Par James_ dans le forum C++Builder
    Réponses: 7
    Dernier message: 07/05/2004, 18h05
  4. [Postgresql]Connecter à une autre base dans une fonction
    Par alex2205 dans le forum Requêtes
    Réponses: 2
    Dernier message: 05/05/2003, 11h30
  5. [Turbo Pascal] Allocation et désallocation de pointeurs dans une fonction
    Par neird dans le forum Turbo Pascal
    Réponses: 13
    Dernier message: 17/11/2002, 20h14

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