0

I am trying to put together a list class, but all of my calls to head are giving me NULL pointer exceptions... I'm not sure what is going on here. The functions are named in french but i have translated their purpose beside it. I've put comments on the affected lines.

I believe that working with head or head->next etc is causing the crash but i can't figure out how to fix it.

Thanks in advance for your advice.

#include <iostream>
 using namespace std;

template <class T>
class Node {
    T element;
    Node<T>* next;
    template <class T> friend class Liste;
    template <class T> friend class Iterator;
};

template <class T>
class Iterator {
    public:
        bool operator==(Iterator i);                
        T operator*();                              
        Iterator<T> operator++(int);                
    private:
        Node<T>* position;                          
        Liste<T>* container;                    
        template <class T> friend class Liste;
};

template<class T>
class Liste {
    public:
        Liste();                                        
        ~Liste();
        bool estVide();                 // checks if empty
        T retournerTete();              // returns head value
        T retournerFin();               // returns tail value
        void ajouterEnTete(T cle);      // insert to head of list
        void ajouterEnFin(T cle);       // insert to tail of list
        void supprimerEnTete();         // delete from head of list
        void supprimerEnFin();          // delete from tail of list
        Iterator<T> begin();            // start iterator at first element  
        Iterator<T> end();              // end iterator by pointing to NULL
        int BinarySearch(Liste<T> Liste, int start, int end, T key);

    private:
        Node<T> *head;
        Node<T> *tail;
};

int main() {

Liste<int> Liste1 ;
int key, position, start = 0, end = 0;
char commande = 'Z';

cout << " Commandes " << endl;
cout << " F     Finir " << endl;                                      //end test
cout << " I     Inserer une valeur a la queue de la liste" << endl;   //insert at tail
cout << " T     Inserer une valeur a la tete de la liste" << endl;    //insert at head
cout << " S     Supprimer la valeur a la tete" << endl;               //delete at head
cout << " D     Supprimer la valeur a la queue" << endl;              //delete at tail
cout << " E     Evaluer la valeur a la tete de la liste" << endl;     //return head value
cout << " Q     Evaluer la valeur a la queue de la liste" << endl;    //return tail value
cout << " R     Rechercher une valeur. " << endl;                     //binary search
cout << " A     Afficher les donnees de la liste. " << endl << endl;  //print list

while (commande != 'F')
{
    cout << endl << "Entrer une commande : ";
    cin >> commande;

    switch (commande)   {
    case 'F':                                                           // Fin du programme
    case 'f':   
        cout << "Le programme termine." << endl;
        commande = 'F';                                                 // Au cas où on aurait entré 'f'.
        break;
    case 'I':                                                           // Insertion d'une valeur a la queue de la liste.
    case 'i':   
        cin >> key;
        Liste1.ajouterEnFin(key);
        cout << key << " a ete ajoute a la fin de la liste." << endl;
        break;
    case 'T':                                                           // Insertion d'une valeur a la tete de la liste.
    case 't':   
        cin >> key;
        Liste1.ajouterEnTete(key);
        cout << key << " a ete ajoute au debut de la liste." << endl;
        break;
    case 'S':                                                           // Suppression de la valeur a la tete de la liste.
    case 's':
            Liste1.supprimerEnTete();
            cout << "une valeur a ete supprime au debut de la liste." << endl;
        break;
case 'D':           // Suppression de la valeur a la queue de la liste. 
case 'd':
    Liste1.supprimerEnFin();
    cout << "une valeur a ete supprime a la fin de la liste." << endl;
        break;
    case 'E':      // Évaluation de la valeur a la tete de la liste.
    case 'e':
        cout << Liste1.retournerTete() << " est a la tete de la file." << endl;
        break;
    case 'Q':       // Évaluation de la valeur au queue de la liste.
    case 'q':   
        cout << Liste1.retournerFin() << " est a la queue de la file." << endl;
        break;
    case 'R':                               // Afficher la liste.
    case 'r':
        for (Iterator<int> i = Liste1.begin(); !(i == Liste1.endIt()); i++) {
            end++;
        }
        cout << " Entrer une valeur : ";
        cin >> key;
        position = Liste1.BinarySearch(start, end, key);
        if (position == -1)
            cout << "pas trouve" << endl;
        else
            cout << " La valeur " << key << " se trouve a la position " << position << endl;
        break;

    case 'A':                                                           // Afficher la liste.
    case 'a':   
        for (Iterator<int> i = Liste1.begin(); !(i == Liste1.endIt()); i++)
            cout << *i << " ";
        break;

    default:
        cout << "La commande n'est pas reconnue." << endl;
    }
}
    cout << "Au revoir" << endl;

    return 0;
}

template<class T>
bool Iterator<T>::operator==(Iterator i) {
    return position == i.position;              
}

template<class T>                                   
T Iterator<T>::operator*() {
    return position->element;
}

template<class T>                               
Iterator<T> Iterator<T>::operator ++(int) {
    if (position != NULL)
        position = position->next;              // exception thrown
    return *this;                               
}

template <class T>                              
Liste<T>::Liste() {
    head = NULL;
    tail = NULL;
}

template <class T>                              
Liste<T>::~Liste() {
    while (!estVide())
        supprimerEnTete();
}

template <class T>                              // voir tete de la liste
T Liste<T>::retournerTete() {
    if (estVide()) {
        cout << " Vide " << endl;
        return 0;
    }
    else
        return head->element;
}

