0

I am trying to create a Hanoi solution by using linkedListStart, but I don't understand where is the leak in my program. I debug it and is is showing an nullptr exception. So can you guys tell me how should I correct it so that my program work? I should not use vector because i didn't see it in class and should use double point for the array.

linkedListstack

#pragma once
#include "Stack.h"
#include "NotImplementedException.h"
class LinkedListStack : public Stack
{
public:
    // ATTENTION, pour chacune des méthodes, 
    // lorsque vous créez sa définition dans le .cpp,
    // vous devez remplacer {} par un ;
    LinkedListStack();
    ~LinkedListStack();
    void push(int element) override;
    void pop() override;
    int top() const override;
    bool isEmpty() const override;
    int size() const override;

private:
    Node* firstNode;
    int length;
    
    //À vous de créer les attributs nécessaires
};

LinkedListStack.h

#include "LinkedListStack.h"
#include "Node.h"
#include <iostream>

LinkedListStack::LinkedListStack()
{
    this->length = 0;
    this->firstNode = nullptr;
}

LinkedListStack::~LinkedListStack()
{
    delete firstNode;
}

void LinkedListStack::push(int newPayload)
{
    this->firstNode = new Node(newPayload, firstNode);
    this->length++;
}

void LinkedListStack::pop()
{
    if (isEmpty()) {
        throw Empty_Stack();
    }

    this->firstNode = firstNode->getNextElement();
    this->length--;
}

int LinkedListStack::top() const
{
    if (isEmpty()) {
        throw Empty_Stack();
    }
    else
    {
        return (firstNode->getContent());
    }
    
}

bool LinkedListStack::isEmpty() const
{
    return (this->length == 0);
}

int LinkedListStack::size() const
{
    return this->length;
}

Node.cpp

#include "Node.h"
Node::Node(int content, Node *node)
{
    setContent(content);
    setNextElement(node);
}

Node::~Node()
{

}

Node* Node::getNextElement() const
{
    return this->nextElement;
}

void Node::setNextElement(Node* nextElement)
{
    this->nextElement = nextElement;
}

int Node::getContent() const
{
    return this->content;
}


void Node::setContent(int& content)
{
    this->content = content;
}

main

// Main.cpp : Ce fichier contient la fonction 'main'. L'exécution du programme commence et se termine à cet endroit.
#include <iostream>
#include <ctime>
#include <vld.h>  //Une fois que tout fonctionne, commentez pour voir la différence de temps
                  //le monitoring de la mémoire est coûteux, que ce soit VLD ou un garbage collector
#include "ArrayStack.h"
#include "LinkedListStack.h"
#include "Hanoi.h"

int main()
{
    setlocale(LC_ALL, "fr-CA");

    int nbrDisques;
    cout << "\nBienvenue dans ce logiciel de résolution automatique des tours de Hanoi!\n\n";
    cout << "Entrez le nombre de disques à implémenter (1 ou plus): ";
    cin >> nbrDisques;
    cout << "\n";

    if (cin.fail() || nbrDisques < 1)
    {
        cout << "Valeur entrée invalide.  Application terminée\n\n";
        return 0;
    }

    //Créez ici les 6 piles, 3 de type ArrayStack et 3 de type LinkedListStack avec nbrDisques que vous venez de saisir
    LinkedListStack linkedListStack1;
    LinkedListStack linkedListStack2;
    LinkedListStack linkedListStack3;

    ArrayStack arrayStack1;
    ArrayStack arrayStack2;
    ArrayStack arrayStack3;
    
    //Créez ici les 2 objets Hanoi (l'un avec 3 piles de type ArrayStack et l'autre 3 piles de type LinkedListStack.
    Hanoi *hanoiArrayStack = new Hanoi(arrayStack1, arrayStack2, arrayStack3, nbrDisques);
    Hanoi *hanoiLinkedListStack = new Hanoi(linkedListStack1, linkedListStack2, linkedListStack3, nbrDisques);

    int firstTimerForFirstHanoi = clock();
    //Appelez ici la méthode resolve() de votre objet Hanoi composé des 3 piles de type ArrayStack.
    hanoiLinkedListStack->resolve();
    int secondTimerForFirstHanoi = clock() - firstTimerForFirstHanoi;

    int firstTimerForSecondHanoi = clock();
    //Appelez ici la méthode resolve() de votre objet Hanoi composé des 3 piles de type LinkedListStack.
    hanoiArrayStack->resolve();
    int secondTimerForSecondHanoi = clock() - firstTimerForSecondHanoi;

    std::cout << "La resolution des tours d'Hanoi avec des 'ArrayStack' a pris :" << secondTimerForFirstHanoi << " millisecondes." << std::endl;
    std::cout << "La resolution des tours d'Hanoi avec des 'LinkedListStack' a pris :" << secondTimerForSecondHanoi << " millisecondes." << std::endl;
    // Regardez les résultats à partir de 20 disques...

    system("Pause");
    return 0;
}

