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 :

Problème d'initialisation de pointeur


Sujet :

C

  1. #1
    Membre du Club
    Profil pro
    Étudiant
    Inscrit en
    Décembre 2008
    Messages
    7
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2008
    Messages : 7
    Par défaut Problème d'initialisation de pointeur
    Bonjour,

    Voici mon problème j'ai la fonction suivante qui me permet de créer dynamiquement un tableau 2D :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    void creat_plateau(int n,int **plateau){
    	int i;
    	int j;
    	plateau = malloc((2*n+1)*sizeof(int*));
    	for (i=0;i<2*n+1;i++){
    		plateau[i]=malloc((2*n+1)*sizeof(int));
    	}
    	for (i=0;i<2*n+1;i++){
    		for (j=0;j<2*n+1;j++){
    			plateau[i][j]=0;
    		}
    	}
    return;
    }
    et le main suivant j'ai mis uniquement la partie qui nous interressai :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    int main(){
    	int n;
    	int **plateau;
    	n=2;
    	creat_plateau(n,plateau);
    ......
    Mais cette solution retourne une erreur car le pointeur n' est pas initialisé

    j'ai donc penser a la solution 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
    19
    20
    21
    22
    23
    24
    int ** creer_plateau(int n){
    	int i;
    	int j;
    	int **plateau;
     
    	plateau = malloc((2*n+1)*sizeof(int*));
    	for (i=0;i<2*n+1;i++){
    		plateau[i]=malloc((2*n+1)*sizeof(int));
    	}
    	for (i=0;i<2*n+1;i++){
    		for (j=0;j<2*n+1;j++){
    			plateau[i][j]=0;
    		}
    	}
    return plateau;
    }
     
    int main(){
    	int n;
    	int **plateau;
    	char jouer;
    .........
    	plateau = creer_plateau(n);
    .........
    Je voudrai donc savoir si cette solution (qui marche car mon programme marche) principalement était juste.
    Peut-on retourner un ** pour une fonction ? (meme si je pense que oui vu que mon compilateur ne me dis rien.

    Pour info je suis sous Visual studio 2008.

    Merci 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
    Je voudrai donc savoir si cette solution (qui marche car mon programme marche) principalement
    était juste.
    Oui. C'est une solution naturelle : La fonction crée le tableau et renvoie l'adresse du tableau qu'elle a créé.
    Peut-on retourner un ** pour une fonction ?
    Bien sûr.

    Sur la fonction elle-même, le code devrait prévoir l'échec possible des allocations demandées avec malloc

  3. #3
    Membre du Club
    Profil pro
    Étudiant
    Inscrit en
    Décembre 2008
    Messages
    7
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2008
    Messages : 7
    Par défaut
    Merci pour ton aide.
    Et pour ta remarque :
    Citation Envoyé par diogene Voir le message
    Sur la fonction elle-même, le code devrait prévoir l'échec possible des allocations demandées avec malloc
    Que pensez vous de 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
    19
    int ** creer_plateau(int n){
    	int i;
    	int j;
    	int **plateau;
    	do{
    		plateau = malloc((2*n+1)*sizeof(int*));
    	}while(plateau==NULL);
    	for (i=0;i<2*n+1;i++){
    		do{
    			plateau[i]=malloc((2*n+1)*sizeof(int));
    		}while(plateau[i]==NULL);
    	}
    	for (i=0;i<2*n+1;i++){
    		for (j=0;j<2*n+1;j++){
    				plateau[i][j]=0;
    		}
    	}
    return plateau;
    }

    En revanche est-ce que ce code libère bien tous les espaces alloués ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    void liberer(int **plateau,int n){
    	int i;
     
    	for (i=0 ;i<2*n+1;i++){
    		free(plateau[i]);
    	}
    	free(plateau);
    return;
    }

  4. #4
    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
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    	do{
    		plateau = malloc((2*n+1)*sizeof(int*));
    	}while(plateau==NULL);
    Le do (ou le while) n'est pas appropié : si l'allocation a échoué, elle échouera pour les appels suivants et on va bouclé indéfiniment.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    plateau = malloc((2*n+1)*sizeof(int*));
    if(plateau!= NULL)
    {
    ....
    }
    return plateau;
    si la fonction renvoie NULL, l'allocation a échoué et le code appellant doit prendre les dispositions adéquates.


    Ca se complique ensuite : il faut libérer la mémoire allouée si il y a un échec.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
      plateau = malloc((2*n+1)*sizeof(int*));
      for (i=0;i<2*n+1 && plateau != NULL ;i++)
      {
         plateau[i]=malloc((2*n+1)*sizeof(int));
         if(plateau[i] == NULL)
         {
             for (j= 0; j<i; j++) free(plateau[j]) ; // libérez tout ce qui a été alloué
             free(plateau) ;
             plateau = NULL;
          }
          else  for (j= 0; j<i; j++) plateau[i][j] = 0;
       }
      return plateau;
    }
    [code non compilé, non testé]

  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
    En revanche est-ce que ce code libère bien tous les espaces alloués ?
    Oui, il y a un free pour chaque malloc dans la création et l'ordre des free est correct (inverse de celui des malloc).

  6. #6
    Membre du Club
    Profil pro
    Étudiant
    Inscrit en
    Décembre 2008
    Messages
    7
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2008
    Messages : 7
    Par défaut
    Merci beaucoup tout mes problèmes sont résolus

  7. #7
    Membre éclairé

    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Février 2005
    Messages
    464
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2005
    Messages : 464
    Par défaut
    Je pense qu'il y a eu un copier/coller malheureux ici :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    else  for (j= 0; j<i; j++) plateau[i][j] = 0;
    Ce ne serait pas plutôt : ?

    Dans ta fonction liberer(), par précaution je te conseille de tester que plateau et plateau[i] ne sont pas NULL avant d'appeler free().

    Sinon tu as bien compris le problème avec :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void creat_plateau(int n,int **plateau)
    Si tu voulais garder plateau en paramètre tu pouvais déclarer ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void creat_plateau(int n,int ***pPlateau)
    et lors de l'appel :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int main(){
    	int n;
    	int **plateau;
    	char jouer;
    .........
    	creer_plateau(&plateau );
    .........

  8. #8
    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 bizulk Voir le message
    Je pense qu'il y a eu un copier/coller malheureux ici :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    else  for (j= 0; j<i; j++) plateau[i][j] = 0;
    Ce ne serait pas plutôt : ?
    Ce code est correct :
    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
    69
    70
    71
    72
    73
    74
    75
    76
     
    #include <stdlib.h>
    #include <stdio.h>
     
    int **creer_plateau (int n)
    {
       int i;
       int j;
       int **plateau;
       plateau = malloc ((2 * n + 1) * sizeof (int *));
       for (i = 0; i < 2 * n + 1 && plateau != NULL; i++)
       {
          plateau[i] = malloc ((2 * n + 1) * sizeof (int));
          if (plateau[i] == NULL)
          {
             for (j = 0; j < i; j++)
                free (plateau[j]);  /* libérez tout ce qui a été alloué */
             free (plateau);
             plateau = NULL;
          }
          else
             for (j = 0; j < i; j++)
                plateau[i][j] = 0;
       }
       return plateau;
    }
     
    void liberer (int **plateau, int n)
    {
       int i;
     
       for (i = 0; i < 2 * n + 1; i++)
       {
          free (plateau[i]);
       }
       free (plateau);
       return;
    }
     
    static void remplir (int **plateau, int n)
    {
       int i;
       for (i = 0; i < n; i++)
       {
          int j;
          for (j = 0; j < n; j++)
          {
             plateau[i][j] = (i*n)+j;
          }
       }
    }
     
    static void afficher (int **plateau, int n)
    {
       int i;
       for (i = 0; i < n; i++)
       {
          int j;
          for (j = 0; j < n; j++)
          {
             printf ("%4d", plateau[i][j]);
          }
          printf ("\n");
       }
    }
    int main (void)
    {
       int **pp = creer_plateau (5);
       {
          remplir (pp, 5);
          afficher (pp, 5);
     
          liberer (pp, 5);
       }
       return 0;
    }
    Mais je en comprends pas pourquoi on doit allouer autant de bytes. La forme canonique est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    T *p = malloc (sizeof *p * n);
    il n'y a aucune raison de ne pas l'appliquer ici. Je ne vois donc pas pourquoi il faudrait faire plus compliqué que :
    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
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
     
    #include <stdlib.h>
    #include <stdio.h>
     
    int **creer_plateau (int n)
    {
       int **plateau = malloc (sizeof *plateau * n);
       int i;
       for (i = 0; plateau != NULL && i < n; i++)
       {
          plateau[i] = malloc (sizeof *plateau[i] * n);
          if (plateau[i] != NULL)
          {
             int j;
             for (j = 0; j < n; j++)
             {
                plateau[i][j] = 0;
             }
          }
          else
          {
             /* libérez tout ce qui a été alloué */
             int j;
             for (j = 0; j < i; j++)
             {
                free (plateau[j]);
             }
             free (plateau);
             plateau = NULL;
          }
       }
       return plateau;
    }
     
    void liberer (int **plateau, int n)
    {
       int i;
     
       for (i = 0; i < n; i++)
       {
          free (plateau[i]);
       }
       free (plateau);
       return;
    }
     
    static void remplir (int **plateau, int n)
    {
       int i;
       for (i = 0; i < n; i++)
       {
          int j;
          for (j = 0; j < n; j++)
          {
             plateau[i][j] = (i * n) + j;
          }
       }
    }
     
    static void afficher (int **plateau, int n)
    {
       int i;
       for (i = 0; i < n; i++)
       {
          int j;
          for (j = 0; j < n; j++)
          {
             printf ("%4d", plateau[i][j]);
          }
          printf ("\n");
       }
       printf ("\n");
    }
     
    int main (void)
    {
       int **pp = creer_plateau (5);
       {
          afficher (pp, 5);
          remplir (pp, 5);
          afficher (pp, 5);
     
          liberer (pp, 5);
       }
       return 0;
    }
    Dans ta fonction liberer(), par précaution je te conseille de tester que plateau et plateau[i] ne sont pas NULL avant d'appeler free().
    est parfaitement défini par la norme (pour une fois) et ne produit rien (no-op).

    Sinon tu as bien compris le problème avec :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void creat_plateau(int n,int **plateau)
    Si tu voulais garder plateau en paramètre tu pouvais déclarer ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void creat_plateau(int n,int ***pPlateau)
    et lors de l'appel :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int main(){
    	int n;
    	int **plateau;
    	char jouer;
    .........
    	creer_plateau(&plateau );
    .........
    Oui, c'est techniquement possible, mais totalement illisible (notamment le code de la fonction est cauchemardesque). L'autre solution est beaucoup plus claire et intuitive.

  9. #9
    Membre éclairé

    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Février 2005
    Messages
    464
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2005
    Messages : 464
    Par défaut
    Salut Emmanuel ! (décidément ...)

    Si il veut initialiser tous les éléments de sa colonne nouvellement crée alors la boucle
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ... for (j= 0; j<i; j++) plateau[i][j] = 0;
    n'est pas bonne ! D'ailleurs tu l'as corrigé dans ton code.
    Sauf erreur de ma part il a crée (2 * n + 1) case dans cette colonne.
    Après il pouvait toujours faire un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    memset(plateau[i], 0, (2 * n + 1) * sizeof (int))
    free(NULL);
    est parfaitement défini par la norme (pour une fois) et ne produit rien (no-op).
    Autant pour moi C'est tout à fait vrai !

    Sinon pour l'autre solution, j'espère ne pas l'avoir présentée comme étant meilleure, mais possible.

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

Discussions similaires

  1. Problème d'initialisation de pointeur
    Par NiKKrO dans le forum Débuter
    Réponses: 8
    Dernier message: 06/01/2009, 17h15
  2. Problème d'initialisation variable tableau
    Par HeZiX dans le forum Langage
    Réponses: 3
    Dernier message: 08/06/2005, 16h30
  3. Réponses: 4
    Dernier message: 08/02/2005, 20h47
  4. Pitié, aidez moi : Problème d'initialisation de postgreSQL
    Par ttalourd dans le forum PostgreSQL
    Réponses: 5
    Dernier message: 16/11/2004, 12h10
  5. Initialisation de pointeurs
    Par Gnux dans le forum C
    Réponses: 5
    Dernier message: 03/10/2003, 17h10

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