template <class T>                              // voir queue de la liste
T Liste<T>::retournerFin() {
    if (estVide()) {
        cout << " Vide " << endl;
        return 0;
    }
    else
        return tail->element;
}

template <class T>                              // inserer au debut
void Liste<T>::ajouterEnTete(T cle) {
    Node<T> *N = new Node<T>;
    N->element = cle;
    if (estVide()) {
        head = N;
        tail = N;
    }
    else {
        N->next = head;
        head = N;
    }

}

template <class T>
void Liste<T>::ajouterEnFin(T cle) {
    Node<T> *N = new Node<T>;
    N->element = cle;
    if (estVide()) {
        tail = N;
        head = N;
    }
    else {
        tail->next = N;
        tail = N;
    } 
}

template<class T>
void Liste<T>::supprimerEnTete() {
    if (!estVide()) {
        Node<T> *p = head;
        if (head->next == NULL)             //exception thrown
            tail = NULL;
        head = p->next;
        delete p;
    }
}

template<class T>
void Liste<T>::supprimerEnFin() {
    if (estVide()) { return; }
    else if (head->next == NULL) {          //exception thrown
         supprimerEnTete();
    }
    else {
        Node<T>* p = head;
        while ((p->next)->next != NULL)     //exception thrown 
            p = p->next;
        tail = p;
        p = p->next;
        tail->next = NULL;
        delete p;
    }
}

template<class T>
Iterator<T> Liste<T>::begin() {
    Iterator<T> i;
    i.position = head;
    i.container = this;                     //pointeur vers Liste
    return i;
}

template<class T>
Iterator<T> Liste<T>::endIt() {
    Iterator<T> i;
    i.position = NULL;
    i.container = this;
    return i;
}

template<class T>                                       
int Liste<T>::BinarySearch(Liste<T> Liste, int start, int end, T key) {
    int middle;
    Node<T> *curser = head;
    while (curser->next != NULL) {                   //exception thrown
        curser = curser->next;
        end++;
    }
    if (end < start)
        return -1;
     middle = ((start + end) / 2);
    if (key > middle)
        BinarySearch(Liste, middle + 1, end, key);
    else if (key < middle)
        BinarySearch(Liste, start, middle - 1, key);
    else
        return middle;
}
Bulbasaur
  • 303
  • 3
  • 19
  • A quick look at the code suggests you never initialise `head` before you use it. That is most likely the root of every problem, so please fix that first. – Ken Y-N Oct 24 '18 at 03:42
  • 2
    `int Liste::BinarySearch(Liste Liste, int start, int end, T key)` -- Your `Liste` class does not follow the [rule of 3](https://stackoverflow.com/questions/4172722/what-is-the-rule-of-three). This function will fail miserably when it's called since you're passing `Liste` by value. Passing by value makes copies, and your `Liste` function does not have proper copy semantics unless you either turn off copying, or supply a user-defined copy constructor and assignment operator, or pass by reference, not by value. – PaulMcKenzie Oct 24 '18 at 04:11
  • 2
    [Rubber duckie](https://en.wikipedia.org/wiki/Rubber_duck_debugging) wants to know why a `Liste` is a parameter to its one member functions. Which `Liste` do you want to operate on? `this` or the parameter? Side note: reusing a typename, such as `Liste Liste`, is a bad idea. In the example `Liste` the variable replaces `Liste` the type, and that can lead to confusing error messages should you attempt to use `Liste` the type after it has been supplanted. – user4581301 Oct 24 '18 at 04:18
  • Try this small program: `int main() { Liste list1; list1.ajouterEnTete(10); Liste list2 = list1;}` -- Assuming `ajoterEnTete` dynamically creates a new node, this 3 line program demonstrates the faultiness of your class and that copying will not work correctly. Bad things should happen after the `}` is executed. – PaulMcKenzie Oct 24 '18 at 04:19
  • `Liste` constructor appears to have handled KenY-N's comment. – user4581301 Oct 24 '18 at 04:19
  • Please post a [mcve] as to how you use your class. I already demonstrated with my own example that your `Liste` can be easily broken, but let's see your `main()` code. – PaulMcKenzie Oct 24 '18 at 04:24
  • could you please add the main method along with this – Ganesh Chowdhary Sadanala Oct 24 '18 at 04:46
  • Why don't you debug your program? – Quimby Oct 24 '18 at 04:54
  • @user4581301 `head` is initialized to NULL but is never assigned to (except in the pop node function), so any uses of it will dereference a NULL pointer. – 1201ProgramAlarm Oct 24 '18 at 06:11
  • Rubber Duckie - liste shouldn't be a parameter for the binary search, i forgot to delete it when i copy/pasted it from outside the liste class. I will fix that. PaulMcKenzie - Thanks, i will change it to pass by reference. I should have known that one, i am pretty new to coding so maybe not as thoughtful as I should be sometimes. Quimby - debugging shows me the lines where the exception is thrown, i've added a comment at each of those lines. @1201ProgramAlarm - I'm sure that's the problem.. what would I assign it to? – Bulbasaur Oct 24 '18 at 20:25
  • edited to include main function – Bulbasaur Oct 25 '18 at 04:17

1 Answers1

0

Solution : pass liste by reference instead of by value in the ajouterEnTete function.

Bulbasaur
  • 303
  • 3
  • 19