PDA

Visualizza la versione completa : [C] Problema lista dinamica


Syntax
07-12-2004, 14:17
Ciao,

dovrei creare una rubrica telefonica utilizzando le liste dinamiche...

il problema è che la parte relativa alla cancellazione di un elemento della lista non mi vuole assolutamente funzionare...

scusatemi se è già stato postato da qualche parte, ma mi son letto tutti i post sulle liste senza trovare niente di utile...

teoricamente mi sembra corretto, ma in pratica non funziona :dhò: :dhò:


Vi posto il codice che fino ad ora ho scritto, provate a cancellare un elemento selezionandolo per nome, perchè a me proprio non va...

le funzioni interessate sono

struct node * delete_node ( struct node * current_node );
void delete_element ( struct node * current_node );

grazie! :ciauz:

e scusatemi se sono proprio un :fagiano: , ma C l'ho iniziato a studiare da un mese...



#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

/* Define boolean Type */

typedef enum { false, true } boolean;

/* Definisco i campi che dovrà memorizzare la mia rubrica per ogni contatto */

typedef struct {

int id;
char nome[50];
char cognome[50];
char telefono[14];
char citta[20];
char email[50];
char indirizzo[20];


} contatto;

/* Definisco il singolo elemento della rubrica */

struct node {

contatto content;
struct node * next_node;

};

/* Creo la rubrica e la inizializzo */

struct node * rubrica = NULL;


/* Prototipi funzioni */

struct node * add_contact( struct node * current_node );

struct node * delete_node ( struct node * current_node );
void delete_element ( struct node * current_node );

void show_contact( struct node * current_node );


contatto get_data( void );

/* Prototipi Procedures // GUI */

void gui_table_line () ;
void gui_table_space () ;
void print_element ( contatto contatto_temp );
void print_delete_menu ();

/* Prototipi funzioni // STRINGHE */
boolean string_compare( char * s1, char * s2 );




/* Variabili globali */

int contact_counter = 0;



/* Rubrica */

int main() {

int i;


/* Inserisco 3 valori per vedere se mi funziona la cancellazione in seguito... */
for ( i=0; i<2; i++ ) {

rubrica = add_contact( rubrica );

}


show_contact( rubrica );


delete_element( rubrica );

show_contact( rubrica );

getch();

return 0;

}






/* Raccogli dati per inserimento/modifica */

contatto get_data () {

contatto contatto_temp;

contatto_temp.id = contact_counter;

contact_counter++;

printf ( "\n\nSTEP 1: Inserire il nome del contatto\n>>");
gets ( contatto_temp.nome );

printf ( "\nSTEP 2: Inserire il cognome\n>>");
gets ( contatto_temp.cognome );

printf ( "\nSTEP 3: Inserire il numero telefonico\n>>");
gets ( contatto_temp.telefono );

printf ( "\nSTEP 4: Inserire l'indirizzo\n>>");
gets ( contatto_temp.indirizzo );

printf ( "\nSTEP 5: Inserire la citta'\n>>");
gets ( contatto_temp.citta );

printf ( "\nSTEP 6: Inserire l'indirizzo email\n>>");
gets ( contatto_temp.email );

return contatto_temp;

}

/* Aggiungi node alla rubrica. L'elemento è aggiunto in testa. */

struct node * add_contact( struct node * current_node ) {

struct node *temp_node;

contatto contatto_temp;



/* Acquisisco i dati da tastiera e li salvo in una struttura temporanea */

contatto_temp = get_data();

/* Alloco la memoria per il nuovo node da inserire in rubrica */

temp_node = malloc( sizeof ( struct node ) );

temp_node->content = contatto_temp;


/* Aggiungo i riferimenti all'elemeno successivo */

temp_node->next_node = current_node;

return temp_node;

}


/* Visualizza elementi presenti in rubrica */

void show_contact( struct node *current_node ) {


while ( current_node != NULL ) {

print_element ( current_node->content );

current_node = current_node->next_node;


}

}

/* Cancella un node */