// Exécuter le programme : Ctrl+F5 ou menu Déboguer > Exécuter sans débogage
// Déboguer le programme : F5 ou menu Déboguer > Démarrer le débogage

// Astuces pour bien démarrer : 
//   1. Utilisez la fenêtre Explorateur de solutions pour ajouter des fichiers et les gérer.
//   2. Utilisez la fenêtre Team Explorer pour vous connecter au contrôle de code source.
//   3. Utilisez la fenêtre Sortie pour voir la sortie de la génération et d'autres messages.
//   4. Utilisez la fenêtre Liste d'erreurs pour voir les erreurs.
//   5. Accédez à Projet > Ajouter un nouvel élément pour créer des fichiers de code, ou à Projet > Ajouter un élément existant pour ajouter des fichiers de code existants au projet.
//   6. Pour rouvrir ce projet plus tard, accédez à Fichier > Ouvrir > Projet et sélectionnez le fichier .sln.

hanoi.h

#pragma once
#include "Stack.h"
class Hanoi
{
public:
    /// <summary>
    /// Initialise l'objet Hanoi et ajoute sur la première pile (stack1) le nombre de disques (int) requis.
    /// </summary>
    /// <param name="stack1"></param>
    /// <param name="stack2"></param>
    /// <param name="stack3"></param>
    /// <param name="nbDisks">Le nombre de disques à ajouter sur la première pile (stack1).</param>
    Hanoi(Stack& stack1, Stack& stack2, Stack& stack3, const int nbDisks);
    ~Hanoi();

    /// <summary>
    /// Résoud le problème des Tours de Hanoï ;-)
    /// </summary>
    void resolve();
private:
    void resolve(Stack& stack1, Stack& stack2, Stack& stack3, int nbDisks);
    void moveDisk(Stack& stack1, Stack& stack2);
    Stack* stack1;
    Stack* stack2;
    Stack* stack3;
    int nbDisks;
};


hanoi.cpp

#include "Hanoi.h"
#include "NotImplementedException.h"
#include "HanoiIllegalMove.h"

Hanoi::Hanoi(Stack& stack1, Stack& stack2, Stack& stack3, const int nbDisks) 
{
    for (int i = nbDisks; i > 0; i--)
    {
        stack1.push(i);
    }

    this->nbDisks = nbDisks;
    this->stack1 = &stack1;
    this->stack2 = &stack2;
    this->stack3 = &stack3;


    // Complétez. N'oubliez pas d'initialiser 
    // la première pile (stack1) avec les disques (int) requis (paramètre nbDisks).
    // Le disque sur le dessus devrait avoir la valeur de 1 et on augmente de 1 par élément en dessous.
    //throw NotImplementedException();
}

Hanoi::~Hanoi() 
{
}

void Hanoi::resolve() 
{
    resolve(*stack1, *stack2, *stack3, nbDisks);
}

void Hanoi::resolve(Stack& stack1, Stack& stack2, Stack& stack3, int nbDisks) 
{
    //Décommentez ce code pour résoudre les tours de Hanoï
    if (nbDisks > 0) {
        resolve(stack1, stack3, stack2, nbDisks - 1);
        moveDisk(stack1, stack3);
        resolve(stack2, stack1, stack3, nbDisks - 1);
    }
}

// Cette méthode est appelée dans la méthode resolve juste au dessus. 
void Hanoi::moveDisk(Stack& stack1, Stack& stack2)
{
    if (stack1.top() < stack2.top())
    {
        throw Hanoi_Illegal_Move();
    }
    int diskToMove = stack1.top();
    stack1.pop();
    stack2.push(diskToMove);
    // Complétez 
    // Prendre le disque sur le dessus de première pile 
    // (premier pramètre, celui de gauche) et le déposer 
    // sur la deuxième (deuxième paramètre, celui de droite).
    //
    // Si le disque que l'on tente de déposer sur une pile a
    // une plus grande valeur que le disque en dessous, une
    // exception doit être lancée (HanoiIllegalMove exception)
    //throw NotImplementedException();
}

arraystack.cpp

#include "ArrayStack.h"

ArrayStack::ArrayStack() 
{
    maxCapacity = DEFAULT_CAPACITY;
    tab = new int* [DEFAULT_CAPACITY];
    for (int i = 0; i < DEFAULT_CAPACITY; ++i) {
        tab[i] = nullptr;
    }
    length = 0;
    topElement = -1;
}

ArrayStack::~ArrayStack()
{
    for (int i = 0; i < length; ++i) {
        delete tab[i];
    }
    delete[] tab;
}

