Why does objects I create in functions are not modified by other functions? (C++)

Viewed 72

I'm having problems using objects in C++. My University teacher assigned us a work in which we have to build a class named Lista (I'm Italian) with every feature it has in its specifics such as setElement, readElement, Head and so on. I'll post my files so you can read what I wrote. My problem is that the Lista object I create in the function "fondi" in servizilista.cpp is not modified by inserisci() function. Whether there could be problems with variables names I'll translate them in English.

Nodo.h

//
//  Nodo.h
//  Lista con Doppio Riferimento
//
//

#ifndef Nodo_h
#define Nodo_h

template <class tipoelem>
class Nodo {
public:
    tipoelem valore;
    Nodo* successivo;
    Nodo* precedente;
    
    Nodo();
    ~Nodo();
};

template <class tipoelem> Nodo <tipoelem> :: Nodo () {
    successivo = NULL;
    precedente = NULL;
}

template <class T> Nodo <T> :: ~Nodo () {}

#endif /* Nodo_h */

Lista.h

//
//  Lista.h
//  Lista con Doppio Riferimento
//
//

#ifndef Lista_h
#define Lista_h

#include "Nodo.h"

template <class tipoelem>
class Lista {
public:
    typedef Nodo <tipoelem> *posizione;
    
    Lista();
    ~Lista();
    bool vuota();
    posizione primo();
    bool fine(posizione);
    posizione successivo(posizione);
    posizione precedente(posizione);
    tipoelem leggi(posizione);
    void scrivi(posizione, tipoelem);
    void inserisci(posizione, tipoelem);
    void rimuovi(posizione);
    int ottieniLunghezza();
    
private:
    posizione testa;
    int lunghezza;
};

template <class tipoelem> Lista <tipoelem> :: Lista() {
    lunghezza = 0;
    testa = NULL;
}

template <class tipoelem> Lista <tipoelem> :: ~Lista() {}

template <class tipoelem> bool Lista <tipoelem> :: vuota() {
    return (testa == NULL);
}

template <class tipoelem> typename Lista <tipoelem> :: posizione Lista <tipoelem> :: primo() {
    return testa;
}

template <class tipoelem> bool Lista <tipoelem> :: fine(posizione pos) {
    return (pos -> successivo == NULL);
}

template <class tipoelem> typename Lista <tipoelem> :: posizione Lista <tipoelem> :: successivo(posizione pos) {
    return (pos -> successivo);
}

template <class tipoelem> typename Lista <tipoelem> :: posizione Lista <tipoelem> :: precedente(posizione pos) {
    return (pos -> precedente);
}

template <class tipoelem> tipoelem Lista <tipoelem> :: leggi(posizione pos) {
    return (pos -> valore);
}

template <class tipoelem> void Lista <tipoelem> :: scrivi(posizione pos, tipoelem elem) {
    pos -> valore = elem;
}

template <class tipoelem> void Lista <tipoelem> :: inserisci(posizione pos, tipoelem elem) {
    Nodo <tipoelem> *nodo = new Nodo <tipoelem>;
    
    nodo -> valore = elem;
    
    if(pos == testa and testa == NULL) {
        nodo -> successivo = NULL;
        testa = nodo;
    }
    else if(pos == testa and testa != NULL) {
        nodo -> successivo = pos;
        pos -> precedente = nodo;
        testa = nodo;
    }
    else if (pos != testa and pos == NULL){
        posizione iter = primo();
        while(!fine(iter)) {
            iter = iter -> successivo;
        }
        
        nodo -> successivo = NULL;
        nodo -> precedente = iter;
        iter -> successivo = nodo;
    }
    else if (pos != testa and pos != NULL) {
        nodo -> successivo = pos;
        nodo -> precedente = pos -> precedente;
        pos -> precedente -> successivo = nodo;
        pos -> precedente = nodo;
    }
    
    lunghezza ++;
}

