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 :

[pointeur][passage par référence] Perte des valeurs.


Sujet :

C

  1. #1
    Expert confirmé
    Avatar de ced600
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Août 2006
    Messages
    3 364
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Août 2006
    Messages : 3 364
    Points : 4 061
    Points
    4 061
    Par défaut [pointeur][passage par référence] Perte des valeurs.
    Bonjour,

    J'ai crée la fonction suivante :
    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
    static void CopyValue(char* data, int start, char *value)
    {
    	int i = 0;
    	char *result;
    	int size = 0;
     
    	size = (strlen(data) - start);
     
    	result = (char*)malloc(size);
     
    	for (i = 0; i < size; i++)
    	{
    		result[i] = data[i + start + 1];
    	}
     
    	result[size] = '\0';
    	value = result;
    }
    Je l'appelle ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    char *touri;
    //p est le résultat d'un strtok
    //7 est un valeur pour décalé ma copie, ne pas la commencer au début de p.
    CopyValue(p, 7, touri);
    D'après le débugger p possède la bonne valeur, et result et value obtienne les bonnes valeurs.

    Pourtant, toujours d'après le débugger (et des puts) touri reste non initialisé.
    Comme si tout était détruis à la fin de la fonction.
    Pourtant je pensé ici faire un passage par référence, est même si result est supprimé, comme value est conservé, je devrais conservé les données non ?

    Je ne comprends plus, c'est dure de repassé du C#, un langage managé, au C où il faut tout gérer soit même !!!

    Je remercie d'avance toutes personnes se penchant sur mon problème.

  2. #2
    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 ced600 Voir le message
    Pourtant, toujours d'après le débugger (et des puts) touri reste non initialisé.
    Comme si tout était détruis à la fin de la fonction.
    Pourtant je pensé ici faire un passage par référence, est même si result est supprimé, comme value est conservé, je devrais conservé les données non ?
    http://emmanuel-delahaye.developpez....difie_variable

  3. #3
    Rédacteur
    Avatar de Vincent Rogier
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    2 373
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 2 373
    Points : 5 306
    Points
    5 306
    Par défaut
    [pointeur][passage par référence] Perte des valeurs.
    Le passage de paramètre par référence n'existe pas en C.

    Le C ne connait que le passage par valeur.

    C'est pourquoi tout valeur affectée à 'value' ne sera sauvegardée en sortie de fonction... car 'value' est une copie de la variable passée à la fonction...

  4. #4
    Expert confirmé
    Avatar de ced600
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Août 2006
    Messages
    3 364
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Août 2006
    Messages : 3 364
    Points : 4 061
    Points
    4 061
    Par défaut
    Merci pour vos réponses.
    Donc si je fais cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    CopyValue(p, 7, &touri);
    Cela devrait marcher ?
    Ou faut il aussi dans le prototype de ma fonction que je fasses ceci ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    static void CopyValue(char* data, int start, char **value)
    Je crois qu'il faut que je revise un peu plsu la notion de pointeur. Je ne pensais pas avoir tant perdu, mais maintenant je me souviens que je me perdais déjà avant dans la symbolique pour désigner les éléments que je désire.

    Si &touri me donne l'adresse d'un pointeur, normalement l'affecté lors du passage en argument à un char *value devrait me créer un pointeur sur le pointeur non ? car si value représente l'élément pointé, *value représente le pointeur, et donc pour moi *value = &touri donnerait le stockage de l'adresse mémoire de touri dans la case mémoire du pointeur.
    Si je me trompe dite le moi.

    Je vais réessayer cette solution, et si cela ne marche pas, je mettrais temporairement le code de la fonction dans la fonction appelante.

    Au début je fonctionnais avec une fonction qui retourne un pointeur, mais au bout de 5 appels j'obtenais une erreur Memory corrutpion.
    D'après ce que j'ai lu, c'est du à une mauvaise getion de la mémoire de ma part, des mauvaises libération, des non libérations, des mauvaises allocation, ...
    Bref je voulais modifier cette fonction pour comprendre un peu mieux ce que je faisais de mal.
    Si le fait de rfaire un malloc constant sur result posais un problème (c'était la ligne pointé par le memory corruption)
    Ma fonction ressemblait à cela :
    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
    static char* CopyValue(char* data, int start)
    {
    	int i = 0;
    	char *result;
    	int size = 0;
     
    	size = (strlen(data) - start);
     
    	result = (char*)malloc(size);
     
    	for (i = 0; i < size; i++)
    	{
    		result[i] = data[i + start + 1];
    	}
     
    	result[size] = '\0';
                 return result;
    }
    et l'appelle :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    char *touri;
    touri = CopyValue(p, 7);
    Bon je vais refaire des tests mais si vous avez d'autre conseils, n'hésitez pas, et encore merci.

  5. #5
    Rédacteur
    Avatar de Vincent Rogier
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    2 373
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 2 373
    Points : 5 306
    Points
    5 306
    Par défaut
    Quelques remarques :
    • pas de test de si 'data' est null
    • pas de test de retour de malloc
    • pas de test si 'start' est plus grand que la longueur de 'data'
    Bon, voici une version modifiée à rapidement :

    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
    static char* CopyValue(const char* src, int start)
    {
        char *dst, *s;
        size_t size;
     
        if (src == NULL)
            return NULL;
     
        size = strlen(src) - start;
     
        if (size <= 0)
           return NULL;
     
        s = dst = malloc(size + 1);
     
        if (s == NULL)
            return NULL;
     
        src += start;
     
        while (*src)
            *s++ = *src++;
     
        *s = 0;
     
       return dst;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    int main(void)
    {
        char *p = CopyValue("TOTO VA A LA PLAGE MAIS OUBLIE SON MAILLOT", 19);
        printf(p);
        free(p);
     
       return EXIT_SUCCESS;
    }
    output :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MAIS OUBLIE SON MAILLOT

  6. #6
    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 ced600 Voir le message
    Donc si je fais cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    CopyValue(p, 7, &touri);
    Cela devrait marcher ?
    Ou faut il aussi dans le prototype de ma fonction que je fasses ceci ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    static void CopyValue(char* data, int start, char **value)
    Oui.
    Si &touri me donne l'adresse d'un pointeur, normalement l'affecté
    Incompréhensible. Tu veux dire "l'affecter" ? Une orthographe correcte, ça sert surtout à se faire comprendre...

    , lors du passage en argument à un char *value devrait me créer un pointeur sur le pointeur non ?
    Ca donne surtout une incompatibilité de type (en principe détectée par le compilateur).
    &touri est de type char ** et non char *.
    car si value représente l'élément pointé, *value représente le pointeur,
    C'est pas un peu le contraire ?
    et donc pour moi *value = &touri donnerait le stockage de l'adresse mémoire de touri dans la case mémoire du pointeur.
    Si je me trompe dite le moi.
    Mal à la tête.

    Je crois qu'on t'a donné tous les éléments. Si tu as une théorie à vérifier, règle bien ton compilateur, fait des essais et tu verras bien. Tant que ça couine, c'est que c'est faux.
    Au début je fonctionnais avec une fonction qui retourne un pointeur, mais au bout de 5 appels j'obtenais une erreur Memory corrutpion.
    Pas normal. Montre ton code.
    Euh, c'est pas parce qu'une technique ne fonctionne pas qu'il faut l'abandonner. Il faut surtout chercher à comprendre pourquoi elle ne fonctionne pas. Si la théorie dit qu'elle doit fonctionner, c'est qu'il y a un bug dans ton code. On ne met pas une théorie à la poubelle pour un bug...
    D'après ce que j'ai lu, c'est du à une mauvaise getion de la mémoire de ma part, des mauvaises libération, des non libérations, des mauvaises allocation,
    Je préfère ça...
    Bref je voulais modifier cette fonction pour comprendre un peu mieux ce que je faisais de mal.
    Passer l'adresse d'un pointeur en paramètre complique considérablement la compréhension et le codage. Retourner l'adresse est plus clair et plus simple. C'est ce que font malloc() et fopen(). Certainement pas un hasard... Il y a quelques âneries de conception dans la bibliothèque standard, mais il y a surtout un tas de bonnes pratiques. Ne jamais les négliger...

    Comme souvent, c'est pas un problème de pointeur, mais de débordement de tableau.

    Il faut allouer une place pour le 0 final.

    Ton code est plus compliqué que nécessaire, mais il manque des contrôles

    Ceci 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
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
     
    /* http://emmanuel-delahaye.developpez.com/clib.htm */
    #include "ed/inc/prt.h"
    #include <string.h>
    #include <stdlib.h>
     
    static char *CopyValue (char const *data, int start)
    {
       char *result = NULL;
       if (data != NULL)
       {
          int size = (strlen (data) + 1 - start);
          if (size > 0)
          {
             result = malloc (size);
             if (result != NULL)
             {
                memcpy (result, data + start, size);
             }
          }
       }
       return result;
    }
     
    int main (void)
    {
       int start;
       for (start = 0; start < 10; start++)
       {
          char const *p = "Hello";
          char *touri = CopyValue (p, start);
          if (touri != NULL)
          {
             PRT_S (touri);
             free (touri);
          }
          else
          {
             puts ("error");
          }
       }
       return 0;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    touri        = 'Hello'
    touri        = 'ello'
    touri        = 'llo'
    touri        = 'lo'
    touri        = 'o'
    touri        = ''
    error
    error
    error
    error
     
    Process returned 0 (0x0)   execution time : 0.010 s
    Press any key to continue.

  7. #7
    Expert confirmé
    Avatar de ced600
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Août 2006
    Messages
    3 364
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Août 2006
    Messages : 3 364
    Points : 4 061
    Points
    4 061
    Par défaut
    Merci pour vos réponse.
    Je vais essayer le solution de vicenzo dès que je peux.

    Pas normal. Montre ton code.
    Euh, c'est pas parce qu'une technique ne fonctionne pas qu'il faut l'abandonner. Il faut surtout chercher à comprendre pourquoi elle ne fonctionne pas. Si la théorie dit qu'elle doit fonctionner, c'est qu'il y a un bug dans ton code. On ne met pas une théorie à la poubelle pour un bug...
    lol c sur, en général je réponds ce genre de chose aussi sur le forum VBS
    Mais bon là je ne voulais pas perdre de temps, maintenant, sur le problème, mais au final, j'en ai quand même perdu

    Ca donne surtout une incompatibilité de type (en principe détectée par le compilateur).
    &touri est de type char ** et non char *.
    En effet, il a couiné.

    Citation:
    car si value représente l'élément pointé, *value représente le pointeur,
    C'est pas un peu le contraire ?
    Citation:
    et donc pour moi *value = &touri donnerait le stockage de l'adresse mémoire de touri dans la case mémoire du pointeur.
    Si je me trompe dite le moi.
    Mal à la tête.
    Oui moi aussi, semaine trop chargée, j'ai actuellement du mal à raisonner, vivement ce soir.


    Je ne pensais pas que le compilo accepté cela

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    while (*src)
            *s++ = *src++;
    Beaucoup mieux que ma boucle, mais je n'y aurais pas pensé seul !

    Edit :
    Merci aussi pour le dernier bout de code.
    Avec tout cela je comprends mieux les choses.
    Le memcpy, c'est vrai que j'aurais pu l'utiliser, surtout que je le fait déjà ailleur.
    Des fois vraiment on se demande à quoi l'on pense.

  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 ced600 Voir le message
    Je ne pensais pas que le compilo accepté cela
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    while (*src)
            *s++ = *src++;
    Beaucoup mieux que ma boucle, mais je n'y aurais pas pensé seul !
    Je déconseille fortement ce genre de syntaxe rusée, mais illisible. En fait, memcpy() est la bonne solution...

  9. #9
    Expert confirmé
    Avatar de ced600
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Août 2006
    Messages
    3 364
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Août 2006
    Messages : 3 364
    Points : 4 061
    Points
    4 061
    Par défaut
    Ok je viens de voir l'Edit.

  10. #10
    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 vicenzo Voir le message
    voici une version modifiée à rapidement :
    Y'a un bug... Avec ce code de test :
    http://www.developpez.net/forums/d60...s/#post3604910
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    touri        = 'Hello'
    touri        = 'ello'
    touri        = 'llo'
    touri        = 'lo'
    touri        = 'o'
    error
    touri        = 'touri'
    error
    error
    error
     
    Process returned 0 (0x0)   execution time : 0.033 s
    Press any key to continue.
    AMA, je suis dans la 4ème dimension...

  11. #11
    Rédacteur
    Avatar de Vincent Rogier
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    2 373
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 2 373
    Points : 5 306
    Points
    5 306
    Par défaut
    Bien vu Emmanuel !

    c'est la déclaration de size en 'size_t' couplée au test (size <= 0) qui est erronée car size ne peut avoir de valeur négative...

    donc, dans le code que j'ai posté il faut déclarer 'size' comme int et non pas size_t...

    Et puis en enlevant les multiple return pour fzire plus propre cela donne :

    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
    static char* CopyValue(const char* src, int start)
    {
        char *dst = NULL;
     
        if (src != NULL)
        {   
            int size = (int) (strlen(src) - start);
     
            if (size > 0)
            {
                char *s;
     
                s = dst = malloc((size_t) (size + 1));
     
                if (s != NULL)
                {             
                    src += start;
     
                    while (*src)
                        *s++ = *src++;
     
                    *s = 0;
                }
            }
        }
     
       return dst;
    }
    Sinon pour memcpy, avant de poster, j'ai aussi été tenté de l'utiliser comme toi car beaucoup plus simple et clair...

    mais pour une simple boucle, ajouter un appel de fonction alors qu'un simple while() suffit...

    De plus le memcpy() du runtime C de MS, est implémenté différemment si on est en 32 ou 64bits et peut être un peut plus longuet...

  12. #12
    Expert confirmé
    Avatar de ced600
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Août 2006
    Messages
    3 364
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Août 2006
    Messages : 3 364
    Points : 4 061
    Points
    4 061
    Par défaut
    hum....

    très intéressant.

    actuellement je code pour que cela marche, mais je vais devoir optimisé un maximum dans une deuxième étape, car on me demande, que tout un processus qu implique des echanges SIP (protocole) entre x machines, prenne moins de 200 ms.

    donc while serait plus rapide que memcpy sur des chaines de caractères de taille < à 100 ?

  13. #13
    Rédacteur
    Avatar de Vincent Rogier
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    2 373
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 2 373
    Points : 5 306
    Points
    5 306
    Par défaut
    Bon, suit le conseil de Emmanuel, la version avec memcpy() sera plus rapide.

    Car memcpy() est souvent codée en assembleur et donc plus optimisée...

    Je viens de faire des tests et la version memcpy() est de très loin la plus rapide !!!!

  14. #14
    Expert confirmé
    Avatar de ced600
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Août 2006
    Messages
    3 364
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Août 2006
    Messages : 3 364
    Points : 4 061
    Points
    4 061
    Par défaut
    Merci pour vos efforts.

    J'utiliserais le memcpy().

    En même temps, je vais faire une refonte de mon application entiérement, car la solution que j'ai choisis est une impasse (pas le pb que j'ai signalé ici, mais le choix fait dans l'utilisation des éléments d'une grosse librairie).
    Donc se bug devrait disparaître, mais au profit d'autre
    Si si je suis réaliste

    Bref l'occasion de coder plus proprement et en suivant les bonnes pratiques

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

Discussions similaires

  1. Pointeurs et passage par référence
    Par stephan1609 dans le forum Débuter
    Réponses: 5
    Dernier message: 08/08/2012, 16h43
  2. Passage par référence versus par pointeur
    Par Seabast888 dans le forum Débuter
    Réponses: 14
    Dernier message: 14/09/2009, 18h17
  3. Passage par référence/pointeur
    Par NiamorH dans le forum C++
    Réponses: 5
    Dernier message: 15/07/2008, 10h05
  4. Réponses: 10
    Dernier message: 27/06/2008, 14h16
  5. Passage par référence et non pas par valeur
    Par GPZ{^_^} dans le forum Flash
    Réponses: 2
    Dernier message: 14/05/2007, 15h21

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