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 :

Les fonctions / pointeurs


Sujet :

C

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    120
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2008
    Messages : 120
    Par défaut Les fonctions / pointeurs
    Bonjour,
    j'ai une question concernant les fonctions/pointeurs:
    dans une fonction je fait int x;
    j'alloue un espace de la mémoire, disons en imageant que l'adresse est la case 16 ( pour simplifié)
    x=10; la case 16 contient l'entier 10

    maintenant dans une autre fonction je passe en paramètre int x
    et je dit dedans que x=12
    la l'entier x sera donc alloué localement dans un espace de la mémoire différente disons que l'adresse est la case 96
    donc cela induit que toutes variables déclarer dans une fonction est définit localement (occupe un espace mémoire spécifique)
    C'est pour cela qu'on passe en paramètre l'adresse, pour pouvoir directement travaillé sur l'espace de la mémoire où est stocker la variable.(je parle dans le cas où on a besoin de la modifié)
    Est ce bien comme cela que sa fonctionne?

    Merci d'avance pour votre aide.

  2. #2
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    120
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2008
    Messages : 120
    Par défaut
    Mais voilà une contradiction à ce que j'ai dit avant:

    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
     
    #include<stdio.h>
    void saisie(char *mot){
      printf("saisir un mot:");
      scanf("%s",mot);
    }
     
    void affiche(char *mot){
      printf("%s\n",mot);
    }
    int size(char *mot){
      int i=0,cpt=0;
      while(mot[i]!='\0'){
        cpt++;
        i++;
      }
      return cpt;
    }
     
    void transforme(char *mot){
      int i;
      for(i=0;i<size(mot);i++){
        if(mot[i]==(tolower(mot[i])))
          mot[i]=toupper(mot[i]);
        else
          mot[i]=tolower(mot[i]);
      }
    }
     
    int main(void){
      char mot[50];
      saisie(mot);
      affiche(mot);
      transforme(mot);
      printf("size=%d\n",size(mot));
      affiche(mot);
      return 0;
    }
    Pour la fonction transforme et saisie je modifie "mot" sans passer l'adresse et je l'est bien modifié dans le main...
    Je ne comprend plus du tout
    Les chaînes de caractères ne sont pas définit localement?

  3. #3
    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
    j'ai une question concernant les fonctions/pointeurs:
    ....
    Est ce bien comme cela que sa fonctionne?
    Oui

    Pour la fonction transforme et saisie je modifie "mot" sans passer l'adresse et je l'est bien modifié dans le main...
    mot est un tableau. L'identificateur d'un tableau (hors le cas des opérateurs sizeof et & (adresse de)) est interprété comme "adresse du premier élément du tableau". Donc tu passes bien l'adresse !

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    120
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2008
    Messages : 120
    Par défaut
    Ok merci , j'essaye de faire apparaitre avec les équivalences, mais je n'arrive pas pour size(mot) (pour le définir localement) (la paramètre aussi qui devrai être un pointeur de pointeur)

    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
     
     
    void transforme(char *(&(*mot))){
      int i;
      for(i=0;i<size(mot);i++){
        if(*(mot+i)==(tolower(*(mot+i))))
          *(mot+i)=toupper(*(mot+i));
        else
          *(mot+i)=tolower(*(mot+i));
      }
    }
    int main(void){
      char mot[50];
      transforme(&(mot[0]));
      return 0;
    }
    mot=mot+0=&(mot[0])
    *mot=mot [0]
    *(mot+i)=mot[i]

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

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par Delnir Voir le message
    Ok merci , j'essaye de faire apparaitre avec les équivalences, mais je n'arrive pas pour size(mot) (pour le définir localement) (la paramètre aussi qui devrai être un pointeur de pointeur)
    Que de complications...
    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
     
    #include <ctype.h>
    #include <stdio.h>
     
    void transforme (char *mot)
    {
       int i;
       for (i = 0; mot[i] != 0; i++)
       {
          if (islower (mot[i]))
          {
             mot[i] = toupper (mot[i]);
          }
          else
          {
             mot[i] = tolower (mot[i]);
          }
       }
    }
     
    int main (void)
    {
       char mot[50] = "Hello world !";
     
       printf ("'%s'\n", mot);
       transforme (mot);
       printf ("'%s'\n", mot);
     
       return 0;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    'Hello world !'
    'hELLO WORLD !'
     
    Process returned 0 (0x0)   execution time : 0.061 s
    Press any key to continue.

  6. #6
    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
    Ok merci , j'essaye de faire apparaitre avec les équivalences, mais je n'arrive pas pour size(mot) (pour le définir localement) (la paramètre aussi qui devrai être un pointeur de pointeur)
    Pourquoi un pointeur de pointeur ? Je ne comprend pas ton problème

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void transforme(char *(&(*mot))){
    ça ne compile pas ce truc !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    void transforme(char *mot){
      int i;
      for(i=0;i<size(mot);i++){
    Pourquoi appeler la fonction à chaque boucle ? Ca coûte cher en temps de reparcourir la chaîne à chaque fois et c'est inutile.

    Ici cpt ne sert à rien :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int size(char *mot){
      int i=0;
      while(mot[i]!='\0'){
        i++;
      }
      return i;
    }

  7. #7
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    120
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2008
    Messages : 120
    Par défaut
    Pour les complications, c'est mon tp qui me demande sa
    Mais en faite mon erreur c'est de mélanger les pointeurs et tableau ce qui est complètement différent.
    Sinon si j'ai bien comprit les variables locales par rapport à mon 1er poste sa n'existe pas avec les tableaux? (car on va toujours passer l'adresse)

  8. #8
    Membre Expert Avatar de nicolas.sitbon
    Profil pro
    Inscrit en
    Août 2007
    Messages
    2 015
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 2 015
    Par défaut
    Citation Envoyé par Emmanuel Delahaye Voir le message
    Que de complications...
    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
     
    #include <ctype.h>
    #include <stdio.h>
     
    void transforme (char *mot)
    {
       int i;
       for (i = 0; mot[i] != 0; i++)
       {
          if (islower (mot[i]))
          {
             mot[i] = toupper (mot[i]);
          }
          else
          {
             mot[i] = tolower (mot[i]);
          }
       }
    }
     
    int main (void)
    {
       char mot[50] = "Hello world !";
     
       printf ("'%s'\n", mot);
       transforme (mot);
       printf ("'%s'\n", mot);
     
       return 0;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    'Hello world !'
    'hELLO WORLD !'
     
    Process returned 0 (0x0)   execution time : 0.061 s
    Press any key to continue.
    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
    #include <ctype.h>
    #include <stdio.h>
    #include <stdlib.h>
     
    static void transforme (char * const mot)
    {
       size_t i;
       for (i = 0; mot[i] != 0; i++)
       {
          if (islower ((unsigned char) mot[i]))
          {
             mot[i] = toupper ((unsigned char) mot[i]);
          }
          else
          {
             mot[i] = tolower ((unsigned char) mot[i]);
          }
       }
    }
     
    int main (void)
    {
       char mot[] = "Hello world !";
     
       puts (mot);
       transforme (mot);
       puts (mot);
     
       return 0;
    }

  9. #9
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    120
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2008
    Messages : 120
    Par défaut
    Autre exo de mon tp:
    écrire une fonction prenant un argument n et qui renvoie un pointeur vers l'adresse d'un tableau dynamique de n entiers

    écrire une fonction permettant d'initialiser le tableau précédent en affectant à chacune de ses cases la valeur de son indice

    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
     
     
    #include<stdio.h>
    #include<stdlib.h>
    int *init(int *tab,int n){
      int i;
      for(i=0;i<n;i++){
        tab=malloc(sizeof(int)+1);
        tab[i]=i;
      }
      return tab;
    }
     
    int *pointe(int n) {
      int *tab;
      tab=init(tab,n);
      return tab;
    }
     
     
    int main(void){
      int n=4;
      int *tab;
      tab=pointe(n);
      printf("%d",tab[1]);
      return 0;
    }
    Toute les cases de mon tableau sont à 0 je ne comprend pas l'erreur

  10. #10
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    120
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2008
    Messages : 120
    Par défaut
    ha c'est bon j'ai trouvé c'est
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    int *init(int *tab,int n){
      int i;
      tab=malloc(sizeof(int *)*n);
      for(i=0;i<n;i++){
        tab[i]=i;
      }
      return tab;
    }
    ou
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    int *init(int *tab,int n){
      int i;
      for(i=0;i<n;i++){
        tab=malloc(sizeof(int *)+i); 
        tab[i]=i;
      }
      return tab;
    }

  11. #11
    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
    Sinon si j'ai bien comprit les variables locales par rapport à mon 1er poste sa n'existe pas avec les tableaux? (car on va toujours passer l'adresse)
    Si, on peut avoir des tableaux en variables locales (si ils sont définis à l'intérieur d'une fonction). La caractéristique des variables locales (automatiques) est qu'elles sont automatiquement créées et automatiquement détruites en sortie de la fonction.
    Par contre, il est exact que lorsqu'on passe un tableau en argument à une fonction, c'est en fait son adresse qui est transmise. Ceci fait que la fonction peut modifier le tableau; toutefois, si la fonction ne doit pas modifier le tableau, on peut lui attribuer la caractéristique de pointeur sur des éléments constants :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    void f1( int * tab) // f1 peut modifier les éléments du tableau d'adresse tab
    void f2( const int * tab // f2 ne le peut pas
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    int *pointe(int n) {
      int *tab;
      tab=init(tab,n);
      return tab;
    }
    Un compilateur bien réglé émettra un avertissement : tab est utilisé sans avoir été initialisé. Il n'y a aucune raison de passer tab en argument (non initialisé par ailleurs) puisque init doit créer le tableau :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    int *pointe(int n) {
      return init(n);
    }
    Alors init devient :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int *init(int n){
      int i;
      tab=malloc(n*sizeof(int)); // demander de la mémoire pour placer UN tableau de n int
      for(i=0;i<n;i++)  tab[i]=i;
      return tab;                    // et renvoyer l'adresse du tableau créé
    }
    Dans cette fonction, tab et i sont des variables locales en allocation automatique (elles n'existent plus lorsque la fonction est terminée) , mais la zone mémoire allouée survit à la fin de la fonction : elle est en allocation dynamique et sera détruite que sur la demande du programmeur ( fonction free)

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

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par nicolas.sitbon Voir le message
    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
    #include <ctype.h>
    #include <stdio.h>
    #include <stdlib.h>
     
    static void transforme (char * const mot)
    {
       size_t i;
       for (i = 0; mot[i] != 0; i++)
       {
          if (islower ((unsigned char) mot[i]))
          {
             mot[i] = toupper ((unsigned char) mot[i]);
          }
          else
          {
             mot[i] = tolower ((unsigned char) mot[i]);
          }
       }
    }
     
    int main (void)
    {
       char mot[] = "Hello world !";
     
       puts (mot);
       transforme (mot);
       puts (mot);
     
       return 0;
    }
    Oui, c'est mieux.

  13. #13
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    120
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2008
    Messages : 120
    Par défaut
    Ok merci.
    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 *init(int n){
      int i;
      int *tab=NULL;
      for(i=0;i<n;i++){
        tab=malloc(sizeof(int *)+i); 
        tab[i]=i;
      }
      return tab;
    }
     
    int *pointe(int n) {
      return init(n);
    }
     
     
    int main(void){
      int n=4;
      int *tab=NULL;
      tab=pointe(n);
      printf("%d\n",tab[3]);
      return 0;
    }
    Je doit toujours initialiser un tableau à NULL, mais quand par exemple je déclare sans allocation dynamique tab[50] je devrai parcourir chaque case est la mettre à NULL?

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

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par Delnir Voir le message
    Je doit toujours initialiser un tableau à NULL,
    Pourquoi ? L'important est de donner tout de suite une valeur valide. Par exemple :
    mais quand par exemple je déclare sans allocation dynamique tab[50] je devrai parcourir chaque case est la mettre à NULL?
    Si c'est un tableau de pointeur, pourquoi pas, mais on peut aussi mettre la bonne valeur directement. Disons, que si on ne sait pas quoi mettre, on met NULL, parce que c'est une valeur valide qui signifie clairement 'pointeur invalide' et que c'est testable.

    Rappel : NULL ne concerne que les pointeurs.

  15. #15
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    120
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2008
    Messages : 120
    Par défaut
    J'ai comprit pour le cas du tableau mais la je ne saisie pas du tout pour les listes chaînées, la fonction pop et popR(même mais récursif), je ne passe pas l'adresse dans le main donc logiquement je ne devrai pas modifié ma liste chaînée?
    Pourtant quand je compile la liste est modifié
    Pourquoi?



    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    #include<stdlib.h>
    #include<stdio.h>
    typedef struct _file{
      int Elt;
      struct _file *suivant;
    }file;
     
    void init(file **p){
      *p=NULL;
    }
     
    void push(file **p,int val){
      file *p2=malloc(sizeof(file));
      p2->Elt=val;
      p2->suivant=*p;
      *p=p2;
    }
     
    void popR(file *p){
      if(p==NULL)
        return;
      if(p->suivant==NULL){
        free(p);
        return;
      }
      if((p)->suivant->suivant==NULL){
        free(p->suivant);
        p->suivant=NULL;
        return;
      }
      popR(p->suivant);
    }
     
     
    void pop(file *p){
      if(p==NULL)
        return;
      if((p)->suivant==NULL){
        free(p);
        return;
      }
      file *p2=p;
      file *p3=(p)->suivant;
      while(p3->suivant!=NULL){
        p2=p2->suivant;
        p3=p3->suivant;
      }
      p2->suivant=p3->suivant;
      free(p3); 
    } 
     
    void affiche(file *p){
      while(p!=NULL){
        printf("%d\n",p->Elt);
        p=p->suivant;
      }
    }
    int main(void){
      file *p;
      init(&p);
      push(&p,5);
      push(&p,3);
      affiche(p);
      pop(p);
      printf("REMOVE\n");
      affiche(p);
      return 0;
    }

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 393
    Par défaut
    Tu passes l'adresse du premier chainon, donc le chaînon et tous les suivants peuvent être modifiés.
    La seule chose que tu ne peux pas modifier, c'est le pointeur vers le premier chaînon.

    Une meilleure nomenclature devrait t'aider à comprendre:
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    #include<stdlib.h>
    #include<stdio.h>
     
    typedef struct chainon {
      int Elt;
      struct chainon *pSuivant;
    } chainonFile;
     
    void init(chainonFile **pp) {
      chainonFile * pNull = NULL;
      *pp = pNull;
    }
     
    void push(chainonFile **pp, int val) {
      chainonFile *p2 = malloc(sizeof(chainonFile));
      p2->Elt = val;
      p2->pSuivant = *pp;
      *pp = p2;
    }
     
    /* Detruit tous les chainons,
       mais ne modifie pas le pointeur vers le premier */
    void detruireFile(chainonFile *p) {
      /* Correction */
      while(p != NULL)
      {
        chainonFile *pDel = p;
        p = p->pSuivant;
        free(pDel);
      }
    }
     
     
    /* Correction: Il faut pouvoir modifier la file entière, 
       donc passer un pointeur de pointeur;
       on le mettra à NULL si on vide completement la pile */
    chainonFile ** getDernierPtr(chainonFile **pp)
    {
      if(pp==NULL) {
        return NULL;
      }
      if((*pp)==NULL) {
        return NULL;
      }
      while((*pp)->pSuivant != NULL)
      {
        pp = &( (*pp)->pSuivant; );
      }
      return pp;
    }
     
    void pop(chainonFile **pp) {
      chainonFile **ppDernier = getDernierPtr(pp);
      /* Note: Ici, ppDernier PEUT être égal à pp */
      if(ppDernier==NULL) {
        return;
      }
      free((*ppDernier));
      (*ppDernier) = NULL;
    } 
     
    void affiche(chainonFile const *p) {
      while(p!=NULL) {
        printf("%d\n",p->Elt);
        p = p->pSuivant;
      }
    }
     
    int main(void) {
      chainonFile *p;
      init(&p);
      push(&p,5);
      push(&p,3);
      affiche(p);
      pop(&p);
      printf("REMOVE\n");
      affiche(p);
      return 0;
    }
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  17. #17
    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
    p (dans main) contient l'adresse du premier maillon (ou NULL si il n'y en a pas).
    On va passer l'adresse de p, &p , en argument si l'adresse du premier maillon est susceptible de changer, comme dans init, push et ce devrait être le cas dans pop et popR :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    void pop(file *p){
      if(p==NULL)
        return;    // liste vide
      if((p)->suivant==NULL){ // liste avec 1 maillon
        free(p);              // suppression de ce maillon : la liste est maintenant vide
    // pourtant, la valeur de p dans la programme appelant n'a pas changé
    // et correspond maintenant à une adresse illégale.
    // Elle aurait du être mise à NULL
        return;
      }
    .....
    je ne passe pas l'adresse dans le main donc logiquement je ne devrai pas modifié ma liste chaînée?
    Si on a l'adresse du premier maillon, on peut modifier tous les maillons les uns après les autres, puisque chaque maillon comporte l'adresse du suivant.

  18. #18
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    120
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2008
    Messages : 120
    Par défaut
    Merci pour l'aide, alors tous d'abord concernant le message de médinoc:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    void init(chainonFile **pp) {
      chainonFile * pNull = NULL;
      *pp = pNull;
    }
    pourquoi ne pas directement mettre *pp=NULL?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    void detruireFile(chainonFile *p) {
      /* Correction */
      while(p != NULL)
      {
        chainonFile *pDel = p;
        p = p->pSuivant;
        free(pDel);
      }
    }
    Sa c'est pour qu'il n'y est pas de fuite mémoire ok, mais pourquoi ne pas supprimé le 1er chainon (je suppose qu'on met sa avant la fin du programme donc on en a plus besoin)?

    La je comprend pas du tout:
    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
     
    chainonFile ** getDernierPtr(chainonFile **pp)
    {
      if(pp==NULL) {
        return NULL;
      }
      if((*pp)==NULL) {
        return NULL;
      }
      while((*pp)->pSuivant != NULL)
      {
        pp = &( (*pp)->pSuivant; );
      }
      return pp;
    }
    Sa te permet d'avoir l'adresse du dernier maillon c'est sa?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
      if(pp==NULL) {
        return NULL;
      }
    Alors ici pp c'est une adresse donc tu test si une adresse est null, je ne savais pas que c'était possible.( sa marche comment sa?)

    Je sait que quand on a une adresse en paramètre d'une fonction on met pointeur de pointeur pour les listes chaînées mais je n'est pas vraiment comprit pourquoi?

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

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 393
    Par défaut
    Citation Envoyé par Delnir Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    void init(chainonFile **pp) {
      chainonFile * pNull = NULL;
      *pp = pNull;
    }
    pourquoi ne pas directement mettre *pp=NULL?
    Juste dans un but pédagogique, pour être plus clair: Ça montre bien les deux niveaux de pointeurs.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    void detruireFile(chainonFile *p) {
      /* Correction */
      while(p != NULL)
      {
        chainonFile *pDel = p;
        p = p->pSuivant;
        free(pDel);
      }
    }
    Sa c'est pour qu'il n'y est pas de fuite mémoire ok, mais pourquoi ne pas supprimé le 1er chainon (je suppose qu'on met sa avant la fin du programme donc on en a plus besoin)?
    Mais ce code supprime bien le premier chaînon. C'est juste qu'il ne change pas le pointeur dessus, qui doit alors être remis à NULL manuellement:
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    detruireFile(pPremier);
    pPremier = NULL;
    J'aurais pu faire comme pour les autres fonctions et passer un pointeur de pointeur, cela aurait été plus propre.

    La je comprend pas du tout:
    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
     
    chainonFile ** getDernierPtr(chainonFile **pp)
    {
      if(pp==NULL) {
        return NULL;
      }
      if((*pp)==NULL) {
        return NULL;
      }
      while((*pp)->pSuivant != NULL)
      {
        pp = &( (*pp)->pSuivant; );
      }
      return pp;
    }
    Sa te permet d'avoir l'adresse du dernier maillon c'est sa?
    Non, il permet d'avoir l'adresse du pointeur sur le dernier maillon.
    C'est-à-dire, l'adresse du pointeur qu'il faudra modifier.
    Et s'il n'y a pas de dernier maillon, on retourne NULL, mais en fait j'aurais dû retourner pp à la place.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
      if(pp==NULL) {
        return NULL;
      }
    Alors ici pp c'est une adresse donc tu test si une adresse est null, je ne savais pas que c'était possible.( sa marche comment sa?)
    Ce n'est pas l'adresse qui peut être nulle, mais le pointeur. C'est juste une vérification, normalement pp ne devrait jamais être nul. En temps normal, je mets une assertion plutôt qu'un test, mais je ne sais pas si tu connais les assertions, donc j'ai préféré ne pas compliquer les choses.

    Je sait que quand on a une adresse en paramètre d'une fonction on met pointeur de pointeur pour les listes chaînées mais je n'est pas vraiment comprit pourquoi?
    Pour que la fonction puisse modifier le pointeur, il faut passer son adresse. Donc, un pointeur de pointeur.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

Discussions similaires

  1. Question sur les pointeurs avec les fonctions
    Par Loester dans le forum Débuter
    Réponses: 2
    Dernier message: 01/02/2012, 22h56
  2. Usage des pointeurs dans les fonctions
    Par didou31 dans le forum Débuter
    Réponses: 12
    Dernier message: 22/11/2011, 13h31
  3. Réponses: 1
    Dernier message: 08/05/2008, 13h13
  4. doc sur les fonctions
    Par masterfab dans le forum C
    Réponses: 18
    Dernier message: 23/06/2005, 17h55
  5. Réponses: 7
    Dernier message: 24/05/2003, 15h56

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