destruction de liste chainée

Bonjour,

J’ai créé une liste chainée simple qui fonctionne.
Lorsque je la détruis je ne peux pas en reconstruire une autre.
Ce doit être ma fonction:

void detruireListe(); qui dysfonctionne mais où?

voici tout mon code

#include <Streaming.h>

/***************************************************************/
#include "arduino.h"
//****************************************************************

struct tNode
{
  tNode *pPrec;
  tNode *pSuiv;
  String str;
};

//...

tNode *pDebut = NULL, 
         *pDernier = NULL;

//*****************************************************************

void ajout(tNode *pEl)
{
  if (pDebut == NULL)         // le premier
  {
    pDebut = pDernier = pEl;  // celui ci est premier et dernier
    pEl->pSuiv = NULL;        // pas de suiv
    pEl->pPrec = NULL;        // pas de prec
  }
  else
  {
    // a la suite du dernier cree
    // modif le dernier cree
    tNode *pPrec = pDernier;    // reouvrir le dernier cree
    
    pPrec->pSuiv = pEl;         // actualiser son champ suiv par celui cree
    
    // celui cree
    pEl->pPrec = pDernier;      // actualiser le champ prec de celui ci
    pEl->pSuiv = NULL;          // pas de suiv à celui ci
    pDernier = pEl;             // actu memorise le dernier qui est celui ci
  }
}


void ajouterAvecValeur( String s)
{
  tNode *pEl = new tNode; // creation d'une nouvelle struct
  
  ajout(pEl);             //  ajouter en fin
  
  pEl->str = s;           // actualiser le champ
}


void detruireListe()
{
  tNode *pDetruire = pDebut;
  while (pDetruire->pSuiv != NULL)
  {
    pDetruire = pDebut;        // ouvrir le premier
    pDebut = pDetruire->pSuiv; // le suiv devient le premier
    free(pDetruire);           // libere le pointeur
  }
  pDebut = NULL;               // pointe sur vide
}


void affiche()
{
  tNode *pAfficher = pDebut ;
  while (pAfficher->pSuiv != NULL)
  {
    pAfficher = pDebut;
    pDebut = pAfficher->pSuiv;
    Serial << pAfficher->str << "\t";
  }
  Serial << endl;
}

///////////////////////////////////////////////////////////////////////////////////////////////

void setup()
{
  Serial.begin(9600);
  Serial<<"prêt"<<endl;
  ajouterAvecValeur("un");
  ajouterAvecValeur("deux");
  ajouterAvecValeur("trois");
  ajouterAvecValeur("quatre");
  affiche();

// JUSQU'ICI CELA FONCTIONNE

  detruireListe();

//APRES PLUS RIEN

  ajouterAvecValeur("cinq");
  ajouterAvecValeur("six");
  ajouterAvecValeur("sept");
  affiche();
}

void loop() {
  // put your main code here, to run repeatedly:

}

Voici le résultat sur le moniteur série

prêt
un	deux	trois	quatre

Ou est mon erreur?
Merci pour votre aide.

ouaip, ta fonction detruireListe est moche :slight_smile:
Tu as oublié de remettre pDernier à NULL ... Ca peut expliquer la glutte ?

Mais bon, essaye ça (sans garantie...)

void detruireListe()
{
  tNode *p = pDebut;
  pDebut = pDernier = NULL;
  while ( p ) {
    tNode* pNext = p->pSuiv;
    delete ( p );
    p = pNext;
  }
}

Merci

ça fonctionne parfaitement.

Sur un petit micro-processeur vous n'avez pas intérêt à trop jouer avec l'allocation dynamique....

êtes vous sûr d'avoir besoin d'une liste chaînée ?

si vous savez combien au max votre application aura à en gérer, allouez un tableau de pointeurs sur Strings et vous gagnez comme cela tous les pointeurs.. (et on essaye d'éviter aussi la classe String d'ailleurs)

Bonjour,

j'ai bien compris J M L.

Je suis un grand débutant.

J'ai vu sur des exemples Web que l'on pouvait spliter un message reçu et stocker les différentes valeurs sur une liste chainée au lieu d'un tableau.

N'ayant jamais fait de liste chainée, j'ai voulu essayer juste pour savoir... D'où mes maladresses.

Eviter les String j'en suis d'accord et je suis tombé sur un écueil:

Le remplacer par un tableau de caractères serait moins gourmand mais la réponse du compilateur m'en a dissuadé.
En gros je ne sais pas l'inclure et le manipuler dans le code

comment feriez vous?

merci

je pense avoir une solution:

En remplaçant le String dans la structure par: char str[14];

la fonction devient:

void ajouterAvecValeur( char s[14])
{
  tNode *pEl = new tNode; // creation d'une nouvelle struct

  ajout(pEl);             //  ajouter en fin
  strcpy(pEl->str, s);

}

donc utiliser: strcpy(dest,source)