void delete_element ( struct node * current_node ) {

/* Cursore ricerca */
struct node * temp_node;


/* Variabile contenente codice operazione */
char action;

/* Variabile di conferma operazioni -> Contiene Y (true) o N (false) */
char confirm;

/* Contatore cancellazioni eseguite */
int counter = 0;

/* Variabile temporanee per confrontare stringhe */
char stringa_temp[50];
char stringa_temp_current_node[50];




/* Menu di selezione */
print_delete_menu ();



/* Acquisisci operazione da effettuare */
printf ( "\n\n>" );
scanf ( "%c%*c" , &action );

switch ( action ) {

/* CANCELLA PER NOME */

case '1' :

/* Acquisisci il nome da ricercare e cancellare */
printf ( "\n\n NOME >" );
gets( stringa_temp );


/* Conferma cancellazione */
printf ( "\n\nSei sicuro di cancellare dalla rubrica tutti gli elementi contenenti %s nel campo nome? [Y/N] >" , stringa_temp);
scanf ( "%c%*c" , &confirm );

confirm = tolower( confirm );

if ( confirm != 'y' ) break;


/* Scorri current_node e cancella elementi corrispondenti */

while ( current_node != NULL ) {

/* Assegna il campo da confrontare nella current_node alla stringa temporanea */
strcpy( stringa_temp_current_node , current_node->content.nome );


/* Confronta e cancella se positivo */
if ( string_compare( stringa_temp , stringa_temp_current_node ) ) {


current_node = delete_node ( current_node );



} else {

current_node = current_node->next_node;

}



}

printf ( "\n Eseguite %d cancellazioni...Premere un tasto per continuare" , counter );


break;


}


}

/* Cancella un node, riassegna gli indirizzi e libera la memoria allocata non più utilizzata */

struct node * delete_node ( struct node * current_node ) {

struct node * temp_node;

temp_node = current_node->next_node;

free ( current_node );

return temp_node;

}

/* STRING FUNCTIONS */


boolean string_compare( char * s1, char * s2 ) {

if ( strcasecmp( s1, s2 ) )

return false;

else

return true;


}


/* GUI ELEMENTS */


/* Stampa il menu per cancellare elementi */

void print_delete_menu () {


gui_table_line ();

gui_table_space ();

printf ( "\n| SELEZIONA ELEMENTO DA CANCELLARE PER: |" );

gui_table_space ();

gui_table_line ();

gui_table_space ();

printf ( "\n| 1. NOME |" );
printf ( "\n| 2. COGNOME |" );
printf ( "\n| 3. ID |" );
printf ( "\n| 4. NUMERO TELEFONO |" );

gui_table_space ();

gui_table_line ();


}

/* Stampa un contatto a schermo */

void print_element ( contatto contatto_temp ) {

gui_table_line ();

gui_table_space ();
printf ( "\n| CONTATTO %d " , contatto_temp.id);
gui_table_space ();

gui_table_line ();

gui_table_space ();
printf ( "\n |" );
printf ( "\n Cognome: | %s " , contatto_temp.cognome);
printf ( "\n Nome: | %s " , contatto_temp.nome);
printf ( "\n Telefono: | %s " , contatto_temp.telefono);
printf ( "\n Indirizzo: | %s " , contatto_temp.indirizzo);
printf ( "\n Città: | %s " , contatto_temp.citta);
printf ( "\n Email: | %s " , contatto_temp.email);
printf ( "\n |" );
gui_table_space ();

gui_table_line ();

}


/* Stampa una linea per le tabelle */

void gui_table_line () {

printf ( "\n+-----------------------------------------------------------+" );

}

/* Stampa una linea vuota con bordi per le tabelle */

void gui_table_space () {

printf ( "\n| |" );

}

Syntax
07-12-2004, 19:31
up!


nn c'è proprio nessuno che ha la voglia di guardarlo :D :fagiano:

sò che è un po' lunghetto il codice, ma la parte che dovete guardare è solo quella relativa alle funzioni



struct node * delete_node ( struct node * current_node );

void delete_element ( struct node * current_node );

Ed_Bunker
07-12-2004, 19:43
Ance a me serve una liksta dinamica che metta a disposizione le operazioni di inserzione, cancellazione, ricerca di un elemento e restituzione degli elelemnti presenti. Allega il sorgente.c che dopo gli do un'occhiata. Quali sono le procedure che ti creano problemi ? In fase di compilazione tutto ok ?

Syntax
07-12-2004, 19:47
copai e incolla il codice che il sorgente è tutto sopra :ciauz: compilazione tutto ok, funzionare funziona, solo che non cancella gli elementi...

