Tableaux dynamiques new delete

Fermé
Ayoub - Modifié le 5 févr. 2021 à 17:47
mamiemando Messages postés 33079 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 23 avril 2024 - 5 févr. 2021 à 18:06
Bonjour

Je suis sur un projet dans lequel je dois coder de petits programmes sur le jeu du Boggle.

Mon but pour l'instant est de coder un programme qui lit deux listes de mots et qui vérifie si les mots de la deuxième liste n'étant pas présents dans la première liste. J'y suis arrivé avec des tableaux statiques, mais la tâche se complique quand j'essaie de les transformer en tableaux dynamiques avec
new
et
delete.
.

Lorsque je compile le programme, les bons résultats s'affichent, mais le programme s'arrête violemment en me renvoyant un message de violation d'accès à la mémoire. Je n'arrive pas à localiser l'erreur programme.

Mon code est disponible via ce dépôt GitHub. Les fonctions à regarder sont
ecrire
(dans
tri.cpp
),
initialiser
(dans
points.cpp
),
lire_listes
(
motspaspresents.cpp
),
exo3
(dans
motspaspresents.cpp
) et les structures sont dans
liste.h
et
listes.h
.

struct Liste {
 Mot* tab_mots;
 unsigned int capa;
 unsigned int pas_extension;
 unsigned int nb_mots = 0;
 unsigned int nb_points;
};


struct Listes {
 Liste tab_listes[MAX_LISTES + 1];
 unsigned int nb_listes = 0;
};


void lire_liste(Mot& id, Liste& liste) {
 cin >> id;
 if (strcmp(id, "*") != 0) {
  if (verification_doublon(liste, id) == false) {
   ecrire(liste, id);
  }
 }
}


void ecrire(Liste& liste, Mot& id) {
 if (liste.nb_mots >= liste.capa) {
  unsigned int newTaille = (liste.capa+1) * liste.pas_extension;
  Mot* newT = new Mot[newTaille];
  unsigned int i;
  for (i = 0; i < liste.nb_mots; ++i) {
   strcpy(newT[i], liste.tab_mots[i]);
  }
  delete[] liste.tab_mots;
  liste.tab_mots = newT;
  liste.capa = newTaille;
 }
 strcpy(liste.tab_mots[liste.nb_mots], id);
 liste.nb_mots++;
}


void initialiser(Liste& liste) {
 liste.nb_mots = 0;
 liste.nb_points = 0;
 liste.capa = 1;
 liste.pas_extension = 5;
 Mot* newT = new Mot[1];
 liste.tab_mots = newT;
}



void exo3(){
 Mot buffer;
 strcpy(buffer, "NULL");
 Listes listes;
 for (unsigned int e = 0; e <= 2; e++) {
  initialiser(listes.tab_listes[e]);
 }
 for (unsigned int i = 0; i < MAX_LISTES; i++) {
  listes.tab_listes[i].nb_mots = 0;
 };
 listes.nb_listes = 0;
 
 for (unsigned int k = 0; k < 2; k++) {
  while (strcmp(buffer, "*") != 0) {
   lire_listes(buffer, listes);
  }
  strcpy(buffer, "NULL");
 }
 for (unsigned int j = 0; j < listes.nb_listes; j++) {
  tri_alphabetique(listes.tab_listes[j]);
 }
 mots_pas_apparents(listes);
 for (unsigned int z = 0; z < listes.tab_listes[2].nb_mots; z++) {
  cout << listes.tab_listes[2].tab_mots[z] << endl;
 }
 cout << "*" << endl;
 for (unsigned int m = 0; m < listes.nb_listes; m++) {
  detruire(listes.tab_listes[m]);
 }
}
A voir également:

1 réponse

mamiemando Messages postés 33079 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 23 avril 2024 7 749
Modifié le 5 févr. 2021 à 18:26
Bonjour,

Pour moi tu te compliques inutilement là vie. La STL te permet d'avoir des classes permettant de manipuler facilement des containers (chaînes, listes, vecteurs, ensembles, dictionnaires) et des algorithmes pour les manipuler.

