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 :

Modifier un void pointer


Sujet :

C

  1. #1
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2014
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2014
    Messages : 6
    Par défaut Modifier un void pointer
    Bonjour,

    Je cherche a modifier un void pointer au sein d'une Hastable.
    Si le mot est présent dans la table j'incrémente son champs data de type (void *) de 1.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    void hastable_add(char *mot){
      Entry e;
      Entry* r;
      e.key=mot;
      r=hsearch(e,FIND);
      //voila ou ca se gate, normalement r contient l'addresse du résultat de ma recherche
      if(r!=null){
        int* nombre;
        nombre=(int *)(r->data);
        (*nombre)++;
        }
    }
    Je n'ai pas les résultats attendus.
    Je ne sais pas si pour changer le champs data je dois faire r->data ou (*r).data
    Si je modifie nombre, r->data doit bien être changé par référence non?

    Je vous remercie d'avance.

  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
    Donne un code compréhensible : il faut aussi donner la définition des types.

    Je ne sais pas si pour changer le champs data je dois faire r->data ou (*r).data
    C'est la même chose : -> est un sucre syntaxique pour alléger l'écriture.

    Si je modifie nombre, r->data doit bien être changé par référence non?
    Surement pas. D'ailleurs, tu ne modifies pas nombre mais *nombre

    D'après ce que tu écris, data serait un champ d'une structure Entry. Ce champ serait une adresse (sans doute un void*) de quelque chose. Ce quelque chose serait un int que tu veux incrémenter. Dans l'affaire, il n'est pas question de modifier r->data mais l'entier dont l'adresse est dans r->data

  3. #3
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2014
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2014
    Messages : 6
    Par défaut
    Merci pour la réponse.

    Je m'excuse pour la propreté du code.
    D'après ce que tu écris, data serait un champ d'une structure Entry.
    Oui, il s'agit bien d'une structure ENTRY.

    Son champs data est bien de type (void*)

    Il me semble qu'un cast en (int *) est nécessaire pour accéder à sa valeur afin de la modifier,mais je en sais pas comment changer cette valeur.
    Est que je dois passer par un nouveau pointeur pour modifier son champs ?

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

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

    Informations forums :
    Inscription : Février 2006
    Messages : 12 856
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Paltoquet Voir le message
    Son champs data est bien de type (void*)

    Il me semble qu'un cast en (int *) est nécessaire pour accéder à sa valeur afin de la modifier
    Bonjour
    Un cast en (int *) n'est nécessaire qu'à la condition que tu veuilles y stocker un int. Si tu veux y stocker un double, tu devras alors le caster en (double *). Et dans tous les cas, t'assurer qu'à l'adresse où tu stockes cet int (ou ce double) tu as la place de l'y mettre...

    Citation Envoyé par Paltoquet Voir le message
    mais je en sais pas comment changer cette valeur.
    Sous réserve que data pointe vers une zone mémoire suffisante pour stocker cette valeur: *(int*)r->data=valeur.

    Dans ton cas, il semble que tu veuilles juste incrémenter la valeur qui s'y trouve: (*(int*)r->data)++ (ce qui correspond en plus compact à ce que t'avais écrit avec ton pointeur "nombre"...

    Citation Envoyé par Paltoquet Voir le message
    Je n'ai pas les résultats attendus.
    Alors vérifie les valeurs initiales...

    Citation Envoyé par Paltoquet Voir le message
    Est que je dois passer par un nouveau pointeur pour modifier son champs ?
    Quand tu as des pièces dans la poche droite, est-ce que tu dois d'abord les passer dans la poche gauche pour payer ton pain ?
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

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

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    il y a une ambiguité dans la manière dont tu présentes les choses:
    Que veux-tu incrémenter , le champ data (donc l'adresse sans doute d'un int) ou ce qui est pointé par le champ data (apparemment un int) ?
    Tu parles toujours d'incrémenter le champ data et tu codes l'incrément de ce qui est pointé par data.
    Tout cela n'est pas clair : Quelle est ton intention ?

  6. #6
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2014
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2014
    Messages : 6
    Par défaut
    Je suis désolé si je m'exprime mal.

    Le but de cette fonction est de lire un fichier text et d'ajouter chacun des mots à une table dont le champs pointé par data contient le nombre d’occurrence du mot.

    Avec vos remarques j'en suis arrivé à ce code là:
    la fonction add
    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
     
    void hash_table_add(char *mot){
    	ENTRY* r;
    	ENTRY e;
    	e.key=mot;
    	r=hsearch(e,FIND);
    	if(r==NULL){
    		int a=1;
    		e.data=&a;
    		e.key=mot;
    		r=hsearch(e,ENTER);
    		return;
    	}
    	else{
    	(*((int*)(r->data)))++;
    }
    }
    la fonction hash_table_search
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    int hash_table_search(char *mot){
    	ENTRY* r;
    	ENTRY e;
    	e.key=mot;
    	r=hsearch(e,FIND);
    	if(r==NULL){
    		return 0;
    		}
    	else {
    	return *(int*)(r->data);
    }
    }
    le problème lorsque je test le code suivant:
    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
    int main(void)
    {
     
      hash_table_create();
      /* Remplissage de la table */
      hash_table_add("foo");
      hash_table_add("bar");
      hash_table_add("bar");
     
      /* Afficher la valeur associée à un mot */
      printf("Nombre d'occurences de bar: %d\n", hash_table_search("bar"));
      printf("Nombre d'occurences de foo: %d\n", hash_table_search("foo"));
      printf("Nombre d'occurences de zoo: %d\n", hash_table_search("zoo"));
     
      hash_table_destroy();
      return EXIT_SUCCESS;
    }
    j'obtient le même nombre d’occurrences (champs pointé par data) pour les 2 mots.
    Si vous avez des conseils n'hésitez pas, merci.

  7. #7
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 785
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 785
    Par défaut
    Voici un bout de code officiel
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
               int i;
     
    // ...
     
                   /* data is just an integer, instead of a
                      pointer to something */
                   e.data = (void *) i;
    Donc ce qui confirme ce que nous attendons. data est un void* donc c'est au développeur de définir ce qu'il veut

    PS: Note que dans le code officiel, un int est casté en pointeur. Mais ce n'est pas un pointeur: c'est un int

    Dans ton cas, data est l'adresse d'une variable locale: c'est crade et plantogène .
    Et en plus toutes les entrées sont initialisées avec cette adresse.
    Ne t'étonne pas d'avoir le même nombre d’occurrences

    De même, tu ne recopies pas la clef, mais tu transfères le pointeur (l'adresse): c'est crade .

  8. #8
    Membre chevronné
    Inscrit en
    Juillet 2012
    Messages
    231
    Détails du profil
    Informations forums :
    Inscription : Juillet 2012
    Messages : 231
    Par défaut
    Citation Envoyé par foetus Voir le message
    Voici un bout de code officiel
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
               int i;
     
    // ...
     
                   /* data is just an integer, instead of a
                      pointer to something */
                   e.data = (void *) i;
    Donc ce qui confirme ce que nous attendons. data est un void* donc c'est au développeur de définir ce qu'il veut

    PS: Note que dans le code officiel, un int est casté en pointeur. Mais ce n'est pas un pointeur: c'est un int
    Code officiel que je ne conseillerais pas de suivre (même si en pratique ça fonctionne souvent, rien ne le garanti). Cf. cette discussion.

  9. #9
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2014
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2014
    Messages : 6
    Par défaut
    Merci pour vos réponses.

    Si j’exécute ce code, j'obtient une erreur de segmentation.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    int a=(*(int*)(r->data))+1;
    r->data=(void*)a
    Sur le manuel de linux ca parait simple mais rien ne marche.
    http://linux.die.net/man/3/hsearch

    Si j'ai bien compris le champs data serait le même pour chaque entrée dans ma table ?
    Dans ton cas, data est l'adresse d'une variable locale: c'est crade et plantogène .
    Et en plus toutes les entrées sont initialisées avec cette adresse.
    Ne t'étonne pas d'avoir le même nombre d’occurrences
    Même ma fonction h_table_search n'obtient plus que des résultats nuls.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    int hash_table_search(char *mot){
    	ENTRY* r;
    	ENTRY e;
    	e.key=mot;
    	r=hsearch(e,FIND);
    	if(r==NULL){
    		return 0;
    		}
    	else {
    	return *(int*)((*r).data); // ce résultat serait nul ???
    }
    }
    Je commence à perdre espoir avec toutes ces erreurs de segmentation, ces pointeurs qui pointent vers une structure qui pointe vers des (void*).

    Je vous remercie pour votre aide jusqu'à présent.

  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
    Dans ENTRY
    - key contient l'adresse de départ de la chaine servant de clé
    - data contient l'adresse où se trouve la donnée
    Lorsqu'on fait hsearch(e,ENTER), une copie de e sera mise dans la table qui contiendra alors l'adresse de départ de la chaine servant de clé et l'adresse où se trouve la donnée.
    Naturellement, lorsqu'on va consulter la table, il faut que ces adresses aient un sens autrement dit que la chaine servant de clé et la donnée existent encore.

    Dans le code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    	if(r==NULL){
    		int a=1;
    		e.data=&a;
    		e.key=mot;
    		r=hsearch(e,ENTER);
    		return;
    	}
    la donnée a est locale au bloc et cesse d'exister dès qu'on sort du bloc. Alors, l'entrée stockée dans la table n'a plus de sens à la sortie de la fonction hash_table_add() puisque cette entrée contient l'adresse d'une variable qui n'existe plus!

    Dans l'exemple horrible du man, il ne se servent pas du champ data pour stocker l'adresse de la donnée mais bidouillent pour stocker la donnée elle-même ce qui fait qu'ils n'ont pas ce problème à résoudre.

    A retenir : dès qu'on prend l'adresse d'une variable locale il faut s'assurer que cette adresse ne sera utilisée que dans le domaine d'existence de la variable locale

  11. #11
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2014
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2014
    Messages : 6
    Par défaut
    Ca marche merci beaucoup.
    Ca
    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
     
    void hash_table_add(char *mot){
    	ENTRY* r;
    	ENTRY e;
    	e.key=mot;
    	r=hsearch(e,FIND);
    	if(r==NULL){
    		int a=1;
    		e.data=&a;
    		e.key=mot;
    		r=hsearch(e,ENTER);
    		return;
    	}
    	else{
    	(*((int*)(r->data)))++;
    }
    }
    devient:
    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
     
    void hash_table_add(char *mot){
    	ENTRY* r;
    	ENTRY e;
    	e.key=mot;
    	r=hsearch(e,FIND);
    	if(r==NULL){
    		e.data=(int*)malloc(sizeof(int));
    		*(int *)(e.data)=1;
    		e.key=mot;
    		r=hsearch(e,ENTER);
    		return;
    	}
    	else{
    	(*((int*)(r->data)))++;
    }
    }
    Une dernière question le malloc est bien nécessaire pour allouer l'espace ou la structure entry le fait déjà?
    Merci à vous tout.

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

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

    Informations forums :
    Inscription : Février 2006
    Messages : 12 856
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Paltoquet Voir le message
    Une dernière question le malloc est bien nécessaire pour allouer l'espace ou la structure entry le fait déjà?
    Définir une variable "toto" de type "struct entry" te garanti que tu auras l'espace pour stocker un pointeur dans le membre "toto.data". Mais si ce pointeur "toto.data" doit pointer sur une (autre) zone contenant des informations, il te faut alors impérativement allouer l'espace mémoire nécessaire au stockage de ces informations. Ou alors, dans l'hypothèse que l'espace mémoire ait été alloué à un autre moment, tu as alors le droit de récupérer dans ce champ "toto.data" l'adresse allouée à ce moment là. Mais d'une façon ou d'une autre l'allocation est, à un moment donné, obligatoire...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  13. #13
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2014
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2014
    Messages : 6
    Par défaut
    Ok merci tout le monde.

    Résolu.

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

Discussions similaires

  1. dereferencing void pointer
    Par Halo2550 dans le forum C
    Réponses: 10
    Dernier message: 06/02/2014, 19h25
  2. modifier une chaîne de caractères dans une fonction void
    Par jujudelyon dans le forum Débuter
    Réponses: 10
    Dernier message: 11/01/2014, 18h47
  3. Fonctions void pour modifier des paramètres
    Par shtroumpf_a_lunettes dans le forum Débuter
    Réponses: 15
    Dernier message: 16/04/2012, 21h37
  4. Réponses: 14
    Dernier message: 19/07/2011, 14h43
  5. Réponses: 3
    Dernier message: 05/12/2008, 09h51

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