template <class tipoelem> void Lista <tipoelem> :: rimuovi(posizione pos) {
    Nodo <tipoelem> *temp = pos;
    
    if(pos == testa)
        testa = pos -> successivo;
    else {
        pos -> precedente -> successivo = pos -> successivo;
        
        if(pos -> successivo != NULL)
            pos -> successivo -> precedente = pos -> precedente;
    }
    
    pos = pos -> successivo;
    
    lunghezza --;
    
    delete temp;
}

template <class tipoelem> int Lista <tipoelem> :: ottieniLunghezza() {
    return lunghezza;
}

#endif /* Lista_h */

servizilista.h

//
//  serviziolista.h
//  Lista con Doppio Riferimento
//
//

#ifndef serviziolista_h
#define serviziolista_h

#include "Lista.h"

void stampa(Lista <double>);
Lista <double> epura(Lista <double>);
Lista <double> fondi (Lista <double>, Lista <double>);

#endif /* serviziolista_h */

servizilista.cpp

//
//  serviziolista.cpp
//  Lista con Doppio Riferimento
//
//

#include <iostream>
#include "serviziolista.h"

using namespace std;

void stampa(Lista <double> l) {
    Lista <double> :: posizione iter = l.primo();
    
    cout << "[";
    while(iter != NULL) {
        cout << l.leggi(iter);
        
        if(l.successivo(iter) != NULL)
            cout << ", ";
        
        iter = l.successivo(iter);
    }
    cout << "]\n\n";
}

Lista <double> epura(Lista <double> l) {
    Lista <double> :: posizione s1;
    Lista <double> :: posizione s2;
    Lista <double> :: posizione temp;

    s1 = l.primo();
    while(s1 != NULL) {
      s2 = l.successivo(s1);
      while(s2 != NULL) {
        if(l.leggi(s1) == l.leggi(s2)) {
            temp = l.successivo(s2);
            l.rimuovi(s2);
            s2 = temp;
        }
        else {
          s2 = l.successivo(s2);
        }
      }
      s1 = l.successivo(s1);
    }
    
    return l;
}

Lista <double> fondi(Lista <double> l1, Lista <double> l2) {
    Lista <double> l;
    Lista <double> :: posizione p1 = l1.primo();
    Lista <double> :: posizione p2 = l2.primo();
    Lista <double> :: posizione pl = l.primo();
    double e1, e2;
    
    while(p1 != NULL and p2 != NULL) {
        e1 = l1.leggi(p1);
        e2 = l2.leggi(p2);
        
        if(e1 < e2) {
            cout << "Valore da inserire in pl: " << e1 << ".\n";
            l.inserisci(pl, e1);
            p1 = l1.successivo(p1);
            cout << "Valore in pl: " << l.leggi(pl) << ".\n";
        }
        else {
            cout << "Valore da inserire in pl: " << e2 << ".\n";
            l.inserisci(pl, e2);
            p2 = l2.successivo(p2);
            cout << "Valore in pl: " << l.leggi(pl) << ".\n";
        }
        
        pl = l.successivo(pl);
    }
    
    while(p1 != NULL) {
        l.inserisci(pl, l1.leggi(p1));
        p1 = l1.successivo(p1);
        pl = l.successivo(pl);
    }
    
    while(p2 != NULL) {
        l.inserisci(pl, l2.leggi(p2));
        p2 = l2.successivo(p2);
        pl = l.successivo(pl);
    }
    
    return l;
}

main.cpp

//
//  main.cpp
//  Lista con Doppio Riferimento
//
//

#include <iostream>
#include "Lista.h"
#include "serviziolista.h"

using namespace std;

