PDA

View Full Version : [C++] Eliminare elemento da lista


Markycap
17-08-2011, 16:00
Salve. Anticipo che da circa un mese tento disperatamente di trovare l'errore in questo programma:

/* Costruire una lista di caratteri, stampare i valori, eliminare
tutti i caratteri che sono vocali, stampare la nuova lista.*/

#include <iostream>
using namespace std;

class lista {
private:
char num;
lista *prox;
public:
lista(void);
void set (int new_num) {num = new_num;};
char get_num() {return num;};
void collega (lista *new_lista) {prox = new_lista;};
lista *get_prox () {return prox;};
};

void inserisci (char nuovo);
void visualizza (void);
void elimina (lista *elem);
void elimina_vocali(void);
int is_vocal(char lettera);
lista *primo = NULL;
lista *ultimo = NULL;
lista *nuovalista;

int main() {
int menu;
char val;
int risp=40;
cout << "Cosa vuoi fare?" << endl;
cout << "1) Inserimento" << endl;
cout << "2) Visualizza lista" << endl;
cout << "3) Esci ";
cin >> menu;
switch (menu)
case 1:
{
while (risp != 0) {
cout << "\nInserisci il nuovo carattere: ";
cin >> val;
inserisci(val);
cout << "Inserisci 0 per uscire" <<endl;
cin >> risp;
};
break;
case 2:
visualizza();
elimina_vocali();
visualizza();
break;
case 3:
return 0;
}
system("cls");
main ();
return 0;
}

lista::lista() {
num = 1;
prox = NULL;
}

void inserisci (char nuovo)
{
nuovalista = new (lista);
nuovalista -> set (nuovo);
if (primo == NULL)
{
primo = nuovalista;
ultimo = nuovalista;
}
else
{
ultimo -> collega (nuovalista);
ultimo = nuovalista;
}
};

int is_vocal(char lettera)
{
switch (lettera) {
case 'a':
return 1;
case 'e':
return 1;
case 'i':
return 1;
case 'o':
return 1;
case 'u':
return 1;
case 'A':
return 1;
case 'E':
return 1;
case 'I':
return 1;
case 'O':
return 1;
case 'U':
return 1;
default:
return 0;
}
};

void elimina_vocali(void)
{
lista *app, *punt_prec;
app = primo;
punt_prec = primo;
if (is_vocal(app -> get_num()) == 1)
{
primo = app -> get_prox();
delete (app);
}
else
{
while (app != NULL)
{
if (is_vocal (app -> get_num()) == 1)
elimina(punt_prec);


punt_prec = app;
// cout << app -> get_num();
app = app -> get_prox();

};
}
};

void elimina (lista *prec)
{
// cout << "precedente VALORE: " << prec -> get_num() << endl;
lista *prossimo, *curr;
curr = prec -> get_prox();
// cout << "current: " << curr << endl << curr -> get_num() << endl;
prossimo = curr -> get_prox();
// cout << "prossimo: " << prossimo << endl << prossimo -> get_num() << endl;
delete (curr);
prec -> collega (prossimo);
// cout << "preced: " << prec << endl << prec -> get_num() << endl;
// cout << (prec -> get_prox()) -> get_num();
system("PAUSE");
};

void visualizza (void) {
lista *app;
app = new(lista);
app = primo;
if (app == NULL)
cout << "\n\n\n\n La lista risulta essere vacante!" << endl << " ";
else
{
while (app != NULL) {
cout << app -> get_num() << "\n";
app = app -> get_prox();
}
}
system("PAUSE");
};

Tutto ciò che vedete commentato sono prove per capire cosa stampava e quando, dato che a compile time non da errori. L'errore pare essere nella funzione elimina: gli passo il puntatore dell'elemento precedente (che mi salvo in una variabile d'appoggio), poi in elimina non faccio altro che salvarmi i vari puntatori per non perderli, liberare o spazio allocato dall'elemento da eliminare e collegare il precedente con il successivo. I nomi delle variabili sono esplicativi... VI prego aiutatemi, sto impazzendo da un bel po' qui sopra... e non mi sembra che ci siano errori... sarà sicuramente una cavolata...:muro: :muro: :muro: :muro: :muro: :muro:

Mixmar
18-08-2011, 09:32
Non hai detto che tipo di errore da' il codice :rolleyes: ... comunque, così ad occhio, senza eseguire il codice:


La funzione "elimina_vocali" è sbagliata perchè, se la lista comincia con due (o più di due) vocali, elimina la prima e poi ritorna beata;
Quando tu chiami


elimina(punt_prec);


cambi il valore di app "sotto i piedi" della tua funzione; difatto, elimini la memoria allocata per punt_prec -> get_prox(); cioè app; che a quel punto non è più valido. Quindi assegni a punt_prec il valore di app, così ti sei perso anche quello: e immagino che ti dia errore questa istruzione:


app = app -> get_prox();


Perchè cerchi di operare su di un'area di memoria non valida.


Ci ho preso? :D

Markycap
18-08-2011, 14:03
Allora mi spiego meglio: l'errore è un loop a runtime. Succede solo quando la vocale non è la prima e sta in mezzo alla lista. Tra l'altro, ho identificato il problema nella funzione "elimina", perchè se non la richiamo, il programma gira bene... Ora non so se è un problema di passaggio di parametri... Magari, dato che sei l'unica anima pia che ha scelto di aiutarmi, puoi eseguirlo e vedi direttamente a runtime cosa fa???In ogno caso, ricontrollerò il tutto seguendo i tuoi consigli...

Per il punto 1 hai ragione, ma mi son bloccato nell'implementazione del codice in quanto non funge l'eliminazione in mezzo... perciò me lo son lasciato come problema da risolvere dopo...

Mixmar
19-08-2011, 09:04
Prova con questo metodo "elimina_vocali":


void elimina_vocali() {
lista* curr, prec;
curr = primo;
prec = NULL;
while(curr != NULL) {
if (is_vocal(curr -> get_num()) == 1) {
if (prec == NULL) {
// Elimina il primo elemento
primo = primo -> get_prox();
delete(curr);
curr = primo;
} else {
// Elimina l'ennesimo elemento
prec -> collega(curr -> get_prox());
delete(curr);
curr = prec -> get_prox();
}
} else {
prec = curr;
curr = curr -> get_prox();
}
}
// Per aggiornare il puntatore all'ultimo elemento
ultimo = prec;
}


(che, tra l'altro, rende inutile la funzione "elimina").

Mi sono reso conto, tra l'altro, che non aggiorni il puntatore all'ultimo elemento della lista, così ho aggiunto l'istruzione in fondo alla routine. Fammi sapere se così va bene.

Markycap
02-09-2011, 17:50
FUNZIONAAAAAA! :D :D :D :D :D Era solo sbagliata la dichiarazione, evidentemente per dichiarare due puntatori di tipo lista servivano due dichiarazioni separate con l'asterisco prima... Te ne sono infinitamente grato XD Tra l'altro, l'aggiornamento del puntatore finale non l'avevo ancora fatto, in questo caso mi hai tolto una cosa da fare XD

Sei stato un gran signore ;)