pprllo
08-12-2004, 00:23
Allora:
1) La tua funzione di confronto di stringhe è sbagliata: strcasecmp() restituisce ZERO se sono uguali, VALORI POSITIVI se s1 è lessicograficamente maggiore di s2, VALORI NEGATIVI se s2 è lessicograficamente maggiore di s1. Da riscrivere.
2) Anche quando questo funzionerà, il tuo codice darà violazione d'accesso alla prima prova. Infatti, rifletti. Nel momento in cui tu cancelli una voce, non modifichi il puntatore che c'era nella voce precedente che puntava alla voce appena cancellata. Risultato ? Un puntatore ad una zona di memoria deallocata -> crash. Mi sa che ti conviene avere sia un *next_node che un *prev_node.

Syntax
08-12-2004, 01:25
uhm allora riguardo al punto 1:

la funzione è corretta




boolean string_compare( char * s1, char * s2 ) {

if ( strcasecmp( s1, s2 ) )

return false;

else

return true;


}



infatti, se strcasecmp restituisce valori diversi da 0 (ossia le stringhe non sono uguali )ritorno false, se restisce zero ( ossia le stringhe sono uguali ) allora restituisco true.

riguardo al punto due, hai ragione, è che non riesco proprio a capire come scriverla corretta...almeno, teoricamente mi sembra sia giusta, ma poi in pratica...

vabbè ci proverò...

pprllo
08-12-2004, 09:35
Giusto, giusto ... Ieri era tardi, mi sono confuso. Comunque secondo me fai meglio ad usare uno strcmp, e scriverti una piccola funzione che ti manda a lowercase tutte e 2 le stringhe, perchè 'sto strcasecmp non mi sembra sia standard ... Comunque devi verificare se in effetti quando lui "scorre" la lista, cancella effettivamente delle voci. Mettici un [cout << "Sto cancellando"], così ti rendi conto.

pprllo
08-12-2004, 10:08
potresti usare una cosa del genere per portare a lowercase le stringhe:


char *tolow(char *s)
{
char *temp = new char;
int i;
for(i = 0; i<strlen(s); i++) *(temp+i) = tolower(*(s+i));
temp[i] = '\0';
return temp;
}


E poi fare uno strcmp(tolow(s1), tolow(s2)); Così usi solo funzioni della libreria standard. Ti ripeto: verifica se in effetti il programma lancia il tuo delete node. In caso positivo, potrebbe essere successo questo: tu hai deallocato la memoria, ma nessun processo l'ha ancora intaccata, per cui i dati sono ancora integri. Quando vai a scorrere la lista, i puntatori che ti portano a scorrere le voci puntano ancora a quelle zone di memoria e quindi è come se la lista fosse ancora intatta. In ogni caso, per il tuo problema basta creare un puntatore *prev_node che punti al nodo precedente ed è fatta.

Syntax
08-12-2004, 12:10
uhm, hai ragione, meglio usare funzioni standard... però la tua funzione per convertire in minuscolo non mi funziona...

mi fà crashare il programma...

l'ho provata anche da sola così, ma non va, crasha sempre. Cosa significava il new char, quando avevi scritto char * temp = new char; ?? Il compilatore me lo segnala come errore...

Scusami per le domande, magari ti sembrano davvero banali, ma sto impazzendo su sto cavolo di problema...




#include <stdio.h>
#include <ctype.h>
#include <string.h>

char * tolow( char * s );

int main () {

char * prova;

strcpy ( prova , "ASFASKFQglhasfeASG3" );

printf ( "%s", prova );

prova = tolow( prova );

printf ( "%s", prova );

getch();

return 0;

}

char *tolow(char *s)
{
char *temp;
int i;
for(i = 0; i<strlen(s); i++) *(temp+i) = tolower(*(s+i));

i++;
temp[i] = '\0';
return temp;

}



per la lista invece sono quasi alla soluzione credo, usando il puntatore come mi hai suggerito al nodo precedente...

pprllo
08-12-2004, 13:10
L'errore lo da perchè alla fine del ciclo for ci hai messo quell'istruzione
i++; che non c'entra nulla. Per il
new char Scusa mi sono sbagliato, è c++. L'istruzione che devi mettere tu è
char *temp = (char*)malloc(sizeof(s))

Loading