Et ça fonctionne!

merci

Madame Irma me dit que ça fonctionne car tu as redéfini ta struct comme ça :

struct tNode
{
  tNode *pPrec;
  tNode *pSuiv;
  char str [14];
};

mais ça ne marcherait pas comme ça :

struct tNode
{
  tNode *pPrec;
  tNode *pSuiv;
  char* str;
};

C'est plus facile de t'aider si tu donnes tout le code (utile).
Sinon on s'arrache la tête pour deviner ce que tu as fait.

dom0834:
En gros je ne sais pas l’inclure et le manipuler dans le code
comment feriez vous?

j’avais posté il n’y a pas très longtemps ce bout de code sur le forum anglais

#define PRE_ALLOCATE_MEMORY true // set it to false if you want to use dynamic memory allocation through strdup()

const uint8_t maxNbofCommand = 20;
const uint8_t maxLengthofCommand = 63;

char serialBuffer[maxLengthofCommand + 1];  // +1 as we want to add a trailing '\0' to terminate a cSrting
uint8_t commandIndex = 0;

#if PRE_ALLOCATE_MEMORY
char listOfCommands[maxNbofCommand][maxLengthofCommand + 1];// +1 as we want to add a trailing '\0' to terminate a cSrting
#else
char* listOfCommands[maxNbofCommand];
#endif


boolean getCommand()
{
  static byte currentIndex = 0;
  boolean commandReady = false;

  while (!commandReady) {
    int c = Serial.read();
    if (c != -1) { // -1 means nothing to read
      switch (c) {
        case '\n':         // end marker --> command complete?
          serialBuffer[currentIndex] = '\0'; // terminate the c-string
          currentIndex = 0; // get ready for next time
          commandReady = true;
          break;

        case '\r':         // ignore CR
          break;

        default:         // otherwise if we have room left, store the incoming char
          if (currentIndex < maxLengthofCommand) serialBuffer[currentIndex++] = (char) c;
          break;
      }
    } else break;
  }
  return commandReady;
}

bool addCommandToList(const char* aCommand)
{
  bool commandAdded = false;
  if (commandIndex < maxNbofCommand) {
#if PRE_ALLOCATE_MEMORY
    strncpy(listOfCommands[commandIndex], aCommand, maxLengthofCommand); // http://www.cplusplus.com/reference/cstring/strncpy/
    listOfCommands[commandIndex][maxLengthofCommand] = '\0'; // to be sure it's properly terminated
    commandIndex++;
    commandAdded = true;
#else
    listOfCommands[commandIndex] = strdup(aCommand); // https://en.cppreference.com/w/c/experimental/dynamic/strdup
    if (listOfCommands[commandIndex] == NULL) {
      Serial.println(F("ERROR: SRAM IS FULL"));
    } else {
      commandIndex++;
      commandAdded = true;
    }
#endif
  } else {
    Serial.println(F("ERROR: COMMAND BUFFER FULL"));
  }
  return commandAdded;
}

void printListOfCommands()
{
  for (byte i = 0; i < commandIndex; i++) {
    Serial.print(i);
    Serial.write('\t');
    Serial.println(listOfCommands[i]);
  }
  Serial.println(F("--------------------------"));
}

void setup()
{
  Serial.begin(115200);
#if PRE_ALLOCATE_MEMORY
  Serial.println(F("STATIC ALLOCATION"));
#else
  Serial.println(F("DYNAMIC ALLOCATION"));
#endif
  Serial.println(F("Ready"));
}

void loop()
{
  if (getCommand())
    if (addCommandToList(serialBuffer)) printListOfCommands();
}

ça écoute le terminal série (ouvert à 115200 bauds et avec CR+LF comme fin de ligne) et chaque phrase que vous entrez est stockée dans un tableau. le tableau a un nombre d’entrée limitées (par la constante maxNbofCommand) et chaque ligne entrée a au maximum maxLengthofCommand caractères.

au début du code il y a un #define PRE_ALLOCATE_MEMORY true // set it to false if you want to use dynamic memory allocation through strdup()qui permet soit d’avoir une allocation dynamique de l’espace de stockage des lignes reçues, soit une allocation statique dans un tableau à 2 dimensions fixes, c’est fait dans ce bout de code

#if PRE_ALLOCATE_MEMORY
char listOfCommands[maxNbofCommand][maxLengthofCommand + 1];// +1 as we want to add a trailing '\0' to terminate a cSrting
#else
char* listOfCommands[maxNbofCommand];
#endif

donc suivant que vous mettez PRE_ALLOCATE_MEMORY à true ou false ça va faire de la gestion statique ou dynamique.

ce code ne gère pas la suppression d’un élément mais en cas de mémoire dynamique il suffirait de mettre le pointeur à NULL et lors de l’ajout au lieu d’y aller en séquence jusqu’à la fin, il faudrait parcourir le tableau pour trouver la première case vide.