Tableau dynamique c++

Résolu
casperfr Messages postés 6 Date d'inscription samedi 14 juillet 2001 Statut Membre Dernière intervention 21 janvier 2015 - 21 janv. 2015 à 16:14
casperfr Messages postés 6 Date d'inscription samedi 14 juillet 2001 Statut Membre Dernière intervention 21 janvier 2015 - 21 janv. 2015 à 18:28
Bonjour,

je suis totalement débutant en c++ et en essayant de comprendre une class servant a créé un tableau dynamique, qui peut changer de taille en préservant les information a la manière de <vector>,
je ne comprend le résultat que j'obtiens, quelqu'un pourrait il m'expliquer mon problème

une class TableauDynamique permet de créé un tableau
puis d'en modifier le nombre d'élément sans perdre ces éléments,

voici la méthode de la class dans lequel j'ai le problème de résultat
void TableauDynamique::ajoutElt(double newelt, int pos){ 
//création d'un tableau temporaire pour stocker les élément du
//tableau de l'objet courant
double *T = new double[dim];
T = Tab;
delete[] Tab;
dim ++; //on incrémente la dimension du tableau
//Réallocation d'un nouveau espace mémoire de taille dim
Tab = new double [dim];
Tab = T;
//Insertion du nouveau element aprés déclage des éléments du tableau
for (int i =dim-1; i>pos; i--)
*(Tab+i) = *(Tab+i-1);
*(Tab+pos) = newelt;
}

le but est donc de copier le contenu du tableau existant dans un nouveau tableau intermédiaire (T=Tab) d'augmenté la taille du tableau (dim étant un des attribut de la class avec Tab) et de refaire une nouvelle réservation mémoire avec la nouvelle taille de tableau,
le problème qui se pose et que je n'arrive pas a comprendre, c'est que quand je fais le delete[] tab, ce delete influence les valeurs qui se trouve dans le tableau T, mais le plus étrange c'est qu'il n'influence que T[0]
je me suis dis, il fait la copie des valeur du pointeur, et donc en supprimant avec le delete, la mémoire est de nouveau disponible et peut donc etre utilisé par un autre programme.
je n'arrive pas a comprendre le faite que le delete de Tab influence les valeurs contenu dans T
(Résultat obtenu avec Dev-c++)
Merci de votre aide.
cordialement

6 réponses

cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
Modifié par cptpingu le 21/01/2015 à 18:19
Bonjour.

Ton souci:
T = Tab; 
delete[] Tab;