int main() {
    Lista <double> l1;
    Lista <double> l2;
    Lista <double> lista;
    
    l1.inserisci(l1.primo(), 4);
    l1.inserisci(l1.primo(), 1);
    l1.inserisci(l1.primo(), 2);
    
    l2.inserisci(l2.primo(), 3);
    
    cout << "Lunghezza l1: " << l1.ottieniLunghezza() << ".\n";
    cout << "Lista l1: ";
    stampa(l1);
    
    cout << "Lunghezza l2: " << l2.ottieniLunghezza() << ".\n";
    cout << "Lista l2: ";
    stampa(l2);
    
    lista = fondi(l1, l2);
    
    cout << "Lunghezza lista fusa: " << lista.ottieniLunghezza() << ".\n";
    cout << "Lista fusa: ";
    stampa(lista);
    
    return 0;
}
2 Answers

Your list code seems OK.

Problem is with how you use it - you never update the variable pl. So do something like that:

    if(e1 < e2) {
        cout << "Valore da inserire in pl: " << e1 << ".\n";
        l.inserisci(pl, e1);
        p1 = l1.successivo(p1);
        pl = l.primo();
        cout << "Valore in pl: " << l.leggi(pl) << ".\n";
    }
    else {
        cout << "Valore da inserire in pl: " << e2 << ".\n";
        l.inserisci(pl, e2);
        p2 = l2.successivo(p2);
        pl = l.primo();
        cout << "Valore in pl: " << l.leggi(pl) << ".\n";
    }

EDIT: OK, now I am getting what you are trying to do. Again, list implementation is OK.

To add element to list head you shoulf call l.inserisci(l.primo(), e1);

To add element to the tail - l.inserisci(NULL, e1);

Here what you want is to always add to tail. So forget about the variable pl. Completely. Drop it, you don't need it. Your code becomes much simpler:

while(p1 != NULL and p2 != NULL) {
    e1 = l1.leggi(p1);
    e2 = l2.leggi(p2);
    
    if(e1 < e2) {
        cout << "Valore da inserire in pl: " << e1 << ".\n";
        l.inserisci(NULL, e1);
        p1 = l1.successivo(p1);
    }
    else {
        cout << "Valore da inserire in pl: " << e2 << ".\n";
        l.inserisci(NULL, e2);
        p2 = l2.successivo(p2);
    }
}

while(p1 != NULL) {
    l.inserisci(NULL, l1.leggi(p1));
    p1 = l1.successivo(p1);
}

while(p2 != NULL) {
    l.inserisci(NULL, l2.leggi(p2));
    p2 = l2.successivo(p2);
}

Good luck

Not sure this is the bug you are hunting, but I can't explain this well in a comment. May the downvotes have mercy on my soul.

I'm going to annotate some code.

Lista <double> fondi(Lista <double> l1, Lista <double> l2) {
    Lista <double> l; //<-- empty list
    Lista <double> :: posizione p1 = l1.primo();
    Lista <double> :: posizione p2 = l2.primo();
    Lista <double> :: posizione pl = l.primo(); //<-- first item in empty list. pl is null
    double e1, e2;

    while(p1 != NULL and p2 != NULL) {
        e1 = l1.leggi(p1); //<-- get value at p1
        e2 = l2.leggi(p2); //<-- get value at p2

        if(e1 < e2) { //<-- let's say e1 is less than e2 and we enter this case
            cout << "Valore da inserire in pl: " << e1 << ".\n";
            l.inserisci(pl, e1); //<-- insert to pl in l. pl is not changed. It is still null
            p1 = l1.successivo(p1); //<-- updates p1, not pl
            cout << "Valore in pl: " << l.leggi(pl) << ".\n"; // attempts to get value at pl
                                                              // but pl is null. Kaboom.
        }

p1 = l1.successivo(p1); advances p1 that's p-the-number-one. The next line l.leggi(pl) uses pl that's p-the-letter-L. Lista <double> :: posizione pl = l.primo(); and pl is null.

Not 100% sure what you want to do here, but I suspect

        p1 = l1.successivo(p1);

should be advancing pl, not p1

        pl = l1.successivo(pl);

If not, I have no clue what you're trying to do and can make no suggestions. The code is still fatal, though.

Suggestion: use descriptive names that don't differ by a single letter. They're too easy to mix up especially l and 1.

Related