void ArrayStack::push(int element)
{

    if (maxCapacity <= length) {
        maxCapacity += DEFAULT_CAPACITY;

        int** temp = new int* [maxCapacity];
        for (int i = 0; i < length; ++i) {
            temp[i] = tab[i];
        }
        for (int i = length; i < maxCapacity; ++i) {
            temp[i] = nullptr;
        }

        delete[] tab;
        tab = temp;
    }
    
    tab[length] = new int(element);
    ++length;

    topElement = element;
    
}

void ArrayStack::pop()
{
    if (isEmpty()) {
        throw Empty_Stack();
    }

    --length;
    delete tab[length];
    tab[length] = nullptr;

    if (isEmpty()) {
        topElement = -1;
    }
    else {
        topElement = *tab[length - 1];
    }
}



int ArrayStack::top() const
{
    if (isEmpty())
    {
        throw Empty_Stack();
    }
    return this->topElement;

}

bool ArrayStack::isEmpty() const
{
    return (this->length == 0);
}

int ArrayStack::size() const
{
    return this->length;
}

arraystack.h

#pragma once
#include "Stack.h"
#include "NotImplementedException.h"
class ArrayStack : public Stack
{
public:
    static const int DEFAULT_CAPACITY = 10;

    // ATTENTION, pour chacune des méthodes, lorsque
    // vous créez sa définition dans le .cpp, vous devez
    // remplacer {} (et éventuellement son contenu) par un ;
    ArrayStack();
    ~ArrayStack();
    void push(int element) override;
    void pop() override;
    int top() const override; 
    bool isEmpty() const override;
    int size() const override;

private:
    int length;
    int** tab;
    int topElement;
    int maxCapacity;
    //À vous de créer les attributs nécessaires

};


  • 1
    ***I debug it and is is showing an nullptr exception*** You should fix that first. When it breaks into the debugger figure out what pointer is null. This most likely has nothing to do with a leak. – drescherjm Oct 09 '21 at 14:04
  • How should I change my constructor if I need to instance it because I don't know which implement class he may start – Nicolas Pellerin Oct 09 '21 at 14:10
  • 1
    When destroying your stack,, you are only deleting the first node. What happens to the other nodes it is pointing to if you didn't pop all of them? Why implement your own linked list when the standard library has a perfectly good one? Also linked lists are terrible; they cause memory fragmenting and cache misses – Eyal K. Oct 09 '21 at 14:17
  • Because My teacher want me to do it like this. An how should I change the nodes? – Nicolas Pellerin Oct 09 '21 at 14:24
  • Can you please tell me how should I change it – Nicolas Pellerin Oct 09 '21 at 14:40
  • Remember fixing the leak has little to do with the bug about the nullptr exception. A memory leak will usually not prevent your program from running. – drescherjm Oct 09 '21 at 14:51
  • You need a while loop instead of: `delete firstNode;` in your `LinkedListStack` to fix the leak. This won't fix the crash however. My advice is to debug the `LinkedListStack` without the `hanoi` code at all. Make sure it does not leak or have undefined behavior before you use it for Hanoi. You may want to also read about the rule of 3/5/0 since this class violates the rule. – drescherjm Oct 09 '21 at 14:52
  • With what condition – Nicolas Pellerin Oct 09 '21 at 15:02
  • You have to iterate through all of the nodes deleting them 1 by 1. – drescherjm Oct 09 '21 at 15:05
  • Requests for debugging help must include a [mre]. This means that it is up to you to narrow down the problem, not just dump your entire program on us. Find a simple case that crashes, then assign appropriate values to your variables; don't rely on user input. Eliminate as many steps as you can. Simplify your classes to just what is needed to reproduce the error. For example, if you don't need the `top()` method to reproduce the error, then get rid of it. For the methods that are needed, inline the function definitions at least for the one-liners, as it makes reading your code easier. – JaMiT Oct 09 '21 at 15:10
  • 2
    Separate your problem into smaller parts, write a simple program that tests your `LinkedListStack`, then write another that tests `ArrayStack` (or maybe reuse the first if both classes have the same/similar behaviour). Once you know those are working correctly you can move on to the tower of Hanoi problem – Alan Birtles Oct 09 '21 at 16:16
  • You know that my node is a pointer and not a double pointer array – Nicolas Pellerin Oct 09 '21 at 17:33
  • I don't believe that would not alter the advice. I agree fully with @AlanBirtles you need to forget about Hanoi program for now and instead test and verify that your linked lists are working correctly. You know about the memory leak in `LinkedListStack` and I told you it has another serious flaw of violating the rule of 3/5/0. Related: [https://stackoverflow.com/questions/4172722/what-is-the-rule-of-three](https://stackoverflow.com/questions/4172722/what-is-the-rule-of-three) – drescherjm Oct 09 '21 at 18:39

0 Answers0