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 :

Différence entre ** et &* ?


Sujet :

C

  1. #1
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2009
    Messages
    62
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2009
    Messages : 62
    Par défaut Différence entre ** et &* ?
    Bonjour,

    J'aimerais comprendre pourquoi ce code fonctionne:
    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
    int main(int argc, char ** argv){
            int     n = 0;
            size_t  taille = 0;
            char    *c1;
            char    *c2;
            char    *saveptr;
     
     
            while(getline(&c1, &taille, stdin) != -1){
                    printf("Ligne %d\n", ++n);
                    c2 = strtok_r(c1, "\t ", &saveptr);
     
                    while(c2 != NULL){
                            printf("\t%s\n", c2);
                            c2 = strtok_r(NULL, "\t ", &saveptr);
                    }   
            }   
     
            printf("\nDone\n");
     
            return 0;
    }
    Et celui ci me sort une erreur de segmentation:
    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
    int main(int argc, char ** argv){
            int     n = 0;
            size_t  taille = 0;
            char    *c1;
            char    *c2;
            char    **saveptr;
     
     
            while(getline(&c1, &taille, stdin) != -1){
                    printf("Ligne %d\n", ++n);
                    c2 = strtok_r(c1, "\t ", saveptr);
     
                    while(c2 != NULL){
                            printf("\t%s\n", c2);
                            c2 = strtok_r(NULL, "\t ", saveptr);
                    }   
            }   
     
            printf("\nDone\n");
     
            return 0;
    }
    Sachant que le prototype de strtok_r est:
    char *strtok_r(char *str, const char *delim, char **saveptr);
    Je croyais que un pointeur1 de pointeur2 contenais l'adresse de pointeur2, equivalent a &pointeur2.

  2. #2
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 026
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 026
    Par défaut
    Déclarer un pointeur ne suffit pas, il faut aussi allouer l'espace.

    Tu as un char ** mais sur quoi pointe-t-il?

    Lorsque tu utilises ta fonction, il va faire une copie de ton char ** puis il va écrire un pointeur char * dans l'objet pointé par ton char ** or tu n'as pas alloué l'espace pour le char * pointé par ton char **.

  3. #3
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2009
    Messages
    62
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2009
    Messages : 62
    Par défaut
    Ha oui, j'oublie a chaque fois..
    Toutefois, je comprend pas pourquoi le premier code fonctionne du coup, simple coup de chance que la mémoire ne soit pas déjà allouée ?

  4. #4
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 026
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 026
    Par défaut
    strtok_r dois allouer l'espace mémoire pour contenir les caractères mais il n'alloue pas le char *.

    Après, en regardant le man, on devrait avoir plus d'informations.

  5. #5
    Membre Expert Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Par défaut
    Salut,

    Comme pour toutes variables, si vous voulez modifier la valeur, il faut alors passer son adresse. Ici le type concerné est char*, en passant son adresse on a un char**.

    Je présume que strtok_r fait quelque chose comme *saveptr = &str[i];. Tu ne pourrais pas mettre à jour saveptr de cette façon si tu passais un char*. Du coup avec ton deuxième code je te laisse imaginer

  6. #6
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 026
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 026
    Par défaut
    Dans son deuxième code saveptr est un char ** et non un char *.

    A par le fait que saveptr ne pointe pas sur un char * alloué, je ne vois pas pourquoi son deuxième code ne marcherait pas.

  7. #7
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2009
    Messages
    62
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2009
    Messages : 62
    Par défaut
    Le deuxième code fonctionne si j'alloue de la mémoire pour **saveptr, mais pourquoi l'allocation n'est pas nécessaire si je déclare *saveptr et non **saveptr ?

  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
    c1 devrait être initialisé à NULL avant le premier appel à getline()

    Cf man pages
    ssize_t getline(char **lineptr, size_t *n, FILE *stream);
    ......
    getline() lit une ligne entière dans stream et stocke l'adresse du tampon contenant le texte dans *lineptr. Le tampon se termine par un caractère nul et inclut le caractère « saut de ligne » s'il y en a un.
    Si *lineptr vaut NULL, getline() alloue un tampon pour recevoir la ligne. Ce tampon devra être libéré par le programme utilisateur. (La valeur dans *n est ignorée). Alternativement, avant d'appeler getline(), *lineptr peut contenir un pointeur vers un tampon alloué par malloc(3) et de taille *n octets. Si le tampon n'est pas suffisant pour recevoir la ligne saisie, getline() le redimensionne avec realloc(3), mettant à jour *lineptr et *n comme il se doit.

  9. #9
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 026
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 026
    Par défaut
    Citation Envoyé par Arkenis Voir le message
    Le deuxième code fonctionne si j'alloue de la mémoire pour **saveptr, mais pourquoi l'allocation n'est pas nécessaire si je déclare *saveptr et non **saveptr ?
    char * saveptr : il faut allouer un/des char
    char ** saveptr : il faut allouer un/des char * et pour chaque char * allouer un/des char

    Or je pense que ta fonction alloue l'espace pour les char donc :

    char * saveptr : rien à faire, ta fonction alloue les char
    char ** saveptr : il faut allouer un/des char * et ta fonction allouera les char pour le premier char *

  10. #10
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2009
    Messages
    62
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2009
    Messages : 62
    Par défaut
    Citation Envoyé par diogene Voir le message
    c1 devrait être initialisé à NULL avant le premier appel à getline()

    Cf man pages
    c1 n'est-il pas automatiquement initialisé a NULL ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    int main(int argc, char ** argv){
     
            char    *c1;
            printf("c1 = %p\n", c1);
            c1 = NULL;
            printf("c1 = %p\n", c1);
     
            return 0;
    }
    c1 = (nil)
    c1 = (nil)
    Y a-t-il un lien avec saveptr ?

  11. #11
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 026
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 026
    Par défaut
    Il me semble que seul les variables globales sont initialisées à NULL.

    Pour toutes les autres variables, le contenu est indéterminé, le fait que c1 vaut NULL s'il n'est pas initialisé est sûrement dû à un coup de chance.

  12. #12
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2009
    Messages
    62
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2009
    Messages : 62
    Par défaut
    Citation Envoyé par Neckara Voir le message
    char * saveptr : rien à faire, ta fonction alloue les char
    char ** saveptr : il faut allouer un/des char * et ta fonction allouera les char pour le premier char *
    Certes, mais ce n'est pas le contenu de *saveptr qu'on passe en paramètre, mais l'adresse de celui-ci, ce qui revient au même qu’écrire le contenu d'un pointeur qui pointe sur *saveptr (= **saveptr non ?), du moins, c'est ce que je croyais

  13. #13
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 026
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 026
    Par défaut
    si tu as un char * x; et que tu fais &x tu obtient un char ** qui pointe vers x et x existe.

    si tu as un char **x; et que tu fais x tu as toujours un char ** mais il pointe n'importe où. D'où l'apparition d'un SEGFAULT.

  14. #14
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2009
    Messages
    62
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2009
    Messages : 62
    Par défaut
    Je pense avoir compris, mais une allocation préalable est nécessaire dans le cas ou on déclare char *x, sinon x n'existe pas en mémoire, tout comme pour char ** x qui pointe sur quelque chose qui n'existe pas si on ne lui alloue pas d'espace, et donc le fait que ça marche sur mon tout premier code sans allouer de mémoire pour char * saveptr n'est qu'un coup de chance non ?

  15. #15
    Membre Expert Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Par défaut
    le fait que ça marche sur mon tout premier code sans allouer de mémoire pour char * saveptr n'est qu'un coup de chance non ?
    Non parce que strtok_r n'a pas besoin que char* saveptr soit alloué car il n'utilise pas saveptr comme un chaine de caractère en soi mais comme une variable pour se souvenir d'un pointeur existant ! Un peu comme un indice lorsque tu parcours un tableau.

    Donc tu peux imaginer que strtok_r fait ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    char *strtok_r(char *str, const char *delim, char *saveptr)
     
     1) Parcourt str jusqu'à rencontrer un délimiteur.
     2) Lorsqu'on a rencontré un délimiteur, on veut pouvoir sauvegarder où on est arrivé, pour pouvoir continuer par la suite. Donc on fait par exemple : 
     
    saveptr = &str[indice_courant];
    Dans le code du dessus, le problème c'est que saveptr est copié par valeur, donc saveptr est une variable locale et modifier le contenu d'une variable locale, qui est ici une adresse, n'est pas vu de "l'extérieure" de la fonction. Si on veut pouvoir modifier l'adresse vers laquelle pointe un pointeur, il faut passer l'adresse de ce pointeur... Et faire:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    char *strtok_r(char *str, const char *delim, char **saveptr)
    {
      *saveptr = &str[indice_courant];
      // ...
    }
    Alors là, les modifications sont vues en dehors de la fonction vu que *saveptr n'est pas local à la fonction contrairement à saveptr.

    Dans le premier exemple *saveptr pointe vers un char... Pas pratique pour stocker une adresse.

  16. #16
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2009
    Messages
    62
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2009
    Messages : 62
    Par défaut
    Si j'ai bien compris cette fois-ci, on a:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    char *saveptr; 
    /* Dans ce cas saveptr est stocké dans la mémoire, seul son contenu vaut NULL c'est bien ca ? 
    Ici saveptr est alloué, et la valeur sur laquelle il pointera par la suite l'est deja aussi */
     
    char *strtok_r(char *str, const char *delim, char &*saveptr){ 
     
       *saveptr = &str[indice_courant]; //Au lieu de valoir NULL, le contenu de saveptr vaudra désormais &str[indice_courant], qui est déjà alloué
       // ...
    }
    Et

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    char ** saveptr;
    /* Ici, saveptr est en mémoire, de même que str, mais le pointeur "entre les deux" ne l'est pas */
    char *strtok_r(char *str, const char *delim, char **saveptr)
    {
      /* On demande alors au pointeur sur lequel saveptr pointe, qui n'est pas alloué ici,
     de pointer sur str[indice_courant], d'ou l'erreur de segmentation */
      *saveptr = &str[indice_courant];
      // ...
    }
    C'est bien ça ?

  17. #17
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 026
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 026
    Par défaut
    Comme je l'ai dit :

    Citation Envoyé par Neckara Voir le message
    Il me semble que seul les variables globales sont initialisées à NULL.

    Pour toutes les autres variables, le contenu est indéterminé, le fait que c1 vaut NULL s'il n'est pas initialisé est sûrement dû à un coup de chance.

    Déclarer une variable ne l'initialise pas (sauf pour les variables globales).
    Le contenu d'une variable déclarée et non initialisée est indéterminé.

    C'est pour cela que Diogene te dis qu'il faut initialiser c1 à NULL avant d'appeler getline.

  18. #18
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2009
    Messages
    62
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2009
    Messages : 62
    Par défaut
    Autant pour moi, au lieu de dire que saveptr pointe sur NULL dans le premier cas, j'aurais du dire qu'il pointe sur n'importe quoi, mais sinon ce que j'ai dit est correct non ?

  19. #19
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 026
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 026
    Par défaut
    Tes commentaires juste avant l'appel de la fonction strtok_r sont un peu ambigüe. Quand tu dis 'ici' considères-tu que tu es dans la fonction strtok_r ou que tu es après la déclaration de ton pointeur?

    L'allocation du tableau de caractère se fait dans strtok_r.

  20. #20
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2009
    Messages
    62
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2009
    Messages : 62
    Par défaut
    Citation Envoyé par Neckara Voir le message
    Tes commentaires juste avant l'appel de la fonction strtok_r sont un peu ambigüe. Quand tu dis 'ici' considères-tu que tu es dans la fonction strtok_r ou que tu es après la déclaration de ton pointeur?

    L'allocation du tableau de caractère se fait dans strtok_r.
    Je considère qu'on est après la déclaration du pointeur, pourquoi une allocation dans la fonction strtok_r serait necessaire si on fait pointer saveptr sur un contenu déjà alloué (str en l'occurence)? L'allocation n'est-elle pas nécessaire uniquement pour pointer sur un contenu "nouveau" ?
    Du style:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    char *c = malloc(4);
    strcpy(c, "Hey"); // On alloue car il faut stocker "Hey" qui est un nouveau contenu
    Mais:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    char *c;
    char *str = malloc(4);
    strcpy(str, "Hey");
    c = str; //Le contenu est déjà alloué, pas besoin d'une autre allocation pour c

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

Discussions similaires

  1. Différence entre un "bidouilleur" et un Pro ?
    Par christ_mallet dans le forum Débats sur le développement - Le Best Of
    Réponses: 290
    Dernier message: 28/11/2011, 10h53
  2. Différence entre TCP, UDP, ICMP
    Par GliGli dans le forum Développement
    Réponses: 1
    Dernier message: 13/09/2002, 08h25
  3. Différences entre jmp, jz, jnz, etc
    Par christbilale dans le forum Assembleur
    Réponses: 3
    Dernier message: 05/07/2002, 15h09
  4. Réponses: 3
    Dernier message: 07/05/2002, 16h06

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