En l'occurrence tu peux utiliser :
  • std::string
    : les chaînes de caractères ;
  • std::set<T>
    : ensemble ordonné (par défaut selon <) contenant des éléments deux à deux distincts;
  • std::set_difference
    : la différence ensembliste (note que la STL implémente les autres opérateurs ensemblistes :
    std::set_intersection
    ,
    std::set_union
    ).


En terme de code, pour trouver les mots dans
s1
mais pas
s2
voici comment tu peux procéder (en prime je t'ai mis les autres opérations ensemblistes) :

#include <algorithm> // std::set_intersection
#include <iostream>  // std::cout
#include <ostream>   // std::ostream
#include <string>    // std::string
#include <set>       // std::set

// Affiche le contenu d'un ensemble
template <typename T>
std::ostream & operator << (
    std::ostream & out,
    const std::set<T> & s
) {
    out << "{";
    for (auto x : s) out << " " << x;
    out << " }";
    return out;
}

template <typename T>
std::set<T> my_set_intersection(
    const std::set<T> & s1,
    const std::set<T> & s2
) {
    std::set<T> s_intersection;
    set_intersection(
        s1.begin(), s1.end(), s2.begin(), s2.end(),
        std::inserter(s_intersection, s_intersection.begin())
    );
    return s_intersection;
}

template <typename T>
std::set<T> my_set_union(
    const std::set<T> & s1,
    const std::set<T> & s2
) {
    std::set<T> s_union;
    set_union(
        s1.begin(), s1.end(), s2.begin(), s2.end(),
        std::inserter(s_union, s_union.begin())
    );
    return s_union;
}

template <typename T>
std::set<T> my_set_difference(
    const std::set<T> & s1,
    const std::set<T> & s2
) {
    std::set<T> s_difference;
    set_difference(
        s1.begin(), s1.end(), s2.begin(), s2.end(),
        std::inserter(s_difference, s_difference.begin())
    );
    return s_difference;
}

int main(){
    using namespace std;
    const set<string>
        s1 = {"chat", "lion", "tigre"},
        s2 = {"chat", "chien", "cheval"};

    // Intersection
    cout << "s1 = " << s1 << endl
         << "s2 = " << s2 << endl
         << "s1 u s2 = "  << my_set_union(s1, s2) << endl
         << "s1 n s2 = "  << my_set_intersection(s1, s2) << endl
         << "s1 \\ s2 = " << my_set_difference(s1, s2) << endl;

    return 0;
}


Dans cet exemple, s1 contient des félins et s2 des animaux domestiques.
  • s1 u s2 : ensemble des animaux qu'ils soient félins, domestiques ou les deux
  • s1 n s2 : ensemble des animaux félins et domestiques
  • s1 \ s2 : ensemble des animaux félins non domestiques


Résultat :

(mando@silk) (~) $ g++ toto.cpp && ./a.out 
s1 = { chat lion tigre }
s2 = { chat cheval chien }
s1 u s2 = { chat cheval chien lion tigre }
s1 n s2 = { chat }
s1 \ s2 = { lion tigre }


Remarque :

Les fonctions
my_set_*
sont template sur le type T, ce qui signifie que le code reste valide quelque soit le type T. Contrairement à une fonction non template, une fonction template est déclarée et implémentée dans le même fichier (e.g. dans un header). Ici comme mon bout de code est très court, j'ai tout mis dans un même fichier.

Dans la fonction
main
, j'utilise des ensembles constants (
const std::set<std::string>
). Bien entendu, tu appliquer ces fonctions sur des ensembles non constants (
std::set<std::string>
) selon le théorème du qui peut le plus peut le moins.

Cela signifie que dans ton projet, il serait sans doute plus aviser de construire des ensembles de mots
std::set<string>
dont tu adapterais le contenu dynamiquement avec les méthodes adéquates (voir la documentation).

Bonne chance
0