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'allocation mémoire matrice


Sujet :

C

  1. #1
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2019
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2019
    Messages : 3
    Points : 3
    Points
    3
    Par défaut Problème d'allocation mémoire matrice
    Bonjour à tous.

    Je suis actuellement étudiant et il nous a été demandé de réaliser un projet (en C) qui est de créer un démineur avec la librairie graphique Libsx.
    Je travaille sur Ubuntu.
    Pour ce faire, j'ai créé une structure ayant comme champ un pointeur sur pointeur d'int, que j'ai écrit de la façon suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    typedef struct {	
    	int **bombe ;//Données partagées
    } Donnees;
    Cette variable me permettra de stocker puis placer, sur un plateau de jeu de taille L * C, un nombre de bombe (qui dépend de la difficulté par exemple) placé aléatoirement.

    Il faut donc que j'alloue dynamiquement de la mémoire à mon "tableau 2D". Voici comment j'ai procédé :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    //L et C sont des #define définis respectivement à 50 et 25
    Donnees d;
     
    d.bombe = (int **) calloc(L, sizeof(int*));
     
    for (i=0; i<L; i++) {
    	*(d.bombe+i) = (int*) calloc(C, sizeof(int));
    }

    Jusqu'ici tout fonctionne bien, je peux même afficher mes bombes (grâce à différentes fonctions graphiques de ma librairie).

    Je suis actuellement entrain de rédiger une fonction permettant de tester si une bombe est présente à GAUCHE, HAUT-GAUCHE, HAUT, HAUT-DROITE, DROITE, BAS-DROITE, BAS, BAS-GAUCHE (soit 8 tests au total) de la case cliqué.
    Il faut donc surveiller à ce que les coordonnées citées ne dépassent pas du tableau (par exemple d.bombe[-1][2]) en cas quel cas, je devrais avoir un retour "segmentation fault" car je tente d'accéder à une case mémoire qui n'est normalement pas alloué à ma matrice.
    => Donc en effet, si je dépasse en -1 ou en L+1 (pour la 1ère dimension de ma matrice) j'ai effectivement un retour "segmentation fault" sur mon terminal (par exemple d.bombe[-1][2] ou par exemple d.bombe[51][2] font crash mon programme).
    => Maintenant, si je fais la même chose pour la 2nd dimension de ma matrice (donc que je dépasse en -1 ou en C+1), il se trouve que ça marche !! J'ai le droit à des indices négatifs et de monter assez haut dans les indices. J'ai donc essayé de voir jusqu'à quelle valeur je pouvais aller. Pour y=1264 (ou +) ou y=-32529 (ou -) le programme me fait un segmentation fault.

    J'ai réalisé ces tests indépendamment des autres fonctions du programme afin de voir d'où pourrait venir "l'erreur", mais je ne comprends vraiment pas d'où cela pourrait venir. Je ne sais même pas si l'accès à ces cases mémoires est possible. Et si oui, pourquoi cela ne marcherait-il pas pour la 1ère dimension ?

    Avez-vous une idée de ce qui pourrait provoquer ceci ?

  2. #2
    Rédacteur/Modérateur


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

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 965
    Points
    32 965
    Billets dans le blog
    4
    Par défaut
    Accéder à un élément d'un tableau c'est juste accéder à de la mémoire avec un offset sur l'élément 0.
    Si par hasard tu arrives sur de la mémoire à laquelle le programme a accès, ça tombera en marche. Si non, c'est un comportement indéterminé et le plus souvent un crash.
    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.

  3. #3
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2019
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2019
    Messages : 3
    Points : 3
    Points
    3
    Par défaut
    Citation Envoyé par Bousk Voir le message
    Accéder à un élément d'un tableau c'est juste accéder à de la mémoire avec un offset sur l'élément 0.
    Si par hasard tu arrives sur de la mémoire à laquelle le programme a accès, ça tombera en marche. Si non, c'est un comportement indéterminé et le plus souvent un crash.
    Donc en soit, cela n'est pas dérangeant ? Si je laisse mon programme codé de cette façon, ce n'est pas gênant ?

  4. #4
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    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 565
    Points : 7 642
    Points
    7 642
    Par défaut
    Citation Envoyé par BenBrou Voir le message
    Donc en soit, cela n'est pas dérangeant ? Si je laisse mon programme codé de cette façon, ce n'est pas gênant ?
    Accéder en dehors de la plage valide d'un tableau est un comportement indéterminé. Tu ne peux pas changer ce principe.

  5. #5
    Rédacteur/Modérateur


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

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 965
    Points
    32 965
    Billets dans le blog
    4
    Par défaut
    Si un truc qui tombe en marche par hasard ne te dérange pas, y'a un sacré problème de compréhension de ces mots.
    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.

  6. #6
    Membre expérimenté
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Juillet 2020
    Messages
    352
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Juillet 2020
    Messages : 352
    Points : 1 376
    Points
    1 376
    Par défaut
    Citation Envoyé par BenBrou Voir le message
    [...] le programme me fait un segmentation fault.

    J'ai réalisé ces tests indépendamment des autres fonctions du programme afin de voir d'où pourrait venir "l'erreur", mais je ne comprends vraiment pas d'où cela pourrait venir. Je ne sais même pas si l'accès à ces cases mémoires est possible. Et si oui, pourquoi cela ne marcherait-il pas pour la 1ère dimension ?

    Avez-vous une idée de ce qui pourrait provoquer ceci ?
    Bonjour,

    Quand tu codes en C et que tu retrouves face à ce genre de problème il y aune solution hypersimple : utiliser un memory profiler comme valgrind et c'est généralement bien plus efficace que d'utiliser un debuger (ce que tu devrais savoir faire également).

    La procédure est simple :
    1. installer valgrind ;
    2. compiler ton projet en mode debug (option -g avec gcc ou clang par exemple) ;
    3. lancer ton exécutable avec valgrind avec les options --leak-check=full --track-origins=yes --show-reachable=yes ;
    4. éplucher le log pour voir où dans ton code il y a une erreur de gestion de mémoire et quelle en est la cause. Le log est très détaillé.


    Je t'incite réellement à suivre cette démarche car sinon tu vas te retrouvé embourbé dans une m%$#!@ sans nom ; et comme disait Confucieus : «Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson.»

    Citation Envoyé par BenBrou Voir le message
    [...]
    Je suis actuellement entrain de rédiger une fonction permettant de tester si une bombe est présente à GAUCHE, HAUT-GAUCHE, HAUT, HAUT-DROITE, DROITE, BAS-DROITE, BAS, BAS-GAUCHE (soit 8 tests au total) de la case cliqué.
    Il faut donc surveiller à ce que les coordonnées citées ne dépassent pas du tableau (par exemple d.bombe[-1][2]) en cas quel cas, je devrais avoir un retour "segmentation fault" car je tente d'accéder à une case mémoire qui n'est normalement pas alloué à ma matrice. [...]
    Une technique pour simplifier la vie est d'ajouter une couronne de cases non accessibles tout autour de ton plateau de jeu, ce qui t'évite d'avoir pleins de tests pour savoir si tu es ou non sur un bord. En gros, au lieu d'avoir un simple plateau [col][lig] tu passes en [col+2][lig+2], ton plateau de jeu se situant dans [1..col][1..lig], les colonnes d'indices 0 et col+1 ainsi que les lignes d'indices 0 et lig+1 contenant des cases non jouables et non affichées mais qui existent …

  7. #7
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    Février 2008
    Messages
    2 291
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : Février 2008
    Messages : 2 291
    Points : 4 941
    Points
    4 941
    Billets dans le blog
    5
    Par défaut
    Citation Envoyé par BenBrou Voir le message
    Bonjour à tous.

    Je suis actuellement étudiant et il nous a été demandé de réaliser un projet (en C) qui est de créer un démineur avec la librairie graphique Libsx.
    Je travaille sur Ubuntu.
    Pour ce faire, j'ai créé une structure ayant comme champ un pointeur sur pointeur d'int, que j'ai écrit de la façon suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    typedef struct {	
    	int **bombe ;//Données partagées
    } Donnees;
    Cette variable me permettra de stocker puis placer, sur un plateau de jeu de taille L * C, un nombre de bombe (qui dépend de la difficulté par exemple) placé aléatoirement.
    Quel est l'intérêt de créer une structure avec une seule variable ? Il doit manquer quelques informations.

    Quel intérêt de déclarer un pointeur sur un pointeur de int ?
    Un tableau, quelque soit sa forme déclarée (n dimensions), est linéaire en mémoire. Un simple pointeur de int suffit ici. Si on désire avoir une tableau en deux dimensions, il suffit de faire un simple petit calcul pour accéder aux éléments en fonction de ses coordonnées.

    Je suis en forme aujourd'hui . Voila un code exemple pour gérer un tableau en deux dimensions. Bonne lecture.
    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
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    typedef struct {
      int *tab;
      size_t width, height;
    } s_table;
     
    char table_init (s_table *table, int width, int height) {
      if (!table) {
        fprintf (stderr, "Impossible to init table !\n");
        fprintf (stderr, "table must be valid in %s();\n", __func__);
        return 0;
      }
     
      if (width<0 || height<0) {
        fprintf (stderr, "Impossible to init table !\n");
        fprintf (stderr, "size of table must be >=0 in %s();\n", __func__);
        return 0;
      }
     
      table->tab = calloc (width*height, sizeof(int));
      if (!table->tab) {
        fprintf (stderr, "An error is occured to initialize table ! \n");
        return 0;
      }
     
      table->width = width;
      table->height = height;
     
      return 1;
    }
     
    void table_free (s_table *table) {
      if (!table)
        return;
     
      free (table->tab);
    }
     
    char table_set_value (s_table *table, int x, int y, int value)
    {
      if (!table) {
        fprintf (stderr, "table must be valid in %s();\n", __func__);
        return 0;
      }
     
      if (x<0 || y<0) {
        fprintf (stderr, "coordinates must be >=0 in %s();\n", __func__);
        return 0;
      }
     
      if (x>table->width-1 || y>table->height-1) {
        fprintf (stderr, "coordinates are too big in %s();\n", __func__);
        return 0;
      }
     
      table->tab[x + table->width*y] = value;
     
      return 1;
    }
     
    int table_get_value (s_table *table, int x, int y, char *error)
    {
      *error = 0;
     
      if (!table) {
        fprintf (stderr, "table must be valid in %s\n", __func__);
        return -1;
      }
     
      if (x<0 || y<0) {
        fprintf (stderr, "coordinates must be >=0 in %s\n", __func__);
        return -1;
      }
     
      if (x>table->width-1 || y>table->height-1) {
        fprintf (stderr, "coordinates are too big in %s\n", __func__);
        return -1;
      }
     
      *error = 1;
      return table->tab[x + table->width*y];
    }
     
    int
    main (int argc, char **argv)
    {
      /* Déclaration d'une taille arbitraire d'un tableau à deux dimensions */
      int a=10, b=20;
     
      /* Initialisation du tableau */
      s_table table;
      if (!table_init (&table, a, b)) {
        exit(EXIT_FAILURE);
      }
     
      /* Placement d'une valeur aux coordonnées (9, 8) */
      if (!table_set_value (&table, 9, 8, -12)) {
        /* Libération mémoire */
        table_free (&table);
     
        exit(EXIT_FAILURE);
      }
     
      /* Récupération d'une donnée aux coordonnées (9, 8) */
      char error; /* Pour vérifier si une erreur est survenue */
      int value;  /* Valeur retournée */
      value = table_get_value (&table, 9, 8, &error);
      if (!error) {
        /* Libération mémoire */
        table_free (&table);
     
        exit(EXIT_FAILURE);
      }
      else
        printf ("value is : %d\n", value);
     
      /* Libération mémoire */
      table_free (&table);
     
      return EXIT_SUCCESS;
    }

  8. #8
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2019
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2019
    Messages : 3
    Points : 3
    Points
    3
    Par défaut
    Citation Envoyé par WhiteCrow Voir le message
    Bonjour à vous.
    En effet, je n'avais pas pensé à utiliser ce genre de logiciel. Je vais installer Valgrind et voir ce qui peut être la cause de mes problèmes.

    Et j'aime beaucoup l'idée du [col+2][lig+2]. Je vais également essayer ceci !

    Merci beaucoup !

    Citation Envoyé par gerald3d Voir le message
    Bonjour à vous.
    En effet, sur le principe, déclarer une structure avec un seul champ peut paraître étrange, mais c'est tout simplement parce que je vais avoir besoin d'autres champs pour la suite du projet.
    Mais pour mon problème actuel, je n'ai pour l'instant besoin que de ça.

    Et effectivement, je n'y avais pas pensé non plus, mais c'est vrai qu'un pointeur sur int seul pourrait suffir. Je vous remercie grandement pour le code que vous m'avez fourni, je m'en vais l'essayer de ce pas !

    Merci à vous et bonne journée !

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

Discussions similaires

  1. Problème d'allocation mémoire
    Par Fibus dans le forum GTK+ avec C & C++
    Réponses: 6
    Dernier message: 10/01/2008, 16h35
  2. Problème d'allocation mémoire
    Par elmayor1983 dans le forum C++
    Réponses: 5
    Dernier message: 14/02/2007, 10h08
  3. Problème d'allocation mémoire et fork
    Par Conap dans le forum Langage
    Réponses: 3
    Dernier message: 20/07/2006, 15h34
  4. Problème d'allocation mémoire
    Par araya dans le forum C
    Réponses: 2
    Dernier message: 04/05/2006, 20h03
  5. Problème d'allocation mémoire
    Par cali1983 dans le forum C++
    Réponses: 10
    Dernier message: 10/03/2006, 23h23

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