Tableau dynamique c++ [Résolu]

Messages postés
6
Date d'inscription
samedi 14 juillet 2001
Dernière intervention
21 janvier 2015
- - Dernière réponse : casperfr
Messages postés
6
Date d'inscription
samedi 14 juillet 2001
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
Afficher la suite 

Votre réponse

6 réponses

Messages postés
3830
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
19 novembre 2018
0
Merci
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
Commenter la réponse de cptpingu
Messages postés
6
Date d'inscription
samedi 14 juillet 2001
Dernière intervention
21 janvier 2015
0
Merci
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.
Commenter la réponse de casperfr
Messages postés
3830
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
19 novembre 2018
0
Merci

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
Commenter la réponse de cptpingu
Messages postés
6
Date d'inscription
samedi 14 juillet 2001
Dernière intervention
21 janvier 2015
0
Merci
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é
Commenter la réponse de casperfr
Messages postés
3830
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
19 novembre 2018
0
Merci
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
Commenter la réponse de cptpingu
Messages postés
6
Date d'inscription
samedi 14 juillet 2001
Dernière intervention
21 janvier 2015
0
Merci
parfait, merci encore,
Commenter la réponse de casperfr

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.