C'est un souci, car "T" pointera sur ce que pointe "Tab", c'est à dire de la mémoire effacée :(.
C'est plutôt ceci que j'aurai fait: *T = *Tab, qui veut dire copier le contenu de Tab dans T.

Techniquement, je préfère la méthode suivante (qui ne fait qu'une passe au lieu de deux pour ta méthode):
- Tu alloues un tableau de taille dim + 1
- Tu fait un boucle dans laquelle tu copies chacun des éléments
- Au sein de la boucle, si i == pos, alors tu insères ton éléments
- Tu continues de copier les autres éléments, avec un décalage de 1.

Ex (non testé):
void TableauDynamique::ajoutElt(double newelt, int pos)
{
  if (pos >= dim)
    pos = dim;

  ++dim;
  double *tmp = new double[dim]; 
  int shift = 0; // décalage
  for (int i = 0;  i < dim; ++i)
  {
     if (i == pos)
    {
        *(tmp + i) = newelt;
        ++shift;
     }
      else
        *(tmp + i) = *(Tab + i - shift);
  }
  delete[] Tab;
  Tab = tmp;
}


Quelques conseils:
- Un attribut se différencie d'une variable par un signe distinctif (un "_"). Ex: dim => _dim.
- Dev-C++ embarque un "trèèès" vieux compilateur. Il est fortement conseillé d'utiliser autre chose (Code::Block est bien plus moderne, tu as aussi QtCreator, ou encore VisualStudio Express). Évite vraiment cet IDE, il est complètement dépassé depuis des années (beaucoup de débutants se font encore avoir, à cause du "nom" qui se trouve facilement).
- Un nom de classe prend une majuscule, mais pas les variables. Préfère les mettre en minuscule.
- Préfère ++var à var++. Pour l'instant ça ne change rien, mais quand tu te serviras des "iterators", tu verras que ça ne fait pas la même chose (l'un est plus performant que l'autre). Par bonne pratique, on utilise généralement ++var.

__________________________________________________________________________________________________

Améliorez votre expérience CodeS-SourceS avec ce plugin:
http://codes-sources.commentcamarche.net/forum/affich-10000111-plugin-better-cs-2#cptpingu-signature
0
casperfr Messages postés 6 Date d'inscription samedi 14 juillet 2001 Statut Membre Dernière intervention 21 janvier 2015
21 janv. 2015 à 16:52
Merci infiniment pour ta réponse rapide,
j'avais essayé la solution que tu me disais, *T = *Tab mais dans ce cas, la totalité des valeurs se retrouvais aléatoire après le delete,

Disons que ce qui m'étonnais le plus, dans tous les essais que j'ai pu faire, seule le 1er élément du tableau a une valeur modifié après de delete.

c'est donc bien ce que je pensais, c'est un problème lié au faite que le nouveau tableau créé pointe sur les valeurs de l'ancien, et quand l'ancien est supprimer, le nouveau tableau s'en retrouve modifié, mais je n'arrive pas a comprendre pourquoi pas toutes les valeurs, et uniquement la première.

l'usage de Dev-c++ est uniquement du a la portabilité et a la petite taille pour le téléchargement.

et c'est la seule chose qui est pré installé sur les machines que j'ai pu essayé (sauf la mienne)

pour ce qui est de l'indentation, je suis obliger de respecter ce qui est donner dans l'énoncé de l'exercice, donc je n'est pas le droit de respecter la convention.

en tout cas merci infiniment pour ton aide, et surtout pour ta rapidité de réponse,
merci encore.
0
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
Modifié par cptpingu le 21/01/2015 à 17:34

j'avais essayé la solution que tu me disais, *T = *Tab mais dans ce cas, la totalité des valeurs se retrouvais aléatoire après le delete,

Tu as du regarder les valeurs de Tab (après un delete de Tab) au lieu de T. La méthode décrite fonctionne (un *T = *Tab va copier les valeurs une à une).


Disons que ce qui m'étonnais le plus, dans tous les essais que j'ai pu faire, seule le 1er élément du tableau a une valeur modifié après de delete.

Il faut bien comprendre qu'un delete ne supprime pas la mémoire, mais la met en mode "Je n'en veux plus, le premier qui passe par là peut prendre ce morceau de mémoire". Donc, la valeur est complètement indeterminée. Tu peux retrouver tes valeurs comme ne pas les retrouver, comme les retrouver partiellement. C'est "quasi" aléatoire.


c'est donc bien ce que je pensais, c'est un problème lié au faite que le nouveau tableau créé pointe sur les valeurs de l'ancien, et quand l'ancien est supprimer, le nouveau tableau s'en retrouve modifié, mais je n'arrive pas a comprendre pourquoi pas toutes les valeurs, et uniquement la première.


Très simple tu fais ceci:
- Allocation de T
- T pointe sur ce que pointe Tab (et donc la mémoire allouée à l'adresse T plus haut est perdue vu que plus personne ne pointe dessus, mais que ça n'a pas été "delete" => fuite mémoire)
- T et Tab sont maintenant tout deux des alias vers la même zone mémoire.
- Tu supprimes la mémoire à l'adresse pointé par Tab. Cette zone est maintenant dans un état indeterminé.
- Tu regardes ton tableau T (donc tu regardes la mémoire que tu as supprimé, vu que T et Tab pointait sur la même chose).
- Tu trouves un état incohérent, ce qui est normal vu que la zone a été "relachée". Avoir ton premier élément correct est un coup de chance, ça pourrait très bien te donner des comportements différents à chaque fois.

l'usage de Dev-c++ est uniquement du a la portabilité et a la petite taille pour le téléchargement.

Portable veut dire: qui s'exécute partout. Dev-C++ n'est pas portable car il ne fonctionne que sous Windows. Code::Block par exemple est portable car il y a une version Windows, Mac et Linux.
Je comprends le besoin, mais fait très attention, Dev-C++ est vraiment très vieux. Ce qui veut dire deux choses:
- Présence de bugs historiques corrigés depuis: tu vas t'arracher les cheveux sur certains cas où ça ne viendra pas de ton code, mais du compilo. Ex: Un template dans un template bug au niveau parsing sur les vieux compilos, il faut ajouter un espace pour que le compilo l'accepte :S.
- Ancienne norme C++: donc tu n'as pas accès à tout ce que "facilite la vie". Les auto, les boucles for étendu (style "foreach"), les messages d'erreurs plus explicites, etc...

__________________________________________________________________________________________________

Améliorez votre expérience CodeS-SourceS avec ce plugin:
http://codes-sources.commentcamarche.net/forum/affich-10000111-plugin-better-cs-2#cptpingu-signature
0
casperfr Messages postés 6 Date d'inscription samedi 14 juillet 2001 Statut Membre Dernière intervention 21 janvier 2015
21 janv. 2015 à 17:45
Merci beaucoup pour ton aide,

suite a tes conseil,
j'ai opté pour une solution entre deux qui fonctionne et qui est simple a comprendre pour mon niveau (c'est a dire 2 mois)

void TableauDynamique::ajoutElt(double newelt, int pos) 
{
double *T = new double[dim+1];
for (int i=0; i<pos; i++)
{ *(T+i)=*(Tab+i); }
*(T+pos) = newelt;
for (int i=pos; i<dim; i++)
{ *(T+i+1)=*(Tab+i); }
dim++;
delete[] Tab;
Tab = new double [dim];
for (int i=0; i<dim; i++)
{ *(Tab+i)=*(T+i); }
delete[] T;
}


tu as parfaitement raison, en se qui concerne dev-c++ ce que j'entendais pas portable c'est le faite de mettre le logiciel sur clé usb et pouvoir le faire fonctionner de la même manière sur tous les ordi (windows) sur lequel je me trouve

en tout cas, je te remercis infiniment pour ton aide et ta rapidité
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
Modifié par cptpingu le 21/01/2015 à 18:31
Pour info, il y a quelques bugs dans ta méthode :(
- Si je te donne une position 1000 pour un tableau de 3 éléments que se passe-t-il ?
- Il n'est pas nécessaire de recréer un tableau pour le re-recopier. Tu supprimes le tableau Tab, et tu lui donne la zone mémoire de T. C'est suffisant.

Correction de ton code (avec du code pour le tester):
#include <iostream>

struct Dummy
{
  Dummy()
    : dim(0), Tab(0)
  {
  }

  ~Dummy()
  {
    delete Tab;
  }

  void ajoutElt(double newelt, int pos)
  {
    // Copie des n premiers éléments semblables.
    double *T = new double[dim + 1];
    for (int i = 0; i < pos && i < dim; ++i)
      *(T + i) = *(Tab + i);

    // Cas ou pos est plus grand que ton tableau.
    if (pos >= dim + 1)
      pos = dim;

    // Copie de l'élément.
    *(T + pos) = newelt;

    // Copie des éléments restants avec un décalage.
    for (int i = pos; i < dim; ++i)
      *(T + i + 1) = *(Tab + i);

    // Remplacement du tableau.
    ++dim;
    delete[] Tab;
    Tab = T;
  }

  void print(std::ostream& out) const
  {
    for (int i = 0; i < dim; ++i)
      out << Tab[i] << " ";
    out << std::endl;
  }

  int dim;
  double* Tab;
};

int main()
{
  Dummy dummy;

  dummy.ajoutElt(1.0, 0);
  dummy.ajoutElt(2.0, 0);
  dummy.ajoutElt(3.0, 0);
  dummy.ajoutElt(9.0, 0);
  dummy.ajoutElt(1.5, 0);
  dummy.ajoutElt(90, 1000);
  dummy.ajoutElt(78, 3);

  dummy.print(std::cout);

  return 0;
}


Pour Code::Block, il existe une version "autonome", dans un zip qui ne nécessite pas d'installation. En revanche, il est vrai que ça fait 185Mo (ce qui ne devrait pas être trop problématique si tu utilises une clé usb). Libre à toi d'utiliser Dev-C++, mais c'est un pari que je ne prendrais personnellement pas :).

__________________________________________________________________________________________________

Améliorez votre expérience CodeS-SourceS avec ce plugin:
http://codes-sources.commentcamarche.net/forum/affich-10000111-plugin-better-cs-2#cptpingu-signature
0
casperfr Messages postés 6 Date d'inscription samedi 14 juillet 2001 Statut Membre Dernière intervention 21 janvier 2015
21 janv. 2015 à 18:28
parfait, merci encore,
0
Rejoignez-nous