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 de portée de variables C


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre régulier
    Homme Profil pro
    Développeur décisionnel
    Inscrit en
    Décembre 2018
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Seine et Marne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2018
    Messages : 8
    Par défaut Problème de portée de variables C
    Bonjour à tous,

    J'ai besoin de votre concernant un problème basique (je fais du C depuis 48h, je demande donc votre indulgence ) concernant une portée de variable. Ci-joint mon code dans lequel le main appelle une fonction AllocInitMat allouant l'espace mémoire pour 3 matrices. Cette fonction remplit également les trois matrices (de façon simpliste, pour l'exemple).

    Mon problème est le suivant : Je peux très bien, après remplissage, dans la fonction imprimer le contenu des matrices. Cependant, je voudrais que celles-ci restent accessibles dans le main une fois l'exécution de la fonction terminée (pour par exemple les réutiliser dans une autre fonction, etc.).

    L'erreur semble donc apparaître lorsque intervient (A semble disparu ou non accessible !):

    Que manque t-il à cet exemple ?

    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
    #include <stdlib.h>
    #include <stdio.h>
     
    void AllocInitMat(int** , int** , int** , int , int );
     
    int main(void){
     
      int dimL = 0, dimC = 0, i = 0, j = 0;
      int** A = NULL;
      int** B = NULL;
      int** RES = NULL;
     
      // Récupération des dimensions
      printf("Nombre de lignes : "); scanf("%d", &dimL);
      printf("Nombre de colonnes : "); scanf("%d", &dimC);
     
      // Allocation et remplissage
      AllocInitMat(A, B, RES, dimL, dimC);
     
      printf("%d", A[0][0]);
     
      // Libération de la mémoire allouée
      free(A); free(B);  free(RES);
     
      return 0;
    }
     
    void AllocInitMat(int** matA, int** matB, int** matC, int nbL, int nbC){
      int i = 0, j = 0;
     
      matA = (int**)malloc(nbL*sizeof(int*));
      matB = (int**)malloc(nbL*sizeof(int*));
      matC = (int**)malloc(nbL*sizeof(int*));
     
      for (i = 0; i < nbL; i++){
        matA[i] = (int*)malloc(nbC*sizeof(int));
        matB[i] = (int*)malloc(nbC*sizeof(int));
        matC[i] = (int*)malloc(nbC*sizeof(int));
      }
     
      for (i = 0; i < nbL; i++){
        for (j = 0; j < nbC; j++){
          matA[i][j] = (i == j) ? 2 : 0;
          matB[i][j] = (i == j) ? 3 : 0;
          matC[i][j] = (i == j) ? 4 : 0;
        }
      }
      for (i = 0; i < nbL; i++){
        for (j = 0; j < nbC; j++) printf("[%d] ", matA[i][j]);
        printf("\n");
    }
    Merci beaucoup par avance pour votre aide !!

  2. #2
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2013
    Messages
    38
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2013
    Messages : 38
    Par défaut
    Hello,

    Je vais te dire pourquoi ça ne fonctionne pas.
    Mais je ne te donnerai pas la solution, ce sera a toi de la trouver (c'est plus formateur).

    Analysons ensemble ton code:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    int main(void)
    {
        // [...]
     
        int** A = NULL;
        int** B = NULL;
        int** RES = NULL;
     
        // [...]
    }
    Dans le main, tu déclares 3 variables, qui sont des pointeurs.
    Chaque pointeurs correspond a une case mémoire.

    Ta mémoire ressemble donc a ça:

    | A** (NULL) | B** (NULL) | RES** (NULL) |


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    int main(void)
    {
        // [...]
     
        // Allocation et remplissage
        AllocInitMat(A, B, RES, dimL, dimC);
     
        // [...]
    }
    Par la suite, tu passes ces 3 variables a ta fonction AllocInitMat.
    Cependant, en C, les variables que tu passes en paramètre sont copiées. Elles ne référencent donc pas la même case mémoire!

    Ta mémoire ressemble maintenant a cela:

    | A** (NULL) | B** (NULL) | RES** (NULL) | A** copie (NULL) | B** copie (NULL)| RES** copie (NULL) |


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void AllocInitMat(int** matA, int** matB, int** matC, int nbL, int nbC)
    {
        // [...]
     
        matA = (int**)malloc(nbL*sizeof(int*));
        matB = (int**)malloc(nbL*sizeof(int*));
        matC = (int**)malloc(nbL*sizeof(int*));
     
        // [...]
    }
    Dans ta fonction AllocInitMat, lorsque tu alloues de la mémoire sur ces 3 variables, tu stock l'adresse dans la case de la variable copiée.

    Ce qui donne:

    | A** (NULL) | B** (NULL) | RES** (NULL) | A** copie (Adresse) | B** copie (Adresse) | RES** copie (Adresse) |


    En sortant du scope de la fonction AllocInitMat, toutes les variables copiées sont détruite. Et par conséquent, tes adresses également.
    Tu te retrouve donc avec les 3 premières cases que tu avais au debut:

    | A** (NULL) | B** (NULL) | RES** (NULL) |


    C'est pour cela que tu n'a plus accès a tes matrices dans le main.


    Maintenant que tu connais la cause de ton problème, a toi de trouver une solution.
    Il en existe plusieurs

  3. #3
    Membre régulier
    Homme Profil pro
    Développeur décisionnel
    Inscrit en
    Décembre 2018
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Seine et Marne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2018
    Messages : 8
    Par défaut
    Merci de ta réponse !
    Je pensais justement avoir anticipé ce type de problème de passage par valeur/passage par adresse en passant bien des pointeurs en entrée de la fonction !
    Preuve que j'ai pas tout compris encore...
    Cependant, je comprends bien qu'il faut modifier l'appel de la fonction pour que ça pointe vers le bon emplacement mémoire...

  4. #4
    Membre régulier
    Homme Profil pro
    Développeur décisionnel
    Inscrit en
    Décembre 2018
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Seine et Marne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2018
    Messages : 8
    Par défaut
    J'en suis arrivé à ça qui marche. Mais s'il y'a plus simple je veux bien l'astuce.

    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
     
    #include <stdlib.h>
    #include <stdio.h>
     
    void AllocInitMat(int*** , int*** , int*** , int* , int* );
     
    int main(void){
     
      int dimL = 0, dimC = 0;
      int i = 0, j = 0;
      int** A = NULL;
      int** B = NULL;
      int** RES = NULL;
     
      // Récupération des dimensions
      printf("Nombre de lignes : "); scanf("%d", &dimL);
      printf("Nombre de colonnes : "); scanf("%d", &dimC);
     
      // Allocation et remplissage
      AllocInitMat(&A, &B, &RES, &dimL, &dimC);
     
      // Test d'affichage/disponibilité de A
      for (i = 0; i < dimL; i++){
        for (j = 0; j< dimC; j++){
          printf("[%d] ", A[i][j]);
        }
      printf("\n");
      }
     
      // Libération de la mémoire allouée
      free(A); free(B); free(RES);
     
      return 0;
    }
     
    void AllocInitMat(int*** matA, int*** matB, int*** matC, int* nbL, int* nbC){
      int i = 0, j = 0;
     
      (*matA) = malloc(*nbL * sizeof *(*matA));
      (*matB) = malloc(*nbL * sizeof *(*matB));
      (*matC) = malloc(*nbL * sizeof *(*matC));
     
      for (i = 0; i < *nbL; i++){
        (*matA)[i] = malloc(*nbC * sizeof *(*matA)[i]);
        (*matB)[i] = malloc(*nbC * sizeof *(*matB)[i]);
        (*matC)[i] = malloc(*nbC * sizeof *(*matC)[i]);
      }
     
      for (i = 0; i < *nbL; i++){
        for (j = 0; j < *nbC; j++){
          (*matA)[i][j] = (i == j) ? 2 : 0;
          (*matB)[i][j] = (i == j) ? 3 : 0;
          (*matC)[i][j] = (i == j) ? 4 : 0;
        }
      }
    }

  5. #5
    Expert confirmé
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 599
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 599
    Par défaut
    Bonjour,

    Pour modifier un tableau de tableaux, il faut bien l'adresse d'un pointeur de pointeur.
    Pour les tailles par contre, pourquoi les passer par pointeurs ?
    Et il y beaucoup plus de malloc() que de free(), il manque beaucoup de free().

  6. #6
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 153
    Billets dans le blog
    4
    Par défaut
    Tu devrais utiliser des tableaux 1 dimension pour les matrices, et en découpant les fonctions ce serait plus simple : 1 fonction pour allouer la matrice, 1 pour la remplir, 1 pour l'afficher, etc.
    Ton code est aussi un nid à fuites mémoire.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  7. #7
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 839
    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 839
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par Oblivion0 Voir le message
    J'en suis arrivé à ça qui marche. Mais s'il y'a plus simple je veux bien l'astuce.
    Ben déjà, au lieu de faire une fonction qui alloue les 3 matrices (avec un code donc répétitif dans la fonction) tu peux faire une fonction un peu plus générique qui alloue une matrice ; et l'appeler 3 fois. La fonction sera bien plus légère donc bien plus lisible.

    Ensuite tu peux représenter chaque matrice par un tableau 1D. En effet, un tableau 2D, 3D, 4D, en mémoire, c'est toujours une suite de cases alignées donc une suite en une dimension.

    L'avantage, c'est que tu t'embêtes plus avec tes malloc/free en cascade (d'autant plus qu'il faut les tester et prévoir une solution de nettoyage si le Xième malloc échoue => nettoyer alors tout ce qui a été alloué). En 1D, un seul malloc, un seul free.
    Le petit inconvénient, c'est qu'il te faut ensuite convertir des coordonnées 2D (lig/col) en 1D pour taper au bon endroit. Et inversement, quand tu balayes ton tableau avec un indice "i", il te faut lui-aussi le convertir en lig/col pour savoir de quelle case 2D il s'agit. Mais c'est pas vraiment compliqué car dans le sens lig/col vers i alors i=lig * nb_col + col. Et dans l'autre sens i vers lig/col alors lig=i/nb_col et col=i%nb_col (nb_col étant le nombre de colonnes de ton tableau 2D). Et bien évidemment on trouve des formules similaires pour passer de 3D, 4D, 5D vers 1D.
    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]

  8. #8
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 487
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 487
    Par défaut
    J'ajoute également que lorsque l'on déclare dynamiquement des tableaux multidimensionnels, il est tout-à-fait possible de réserver la mémoire nécessaire en une fois avec malloc() puis de transtyper le pointeur renvoyé en pointeur sur un tableau multidimensionnel :

    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
    #include <stddef.h>
    #include <stdlib.h>
    #include <stdio.h>
     
    int main (void)
    {
        int (*ptr) [4][3];
        int i,j,k;
     
        printf("%lu\n",sizeof ptr);
        ptr = malloc(5*4*3*sizeof (int));
     
        for (i=0;i<60;i++) ((int *)ptr)[i] = i;
     
        for (i=0;i<5;i++)
        for (j=0;j<4;j++)
        for (k=0;k<3;k++) printf ("%d %d %d: %2d\n",i,j,k,ptr[i][j][k]);
     
        free (ptr),ptr=NULL;
        return 0;
    }

    C'est d'ailleurs un sujet qui revient régulièrement. La seule réelle contrainte est que cela oblige à fixer à l'avance les dimensions du tableau, ou d'utiliser les VLA pour redéfinir le pointeur à l'intérieur d'un bloc local à l'exécution, ce qui peut le rendre compliqué à transmettre d'une fonction à l'autre.

    C'est aussi quelque chose qu'on évite d'aborder d'emblée (on devrait peut-être, d'ailleurs) avec quelqu'un qui n'a que 48 heures de C mais comme le primo-postant a l'air d'être expérimenté et de bien maîtriser ce qu'il nous présente, c'est peut-être la meilleure option.

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

Discussions similaires

  1. Problème de portée de variables (VBS)
    Par befast dans le forum Windows
    Réponses: 0
    Dernier message: 18/09/2007, 09h40
  2. [Mail] problème de portée de variables
    Par xclam dans le forum Langage
    Réponses: 2
    Dernier message: 12/04/2007, 09h35
  3. Problème de Portée de Variable
    Par Julien_C++ dans le forum C++
    Réponses: 7
    Dernier message: 18/09/2006, 10h13
  4. [VBA-E] Problème de portée de variable [débutant]
    Par vivelesgnous dans le forum Macros et VBA Excel
    Réponses: 7
    Dernier message: 01/03/2006, 18h28
  5. [XSL]Problème de portée des variables
    Par djulesp dans le forum XSL/XSLT/XPATH
    Réponses: 6
    Dernier message: 17/09/2004, 10h34

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