27/01/14 17:35
mik_91
Nel file allegato vi è il codice di un programma che gestisce un database di vini. Il mio problema è che ricevo un errore di segmentazione entrando nella funzione "inserisci_in_albero_bin". E' da un pò di giorni che stò cercando una soluzione ma non riesco a venirne a capo...qualcuno saprebbe aiutarmi??
/******************************************************************/ /* Programma per manipolare un file contenente una lista di vini. */ /* Michele Petrocchi Matricola 256507 */ /******************************************************************/ /***********************/ /* inclusione librerie */ /***********************/ #include <stdio.h> #include <stdlib.h> #include <string.h> /*************************************/ /* Dichiarazione costanti simboliche */ /*************************************/ #define LUNGHEZZA_NOME 51 /* lunghezza della stringa del nome del vino */ #define LUNGHEZZA_CODICE 5 /* lunghezza della stringa del codice del vino */ #define LUNGHEZZA_ANNO_PRODUZIONE 5 /* lunghezza della stringa dell'anno di produzione del vino */ #define LUNGHEZZA_LUOGO_PRODUZIONE 51 /* lunghezza della stringa del luogo di produzione del vino */ #define PERCORSO_FILE "./file_vini" /* percorso del file di output */ /************************/ /* Defibizione dei tipi */ /************************/ typedef struct nodo_albero_bin { char nome_vino[LUNGHEZZA_NOME], /* nome del vino */ codice_vino[LUNGHEZZA_CODICE], /* codice del vino */ anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], /* anno di produzione del vino */ luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE]; /* luogo di produzione del vino */ struct nodo_albero_bin *sx_p, *dx_p; } nodo_albero_bin_t; typedef struct vino { char nome_vino[LUNGHEZZA_NOME], /* nome del vino */ codice_vino[LUNGHEZZA_CODICE], /* codice del vino */ anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], /* anno di produzione del vino */ luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE]; /* luogo di produzione del vino */ } vino_t; /********************************/ /* Dichiarazione delle funzioni */ /********************************/ int controllo_correttezza_file(nodo_albero_bin_t **, FILE *, int *); int inserisci_in_albero_bin(nodo_albero_bin_t ***, char[], char[], char[], char[]); int inserisci_nuovo_vino(nodo_albero_bin_t **); int rimuovi_vino(nodo_albero_bin_t **); int rimuovi_da_albero_bin(nodo_albero_bin_t ***, char[]); void stampa_codice(nodo_albero_bin_t *); void stampa_vini(nodo_albero_bin_t *, int, int); void inserisci_vini_in_array(nodo_albero_bin_t *, vino_t [], int); void quicksort_nome(vino_t [], int, int); void quicksort_anno(vino_t [], int, int); void quicksort_luogo(vino_t [], int, int); void stampa_array(int, vino_t *); /******************************/ /* Definizione delle funzioni */ /******************************/ int main (int argc, /* numero stringhe acquisite lancio comandi */ char *argv[]) /* stringhe acqusite dal lancio comandi */ { int esito = 0, esito_ordinamento = 0, esito_pulizia = 1, esito_pulizia_ordinamento = 1, scelta_utente = 0, scelta_ordinamento = 0, rimosso = 0, numero_vini = 0, controllo = 0; FILE *input; /* file da dove preleverò la lista dei vini */ nodo_albero_bin_t *radice_p = NULL; /* lavoro: puntatore alla radice dell'albero */ /* specifichiamo il file di input, quindi deve essere 1 il numero degli argomenti */ if(argc > 1) { /* apriamo il file specificato */ input = fopen(argv[1],"r"); /* se il file specificato esiste */ if (input != NULL) { /* acquisisci il numero di vini */ esito = fscanf(input, "%d", &numero_vini); /* se il numero di vini non è valido */ if (esito != 1 || numero_vini < 0) printf("Lettura del numero di vini non riuscita.\n\n"); else controllo = controllo_correttezza_file(&radice_p, input, &numero_vini); /* chiudere il file di input */ fclose(input); /* se non si sono verificati errori */ if (controllo != 1) { do { do { printf("\nL'utente digiti:"); printf("\n 1-Se si vuole procedere nell'inserimento di un nuovo vino"); printf("\n 2-Se si vuole procedere nella cancellazione di un altro"); printf("\n 3-Se si vuole visualizzare la lista con i vini inseriti"); printf("\n 4-Se si vuole uscire dal programma"); printf("\nPremere Invio per confermare.\n"); printf("\n"); /* pulizia del buffer della scanf */ esito_pulizia = scanf("\n"); esito = scanf("%d", &scelta_utente); while (getchar() != '\n'); } while ((scelta_utente < 1) || (scelta_utente > 4) || (esito != 1) || (esito_pulizia != 0)); switch (scelta_utente) { case 1: esito = inserisci_nuovo_vino(&radice_p); if (esito == 1) /* incrementa il numero di vini */ numero_vini++; printf(" (premere Invio per tornare al menù)\n"); while (getchar() != '\n'); break; case 2: rimosso = rimuovi_vino(&radice_p); /* se la rimozione è andata a buon fine */ if (rimosso == 1) /* decremento il numero di vini */ numero_vini--; printf(" (premere Invio per tornare al menù)\n"); while (getchar() != '\n'); break; case 3: do { printf("\nL'utente scelga l'ordine di visualizzaione dei vini:"); printf("\n 1-Nome"); printf("\n 2-Codice"); printf("\n 3-Luogo di produzione"); printf("\n 4-Anno di produzione"); printf("\nPremere Invio per confermare.\n"); printf("\n"); /* pulizia del buffer della scanf */ esito_pulizia_ordinamento = scanf("\n"); esito_ordinamento = scanf("%d", &scelta_ordinamento); while (getchar() != '\n'); } while ((scelta_utente < 1) || (scelta_utente > 4) || (esito_ordinamento != 1) || (esito_pulizia_ordinamento != 0)); /* visualizzare la lista dei vini inseriti */ printf("\n%d vini inseriti:\n", numero_vini); if (scelta_ordinamento == 2) /* stampa i vini in base al codice */ stampa_codice(radice_p); else stampa_vini(radice_p, numero_vini, scelta_ordinamento); printf("\n"); printf("(premere Invio per tornare al menù)\n"); while (getchar() != '\n'); break; case 4: /* se l'utente decide di uscire stampiamo un messaggio di saluto */ printf("\nGrazie per aver utilizzato questo programma!"); printf("\n\n"); break; } } while ((scelta_utente != 4)); } } else/* se il file specificato è uguale a NULL e quindi inesistente */ printf("\nIl file specificato non esiste!\n"); } else { /* se non è stato inserito il parametro di lancio del file */ printf("\nNon è stato immesso il nome del file da dove importare i dati riguardanti i vini!"); printf("\nrilanciare il programma con queste specifiche:"); printf("\n./<nome_eseguibile> <nome_file_input>\n"); printf("\nIl file può essere generato tramite il programma che viene lanciato con ./genera"); printf("\n(per la compilazione il comando è make genera_vini!)\n"); printf("\n(se il file è nella dir. di lavoro basta specificarne il nome!)\n\n"); } return(0); } int controllo_correttezza_file(nodo_albero_bin_t **radice_p, FILE * input, int *numero_vini) { int esito, controllo_errori = 0, i, j; char nome_vino[LUNGHEZZA_NOME], codice_vino[LUNGHEZZA_CODICE], anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE], carattere_acquisito = '~'; /* lavoro: variabile utilizzata */ /* per acquisizioni e controlli */ /* il ciclo acquisce i vini uno ad uno dal file e li inserisce nella struttura dati */ for (i = 0; ((i < *numero_vini) && (controllo_errori == 0)); i++) { /* scorro il file fino a trovare il carattere successivo */ while (carattere_acquisito != '\n') carattere_acquisito = getc(input); /* acquisizione del nome del vino */ for (j = 0, carattere_acquisito = '~'; ((j < (LUNGHEZZA_NOME - 1)) && (carattere_acquisito != ' ') && (carattere_acquisito != '\n') && (controllo_errori == 0)); j++) { carattere_acquisito = getc(input); if ((carattere_acquisito != ' ') && (carattere_acquisito != '\n')) nome_vino[j] = carattere_acquisito; else j--; } nome_vino[j] = 'Nel file allegato vi è il codice di un programma che gestisce un database di vini. Il mio problema è che ricevo un errore di segmentazione entrando nella funzione "inserisci_in_albero_bin". E' da un pò di giorni che stò cercando una soluzione ma non riesco a venirne a capo...qualcuno saprebbe aiutarmi??/******************************************************************/ /* Programma per manipolare un file contenente una lista di vini. */ /* Michele Petrocchi Matricola 256507 */ /******************************************************************/ /***********************/ /* inclusione librerie */ /***********************/ #include <stdio.h> #include <stdlib.h> #include <string.h> /*************************************/ /* Dichiarazione costanti simboliche */ /*************************************/ #define LUNGHEZZA_NOME 51 /* lunghezza della stringa del nome del vino */ #define LUNGHEZZA_CODICE 5 /* lunghezza della stringa del codice del vino */ #define LUNGHEZZA_ANNO_PRODUZIONE 5 /* lunghezza della stringa dell'anno di produzione del vino */ #define LUNGHEZZA_LUOGO_PRODUZIONE 51 /* lunghezza della stringa del luogo di produzione del vino */ #define PERCORSO_FILE "./file_vini" /* percorso del file di output */ /************************/ /* Defibizione dei tipi */ /************************/ typedef struct nodo_albero_bin { char nome_vino[LUNGHEZZA_NOME], /* nome del vino */ codice_vino[LUNGHEZZA_CODICE], /* codice del vino */ anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], /* anno di produzione del vino */ luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE]; /* luogo di produzione del vino */ struct nodo_albero_bin *sx_p, *dx_p; } nodo_albero_bin_t; typedef struct vino { char nome_vino[LUNGHEZZA_NOME], /* nome del vino */ codice_vino[LUNGHEZZA_CODICE], /* codice del vino */ anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], /* anno di produzione del vino */ luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE]; /* luogo di produzione del vino */ } vino_t; /********************************/ /* Dichiarazione delle funzioni */ /********************************/ int controllo_correttezza_file(nodo_albero_bin_t **, FILE *, int *); int inserisci_in_albero_bin(nodo_albero_bin_t ***, char[], char[], char[], char[]); int inserisci_nuovo_vino(nodo_albero_bin_t **); int rimuovi_vino(nodo_albero_bin_t **); int rimuovi_da_albero_bin(nodo_albero_bin_t ***, char[]); void stampa_codice(nodo_albero_bin_t *); void stampa_vini(nodo_albero_bin_t *, int, int); void inserisci_vini_in_array(nodo_albero_bin_t *, vino_t [], int); void quicksort_nome(vino_t [], int, int); void quicksort_anno(vino_t [], int, int); void quicksort_luogo(vino_t [], int, int); void stampa_array(int, vino_t *); /******************************/ /* Definizione delle funzioni */ /******************************/ int main (int argc, /* numero stringhe acquisite lancio comandi */ char *argv[]) /* stringhe acqusite dal lancio comandi */ { int esito = 0, esito_ordinamento = 0, esito_pulizia = 1, esito_pulizia_ordinamento = 1, scelta_utente = 0, scelta_ordinamento = 0, rimosso = 0, numero_vini = 0, controllo = 0; FILE *input; /* file da dove preleverò la lista dei vini */ nodo_albero_bin_t *radice_p = NULL; /* lavoro: puntatore alla radice dell'albero */ /* specifichiamo il file di input, quindi deve essere 1 il numero degli argomenti */ if(argc > 1) { /* apriamo il file specificato */ input = fopen(argv[1],"r"); /* se il file specificato esiste */ if (input != NULL) { /* acquisisci il numero di vini */ esito = fscanf(input, "%d", &numero_vini); /* se il numero di vini non è valido */ if (esito != 1 || numero_vini < 0) printf("Lettura del numero di vini non riuscita.\n\n"); else controllo = controllo_correttezza_file(&radice_p, input, &numero_vini); /* chiudere il file di input */ fclose(input); /* se non si sono verificati errori */ if (controllo != 1) { do { do { printf("\nL'utente digiti:"); printf("\n 1-Se si vuole procedere nell'inserimento di un nuovo vino"); printf("\n 2-Se si vuole procedere nella cancellazione di un altro"); printf("\n 3-Se si vuole visualizzare la lista con i vini inseriti"); printf("\n 4-Se si vuole uscire dal programma"); printf("\nPremere Invio per confermare.\n"); printf("\n"); /* pulizia del buffer della scanf */ esito_pulizia = scanf("\n"); esito = scanf("%d", &scelta_utente); while (getchar() != '\n'); } while ((scelta_utente < 1) || (scelta_utente > 4) || (esito != 1) || (esito_pulizia != 0)); switch (scelta_utente) { case 1: esito = inserisci_nuovo_vino(&radice_p); if (esito == 1) /* incrementa il numero di vini */ numero_vini++; printf(" (premere Invio per tornare al menù)\n"); while (getchar() != '\n'); break; case 2: rimosso = rimuovi_vino(&radice_p); /* se la rimozione è andata a buon fine */ if (rimosso == 1) /* decremento il numero di vini */ numero_vini--; printf(" (premere Invio per tornare al menù)\n"); while (getchar() != '\n'); break; case 3: do { printf("\nL'utente scelga l'ordine di visualizzaione dei vini:"); printf("\n 1-Nome"); printf("\n 2-Codice"); printf("\n 3-Luogo di produzione"); printf("\n 4-Anno di produzione"); printf("\nPremere Invio per confermare.\n"); printf("\n"); /* pulizia del buffer della scanf */ esito_pulizia_ordinamento = scanf("\n"); esito_ordinamento = scanf("%d", &scelta_ordinamento); while (getchar() != '\n'); } while ((scelta_utente < 1) || (scelta_utente > 4) || (esito_ordinamento != 1) || (esito_pulizia_ordinamento != 0)); /* visualizzare la lista dei vini inseriti */ printf("\n%d vini inseriti:\n", numero_vini); if (scelta_ordinamento == 2) /* stampa i vini in base al codice */ stampa_codice(radice_p); else stampa_vini(radice_p, numero_vini, scelta_ordinamento); printf("\n"); printf("(premere Invio per tornare al menù)\n"); while (getchar() != '\n'); break; case 4: /* se l'utente decide di uscire stampiamo un messaggio di saluto */ printf("\nGrazie per aver utilizzato questo programma!"); printf("\n\n"); break; } } while ((scelta_utente != 4)); } } else/* se il file specificato è uguale a NULL e quindi inesistente */ printf("\nIl file specificato non esiste!\n"); } else { /* se non è stato inserito il parametro di lancio del file */ printf("\nNon è stato immesso il nome del file da dove importare i dati riguardanti i vini!"); printf("\nrilanciare il programma con queste specifiche:"); printf("\n./<nome_eseguibile> <nome_file_input>\n"); printf("\nIl file può essere generato tramite il programma che viene lanciato con ./genera"); printf("\n(per la compilazione il comando è make genera_vini!)\n"); printf("\n(se il file è nella dir. di lavoro basta specificarne il nome!)\n\n"); } return(0); } int controllo_correttezza_file(nodo_albero_bin_t **radice_p, FILE * input, int *numero_vini) { int esito, controllo_errori = 0, i, j; char nome_vino[LUNGHEZZA_NOME], codice_vino[LUNGHEZZA_CODICE], anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE], carattere_acquisito = '~'; /* lavoro: variabile utilizzata */ /* per acquisizioni e controlli */ /* il ciclo acquisce i vini uno ad uno dal file e li inserisce nella struttura dati */ for (i = 0; ((i < *numero_vini) && (controllo_errori == 0)); i++) { /* scorro il file fino a trovare il carattere successivo */ while (carattere_acquisito != '\n') carattere_acquisito = getc(input); /* acquisizione del nome del vino */ for (j = 0, carattere_acquisito = '~'; ((j < (LUNGHEZZA_NOME - 1)) && (carattere_acquisito != ' ') && (carattere_acquisito != '\n') && (controllo_errori == 0)); j++) { carattere_acquisito = getc(input); if ((carattere_acquisito != ' ') && (carattere_acquisito != '\n')) nome_vino[j] = carattere_acquisito; else j--; } nome_vino[j] = '{parsed_message}'; /* se il nome del vino ha più caratteri del previsto */ if (carattere_acquisito != ' ') printf("I nomi che superano i %d caratteri sono stati abbreviati!\n", (LUNGHEZZA_NOME - 1)); /* spostati in avanti nel file in avanti fino ad arrivare all'inizio del codice */ while (carattere_acquisito != ' ') carattere_acquisito = getc(input); /* acquisizione del codice del vino */ for (j = 0; ((j < (LUNGHEZZA_CODICE - 1)) && (controllo_errori == 0)); j++) { codice_vino[j] = getc(input); /* se il codice vino ha meno caratteri del previsto */ if (codice_vino[j] == ' ') { printf("I codici dei vini devono contenere %d caratteri!\n", (LUNGHEZZA_CODICE - 1)); controllo_errori = 1; } /* se il codice contiene caratteri non alfanumerici */ else if (codice_vino[j] < '0' || (codice_vino[j] > '9' && codice_vino[j] < 'A') || (codice_vino[j] > 'Z' && codice_vino[j] < 'a') || codice_vino[j] > 'z') { printf("I codici dei vini possono contenere solo caratteri alfanumerici!\n"); /* forza la chiusura del programma */ controllo_errori = 1; } } codice_vino[j] = '{parsed_message}'; carattere_acquisito = getc(input); /* spostati in avanti nel file fino ad arrivare all'inizio dell'anno di produzione */ while (carattere_acquisito != ' ') carattere_acquisito = getc(input); /* acquisizione dell'anno di produzione */ for (j = 0, carattere_acquisito = '~'; ((j < (LUNGHEZZA_ANNO_PRODUZIONE - 1)) && (controllo_errori == 0)); j++) { anno_vino[j] = getc(input); /* se l'anno del vino ha meno caratteri del previsto */ if (anno_vino[j] == ' ') { printf("L'anno di produzione dei vini devono contenere %d caratteri!\n", (LUNGHEZZA_ANNO_PRODUZIONE - 1)); controllo_errori = 1; } /* se l'anno contiene caratteri non numerici */ else if (anno_vino[j] < '0' || anno_vino[j] > '9' ) { printf("Gli anni dei vini possono contenere solo caratteri numerici!\n"); /* forza la chiusura del programma */ controllo_errori = 1; } } anno_vino[j] = '{parsed_message}'; carattere_acquisito = getc(input); /* spostati in avanti nel file in avanti fino ad arrivare all'inizio del luogo di produzione */ while (carattere_acquisito != ' ') carattere_acquisito = getc(input); /* acquisizione del luogo di produzione del vino */ for (j = 0, carattere_acquisito = '~'; ((j < (LUNGHEZZA_LUOGO_PRODUZIONE - 1)) && (carattere_acquisito != ' ') && (carattere_acquisito != '\n') && (controllo_errori == 0)); j++) { carattere_acquisito = getc(input); if ((carattere_acquisito != ' ') && (carattere_acquisito != '\n')) luogo_vino[j] = carattere_acquisito; else j--; } luogo_vino[j] = '{parsed_message}'; /* se il luogo di produzione del vino ha più caratteri del previsto */ if ((carattere_acquisito != '\n') && (controllo_errori == 0)) printf("I luoghi che superano i %d caratteri sono stati abbreviati!\n", (LUNGHEZZA_LUOGO_PRODUZIONE - 1)); /* inserimento del vino nell'albero ordinato secondo il codice */ esito = inserisci_in_albero_bin(&radice_p, codice_vino, nome_vino, anno_vino, luogo_vino); /* se l'inserimento non è andato a buon fine */ if (esito == 0) { printf("\nIl vino con codice \"%s\" non è stato inserito perchè già presente nella lista!\n", codice_vino); /* decrementa il numero dei vini del numero di inserimenti falliti */ *numero_vini = *numero_vini - 1; } } return (controllo_errori); } /* Algoritmo per l'inserimento di un vino nell'albero binario ordinato secondo il codice */ int inserisci_in_albero_bin(nodo_albero_bin_t ***radice_p, /* lavoro: puntatore al puntatore alla radice dell'albero */ char codice_vino[], /* input: codice del vino da inserire */ char nome_vino[], /* input: nome del vino da inserire */ char anno_vino[], /* input: anno di produzione del vino da inserire */ char luogo_vino[]) /* input: luogo di produzione del vino da inserire */ { int inserito, /* output: esito dell'inserimento */ i; /* lavoro: indice per i cicli for */ nodo_albero_bin_t *nodo_p, /* lavoro: puntatore ad un nodo */ *padre_p, /* lavoro: puntatore al padre del nodo_p */ *nuovo_p; /* lavoro: puntatore al nodo che conterrà il nuovo vino */ /* nodo_p e padre_p vengono inizializzati con l'indirizzo della radice e ad ogni */ /* iterazione padre_p prende l'indirizzo di nodo_p.nodo_p prende l'indirizzo del */ /* suo figlio sx o dx a seconda che il codice da inserire sia < o >= al codice */ /* puntato da nodo_p.Il ciclo termina quando nodo_p punta a NULL oppure ad un */ /* elemento che contiene un codice uguale a quello da inserire. */ for (nodo_p = padre_p = **radice_p; ((nodo_p != NULL) && (strcmp(nodo_p->codice_vino, codice_vino) != 0)); padre_p = nodo_p, nodo_p = (strcmp(codice_vino, nodo_p->codice_vino) < 0)? nodo_p->sx_p: nodo_p->dx_p); /* il vino non verrà inserito se era già presente, ovvero se nodo_p non punta a NULL */ if (nodo_p != NULL) inserito = 0; else { inserito = 1; /* viene allocata memoria per il nuovo nodo */ nuovo_p = (nodo_albero_bin_t *)malloc(sizeof(nodo_albero_bin_t)); /* inserimento del codice del vino */ for (i = 0; (i < LUNGHEZZA_CODICE); i++) nuovo_p->codice_vino[i] = codice_vino[i]; /* inserimento del nome del vino */ for (i = 0; (i < LUNGHEZZA_NOME); i++) nuovo_p->nome_vino[i] = nome_vino[i]; /* inserimento dell'anno di produzione del vino */ for (i = 0; (i < LUNGHEZZA_ANNO_PRODUZIONE); i++) nuovo_p->anno_vino[i] = anno_vino[i]; /* inserimento del luogo di produzione del vino */ for (i = 0; (i < LUNGHEZZA_LUOGO_PRODUZIONE); i++) nuovo_p->luogo_vino[i] = luogo_vino[i]; /* i puntatori vengono inizializzati a NULL */ nuovo_p->sx_p = nuovo_p->dx_p = NULL; /* se il nodo si trova in cima all'albero diventa la radice */ if (nodo_p == **radice_p) **radice_p = nuovo_p; /* se il codice inserito è inferiore a quello contenuto nel nodo padre */ else if (strcmp(codice_vino, padre_p->codice_vino) < 0) /* il nuovo nodo diventa figlio sinistro */ padre_p->sx_p = nuovo_p; else /* il nuovo nodo diventa figlio destro */ padre_p->dx_p = nuovo_p; } /* viene restituito il valore di esito dell'inserimento */ return(inserito); } /* Funzione per l'inserimento di un nuovo vino */ int inserisci_nuovo_vino(nodo_albero_bin_t **radice_p) /* lavoro: puntatore alla radice dell'albero */ { char nome_vino[LUNGHEZZA_NOME], /* input: nome del vino da inserire */ codice_vino[LUNGHEZZA_CODICE], /* input: codice del vino da inserire */ anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], /* input: anno di produzione del vino da inserire */ luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE], /* input: luogo di produzione del vino da inserire */ carattere_acquisito = '~'; /* lavoro: variabile usata per acquisizioni e controlli */ int inserito = 0, /* output: esito dell'inserimento */ controllo_errori, /* lavoro: variabile di controllo */ i; /* lavoro: indice per i cicli for */ /* acquisizione del codice del vino da inserire */ printf("\nScrivere il codice del vino da inserire: "); /* non esce dal ciclo se il codice inserito da tastiera è troppo corto */ do { controllo_errori = 0; carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_CODICE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ') && (controllo_errori == 0)); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) codice_vino[i] = carattere_acquisito; else { i--; printf("\nIl codice deve contenere %d caratteri alfanumerici!\n", (LUNGHEZZA_CODICE - 1)); printf("\nRiscrivere il codice del vino: "); } /* se il codice contiene caratteri non alfanumerici */ if (codice_vino[i] < '0' || (codice_vino[i] > '9' && codice_vino[i] < 'A') || (codice_vino[i] > 'Z' && codice_vino[i] < 'a') || codice_vino[i] > 'z') { controllo_errori = 1; printf("\nRiscrivere il codice del vino: "); } } codice_vino[i] = '{parsed_message}'; } while ((strlen(codice_vino) != (LUNGHEZZA_CODICE - 1)) || (controllo_errori == 1)); carattere_acquisito = getchar(); /* se l'utente ha inserito un codice troppo lungo */ if (carattere_acquisito != '\n') /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); /* acquisizione del nome del vino da inserire */ /* non esce dal ciclo se l'utente non inserisce nessun nome */ do { printf("Scrivere il nome del vino da inserire: "); carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_NOME - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ')); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) nome_vino[i] = carattere_acquisito; else i--; } nome_vino[i] = '{parsed_message}'; /* se l'utente ha inserito un nome troppo lungo */ if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) { printf("\nIl nome è stato abbreviato a %d caratteri!\n\n", (LUNGHEZZA_NOME - 1)); /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); } } while (strlen(nome_vino) == 0); /* acquisizione dell'anno di produzione del vino da inserire */ printf("Scrivere l'anno di produzione del vino da inserire: "); /* non esce dal ciclo se l'anno inserito da tastiera è troppo corto */ do { controllo_errori = 0; carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_ANNO_PRODUZIONE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ') && (controllo_errori == 0)); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) anno_vino[i] = carattere_acquisito; else { i--; printf("\nL'anno deve contenere %d caratteri numerici!\n", (LUNGHEZZA_ANNO_PRODUZIONE - 1)); printf("\nRiscrivere l'anno di produzione del vino: "); } /* se l'anno contiene caratteri non numerici */ if (anno_vino[i] < '0' || anno_vino[i] > '9') controllo_errori = 1; } anno_vino[i] = '{parsed_message}'; } while ((strlen(anno_vino) != (LUNGHEZZA_ANNO_PRODUZIONE - 1)) || (controllo_errori == 1)); carattere_acquisito = getchar(); /* se l'utente ha inserito un anno troppo lungo */ if (carattere_acquisito != '\n') /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); /* acquisizione del luogo di produzione del vino da inserire */ /* non esce dal ciclo se l'utente non inserisce nessun luogo */ do { printf("Scrivere il luogo di produzione del vino da inserire: "); carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_LUOGO_PRODUZIONE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ')); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) luogo_vino[i] = carattere_acquisito; else i--; } luogo_vino[i] = '{parsed_message}'; /* se l'utente ha inserito un luogo troppo lungo */ if (carattere_acquisito != '\n') { printf("\nIl luogo è stato abbreviato a %d caratteri!\n\n", (LUNGHEZZA_LUOGO_PRODUZIONE - 1)); /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); } } while (strlen(luogo_vino) == 0); /* inserimento del vino nell'albero */ inserito = inserisci_in_albero_bin(&radice_p, codice_vino, nome_vino, anno_vino, luogo_vino); /* se l'inserimento è andato a buon fine */ if (inserito != 1) printf("\nVino \"%s\" già presente!", codice_vino); else printf("\nIl vino è stato inserito."); /* viene restituito l'esito dell'inserimento */ return (inserito); } int rimuovi_vino(nodo_albero_bin_t **radice_p) /* lavoro: puntatore alla radice dell'albero */ { char codice_vino[LUNGHEZZA_CODICE], /* input: codice del vino da rimuovere */ carattere_acquisito = '~'; /* lavoro: variabile usata per acquisizioni e controlli */ int rimosso = 0, /* output: esito rimozione */ controllo_errori, /* lavoro: variabile di controllo */ i; /* lavoro: indice per i cicli */ /* acquisizione del codice del vino da rimuovere */ printf("\nScrivere il codice del vino da rimuovere: "); /* non esce dal ciclo se l'utente non inserisce un codice corretto */ do { controllo_errori = 0; carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_CODICE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ') && (controllo_errori == 0)); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) codice_vino[i] = carattere_acquisito; else { i--; printf("\nIl codice deve contenere %d caratteri alfanumerici!\n", (LUNGHEZZA_CODICE - 1)); printf("\nRiscrivere il codice del vino: "); } /* se il codice contiene caratteri non alfanumerici */ if (codice_vino[i] < '0' || (codice_vino[i] > '9' && codice_vino[i] < 'A') || (codice_vino[i] > 'Z' && codice_vino[i] < 'a') || codice_vino[i] > 'z') { controllo_errori = 1; printf("\nRiscrivere il codice del vino: "); } } codice_vino[i] = '{parsed_message}'; } while ((strlen(codice_vino) != (LUNGHEZZA_CODICE - 1)) || (controllo_errori == 1)); carattere_acquisito = getchar(); /* se l'utente ha inserito un codice troppo lungo */ if (carattere_acquisito != '\n') /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); /* rimozione del vino dall'albero */ rimosso = rimuovi_da_albero_bin(&radice_p, codice_vino); if (rimosso == 1) printf("\nIl vino è stato rimosso!"); else printf("\nIl vino non è presente nella lista!"); /* viene restituito l'esito della rimozione */ return (rimosso); } /* Algoritmo per la rimozione di un vino dall'albero binario */ int rimuovi_da_albero_bin(nodo_albero_bin_t ***radice_p, /* lavoro: puntatore al puntatore alla radice dell'albero */ char codice_vino[]) /* input: codice del vino da rimuovere */ { int rimosso, /* output: esito della rimozione */ i; /* lavoro: contatore per i cicli for */ nodo_albero_bin_t *nodo_p, /* lavoro: puntatore a un nodo */ *padre_p, /* lavoro: padre di nodo_p */ *sost_p; /* lavoro: sostituto di nodo_p */ /* nodo_p e padre_p vengono inizializzati con l'indirizzo della radice e ad ogni */ /* iterazione padre_p prende l'indirizzo di nodo_p.nodo_p prende l'indirizzo del */ /* suo figlio sx o dx a seconda che il codice da inserire sia < o >= al codice */ /* puntato da nodo_p.Il ciclo termina quando nodo_p punta a NULL oppure ad un */ /* elemento che contiene un codice uguale a quello da rimuovere. */ for (nodo_p = padre_p = **radice_p; ((nodo_p != NULL) && (strcmp(nodo_p->codice_vino,codice_vino) != 0)); padre_p = nodo_p, nodo_p = (strcmp(codice_vino,nodo_p->codice_vino) < 0)? nodo_p->sx_p: nodo_p->dx_p); /* il vino non verrà rimosso se non era presente, ovvero se nodo_p punta a NULL */ if (nodo_p == NULL) rimosso = 0; else { rimosso = 1; /* se nodo_p non ha figlio sx */ if (nodo_p->sx_p == NULL) { /* se nodo_p si trova in cima all'albero */ if (nodo_p == **radice_p) /* il figlio destro del nodo diventa la radice */ **radice_p = nodo_p->dx_p; /* altrimenti se il codice da rimuovere è minore di quello del padre */ else if (strcmp(codice_vino, padre_p->codice_vino) < 0) /* il figlio destro del nodo_p, diventa figlio sinistro del padre */ padre_p->sx_p = nodo_p->dx_p; else /* il figlio destro del nodo_p, diventa figlio destro del padre */ padre_p->dx_p = nodo_p->dx_p; } /* altrimenti, se nodo_p non ha figlio destro */ else if (nodo_p->dx_p == NULL) { /* se nodo_p si trova in cima all'albero */ if (nodo_p == **radice_p) /* il figlio sinistro del nodo diventa la radice */ **radice_p = nodo_p->sx_p; /* altrimenti, se il codice da rimuovere è minore di quello del padre */ else if (strcmp(codice_vino, padre_p->codice_vino) < 0) /* il figlio sinistro del nodo_p diventa figlio sinistro del padre */ padre_p->sx_p = nodo_p->sx_p; else /* il figlio sinistro del nodo_p diventa figlio destro del padre */ padre_p->dx_p = nodo_p->sx_p; } /* altrimenti, se il nodo_p ha entrambi i figli */ else { /* sost_p prende l'indirizzo contenuto in nodo_p */ sost_p = nodo_p; /* ad ogni iterazione del ciclo, padre_p prende l'indirizzo di nodo_p e nodo_p prende */ /* l'indirizzo del figlio destro; il ciclo termina quando nodo_p non ha figlio destro */ for (padre_p = sost_p, nodo_p = sost_p->sx_p; (nodo_p->dx_p != NULL); padre_p = nodo_p, nodo_p = nodo_p->dx_p); /* sostuzione del codice del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_CODICE); i++) sost_p->codice_vino[i] = nodo_p->codice_vino[i]; /* sostituzione del nome del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_NOME); i++) sost_p->nome_vino[i] = nodo_p->nome_vino[i]; /* sostuzione dell'anno del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_ANNO_PRODUZIONE); i++) sost_p->anno_vino[i] = nodo_p->anno_vino[i]; /* sostituzione del luogo del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_LUOGO_PRODUZIONE); i++) sost_p->anno_vino[i] = nodo_p->anno_vino[i]; /* se padre_p e sost_p puntano allo stesso nodo */ if (padre_p == sost_p) /* il figlio sinistro del nodo_p diventa figlio sinistro del padre_p */ padre_p->sx_p = nodo_p->sx_p; else /* il figlio sinistro del nodo_p diventa figlio destro del padre_p */ padre_p->dx_p = nodo_p->sx_p; } /* il nodo puntato da nodo_p viene rimosso dalla memoria */ free(nodo_p); } return(rimosso); } /* funzione per la stampa dei vini in base al codice */ void stampa_codice(nodo_albero_bin_t *nodo_p) { if (nodo_p != NULL) { stampa_codice(nodo_p->sx_p); printf("%s %s %s %s\n", nodo_p->nome_vino, nodo_p->codice_vino, nodo_p->anno_vino, nodo_p->luogo_vino); stampa_codice(nodo_p->dx_p); } } void stampa_vini(nodo_albero_bin_t *radice_p, int numero_vini, int scelta_ordinamento) { vino_t vini[numero_vini]; /* array per l'ordinamento */ /* trasferimento dei vini dall'albero in un array */ inserisci_vini_in_array(radice_p, vini, 0); switch(scelta_ordinamento) { case 1: /* ordina i vini in base al nome */ quicksort_nome(vini, 0, numero_vini - 1); break; case 3: /* ordina i vini in base all'anno */ quicksort_anno(vini, 0, numero_vini - 1); break; case 4: /* ordina i vini in base al luogo */ quicksort_luogo(vini, 0, numero_vini - 1); break; } stampa_array(numero_vini, vini); } /* funzione per il trasferimento dei vini dall'albero in un array */ void inserisci_vini_in_array(nodo_albero_bin_t *nodo_p, vino_t *vini, int i) { if (nodo_p->codice_vino != NULL) { inserisci_vini_in_array(nodo_p->sx_p, vini, i); strcpy(vini[i].nome_vino, nodo_p->nome_vino); strcpy(vini[i].codice_vino, nodo_p->codice_vino); strcpy(vini[i].anno_vino, nodo_p->anno_vino); strcpy(vini[i].luogo_vino, nodo_p->luogo_vino); i = i + 1; inserisci_vini_in_array(nodo_p->dx_p, vini, i); } } void quicksort_nome(vino_t a[], int sx, int dx) { int i, j; /* variabili di lavoro */ vino_t tmp, /* variabile usata per lo scambio */ pivot; /* puntatore all'elemento che fungera' da pivot */ /* si sceglie come pivot il valore centrale e si attua una tri-partizione */ /* scambiando gli elementi in modo che nella porzione a destra del pivot vi */ /* siano elementi maggiori del pivot e nella porzione sinistra quelli minori */ for (pivot = a[(sx + dx) / 2], i = sx, j = dx; (i <= j);) { while (strcmp(a[i].nome_vino, pivot.nome_vino) == -1) i++; while (strcmp(a[j].nome_vino, pivot.nome_vino) == 1) j--; if (i <= j) { if (i < j) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; } i++; j--; } } /* si invoca ricorsivamente la funzione sulle porzioni sinistra e destra */ if (sx < j) quicksort_nome(a, sx, j); if (i < dx) quicksort_nome(a, i, dx); } void quicksort_anno(vino_t a[], int sx, int dx) { int i, j; /* variabili di lavoro */ vino_t tmp, /* variabile usata per lo scambio */ pivot; /* puntatore all'elemento che fungera' da pivot */ /* si sceglie come pivot il valore centrale e si attua una tri-partizione */ /* scambiando gli elementi in modo che nella porzione a destra del pivot vi */ /* siano elementi maggiori del pivot e nella porzione sinistra quelli minori */ for (pivot = a[(sx + dx) / 2], i = sx, j = dx; (i <= j);) { while (strcmp(a[i].anno_vino, pivot.anno_vino) == -1) i++; while (strcmp(a[j].anno_vino, pivot.anno_vino) == 1) j--; if (i <= j) { if (i < j) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; } i++; j--; } } /* si invoca ricorsivamente la funzione sulle porzioni sinistra e destra */ if (sx < j) quicksort_anno(a, sx, j); if (i < dx) quicksort_anno(a, i, dx); } void quicksort_luogo(vino_t a[], int sx, int dx) { int i, j; /* variabili di lavoro */ vino_t tmp, /* variabile usata per lo scambio */ pivot; /* puntatore all'elemento che fungera' da pivot */ /* si sceglie come pivot il valore centrale e si attua una tri-partizione */ /* scambiando gli elementi in modo che nella porzione a destra del pivot vi */ /* siano elementi maggiori del pivot e nella porzione sinistra quelli minori */ for (pivot = a[(sx + dx) / 2], i = sx, j = dx; (i <= j);) { while (strcmp(a[i].luogo_vino, pivot.luogo_vino) == -1) i++; while (strcmp(a[j].luogo_vino, pivot.luogo_vino) == 1) j--; if (i <= j) { if (i < j) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; } i++; j--; } } /*Si invoca ricorsivamente la funzione sulle porzioni sinistra e destra*/ if (sx < j) quicksort_luogo(a, sx, j); if (i < dx) quicksort_luogo(a, i, dx); } void stampa_array(int numero_vini, vino_t *vini) { int i; /*Vengono stampati gli elementi ordinati*/ for(i = 0; i < numero_vini; i++) printf("\n%20s %4s %4s %s", vini[i].nome_vino, vini[i].codice_vino, vini[i].anno_vino, vini[i].luogo_vino); }'; /* se il nome del vino ha più caratteri del previsto */ if (carattere_acquisito != ' ') printf("I nomi che superano i %d caratteri sono stati abbreviati!\n", (LUNGHEZZA_NOME - 1)); /* spostati in avanti nel file in avanti fino ad arrivare all'inizio del codice */ while (carattere_acquisito != ' ') carattere_acquisito = getc(input); /* acquisizione del codice del vino */ for (j = 0; ((j < (LUNGHEZZA_CODICE - 1)) && (controllo_errori == 0)); j++) { codice_vino[j] = getc(input); /* se il codice vino ha meno caratteri del previsto */ if (codice_vino[j] == ' ') { printf("I codici dei vini devono contenere %d caratteri!\n", (LUNGHEZZA_CODICE - 1)); controllo_errori = 1; } /* se il codice contiene caratteri non alfanumerici */ else if (codice_vino[j] < '0' || (codice_vino[j] > '9' && codice_vino[j] < 'A') || (codice_vino[j] > 'Z' && codice_vino[j] < 'a') || codice_vino[j] > 'z') { printf("I codici dei vini possono contenere solo caratteri alfanumerici!\n"); /* forza la chiusura del programma */ controllo_errori = 1; } } codice_vino[j] = 'Nel file allegato vi è il codice di un programma che gestisce un database di vini. Il mio problema è che ricevo un errore di segmentazione entrando nella funzione "inserisci_in_albero_bin". E' da un pò di giorni che stò cercando una soluzione ma non riesco a venirne a capo...qualcuno saprebbe aiutarmi??/******************************************************************/ /* Programma per manipolare un file contenente una lista di vini. */ /* Michele Petrocchi Matricola 256507 */ /******************************************************************/ /***********************/ /* inclusione librerie */ /***********************/ #include <stdio.h> #include <stdlib.h> #include <string.h> /*************************************/ /* Dichiarazione costanti simboliche */ /*************************************/ #define LUNGHEZZA_NOME 51 /* lunghezza della stringa del nome del vino */ #define LUNGHEZZA_CODICE 5 /* lunghezza della stringa del codice del vino */ #define LUNGHEZZA_ANNO_PRODUZIONE 5 /* lunghezza della stringa dell'anno di produzione del vino */ #define LUNGHEZZA_LUOGO_PRODUZIONE 51 /* lunghezza della stringa del luogo di produzione del vino */ #define PERCORSO_FILE "./file_vini" /* percorso del file di output */ /************************/ /* Defibizione dei tipi */ /************************/ typedef struct nodo_albero_bin { char nome_vino[LUNGHEZZA_NOME], /* nome del vino */ codice_vino[LUNGHEZZA_CODICE], /* codice del vino */ anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], /* anno di produzione del vino */ luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE]; /* luogo di produzione del vino */ struct nodo_albero_bin *sx_p, *dx_p; } nodo_albero_bin_t; typedef struct vino { char nome_vino[LUNGHEZZA_NOME], /* nome del vino */ codice_vino[LUNGHEZZA_CODICE], /* codice del vino */ anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], /* anno di produzione del vino */ luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE]; /* luogo di produzione del vino */ } vino_t; /********************************/ /* Dichiarazione delle funzioni */ /********************************/ int controllo_correttezza_file(nodo_albero_bin_t **, FILE *, int *); int inserisci_in_albero_bin(nodo_albero_bin_t ***, char[], char[], char[], char[]); int inserisci_nuovo_vino(nodo_albero_bin_t **); int rimuovi_vino(nodo_albero_bin_t **); int rimuovi_da_albero_bin(nodo_albero_bin_t ***, char[]); void stampa_codice(nodo_albero_bin_t *); void stampa_vini(nodo_albero_bin_t *, int, int); void inserisci_vini_in_array(nodo_albero_bin_t *, vino_t [], int); void quicksort_nome(vino_t [], int, int); void quicksort_anno(vino_t [], int, int); void quicksort_luogo(vino_t [], int, int); void stampa_array(int, vino_t *); /******************************/ /* Definizione delle funzioni */ /******************************/ int main (int argc, /* numero stringhe acquisite lancio comandi */ char *argv[]) /* stringhe acqusite dal lancio comandi */ { int esito = 0, esito_ordinamento = 0, esito_pulizia = 1, esito_pulizia_ordinamento = 1, scelta_utente = 0, scelta_ordinamento = 0, rimosso = 0, numero_vini = 0, controllo = 0; FILE *input; /* file da dove preleverò la lista dei vini */ nodo_albero_bin_t *radice_p = NULL; /* lavoro: puntatore alla radice dell'albero */ /* specifichiamo il file di input, quindi deve essere 1 il numero degli argomenti */ if(argc > 1) { /* apriamo il file specificato */ input = fopen(argv[1],"r"); /* se il file specificato esiste */ if (input != NULL) { /* acquisisci il numero di vini */ esito = fscanf(input, "%d", &numero_vini); /* se il numero di vini non è valido */ if (esito != 1 || numero_vini < 0) printf("Lettura del numero di vini non riuscita.\n\n"); else controllo = controllo_correttezza_file(&radice_p, input, &numero_vini); /* chiudere il file di input */ fclose(input); /* se non si sono verificati errori */ if (controllo != 1) { do { do { printf("\nL'utente digiti:"); printf("\n 1-Se si vuole procedere nell'inserimento di un nuovo vino"); printf("\n 2-Se si vuole procedere nella cancellazione di un altro"); printf("\n 3-Se si vuole visualizzare la lista con i vini inseriti"); printf("\n 4-Se si vuole uscire dal programma"); printf("\nPremere Invio per confermare.\n"); printf("\n"); /* pulizia del buffer della scanf */ esito_pulizia = scanf("\n"); esito = scanf("%d", &scelta_utente); while (getchar() != '\n'); } while ((scelta_utente < 1) || (scelta_utente > 4) || (esito != 1) || (esito_pulizia != 0)); switch (scelta_utente) { case 1: esito = inserisci_nuovo_vino(&radice_p); if (esito == 1) /* incrementa il numero di vini */ numero_vini++; printf(" (premere Invio per tornare al menù)\n"); while (getchar() != '\n'); break; case 2: rimosso = rimuovi_vino(&radice_p); /* se la rimozione è andata a buon fine */ if (rimosso == 1) /* decremento il numero di vini */ numero_vini--; printf(" (premere Invio per tornare al menù)\n"); while (getchar() != '\n'); break; case 3: do { printf("\nL'utente scelga l'ordine di visualizzaione dei vini:"); printf("\n 1-Nome"); printf("\n 2-Codice"); printf("\n 3-Luogo di produzione"); printf("\n 4-Anno di produzione"); printf("\nPremere Invio per confermare.\n"); printf("\n"); /* pulizia del buffer della scanf */ esito_pulizia_ordinamento = scanf("\n"); esito_ordinamento = scanf("%d", &scelta_ordinamento); while (getchar() != '\n'); } while ((scelta_utente < 1) || (scelta_utente > 4) || (esito_ordinamento != 1) || (esito_pulizia_ordinamento != 0)); /* visualizzare la lista dei vini inseriti */ printf("\n%d vini inseriti:\n", numero_vini); if (scelta_ordinamento == 2) /* stampa i vini in base al codice */ stampa_codice(radice_p); else stampa_vini(radice_p, numero_vini, scelta_ordinamento); printf("\n"); printf("(premere Invio per tornare al menù)\n"); while (getchar() != '\n'); break; case 4: /* se l'utente decide di uscire stampiamo un messaggio di saluto */ printf("\nGrazie per aver utilizzato questo programma!"); printf("\n\n"); break; } } while ((scelta_utente != 4)); } } else/* se il file specificato è uguale a NULL e quindi inesistente */ printf("\nIl file specificato non esiste!\n"); } else { /* se non è stato inserito il parametro di lancio del file */ printf("\nNon è stato immesso il nome del file da dove importare i dati riguardanti i vini!"); printf("\nrilanciare il programma con queste specifiche:"); printf("\n./<nome_eseguibile> <nome_file_input>\n"); printf("\nIl file può essere generato tramite il programma che viene lanciato con ./genera"); printf("\n(per la compilazione il comando è make genera_vini!)\n"); printf("\n(se il file è nella dir. di lavoro basta specificarne il nome!)\n\n"); } return(0); } int controllo_correttezza_file(nodo_albero_bin_t **radice_p, FILE * input, int *numero_vini) { int esito, controllo_errori = 0, i, j; char nome_vino[LUNGHEZZA_NOME], codice_vino[LUNGHEZZA_CODICE], anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE], carattere_acquisito = '~'; /* lavoro: variabile utilizzata */ /* per acquisizioni e controlli */ /* il ciclo acquisce i vini uno ad uno dal file e li inserisce nella struttura dati */ for (i = 0; ((i < *numero_vini) && (controllo_errori == 0)); i++) { /* scorro il file fino a trovare il carattere successivo */ while (carattere_acquisito != '\n') carattere_acquisito = getc(input); /* acquisizione del nome del vino */ for (j = 0, carattere_acquisito = '~'; ((j < (LUNGHEZZA_NOME - 1)) && (carattere_acquisito != ' ') && (carattere_acquisito != '\n') && (controllo_errori == 0)); j++) { carattere_acquisito = getc(input); if ((carattere_acquisito != ' ') && (carattere_acquisito != '\n')) nome_vino[j] = carattere_acquisito; else j--; } nome_vino[j] = '{parsed_message}'; /* se il nome del vino ha più caratteri del previsto */ if (carattere_acquisito != ' ') printf("I nomi che superano i %d caratteri sono stati abbreviati!\n", (LUNGHEZZA_NOME - 1)); /* spostati in avanti nel file in avanti fino ad arrivare all'inizio del codice */ while (carattere_acquisito != ' ') carattere_acquisito = getc(input); /* acquisizione del codice del vino */ for (j = 0; ((j < (LUNGHEZZA_CODICE - 1)) && (controllo_errori == 0)); j++) { codice_vino[j] = getc(input); /* se il codice vino ha meno caratteri del previsto */ if (codice_vino[j] == ' ') { printf("I codici dei vini devono contenere %d caratteri!\n", (LUNGHEZZA_CODICE - 1)); controllo_errori = 1; } /* se il codice contiene caratteri non alfanumerici */ else if (codice_vino[j] < '0' || (codice_vino[j] > '9' && codice_vino[j] < 'A') || (codice_vino[j] > 'Z' && codice_vino[j] < 'a') || codice_vino[j] > 'z') { printf("I codici dei vini possono contenere solo caratteri alfanumerici!\n"); /* forza la chiusura del programma */ controllo_errori = 1; } } codice_vino[j] = '{parsed_message}'; carattere_acquisito = getc(input); /* spostati in avanti nel file fino ad arrivare all'inizio dell'anno di produzione */ while (carattere_acquisito != ' ') carattere_acquisito = getc(input); /* acquisizione dell'anno di produzione */ for (j = 0, carattere_acquisito = '~'; ((j < (LUNGHEZZA_ANNO_PRODUZIONE - 1)) && (controllo_errori == 0)); j++) { anno_vino[j] = getc(input); /* se l'anno del vino ha meno caratteri del previsto */ if (anno_vino[j] == ' ') { printf("L'anno di produzione dei vini devono contenere %d caratteri!\n", (LUNGHEZZA_ANNO_PRODUZIONE - 1)); controllo_errori = 1; } /* se l'anno contiene caratteri non numerici */ else if (anno_vino[j] < '0' || anno_vino[j] > '9' ) { printf("Gli anni dei vini possono contenere solo caratteri numerici!\n"); /* forza la chiusura del programma */ controllo_errori = 1; } } anno_vino[j] = '{parsed_message}'; carattere_acquisito = getc(input); /* spostati in avanti nel file in avanti fino ad arrivare all'inizio del luogo di produzione */ while (carattere_acquisito != ' ') carattere_acquisito = getc(input); /* acquisizione del luogo di produzione del vino */ for (j = 0, carattere_acquisito = '~'; ((j < (LUNGHEZZA_LUOGO_PRODUZIONE - 1)) && (carattere_acquisito != ' ') && (carattere_acquisito != '\n') && (controllo_errori == 0)); j++) { carattere_acquisito = getc(input); if ((carattere_acquisito != ' ') && (carattere_acquisito != '\n')) luogo_vino[j] = carattere_acquisito; else j--; } luogo_vino[j] = '{parsed_message}'; /* se il luogo di produzione del vino ha più caratteri del previsto */ if ((carattere_acquisito != '\n') && (controllo_errori == 0)) printf("I luoghi che superano i %d caratteri sono stati abbreviati!\n", (LUNGHEZZA_LUOGO_PRODUZIONE - 1)); /* inserimento del vino nell'albero ordinato secondo il codice */ esito = inserisci_in_albero_bin(&radice_p, codice_vino, nome_vino, anno_vino, luogo_vino); /* se l'inserimento non è andato a buon fine */ if (esito == 0) { printf("\nIl vino con codice \"%s\" non è stato inserito perchè già presente nella lista!\n", codice_vino); /* decrementa il numero dei vini del numero di inserimenti falliti */ *numero_vini = *numero_vini - 1; } } return (controllo_errori); } /* Algoritmo per l'inserimento di un vino nell'albero binario ordinato secondo il codice */ int inserisci_in_albero_bin(nodo_albero_bin_t ***radice_p, /* lavoro: puntatore al puntatore alla radice dell'albero */ char codice_vino[], /* input: codice del vino da inserire */ char nome_vino[], /* input: nome del vino da inserire */ char anno_vino[], /* input: anno di produzione del vino da inserire */ char luogo_vino[]) /* input: luogo di produzione del vino da inserire */ { int inserito, /* output: esito dell'inserimento */ i; /* lavoro: indice per i cicli for */ nodo_albero_bin_t *nodo_p, /* lavoro: puntatore ad un nodo */ *padre_p, /* lavoro: puntatore al padre del nodo_p */ *nuovo_p; /* lavoro: puntatore al nodo che conterrà il nuovo vino */ /* nodo_p e padre_p vengono inizializzati con l'indirizzo della radice e ad ogni */ /* iterazione padre_p prende l'indirizzo di nodo_p.nodo_p prende l'indirizzo del */ /* suo figlio sx o dx a seconda che il codice da inserire sia < o >= al codice */ /* puntato da nodo_p.Il ciclo termina quando nodo_p punta a NULL oppure ad un */ /* elemento che contiene un codice uguale a quello da inserire. */ for (nodo_p = padre_p = **radice_p; ((nodo_p != NULL) && (strcmp(nodo_p->codice_vino, codice_vino) != 0)); padre_p = nodo_p, nodo_p = (strcmp(codice_vino, nodo_p->codice_vino) < 0)? nodo_p->sx_p: nodo_p->dx_p); /* il vino non verrà inserito se era già presente, ovvero se nodo_p non punta a NULL */ if (nodo_p != NULL) inserito = 0; else { inserito = 1; /* viene allocata memoria per il nuovo nodo */ nuovo_p = (nodo_albero_bin_t *)malloc(sizeof(nodo_albero_bin_t)); /* inserimento del codice del vino */ for (i = 0; (i < LUNGHEZZA_CODICE); i++) nuovo_p->codice_vino[i] = codice_vino[i]; /* inserimento del nome del vino */ for (i = 0; (i < LUNGHEZZA_NOME); i++) nuovo_p->nome_vino[i] = nome_vino[i]; /* inserimento dell'anno di produzione del vino */ for (i = 0; (i < LUNGHEZZA_ANNO_PRODUZIONE); i++) nuovo_p->anno_vino[i] = anno_vino[i]; /* inserimento del luogo di produzione del vino */ for (i = 0; (i < LUNGHEZZA_LUOGO_PRODUZIONE); i++) nuovo_p->luogo_vino[i] = luogo_vino[i]; /* i puntatori vengono inizializzati a NULL */ nuovo_p->sx_p = nuovo_p->dx_p = NULL; /* se il nodo si trova in cima all'albero diventa la radice */ if (nodo_p == **radice_p) **radice_p = nuovo_p; /* se il codice inserito è inferiore a quello contenuto nel nodo padre */ else if (strcmp(codice_vino, padre_p->codice_vino) < 0) /* il nuovo nodo diventa figlio sinistro */ padre_p->sx_p = nuovo_p; else /* il nuovo nodo diventa figlio destro */ padre_p->dx_p = nuovo_p; } /* viene restituito il valore di esito dell'inserimento */ return(inserito); } /* Funzione per l'inserimento di un nuovo vino */ int inserisci_nuovo_vino(nodo_albero_bin_t **radice_p) /* lavoro: puntatore alla radice dell'albero */ { char nome_vino[LUNGHEZZA_NOME], /* input: nome del vino da inserire */ codice_vino[LUNGHEZZA_CODICE], /* input: codice del vino da inserire */ anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], /* input: anno di produzione del vino da inserire */ luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE], /* input: luogo di produzione del vino da inserire */ carattere_acquisito = '~'; /* lavoro: variabile usata per acquisizioni e controlli */ int inserito = 0, /* output: esito dell'inserimento */ controllo_errori, /* lavoro: variabile di controllo */ i; /* lavoro: indice per i cicli for */ /* acquisizione del codice del vino da inserire */ printf("\nScrivere il codice del vino da inserire: "); /* non esce dal ciclo se il codice inserito da tastiera è troppo corto */ do { controllo_errori = 0; carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_CODICE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ') && (controllo_errori == 0)); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) codice_vino[i] = carattere_acquisito; else { i--; printf("\nIl codice deve contenere %d caratteri alfanumerici!\n", (LUNGHEZZA_CODICE - 1)); printf("\nRiscrivere il codice del vino: "); } /* se il codice contiene caratteri non alfanumerici */ if (codice_vino[i] < '0' || (codice_vino[i] > '9' && codice_vino[i] < 'A') || (codice_vino[i] > 'Z' && codice_vino[i] < 'a') || codice_vino[i] > 'z') { controllo_errori = 1; printf("\nRiscrivere il codice del vino: "); } } codice_vino[i] = '{parsed_message}'; } while ((strlen(codice_vino) != (LUNGHEZZA_CODICE - 1)) || (controllo_errori == 1)); carattere_acquisito = getchar(); /* se l'utente ha inserito un codice troppo lungo */ if (carattere_acquisito != '\n') /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); /* acquisizione del nome del vino da inserire */ /* non esce dal ciclo se l'utente non inserisce nessun nome */ do { printf("Scrivere il nome del vino da inserire: "); carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_NOME - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ')); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) nome_vino[i] = carattere_acquisito; else i--; } nome_vino[i] = '{parsed_message}'; /* se l'utente ha inserito un nome troppo lungo */ if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) { printf("\nIl nome è stato abbreviato a %d caratteri!\n\n", (LUNGHEZZA_NOME - 1)); /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); } } while (strlen(nome_vino) == 0); /* acquisizione dell'anno di produzione del vino da inserire */ printf("Scrivere l'anno di produzione del vino da inserire: "); /* non esce dal ciclo se l'anno inserito da tastiera è troppo corto */ do { controllo_errori = 0; carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_ANNO_PRODUZIONE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ') && (controllo_errori == 0)); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) anno_vino[i] = carattere_acquisito; else { i--; printf("\nL'anno deve contenere %d caratteri numerici!\n", (LUNGHEZZA_ANNO_PRODUZIONE - 1)); printf("\nRiscrivere l'anno di produzione del vino: "); } /* se l'anno contiene caratteri non numerici */ if (anno_vino[i] < '0' || anno_vino[i] > '9') controllo_errori = 1; } anno_vino[i] = '{parsed_message}'; } while ((strlen(anno_vino) != (LUNGHEZZA_ANNO_PRODUZIONE - 1)) || (controllo_errori == 1)); carattere_acquisito = getchar(); /* se l'utente ha inserito un anno troppo lungo */ if (carattere_acquisito != '\n') /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); /* acquisizione del luogo di produzione del vino da inserire */ /* non esce dal ciclo se l'utente non inserisce nessun luogo */ do { printf("Scrivere il luogo di produzione del vino da inserire: "); carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_LUOGO_PRODUZIONE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ')); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) luogo_vino[i] = carattere_acquisito; else i--; } luogo_vino[i] = '{parsed_message}'; /* se l'utente ha inserito un luogo troppo lungo */ if (carattere_acquisito != '\n') { printf("\nIl luogo è stato abbreviato a %d caratteri!\n\n", (LUNGHEZZA_LUOGO_PRODUZIONE - 1)); /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); } } while (strlen(luogo_vino) == 0); /* inserimento del vino nell'albero */ inserito = inserisci_in_albero_bin(&radice_p, codice_vino, nome_vino, anno_vino, luogo_vino); /* se l'inserimento è andato a buon fine */ if (inserito != 1) printf("\nVino \"%s\" già presente!", codice_vino); else printf("\nIl vino è stato inserito."); /* viene restituito l'esito dell'inserimento */ return (inserito); } int rimuovi_vino(nodo_albero_bin_t **radice_p) /* lavoro: puntatore alla radice dell'albero */ { char codice_vino[LUNGHEZZA_CODICE], /* input: codice del vino da rimuovere */ carattere_acquisito = '~'; /* lavoro: variabile usata per acquisizioni e controlli */ int rimosso = 0, /* output: esito rimozione */ controllo_errori, /* lavoro: variabile di controllo */ i; /* lavoro: indice per i cicli */ /* acquisizione del codice del vino da rimuovere */ printf("\nScrivere il codice del vino da rimuovere: "); /* non esce dal ciclo se l'utente non inserisce un codice corretto */ do { controllo_errori = 0; carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_CODICE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ') && (controllo_errori == 0)); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) codice_vino[i] = carattere_acquisito; else { i--; printf("\nIl codice deve contenere %d caratteri alfanumerici!\n", (LUNGHEZZA_CODICE - 1)); printf("\nRiscrivere il codice del vino: "); } /* se il codice contiene caratteri non alfanumerici */ if (codice_vino[i] < '0' || (codice_vino[i] > '9' && codice_vino[i] < 'A') || (codice_vino[i] > 'Z' && codice_vino[i] < 'a') || codice_vino[i] > 'z') { controllo_errori = 1; printf("\nRiscrivere il codice del vino: "); } } codice_vino[i] = '{parsed_message}'; } while ((strlen(codice_vino) != (LUNGHEZZA_CODICE - 1)) || (controllo_errori == 1)); carattere_acquisito = getchar(); /* se l'utente ha inserito un codice troppo lungo */ if (carattere_acquisito != '\n') /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); /* rimozione del vino dall'albero */ rimosso = rimuovi_da_albero_bin(&radice_p, codice_vino); if (rimosso == 1) printf("\nIl vino è stato rimosso!"); else printf("\nIl vino non è presente nella lista!"); /* viene restituito l'esito della rimozione */ return (rimosso); } /* Algoritmo per la rimozione di un vino dall'albero binario */ int rimuovi_da_albero_bin(nodo_albero_bin_t ***radice_p, /* lavoro: puntatore al puntatore alla radice dell'albero */ char codice_vino[]) /* input: codice del vino da rimuovere */ { int rimosso, /* output: esito della rimozione */ i; /* lavoro: contatore per i cicli for */ nodo_albero_bin_t *nodo_p, /* lavoro: puntatore a un nodo */ *padre_p, /* lavoro: padre di nodo_p */ *sost_p; /* lavoro: sostituto di nodo_p */ /* nodo_p e padre_p vengono inizializzati con l'indirizzo della radice e ad ogni */ /* iterazione padre_p prende l'indirizzo di nodo_p.nodo_p prende l'indirizzo del */ /* suo figlio sx o dx a seconda che il codice da inserire sia < o >= al codice */ /* puntato da nodo_p.Il ciclo termina quando nodo_p punta a NULL oppure ad un */ /* elemento che contiene un codice uguale a quello da rimuovere. */ for (nodo_p = padre_p = **radice_p; ((nodo_p != NULL) && (strcmp(nodo_p->codice_vino,codice_vino) != 0)); padre_p = nodo_p, nodo_p = (strcmp(codice_vino,nodo_p->codice_vino) < 0)? nodo_p->sx_p: nodo_p->dx_p); /* il vino non verrà rimosso se non era presente, ovvero se nodo_p punta a NULL */ if (nodo_p == NULL) rimosso = 0; else { rimosso = 1; /* se nodo_p non ha figlio sx */ if (nodo_p->sx_p == NULL) { /* se nodo_p si trova in cima all'albero */ if (nodo_p == **radice_p) /* il figlio destro del nodo diventa la radice */ **radice_p = nodo_p->dx_p; /* altrimenti se il codice da rimuovere è minore di quello del padre */ else if (strcmp(codice_vino, padre_p->codice_vino) < 0) /* il figlio destro del nodo_p, diventa figlio sinistro del padre */ padre_p->sx_p = nodo_p->dx_p; else /* il figlio destro del nodo_p, diventa figlio destro del padre */ padre_p->dx_p = nodo_p->dx_p; } /* altrimenti, se nodo_p non ha figlio destro */ else if (nodo_p->dx_p == NULL) { /* se nodo_p si trova in cima all'albero */ if (nodo_p == **radice_p) /* il figlio sinistro del nodo diventa la radice */ **radice_p = nodo_p->sx_p; /* altrimenti, se il codice da rimuovere è minore di quello del padre */ else if (strcmp(codice_vino, padre_p->codice_vino) < 0) /* il figlio sinistro del nodo_p diventa figlio sinistro del padre */ padre_p->sx_p = nodo_p->sx_p; else /* il figlio sinistro del nodo_p diventa figlio destro del padre */ padre_p->dx_p = nodo_p->sx_p; } /* altrimenti, se il nodo_p ha entrambi i figli */ else { /* sost_p prende l'indirizzo contenuto in nodo_p */ sost_p = nodo_p; /* ad ogni iterazione del ciclo, padre_p prende l'indirizzo di nodo_p e nodo_p prende */ /* l'indirizzo del figlio destro; il ciclo termina quando nodo_p non ha figlio destro */ for (padre_p = sost_p, nodo_p = sost_p->sx_p; (nodo_p->dx_p != NULL); padre_p = nodo_p, nodo_p = nodo_p->dx_p); /* sostuzione del codice del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_CODICE); i++) sost_p->codice_vino[i] = nodo_p->codice_vino[i]; /* sostituzione del nome del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_NOME); i++) sost_p->nome_vino[i] = nodo_p->nome_vino[i]; /* sostuzione dell'anno del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_ANNO_PRODUZIONE); i++) sost_p->anno_vino[i] = nodo_p->anno_vino[i]; /* sostituzione del luogo del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_LUOGO_PRODUZIONE); i++) sost_p->anno_vino[i] = nodo_p->anno_vino[i]; /* se padre_p e sost_p puntano allo stesso nodo */ if (padre_p == sost_p) /* il figlio sinistro del nodo_p diventa figlio sinistro del padre_p */ padre_p->sx_p = nodo_p->sx_p; else /* il figlio sinistro del nodo_p diventa figlio destro del padre_p */ padre_p->dx_p = nodo_p->sx_p; } /* il nodo puntato da nodo_p viene rimosso dalla memoria */ free(nodo_p); } return(rimosso); } /* funzione per la stampa dei vini in base al codice */ void stampa_codice(nodo_albero_bin_t *nodo_p) { if (nodo_p != NULL) { stampa_codice(nodo_p->sx_p); printf("%s %s %s %s\n", nodo_p->nome_vino, nodo_p->codice_vino, nodo_p->anno_vino, nodo_p->luogo_vino); stampa_codice(nodo_p->dx_p); } } void stampa_vini(nodo_albero_bin_t *radice_p, int numero_vini, int scelta_ordinamento) { vino_t vini[numero_vini]; /* array per l'ordinamento */ /* trasferimento dei vini dall'albero in un array */ inserisci_vini_in_array(radice_p, vini, 0); switch(scelta_ordinamento) { case 1: /* ordina i vini in base al nome */ quicksort_nome(vini, 0, numero_vini - 1); break; case 3: /* ordina i vini in base all'anno */ quicksort_anno(vini, 0, numero_vini - 1); break; case 4: /* ordina i vini in base al luogo */ quicksort_luogo(vini, 0, numero_vini - 1); break; } stampa_array(numero_vini, vini); } /* funzione per il trasferimento dei vini dall'albero in un array */ void inserisci_vini_in_array(nodo_albero_bin_t *nodo_p, vino_t *vini, int i) { if (nodo_p->codice_vino != NULL) { inserisci_vini_in_array(nodo_p->sx_p, vini, i); strcpy(vini[i].nome_vino, nodo_p->nome_vino); strcpy(vini[i].codice_vino, nodo_p->codice_vino); strcpy(vini[i].anno_vino, nodo_p->anno_vino); strcpy(vini[i].luogo_vino, nodo_p->luogo_vino); i = i + 1; inserisci_vini_in_array(nodo_p->dx_p, vini, i); } } void quicksort_nome(vino_t a[], int sx, int dx) { int i, j; /* variabili di lavoro */ vino_t tmp, /* variabile usata per lo scambio */ pivot; /* puntatore all'elemento che fungera' da pivot */ /* si sceglie come pivot il valore centrale e si attua una tri-partizione */ /* scambiando gli elementi in modo che nella porzione a destra del pivot vi */ /* siano elementi maggiori del pivot e nella porzione sinistra quelli minori */ for (pivot = a[(sx + dx) / 2], i = sx, j = dx; (i <= j);) { while (strcmp(a[i].nome_vino, pivot.nome_vino) == -1) i++; while (strcmp(a[j].nome_vino, pivot.nome_vino) == 1) j--; if (i <= j) { if (i < j) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; } i++; j--; } } /* si invoca ricorsivamente la funzione sulle porzioni sinistra e destra */ if (sx < j) quicksort_nome(a, sx, j); if (i < dx) quicksort_nome(a, i, dx); } void quicksort_anno(vino_t a[], int sx, int dx) { int i, j; /* variabili di lavoro */ vino_t tmp, /* variabile usata per lo scambio */ pivot; /* puntatore all'elemento che fungera' da pivot */ /* si sceglie come pivot il valore centrale e si attua una tri-partizione */ /* scambiando gli elementi in modo che nella porzione a destra del pivot vi */ /* siano elementi maggiori del pivot e nella porzione sinistra quelli minori */ for (pivot = a[(sx + dx) / 2], i = sx, j = dx; (i <= j);) { while (strcmp(a[i].anno_vino, pivot.anno_vino) == -1) i++; while (strcmp(a[j].anno_vino, pivot.anno_vino) == 1) j--; if (i <= j) { if (i < j) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; } i++; j--; } } /* si invoca ricorsivamente la funzione sulle porzioni sinistra e destra */ if (sx < j) quicksort_anno(a, sx, j); if (i < dx) quicksort_anno(a, i, dx); } void quicksort_luogo(vino_t a[], int sx, int dx) { int i, j; /* variabili di lavoro */ vino_t tmp, /* variabile usata per lo scambio */ pivot; /* puntatore all'elemento che fungera' da pivot */ /* si sceglie come pivot il valore centrale e si attua una tri-partizione */ /* scambiando gli elementi in modo che nella porzione a destra del pivot vi */ /* siano elementi maggiori del pivot e nella porzione sinistra quelli minori */ for (pivot = a[(sx + dx) / 2], i = sx, j = dx; (i <= j);) { while (strcmp(a[i].luogo_vino, pivot.luogo_vino) == -1) i++; while (strcmp(a[j].luogo_vino, pivot.luogo_vino) == 1) j--; if (i <= j) { if (i < j) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; } i++; j--; } } /*Si invoca ricorsivamente la funzione sulle porzioni sinistra e destra*/ if (sx < j) quicksort_luogo(a, sx, j); if (i < dx) quicksort_luogo(a, i, dx); } void stampa_array(int numero_vini, vino_t *vini) { int i; /*Vengono stampati gli elementi ordinati*/ for(i = 0; i < numero_vini; i++) printf("\n%20s %4s %4s %s", vini[i].nome_vino, vini[i].codice_vino, vini[i].anno_vino, vini[i].luogo_vino); }'; carattere_acquisito = getc(input); /* spostati in avanti nel file fino ad arrivare all'inizio dell'anno di produzione */ while (carattere_acquisito != ' ') carattere_acquisito = getc(input); /* acquisizione dell'anno di produzione */ for (j = 0, carattere_acquisito = '~'; ((j < (LUNGHEZZA_ANNO_PRODUZIONE - 1)) && (controllo_errori == 0)); j++) { anno_vino[j] = getc(input); /* se l'anno del vino ha meno caratteri del previsto */ if (anno_vino[j] == ' ') { printf("L'anno di produzione dei vini devono contenere %d caratteri!\n", (LUNGHEZZA_ANNO_PRODUZIONE - 1)); controllo_errori = 1; } /* se l'anno contiene caratteri non numerici */ else if (anno_vino[j] < '0' || anno_vino[j] > '9' ) { printf("Gli anni dei vini possono contenere solo caratteri numerici!\n"); /* forza la chiusura del programma */ controllo_errori = 1; } } anno_vino[j] = 'Nel file allegato vi è il codice di un programma che gestisce un database di vini. Il mio problema è che ricevo un errore di segmentazione entrando nella funzione "inserisci_in_albero_bin". E' da un pò di giorni che stò cercando una soluzione ma non riesco a venirne a capo...qualcuno saprebbe aiutarmi??/******************************************************************/ /* Programma per manipolare un file contenente una lista di vini. */ /* Michele Petrocchi Matricola 256507 */ /******************************************************************/ /***********************/ /* inclusione librerie */ /***********************/ #include <stdio.h> #include <stdlib.h> #include <string.h> /*************************************/ /* Dichiarazione costanti simboliche */ /*************************************/ #define LUNGHEZZA_NOME 51 /* lunghezza della stringa del nome del vino */ #define LUNGHEZZA_CODICE 5 /* lunghezza della stringa del codice del vino */ #define LUNGHEZZA_ANNO_PRODUZIONE 5 /* lunghezza della stringa dell'anno di produzione del vino */ #define LUNGHEZZA_LUOGO_PRODUZIONE 51 /* lunghezza della stringa del luogo di produzione del vino */ #define PERCORSO_FILE "./file_vini" /* percorso del file di output */ /************************/ /* Defibizione dei tipi */ /************************/ typedef struct nodo_albero_bin { char nome_vino[LUNGHEZZA_NOME], /* nome del vino */ codice_vino[LUNGHEZZA_CODICE], /* codice del vino */ anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], /* anno di produzione del vino */ luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE]; /* luogo di produzione del vino */ struct nodo_albero_bin *sx_p, *dx_p; } nodo_albero_bin_t; typedef struct vino { char nome_vino[LUNGHEZZA_NOME], /* nome del vino */ codice_vino[LUNGHEZZA_CODICE], /* codice del vino */ anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], /* anno di produzione del vino */ luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE]; /* luogo di produzione del vino */ } vino_t; /********************************/ /* Dichiarazione delle funzioni */ /********************************/ int controllo_correttezza_file(nodo_albero_bin_t **, FILE *, int *); int inserisci_in_albero_bin(nodo_albero_bin_t ***, char[], char[], char[], char[]); int inserisci_nuovo_vino(nodo_albero_bin_t **); int rimuovi_vino(nodo_albero_bin_t **); int rimuovi_da_albero_bin(nodo_albero_bin_t ***, char[]); void stampa_codice(nodo_albero_bin_t *); void stampa_vini(nodo_albero_bin_t *, int, int); void inserisci_vini_in_array(nodo_albero_bin_t *, vino_t [], int); void quicksort_nome(vino_t [], int, int); void quicksort_anno(vino_t [], int, int); void quicksort_luogo(vino_t [], int, int); void stampa_array(int, vino_t *); /******************************/ /* Definizione delle funzioni */ /******************************/ int main (int argc, /* numero stringhe acquisite lancio comandi */ char *argv[]) /* stringhe acqusite dal lancio comandi */ { int esito = 0, esito_ordinamento = 0, esito_pulizia = 1, esito_pulizia_ordinamento = 1, scelta_utente = 0, scelta_ordinamento = 0, rimosso = 0, numero_vini = 0, controllo = 0; FILE *input; /* file da dove preleverò la lista dei vini */ nodo_albero_bin_t *radice_p = NULL; /* lavoro: puntatore alla radice dell'albero */ /* specifichiamo il file di input, quindi deve essere 1 il numero degli argomenti */ if(argc > 1) { /* apriamo il file specificato */ input = fopen(argv[1],"r"); /* se il file specificato esiste */ if (input != NULL) { /* acquisisci il numero di vini */ esito = fscanf(input, "%d", &numero_vini); /* se il numero di vini non è valido */ if (esito != 1 || numero_vini < 0) printf("Lettura del numero di vini non riuscita.\n\n"); else controllo = controllo_correttezza_file(&radice_p, input, &numero_vini); /* chiudere il file di input */ fclose(input); /* se non si sono verificati errori */ if (controllo != 1) { do { do { printf("\nL'utente digiti:"); printf("\n 1-Se si vuole procedere nell'inserimento di un nuovo vino"); printf("\n 2-Se si vuole procedere nella cancellazione di un altro"); printf("\n 3-Se si vuole visualizzare la lista con i vini inseriti"); printf("\n 4-Se si vuole uscire dal programma"); printf("\nPremere Invio per confermare.\n"); printf("\n"); /* pulizia del buffer della scanf */ esito_pulizia = scanf("\n"); esito = scanf("%d", &scelta_utente); while (getchar() != '\n'); } while ((scelta_utente < 1) || (scelta_utente > 4) || (esito != 1) || (esito_pulizia != 0)); switch (scelta_utente) { case 1: esito = inserisci_nuovo_vino(&radice_p); if (esito == 1) /* incrementa il numero di vini */ numero_vini++; printf(" (premere Invio per tornare al menù)\n"); while (getchar() != '\n'); break; case 2: rimosso = rimuovi_vino(&radice_p); /* se la rimozione è andata a buon fine */ if (rimosso == 1) /* decremento il numero di vini */ numero_vini--; printf(" (premere Invio per tornare al menù)\n"); while (getchar() != '\n'); break; case 3: do { printf("\nL'utente scelga l'ordine di visualizzaione dei vini:"); printf("\n 1-Nome"); printf("\n 2-Codice"); printf("\n 3-Luogo di produzione"); printf("\n 4-Anno di produzione"); printf("\nPremere Invio per confermare.\n"); printf("\n"); /* pulizia del buffer della scanf */ esito_pulizia_ordinamento = scanf("\n"); esito_ordinamento = scanf("%d", &scelta_ordinamento); while (getchar() != '\n'); } while ((scelta_utente < 1) || (scelta_utente > 4) || (esito_ordinamento != 1) || (esito_pulizia_ordinamento != 0)); /* visualizzare la lista dei vini inseriti */ printf("\n%d vini inseriti:\n", numero_vini); if (scelta_ordinamento == 2) /* stampa i vini in base al codice */ stampa_codice(radice_p); else stampa_vini(radice_p, numero_vini, scelta_ordinamento); printf("\n"); printf("(premere Invio per tornare al menù)\n"); while (getchar() != '\n'); break; case 4: /* se l'utente decide di uscire stampiamo un messaggio di saluto */ printf("\nGrazie per aver utilizzato questo programma!"); printf("\n\n"); break; } } while ((scelta_utente != 4)); } } else/* se il file specificato è uguale a NULL e quindi inesistente */ printf("\nIl file specificato non esiste!\n"); } else { /* se non è stato inserito il parametro di lancio del file */ printf("\nNon è stato immesso il nome del file da dove importare i dati riguardanti i vini!"); printf("\nrilanciare il programma con queste specifiche:"); printf("\n./<nome_eseguibile> <nome_file_input>\n"); printf("\nIl file può essere generato tramite il programma che viene lanciato con ./genera"); printf("\n(per la compilazione il comando è make genera_vini!)\n"); printf("\n(se il file è nella dir. di lavoro basta specificarne il nome!)\n\n"); } return(0); } int controllo_correttezza_file(nodo_albero_bin_t **radice_p, FILE * input, int *numero_vini) { int esito, controllo_errori = 0, i, j; char nome_vino[LUNGHEZZA_NOME], codice_vino[LUNGHEZZA_CODICE], anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE], carattere_acquisito = '~'; /* lavoro: variabile utilizzata */ /* per acquisizioni e controlli */ /* il ciclo acquisce i vini uno ad uno dal file e li inserisce nella struttura dati */ for (i = 0; ((i < *numero_vini) && (controllo_errori == 0)); i++) { /* scorro il file fino a trovare il carattere successivo */ while (carattere_acquisito != '\n') carattere_acquisito = getc(input); /* acquisizione del nome del vino */ for (j = 0, carattere_acquisito = '~'; ((j < (LUNGHEZZA_NOME - 1)) && (carattere_acquisito != ' ') && (carattere_acquisito != '\n') && (controllo_errori == 0)); j++) { carattere_acquisito = getc(input); if ((carattere_acquisito != ' ') && (carattere_acquisito != '\n')) nome_vino[j] = carattere_acquisito; else j--; } nome_vino[j] = '{parsed_message}'; /* se il nome del vino ha più caratteri del previsto */ if (carattere_acquisito != ' ') printf("I nomi che superano i %d caratteri sono stati abbreviati!\n", (LUNGHEZZA_NOME - 1)); /* spostati in avanti nel file in avanti fino ad arrivare all'inizio del codice */ while (carattere_acquisito != ' ') carattere_acquisito = getc(input); /* acquisizione del codice del vino */ for (j = 0; ((j < (LUNGHEZZA_CODICE - 1)) && (controllo_errori == 0)); j++) { codice_vino[j] = getc(input); /* se il codice vino ha meno caratteri del previsto */ if (codice_vino[j] == ' ') { printf("I codici dei vini devono contenere %d caratteri!\n", (LUNGHEZZA_CODICE - 1)); controllo_errori = 1; } /* se il codice contiene caratteri non alfanumerici */ else if (codice_vino[j] < '0' || (codice_vino[j] > '9' && codice_vino[j] < 'A') || (codice_vino[j] > 'Z' && codice_vino[j] < 'a') || codice_vino[j] > 'z') { printf("I codici dei vini possono contenere solo caratteri alfanumerici!\n"); /* forza la chiusura del programma */ controllo_errori = 1; } } codice_vino[j] = '{parsed_message}'; carattere_acquisito = getc(input); /* spostati in avanti nel file fino ad arrivare all'inizio dell'anno di produzione */ while (carattere_acquisito != ' ') carattere_acquisito = getc(input); /* acquisizione dell'anno di produzione */ for (j = 0, carattere_acquisito = '~'; ((j < (LUNGHEZZA_ANNO_PRODUZIONE - 1)) && (controllo_errori == 0)); j++) { anno_vino[j] = getc(input); /* se l'anno del vino ha meno caratteri del previsto */ if (anno_vino[j] == ' ') { printf("L'anno di produzione dei vini devono contenere %d caratteri!\n", (LUNGHEZZA_ANNO_PRODUZIONE - 1)); controllo_errori = 1; } /* se l'anno contiene caratteri non numerici */ else if (anno_vino[j] < '0' || anno_vino[j] > '9' ) { printf("Gli anni dei vini possono contenere solo caratteri numerici!\n"); /* forza la chiusura del programma */ controllo_errori = 1; } } anno_vino[j] = '{parsed_message}'; carattere_acquisito = getc(input); /* spostati in avanti nel file in avanti fino ad arrivare all'inizio del luogo di produzione */ while (carattere_acquisito != ' ') carattere_acquisito = getc(input); /* acquisizione del luogo di produzione del vino */ for (j = 0, carattere_acquisito = '~'; ((j < (LUNGHEZZA_LUOGO_PRODUZIONE - 1)) && (carattere_acquisito != ' ') && (carattere_acquisito != '\n') && (controllo_errori == 0)); j++) { carattere_acquisito = getc(input); if ((carattere_acquisito != ' ') && (carattere_acquisito != '\n')) luogo_vino[j] = carattere_acquisito; else j--; } luogo_vino[j] = '{parsed_message}'; /* se il luogo di produzione del vino ha più caratteri del previsto */ if ((carattere_acquisito != '\n') && (controllo_errori == 0)) printf("I luoghi che superano i %d caratteri sono stati abbreviati!\n", (LUNGHEZZA_LUOGO_PRODUZIONE - 1)); /* inserimento del vino nell'albero ordinato secondo il codice */ esito = inserisci_in_albero_bin(&radice_p, codice_vino, nome_vino, anno_vino, luogo_vino); /* se l'inserimento non è andato a buon fine */ if (esito == 0) { printf("\nIl vino con codice \"%s\" non è stato inserito perchè già presente nella lista!\n", codice_vino); /* decrementa il numero dei vini del numero di inserimenti falliti */ *numero_vini = *numero_vini - 1; } } return (controllo_errori); } /* Algoritmo per l'inserimento di un vino nell'albero binario ordinato secondo il codice */ int inserisci_in_albero_bin(nodo_albero_bin_t ***radice_p, /* lavoro: puntatore al puntatore alla radice dell'albero */ char codice_vino[], /* input: codice del vino da inserire */ char nome_vino[], /* input: nome del vino da inserire */ char anno_vino[], /* input: anno di produzione del vino da inserire */ char luogo_vino[]) /* input: luogo di produzione del vino da inserire */ { int inserito, /* output: esito dell'inserimento */ i; /* lavoro: indice per i cicli for */ nodo_albero_bin_t *nodo_p, /* lavoro: puntatore ad un nodo */ *padre_p, /* lavoro: puntatore al padre del nodo_p */ *nuovo_p; /* lavoro: puntatore al nodo che conterrà il nuovo vino */ /* nodo_p e padre_p vengono inizializzati con l'indirizzo della radice e ad ogni */ /* iterazione padre_p prende l'indirizzo di nodo_p.nodo_p prende l'indirizzo del */ /* suo figlio sx o dx a seconda che il codice da inserire sia < o >= al codice */ /* puntato da nodo_p.Il ciclo termina quando nodo_p punta a NULL oppure ad un */ /* elemento che contiene un codice uguale a quello da inserire. */ for (nodo_p = padre_p = **radice_p; ((nodo_p != NULL) && (strcmp(nodo_p->codice_vino, codice_vino) != 0)); padre_p = nodo_p, nodo_p = (strcmp(codice_vino, nodo_p->codice_vino) < 0)? nodo_p->sx_p: nodo_p->dx_p); /* il vino non verrà inserito se era già presente, ovvero se nodo_p non punta a NULL */ if (nodo_p != NULL) inserito = 0; else { inserito = 1; /* viene allocata memoria per il nuovo nodo */ nuovo_p = (nodo_albero_bin_t *)malloc(sizeof(nodo_albero_bin_t)); /* inserimento del codice del vino */ for (i = 0; (i < LUNGHEZZA_CODICE); i++) nuovo_p->codice_vino[i] = codice_vino[i]; /* inserimento del nome del vino */ for (i = 0; (i < LUNGHEZZA_NOME); i++) nuovo_p->nome_vino[i] = nome_vino[i]; /* inserimento dell'anno di produzione del vino */ for (i = 0; (i < LUNGHEZZA_ANNO_PRODUZIONE); i++) nuovo_p->anno_vino[i] = anno_vino[i]; /* inserimento del luogo di produzione del vino */ for (i = 0; (i < LUNGHEZZA_LUOGO_PRODUZIONE); i++) nuovo_p->luogo_vino[i] = luogo_vino[i]; /* i puntatori vengono inizializzati a NULL */ nuovo_p->sx_p = nuovo_p->dx_p = NULL; /* se il nodo si trova in cima all'albero diventa la radice */ if (nodo_p == **radice_p) **radice_p = nuovo_p; /* se il codice inserito è inferiore a quello contenuto nel nodo padre */ else if (strcmp(codice_vino, padre_p->codice_vino) < 0) /* il nuovo nodo diventa figlio sinistro */ padre_p->sx_p = nuovo_p; else /* il nuovo nodo diventa figlio destro */ padre_p->dx_p = nuovo_p; } /* viene restituito il valore di esito dell'inserimento */ return(inserito); } /* Funzione per l'inserimento di un nuovo vino */ int inserisci_nuovo_vino(nodo_albero_bin_t **radice_p) /* lavoro: puntatore alla radice dell'albero */ { char nome_vino[LUNGHEZZA_NOME], /* input: nome del vino da inserire */ codice_vino[LUNGHEZZA_CODICE], /* input: codice del vino da inserire */ anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], /* input: anno di produzione del vino da inserire */ luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE], /* input: luogo di produzione del vino da inserire */ carattere_acquisito = '~'; /* lavoro: variabile usata per acquisizioni e controlli */ int inserito = 0, /* output: esito dell'inserimento */ controllo_errori, /* lavoro: variabile di controllo */ i; /* lavoro: indice per i cicli for */ /* acquisizione del codice del vino da inserire */ printf("\nScrivere il codice del vino da inserire: "); /* non esce dal ciclo se il codice inserito da tastiera è troppo corto */ do { controllo_errori = 0; carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_CODICE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ') && (controllo_errori == 0)); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) codice_vino[i] = carattere_acquisito; else { i--; printf("\nIl codice deve contenere %d caratteri alfanumerici!\n", (LUNGHEZZA_CODICE - 1)); printf("\nRiscrivere il codice del vino: "); } /* se il codice contiene caratteri non alfanumerici */ if (codice_vino[i] < '0' || (codice_vino[i] > '9' && codice_vino[i] < 'A') || (codice_vino[i] > 'Z' && codice_vino[i] < 'a') || codice_vino[i] > 'z') { controllo_errori = 1; printf("\nRiscrivere il codice del vino: "); } } codice_vino[i] = '{parsed_message}'; } while ((strlen(codice_vino) != (LUNGHEZZA_CODICE - 1)) || (controllo_errori == 1)); carattere_acquisito = getchar(); /* se l'utente ha inserito un codice troppo lungo */ if (carattere_acquisito != '\n') /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); /* acquisizione del nome del vino da inserire */ /* non esce dal ciclo se l'utente non inserisce nessun nome */ do { printf("Scrivere il nome del vino da inserire: "); carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_NOME - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ')); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) nome_vino[i] = carattere_acquisito; else i--; } nome_vino[i] = '{parsed_message}'; /* se l'utente ha inserito un nome troppo lungo */ if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) { printf("\nIl nome è stato abbreviato a %d caratteri!\n\n", (LUNGHEZZA_NOME - 1)); /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); } } while (strlen(nome_vino) == 0); /* acquisizione dell'anno di produzione del vino da inserire */ printf("Scrivere l'anno di produzione del vino da inserire: "); /* non esce dal ciclo se l'anno inserito da tastiera è troppo corto */ do { controllo_errori = 0; carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_ANNO_PRODUZIONE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ') && (controllo_errori == 0)); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) anno_vino[i] = carattere_acquisito; else { i--; printf("\nL'anno deve contenere %d caratteri numerici!\n", (LUNGHEZZA_ANNO_PRODUZIONE - 1)); printf("\nRiscrivere l'anno di produzione del vino: "); } /* se l'anno contiene caratteri non numerici */ if (anno_vino[i] < '0' || anno_vino[i] > '9') controllo_errori = 1; } anno_vino[i] = '{parsed_message}'; } while ((strlen(anno_vino) != (LUNGHEZZA_ANNO_PRODUZIONE - 1)) || (controllo_errori == 1)); carattere_acquisito = getchar(); /* se l'utente ha inserito un anno troppo lungo */ if (carattere_acquisito != '\n') /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); /* acquisizione del luogo di produzione del vino da inserire */ /* non esce dal ciclo se l'utente non inserisce nessun luogo */ do { printf("Scrivere il luogo di produzione del vino da inserire: "); carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_LUOGO_PRODUZIONE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ')); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) luogo_vino[i] = carattere_acquisito; else i--; } luogo_vino[i] = '{parsed_message}'; /* se l'utente ha inserito un luogo troppo lungo */ if (carattere_acquisito != '\n') { printf("\nIl luogo è stato abbreviato a %d caratteri!\n\n", (LUNGHEZZA_LUOGO_PRODUZIONE - 1)); /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); } } while (strlen(luogo_vino) == 0); /* inserimento del vino nell'albero */ inserito = inserisci_in_albero_bin(&radice_p, codice_vino, nome_vino, anno_vino, luogo_vino); /* se l'inserimento è andato a buon fine */ if (inserito != 1) printf("\nVino \"%s\" già presente!", codice_vino); else printf("\nIl vino è stato inserito."); /* viene restituito l'esito dell'inserimento */ return (inserito); } int rimuovi_vino(nodo_albero_bin_t **radice_p) /* lavoro: puntatore alla radice dell'albero */ { char codice_vino[LUNGHEZZA_CODICE], /* input: codice del vino da rimuovere */ carattere_acquisito = '~'; /* lavoro: variabile usata per acquisizioni e controlli */ int rimosso = 0, /* output: esito rimozione */ controllo_errori, /* lavoro: variabile di controllo */ i; /* lavoro: indice per i cicli */ /* acquisizione del codice del vino da rimuovere */ printf("\nScrivere il codice del vino da rimuovere: "); /* non esce dal ciclo se l'utente non inserisce un codice corretto */ do { controllo_errori = 0; carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_CODICE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ') && (controllo_errori == 0)); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) codice_vino[i] = carattere_acquisito; else { i--; printf("\nIl codice deve contenere %d caratteri alfanumerici!\n", (LUNGHEZZA_CODICE - 1)); printf("\nRiscrivere il codice del vino: "); } /* se il codice contiene caratteri non alfanumerici */ if (codice_vino[i] < '0' || (codice_vino[i] > '9' && codice_vino[i] < 'A') || (codice_vino[i] > 'Z' && codice_vino[i] < 'a') || codice_vino[i] > 'z') { controllo_errori = 1; printf("\nRiscrivere il codice del vino: "); } } codice_vino[i] = '{parsed_message}'; } while ((strlen(codice_vino) != (LUNGHEZZA_CODICE - 1)) || (controllo_errori == 1)); carattere_acquisito = getchar(); /* se l'utente ha inserito un codice troppo lungo */ if (carattere_acquisito != '\n') /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); /* rimozione del vino dall'albero */ rimosso = rimuovi_da_albero_bin(&radice_p, codice_vino); if (rimosso == 1) printf("\nIl vino è stato rimosso!"); else printf("\nIl vino non è presente nella lista!"); /* viene restituito l'esito della rimozione */ return (rimosso); } /* Algoritmo per la rimozione di un vino dall'albero binario */ int rimuovi_da_albero_bin(nodo_albero_bin_t ***radice_p, /* lavoro: puntatore al puntatore alla radice dell'albero */ char codice_vino[]) /* input: codice del vino da rimuovere */ { int rimosso, /* output: esito della rimozione */ i; /* lavoro: contatore per i cicli for */ nodo_albero_bin_t *nodo_p, /* lavoro: puntatore a un nodo */ *padre_p, /* lavoro: padre di nodo_p */ *sost_p; /* lavoro: sostituto di nodo_p */ /* nodo_p e padre_p vengono inizializzati con l'indirizzo della radice e ad ogni */ /* iterazione padre_p prende l'indirizzo di nodo_p.nodo_p prende l'indirizzo del */ /* suo figlio sx o dx a seconda che il codice da inserire sia < o >= al codice */ /* puntato da nodo_p.Il ciclo termina quando nodo_p punta a NULL oppure ad un */ /* elemento che contiene un codice uguale a quello da rimuovere. */ for (nodo_p = padre_p = **radice_p; ((nodo_p != NULL) && (strcmp(nodo_p->codice_vino,codice_vino) != 0)); padre_p = nodo_p, nodo_p = (strcmp(codice_vino,nodo_p->codice_vino) < 0)? nodo_p->sx_p: nodo_p->dx_p); /* il vino non verrà rimosso se non era presente, ovvero se nodo_p punta a NULL */ if (nodo_p == NULL) rimosso = 0; else { rimosso = 1; /* se nodo_p non ha figlio sx */ if (nodo_p->sx_p == NULL) { /* se nodo_p si trova in cima all'albero */ if (nodo_p == **radice_p) /* il figlio destro del nodo diventa la radice */ **radice_p = nodo_p->dx_p; /* altrimenti se il codice da rimuovere è minore di quello del padre */ else if (strcmp(codice_vino, padre_p->codice_vino) < 0) /* il figlio destro del nodo_p, diventa figlio sinistro del padre */ padre_p->sx_p = nodo_p->dx_p; else /* il figlio destro del nodo_p, diventa figlio destro del padre */ padre_p->dx_p = nodo_p->dx_p; } /* altrimenti, se nodo_p non ha figlio destro */ else if (nodo_p->dx_p == NULL) { /* se nodo_p si trova in cima all'albero */ if (nodo_p == **radice_p) /* il figlio sinistro del nodo diventa la radice */ **radice_p = nodo_p->sx_p; /* altrimenti, se il codice da rimuovere è minore di quello del padre */ else if (strcmp(codice_vino, padre_p->codice_vino) < 0) /* il figlio sinistro del nodo_p diventa figlio sinistro del padre */ padre_p->sx_p = nodo_p->sx_p; else /* il figlio sinistro del nodo_p diventa figlio destro del padre */ padre_p->dx_p = nodo_p->sx_p; } /* altrimenti, se il nodo_p ha entrambi i figli */ else { /* sost_p prende l'indirizzo contenuto in nodo_p */ sost_p = nodo_p; /* ad ogni iterazione del ciclo, padre_p prende l'indirizzo di nodo_p e nodo_p prende */ /* l'indirizzo del figlio destro; il ciclo termina quando nodo_p non ha figlio destro */ for (padre_p = sost_p, nodo_p = sost_p->sx_p; (nodo_p->dx_p != NULL); padre_p = nodo_p, nodo_p = nodo_p->dx_p); /* sostuzione del codice del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_CODICE); i++) sost_p->codice_vino[i] = nodo_p->codice_vino[i]; /* sostituzione del nome del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_NOME); i++) sost_p->nome_vino[i] = nodo_p->nome_vino[i]; /* sostuzione dell'anno del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_ANNO_PRODUZIONE); i++) sost_p->anno_vino[i] = nodo_p->anno_vino[i]; /* sostituzione del luogo del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_LUOGO_PRODUZIONE); i++) sost_p->anno_vino[i] = nodo_p->anno_vino[i]; /* se padre_p e sost_p puntano allo stesso nodo */ if (padre_p == sost_p) /* il figlio sinistro del nodo_p diventa figlio sinistro del padre_p */ padre_p->sx_p = nodo_p->sx_p; else /* il figlio sinistro del nodo_p diventa figlio destro del padre_p */ padre_p->dx_p = nodo_p->sx_p; } /* il nodo puntato da nodo_p viene rimosso dalla memoria */ free(nodo_p); } return(rimosso); } /* funzione per la stampa dei vini in base al codice */ void stampa_codice(nodo_albero_bin_t *nodo_p) { if (nodo_p != NULL) { stampa_codice(nodo_p->sx_p); printf("%s %s %s %s\n", nodo_p->nome_vino, nodo_p->codice_vino, nodo_p->anno_vino, nodo_p->luogo_vino); stampa_codice(nodo_p->dx_p); } } void stampa_vini(nodo_albero_bin_t *radice_p, int numero_vini, int scelta_ordinamento) { vino_t vini[numero_vini]; /* array per l'ordinamento */ /* trasferimento dei vini dall'albero in un array */ inserisci_vini_in_array(radice_p, vini, 0); switch(scelta_ordinamento) { case 1: /* ordina i vini in base al nome */ quicksort_nome(vini, 0, numero_vini - 1); break; case 3: /* ordina i vini in base all'anno */ quicksort_anno(vini, 0, numero_vini - 1); break; case 4: /* ordina i vini in base al luogo */ quicksort_luogo(vini, 0, numero_vini - 1); break; } stampa_array(numero_vini, vini); } /* funzione per il trasferimento dei vini dall'albero in un array */ void inserisci_vini_in_array(nodo_albero_bin_t *nodo_p, vino_t *vini, int i) { if (nodo_p->codice_vino != NULL) { inserisci_vini_in_array(nodo_p->sx_p, vini, i); strcpy(vini[i].nome_vino, nodo_p->nome_vino); strcpy(vini[i].codice_vino, nodo_p->codice_vino); strcpy(vini[i].anno_vino, nodo_p->anno_vino); strcpy(vini[i].luogo_vino, nodo_p->luogo_vino); i = i + 1; inserisci_vini_in_array(nodo_p->dx_p, vini, i); } } void quicksort_nome(vino_t a[], int sx, int dx) { int i, j; /* variabili di lavoro */ vino_t tmp, /* variabile usata per lo scambio */ pivot; /* puntatore all'elemento che fungera' da pivot */ /* si sceglie come pivot il valore centrale e si attua una tri-partizione */ /* scambiando gli elementi in modo che nella porzione a destra del pivot vi */ /* siano elementi maggiori del pivot e nella porzione sinistra quelli minori */ for (pivot = a[(sx + dx) / 2], i = sx, j = dx; (i <= j);) { while (strcmp(a[i].nome_vino, pivot.nome_vino) == -1) i++; while (strcmp(a[j].nome_vino, pivot.nome_vino) == 1) j--; if (i <= j) { if (i < j) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; } i++; j--; } } /* si invoca ricorsivamente la funzione sulle porzioni sinistra e destra */ if (sx < j) quicksort_nome(a, sx, j); if (i < dx) quicksort_nome(a, i, dx); } void quicksort_anno(vino_t a[], int sx, int dx) { int i, j; /* variabili di lavoro */ vino_t tmp, /* variabile usata per lo scambio */ pivot; /* puntatore all'elemento che fungera' da pivot */ /* si sceglie come pivot il valore centrale e si attua una tri-partizione */ /* scambiando gli elementi in modo che nella porzione a destra del pivot vi */ /* siano elementi maggiori del pivot e nella porzione sinistra quelli minori */ for (pivot = a[(sx + dx) / 2], i = sx, j = dx; (i <= j);) { while (strcmp(a[i].anno_vino, pivot.anno_vino) == -1) i++; while (strcmp(a[j].anno_vino, pivot.anno_vino) == 1) j--; if (i <= j) { if (i < j) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; } i++; j--; } } /* si invoca ricorsivamente la funzione sulle porzioni sinistra e destra */ if (sx < j) quicksort_anno(a, sx, j); if (i < dx) quicksort_anno(a, i, dx); } void quicksort_luogo(vino_t a[], int sx, int dx) { int i, j; /* variabili di lavoro */ vino_t tmp, /* variabile usata per lo scambio */ pivot; /* puntatore all'elemento che fungera' da pivot */ /* si sceglie come pivot il valore centrale e si attua una tri-partizione */ /* scambiando gli elementi in modo che nella porzione a destra del pivot vi */ /* siano elementi maggiori del pivot e nella porzione sinistra quelli minori */ for (pivot = a[(sx + dx) / 2], i = sx, j = dx; (i <= j);) { while (strcmp(a[i].luogo_vino, pivot.luogo_vino) == -1) i++; while (strcmp(a[j].luogo_vino, pivot.luogo_vino) == 1) j--; if (i <= j) { if (i < j) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; } i++; j--; } } /*Si invoca ricorsivamente la funzione sulle porzioni sinistra e destra*/ if (sx < j) quicksort_luogo(a, sx, j); if (i < dx) quicksort_luogo(a, i, dx); } void stampa_array(int numero_vini, vino_t *vini) { int i; /*Vengono stampati gli elementi ordinati*/ for(i = 0; i < numero_vini; i++) printf("\n%20s %4s %4s %s", vini[i].nome_vino, vini[i].codice_vino, vini[i].anno_vino, vini[i].luogo_vino); }'; carattere_acquisito = getc(input); /* spostati in avanti nel file in avanti fino ad arrivare all'inizio del luogo di produzione */ while (carattere_acquisito != ' ') carattere_acquisito = getc(input); /* acquisizione del luogo di produzione del vino */ for (j = 0, carattere_acquisito = '~'; ((j < (LUNGHEZZA_LUOGO_PRODUZIONE - 1)) && (carattere_acquisito != ' ') && (carattere_acquisito != '\n') && (controllo_errori == 0)); j++) { carattere_acquisito = getc(input); if ((carattere_acquisito != ' ') && (carattere_acquisito != '\n')) luogo_vino[j] = carattere_acquisito; else j--; } luogo_vino[j] = 'Nel file allegato vi è il codice di un programma che gestisce un database di vini. Il mio problema è che ricevo un errore di segmentazione entrando nella funzione "inserisci_in_albero_bin". E' da un pò di giorni che stò cercando una soluzione ma non riesco a venirne a capo...qualcuno saprebbe aiutarmi??/******************************************************************/ /* Programma per manipolare un file contenente una lista di vini. */ /* Michele Petrocchi Matricola 256507 */ /******************************************************************/ /***********************/ /* inclusione librerie */ /***********************/ #include <stdio.h> #include <stdlib.h> #include <string.h> /*************************************/ /* Dichiarazione costanti simboliche */ /*************************************/ #define LUNGHEZZA_NOME 51 /* lunghezza della stringa del nome del vino */ #define LUNGHEZZA_CODICE 5 /* lunghezza della stringa del codice del vino */ #define LUNGHEZZA_ANNO_PRODUZIONE 5 /* lunghezza della stringa dell'anno di produzione del vino */ #define LUNGHEZZA_LUOGO_PRODUZIONE 51 /* lunghezza della stringa del luogo di produzione del vino */ #define PERCORSO_FILE "./file_vini" /* percorso del file di output */ /************************/ /* Defibizione dei tipi */ /************************/ typedef struct nodo_albero_bin { char nome_vino[LUNGHEZZA_NOME], /* nome del vino */ codice_vino[LUNGHEZZA_CODICE], /* codice del vino */ anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], /* anno di produzione del vino */ luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE]; /* luogo di produzione del vino */ struct nodo_albero_bin *sx_p, *dx_p; } nodo_albero_bin_t; typedef struct vino { char nome_vino[LUNGHEZZA_NOME], /* nome del vino */ codice_vino[LUNGHEZZA_CODICE], /* codice del vino */ anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], /* anno di produzione del vino */ luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE]; /* luogo di produzione del vino */ } vino_t; /********************************/ /* Dichiarazione delle funzioni */ /********************************/ int controllo_correttezza_file(nodo_albero_bin_t **, FILE *, int *); int inserisci_in_albero_bin(nodo_albero_bin_t ***, char[], char[], char[], char[]); int inserisci_nuovo_vino(nodo_albero_bin_t **); int rimuovi_vino(nodo_albero_bin_t **); int rimuovi_da_albero_bin(nodo_albero_bin_t ***, char[]); void stampa_codice(nodo_albero_bin_t *); void stampa_vini(nodo_albero_bin_t *, int, int); void inserisci_vini_in_array(nodo_albero_bin_t *, vino_t [], int); void quicksort_nome(vino_t [], int, int); void quicksort_anno(vino_t [], int, int); void quicksort_luogo(vino_t [], int, int); void stampa_array(int, vino_t *); /******************************/ /* Definizione delle funzioni */ /******************************/ int main (int argc, /* numero stringhe acquisite lancio comandi */ char *argv[]) /* stringhe acqusite dal lancio comandi */ { int esito = 0, esito_ordinamento = 0, esito_pulizia = 1, esito_pulizia_ordinamento = 1, scelta_utente = 0, scelta_ordinamento = 0, rimosso = 0, numero_vini = 0, controllo = 0; FILE *input; /* file da dove preleverò la lista dei vini */ nodo_albero_bin_t *radice_p = NULL; /* lavoro: puntatore alla radice dell'albero */ /* specifichiamo il file di input, quindi deve essere 1 il numero degli argomenti */ if(argc > 1) { /* apriamo il file specificato */ input = fopen(argv[1],"r"); /* se il file specificato esiste */ if (input != NULL) { /* acquisisci il numero di vini */ esito = fscanf(input, "%d", &numero_vini); /* se il numero di vini non è valido */ if (esito != 1 || numero_vini < 0) printf("Lettura del numero di vini non riuscita.\n\n"); else controllo = controllo_correttezza_file(&radice_p, input, &numero_vini); /* chiudere il file di input */ fclose(input); /* se non si sono verificati errori */ if (controllo != 1) { do { do { printf("\nL'utente digiti:"); printf("\n 1-Se si vuole procedere nell'inserimento di un nuovo vino"); printf("\n 2-Se si vuole procedere nella cancellazione di un altro"); printf("\n 3-Se si vuole visualizzare la lista con i vini inseriti"); printf("\n 4-Se si vuole uscire dal programma"); printf("\nPremere Invio per confermare.\n"); printf("\n"); /* pulizia del buffer della scanf */ esito_pulizia = scanf("\n"); esito = scanf("%d", &scelta_utente); while (getchar() != '\n'); } while ((scelta_utente < 1) || (scelta_utente > 4) || (esito != 1) || (esito_pulizia != 0)); switch (scelta_utente) { case 1: esito = inserisci_nuovo_vino(&radice_p); if (esito == 1) /* incrementa il numero di vini */ numero_vini++; printf(" (premere Invio per tornare al menù)\n"); while (getchar() != '\n'); break; case 2: rimosso = rimuovi_vino(&radice_p); /* se la rimozione è andata a buon fine */ if (rimosso == 1) /* decremento il numero di vini */ numero_vini--; printf(" (premere Invio per tornare al menù)\n"); while (getchar() != '\n'); break; case 3: do { printf("\nL'utente scelga l'ordine di visualizzaione dei vini:"); printf("\n 1-Nome"); printf("\n 2-Codice"); printf("\n 3-Luogo di produzione"); printf("\n 4-Anno di produzione"); printf("\nPremere Invio per confermare.\n"); printf("\n"); /* pulizia del buffer della scanf */ esito_pulizia_ordinamento = scanf("\n"); esito_ordinamento = scanf("%d", &scelta_ordinamento); while (getchar() != '\n'); } while ((scelta_utente < 1) || (scelta_utente > 4) || (esito_ordinamento != 1) || (esito_pulizia_ordinamento != 0)); /* visualizzare la lista dei vini inseriti */ printf("\n%d vini inseriti:\n", numero_vini); if (scelta_ordinamento == 2) /* stampa i vini in base al codice */ stampa_codice(radice_p); else stampa_vini(radice_p, numero_vini, scelta_ordinamento); printf("\n"); printf("(premere Invio per tornare al menù)\n"); while (getchar() != '\n'); break; case 4: /* se l'utente decide di uscire stampiamo un messaggio di saluto */ printf("\nGrazie per aver utilizzato questo programma!"); printf("\n\n"); break; } } while ((scelta_utente != 4)); } } else/* se il file specificato è uguale a NULL e quindi inesistente */ printf("\nIl file specificato non esiste!\n"); } else { /* se non è stato inserito il parametro di lancio del file */ printf("\nNon è stato immesso il nome del file da dove importare i dati riguardanti i vini!"); printf("\nrilanciare il programma con queste specifiche:"); printf("\n./<nome_eseguibile> <nome_file_input>\n"); printf("\nIl file può essere generato tramite il programma che viene lanciato con ./genera"); printf("\n(per la compilazione il comando è make genera_vini!)\n"); printf("\n(se il file è nella dir. di lavoro basta specificarne il nome!)\n\n"); } return(0); } int controllo_correttezza_file(nodo_albero_bin_t **radice_p, FILE * input, int *numero_vini) { int esito, controllo_errori = 0, i, j; char nome_vino[LUNGHEZZA_NOME], codice_vino[LUNGHEZZA_CODICE], anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE], carattere_acquisito = '~'; /* lavoro: variabile utilizzata */ /* per acquisizioni e controlli */ /* il ciclo acquisce i vini uno ad uno dal file e li inserisce nella struttura dati */ for (i = 0; ((i < *numero_vini) && (controllo_errori == 0)); i++) { /* scorro il file fino a trovare il carattere successivo */ while (carattere_acquisito != '\n') carattere_acquisito = getc(input); /* acquisizione del nome del vino */ for (j = 0, carattere_acquisito = '~'; ((j < (LUNGHEZZA_NOME - 1)) && (carattere_acquisito != ' ') && (carattere_acquisito != '\n') && (controllo_errori == 0)); j++) { carattere_acquisito = getc(input); if ((carattere_acquisito != ' ') && (carattere_acquisito != '\n')) nome_vino[j] = carattere_acquisito; else j--; } nome_vino[j] = '{parsed_message}'; /* se il nome del vino ha più caratteri del previsto */ if (carattere_acquisito != ' ') printf("I nomi che superano i %d caratteri sono stati abbreviati!\n", (LUNGHEZZA_NOME - 1)); /* spostati in avanti nel file in avanti fino ad arrivare all'inizio del codice */ while (carattere_acquisito != ' ') carattere_acquisito = getc(input); /* acquisizione del codice del vino */ for (j = 0; ((j < (LUNGHEZZA_CODICE - 1)) && (controllo_errori == 0)); j++) { codice_vino[j] = getc(input); /* se il codice vino ha meno caratteri del previsto */ if (codice_vino[j] == ' ') { printf("I codici dei vini devono contenere %d caratteri!\n", (LUNGHEZZA_CODICE - 1)); controllo_errori = 1; } /* se il codice contiene caratteri non alfanumerici */ else if (codice_vino[j] < '0' || (codice_vino[j] > '9' && codice_vino[j] < 'A') || (codice_vino[j] > 'Z' && codice_vino[j] < 'a') || codice_vino[j] > 'z') { printf("I codici dei vini possono contenere solo caratteri alfanumerici!\n"); /* forza la chiusura del programma */ controllo_errori = 1; } } codice_vino[j] = '{parsed_message}'; carattere_acquisito = getc(input); /* spostati in avanti nel file fino ad arrivare all'inizio dell'anno di produzione */ while (carattere_acquisito != ' ') carattere_acquisito = getc(input); /* acquisizione dell'anno di produzione */ for (j = 0, carattere_acquisito = '~'; ((j < (LUNGHEZZA_ANNO_PRODUZIONE - 1)) && (controllo_errori == 0)); j++) { anno_vino[j] = getc(input); /* se l'anno del vino ha meno caratteri del previsto */ if (anno_vino[j] == ' ') { printf("L'anno di produzione dei vini devono contenere %d caratteri!\n", (LUNGHEZZA_ANNO_PRODUZIONE - 1)); controllo_errori = 1; } /* se l'anno contiene caratteri non numerici */ else if (anno_vino[j] < '0' || anno_vino[j] > '9' ) { printf("Gli anni dei vini possono contenere solo caratteri numerici!\n"); /* forza la chiusura del programma */ controllo_errori = 1; } } anno_vino[j] = '{parsed_message}'; carattere_acquisito = getc(input); /* spostati in avanti nel file in avanti fino ad arrivare all'inizio del luogo di produzione */ while (carattere_acquisito != ' ') carattere_acquisito = getc(input); /* acquisizione del luogo di produzione del vino */ for (j = 0, carattere_acquisito = '~'; ((j < (LUNGHEZZA_LUOGO_PRODUZIONE - 1)) && (carattere_acquisito != ' ') && (carattere_acquisito != '\n') && (controllo_errori == 0)); j++) { carattere_acquisito = getc(input); if ((carattere_acquisito != ' ') && (carattere_acquisito != '\n')) luogo_vino[j] = carattere_acquisito; else j--; } luogo_vino[j] = '{parsed_message}'; /* se il luogo di produzione del vino ha più caratteri del previsto */ if ((carattere_acquisito != '\n') && (controllo_errori == 0)) printf("I luoghi che superano i %d caratteri sono stati abbreviati!\n", (LUNGHEZZA_LUOGO_PRODUZIONE - 1)); /* inserimento del vino nell'albero ordinato secondo il codice */ esito = inserisci_in_albero_bin(&radice_p, codice_vino, nome_vino, anno_vino, luogo_vino); /* se l'inserimento non è andato a buon fine */ if (esito == 0) { printf("\nIl vino con codice \"%s\" non è stato inserito perchè già presente nella lista!\n", codice_vino); /* decrementa il numero dei vini del numero di inserimenti falliti */ *numero_vini = *numero_vini - 1; } } return (controllo_errori); } /* Algoritmo per l'inserimento di un vino nell'albero binario ordinato secondo il codice */ int inserisci_in_albero_bin(nodo_albero_bin_t ***radice_p, /* lavoro: puntatore al puntatore alla radice dell'albero */ char codice_vino[], /* input: codice del vino da inserire */ char nome_vino[], /* input: nome del vino da inserire */ char anno_vino[], /* input: anno di produzione del vino da inserire */ char luogo_vino[]) /* input: luogo di produzione del vino da inserire */ { int inserito, /* output: esito dell'inserimento */ i; /* lavoro: indice per i cicli for */ nodo_albero_bin_t *nodo_p, /* lavoro: puntatore ad un nodo */ *padre_p, /* lavoro: puntatore al padre del nodo_p */ *nuovo_p; /* lavoro: puntatore al nodo che conterrà il nuovo vino */ /* nodo_p e padre_p vengono inizializzati con l'indirizzo della radice e ad ogni */ /* iterazione padre_p prende l'indirizzo di nodo_p.nodo_p prende l'indirizzo del */ /* suo figlio sx o dx a seconda che il codice da inserire sia < o >= al codice */ /* puntato da nodo_p.Il ciclo termina quando nodo_p punta a NULL oppure ad un */ /* elemento che contiene un codice uguale a quello da inserire. */ for (nodo_p = padre_p = **radice_p; ((nodo_p != NULL) && (strcmp(nodo_p->codice_vino, codice_vino) != 0)); padre_p = nodo_p, nodo_p = (strcmp(codice_vino, nodo_p->codice_vino) < 0)? nodo_p->sx_p: nodo_p->dx_p); /* il vino non verrà inserito se era già presente, ovvero se nodo_p non punta a NULL */ if (nodo_p != NULL) inserito = 0; else { inserito = 1; /* viene allocata memoria per il nuovo nodo */ nuovo_p = (nodo_albero_bin_t *)malloc(sizeof(nodo_albero_bin_t)); /* inserimento del codice del vino */ for (i = 0; (i < LUNGHEZZA_CODICE); i++) nuovo_p->codice_vino[i] = codice_vino[i]; /* inserimento del nome del vino */ for (i = 0; (i < LUNGHEZZA_NOME); i++) nuovo_p->nome_vino[i] = nome_vino[i]; /* inserimento dell'anno di produzione del vino */ for (i = 0; (i < LUNGHEZZA_ANNO_PRODUZIONE); i++) nuovo_p->anno_vino[i] = anno_vino[i]; /* inserimento del luogo di produzione del vino */ for (i = 0; (i < LUNGHEZZA_LUOGO_PRODUZIONE); i++) nuovo_p->luogo_vino[i] = luogo_vino[i]; /* i puntatori vengono inizializzati a NULL */ nuovo_p->sx_p = nuovo_p->dx_p = NULL; /* se il nodo si trova in cima all'albero diventa la radice */ if (nodo_p == **radice_p) **radice_p = nuovo_p; /* se il codice inserito è inferiore a quello contenuto nel nodo padre */ else if (strcmp(codice_vino, padre_p->codice_vino) < 0) /* il nuovo nodo diventa figlio sinistro */ padre_p->sx_p = nuovo_p; else /* il nuovo nodo diventa figlio destro */ padre_p->dx_p = nuovo_p; } /* viene restituito il valore di esito dell'inserimento */ return(inserito); } /* Funzione per l'inserimento di un nuovo vino */ int inserisci_nuovo_vino(nodo_albero_bin_t **radice_p) /* lavoro: puntatore alla radice dell'albero */ { char nome_vino[LUNGHEZZA_NOME], /* input: nome del vino da inserire */ codice_vino[LUNGHEZZA_CODICE], /* input: codice del vino da inserire */ anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], /* input: anno di produzione del vino da inserire */ luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE], /* input: luogo di produzione del vino da inserire */ carattere_acquisito = '~'; /* lavoro: variabile usata per acquisizioni e controlli */ int inserito = 0, /* output: esito dell'inserimento */ controllo_errori, /* lavoro: variabile di controllo */ i; /* lavoro: indice per i cicli for */ /* acquisizione del codice del vino da inserire */ printf("\nScrivere il codice del vino da inserire: "); /* non esce dal ciclo se il codice inserito da tastiera è troppo corto */ do { controllo_errori = 0; carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_CODICE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ') && (controllo_errori == 0)); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) codice_vino[i] = carattere_acquisito; else { i--; printf("\nIl codice deve contenere %d caratteri alfanumerici!\n", (LUNGHEZZA_CODICE - 1)); printf("\nRiscrivere il codice del vino: "); } /* se il codice contiene caratteri non alfanumerici */ if (codice_vino[i] < '0' || (codice_vino[i] > '9' && codice_vino[i] < 'A') || (codice_vino[i] > 'Z' && codice_vino[i] < 'a') || codice_vino[i] > 'z') { controllo_errori = 1; printf("\nRiscrivere il codice del vino: "); } } codice_vino[i] = '{parsed_message}'; } while ((strlen(codice_vino) != (LUNGHEZZA_CODICE - 1)) || (controllo_errori == 1)); carattere_acquisito = getchar(); /* se l'utente ha inserito un codice troppo lungo */ if (carattere_acquisito != '\n') /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); /* acquisizione del nome del vino da inserire */ /* non esce dal ciclo se l'utente non inserisce nessun nome */ do { printf("Scrivere il nome del vino da inserire: "); carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_NOME - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ')); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) nome_vino[i] = carattere_acquisito; else i--; } nome_vino[i] = '{parsed_message}'; /* se l'utente ha inserito un nome troppo lungo */ if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) { printf("\nIl nome è stato abbreviato a %d caratteri!\n\n", (LUNGHEZZA_NOME - 1)); /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); } } while (strlen(nome_vino) == 0); /* acquisizione dell'anno di produzione del vino da inserire */ printf("Scrivere l'anno di produzione del vino da inserire: "); /* non esce dal ciclo se l'anno inserito da tastiera è troppo corto */ do { controllo_errori = 0; carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_ANNO_PRODUZIONE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ') && (controllo_errori == 0)); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) anno_vino[i] = carattere_acquisito; else { i--; printf("\nL'anno deve contenere %d caratteri numerici!\n", (LUNGHEZZA_ANNO_PRODUZIONE - 1)); printf("\nRiscrivere l'anno di produzione del vino: "); } /* se l'anno contiene caratteri non numerici */ if (anno_vino[i] < '0' || anno_vino[i] > '9') controllo_errori = 1; } anno_vino[i] = '{parsed_message}'; } while ((strlen(anno_vino) != (LUNGHEZZA_ANNO_PRODUZIONE - 1)) || (controllo_errori == 1)); carattere_acquisito = getchar(); /* se l'utente ha inserito un anno troppo lungo */ if (carattere_acquisito != '\n') /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); /* acquisizione del luogo di produzione del vino da inserire */ /* non esce dal ciclo se l'utente non inserisce nessun luogo */ do { printf("Scrivere il luogo di produzione del vino da inserire: "); carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_LUOGO_PRODUZIONE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ')); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) luogo_vino[i] = carattere_acquisito; else i--; } luogo_vino[i] = '{parsed_message}'; /* se l'utente ha inserito un luogo troppo lungo */ if (carattere_acquisito != '\n') { printf("\nIl luogo è stato abbreviato a %d caratteri!\n\n", (LUNGHEZZA_LUOGO_PRODUZIONE - 1)); /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); } } while (strlen(luogo_vino) == 0); /* inserimento del vino nell'albero */ inserito = inserisci_in_albero_bin(&radice_p, codice_vino, nome_vino, anno_vino, luogo_vino); /* se l'inserimento è andato a buon fine */ if (inserito != 1) printf("\nVino \"%s\" già presente!", codice_vino); else printf("\nIl vino è stato inserito."); /* viene restituito l'esito dell'inserimento */ return (inserito); } int rimuovi_vino(nodo_albero_bin_t **radice_p) /* lavoro: puntatore alla radice dell'albero */ { char codice_vino[LUNGHEZZA_CODICE], /* input: codice del vino da rimuovere */ carattere_acquisito = '~'; /* lavoro: variabile usata per acquisizioni e controlli */ int rimosso = 0, /* output: esito rimozione */ controllo_errori, /* lavoro: variabile di controllo */ i; /* lavoro: indice per i cicli */ /* acquisizione del codice del vino da rimuovere */ printf("\nScrivere il codice del vino da rimuovere: "); /* non esce dal ciclo se l'utente non inserisce un codice corretto */ do { controllo_errori = 0; carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_CODICE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ') && (controllo_errori == 0)); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) codice_vino[i] = carattere_acquisito; else { i--; printf("\nIl codice deve contenere %d caratteri alfanumerici!\n", (LUNGHEZZA_CODICE - 1)); printf("\nRiscrivere il codice del vino: "); } /* se il codice contiene caratteri non alfanumerici */ if (codice_vino[i] < '0' || (codice_vino[i] > '9' && codice_vino[i] < 'A') || (codice_vino[i] > 'Z' && codice_vino[i] < 'a') || codice_vino[i] > 'z') { controllo_errori = 1; printf("\nRiscrivere il codice del vino: "); } } codice_vino[i] = '{parsed_message}'; } while ((strlen(codice_vino) != (LUNGHEZZA_CODICE - 1)) || (controllo_errori == 1)); carattere_acquisito = getchar(); /* se l'utente ha inserito un codice troppo lungo */ if (carattere_acquisito != '\n') /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); /* rimozione del vino dall'albero */ rimosso = rimuovi_da_albero_bin(&radice_p, codice_vino); if (rimosso == 1) printf("\nIl vino è stato rimosso!"); else printf("\nIl vino non è presente nella lista!"); /* viene restituito l'esito della rimozione */ return (rimosso); } /* Algoritmo per la rimozione di un vino dall'albero binario */ int rimuovi_da_albero_bin(nodo_albero_bin_t ***radice_p, /* lavoro: puntatore al puntatore alla radice dell'albero */ char codice_vino[]) /* input: codice del vino da rimuovere */ { int rimosso, /* output: esito della rimozione */ i; /* lavoro: contatore per i cicli for */ nodo_albero_bin_t *nodo_p, /* lavoro: puntatore a un nodo */ *padre_p, /* lavoro: padre di nodo_p */ *sost_p; /* lavoro: sostituto di nodo_p */ /* nodo_p e padre_p vengono inizializzati con l'indirizzo della radice e ad ogni */ /* iterazione padre_p prende l'indirizzo di nodo_p.nodo_p prende l'indirizzo del */ /* suo figlio sx o dx a seconda che il codice da inserire sia < o >= al codice */ /* puntato da nodo_p.Il ciclo termina quando nodo_p punta a NULL oppure ad un */ /* elemento che contiene un codice uguale a quello da rimuovere. */ for (nodo_p = padre_p = **radice_p; ((nodo_p != NULL) && (strcmp(nodo_p->codice_vino,codice_vino) != 0)); padre_p = nodo_p, nodo_p = (strcmp(codice_vino,nodo_p->codice_vino) < 0)? nodo_p->sx_p: nodo_p->dx_p); /* il vino non verrà rimosso se non era presente, ovvero se nodo_p punta a NULL */ if (nodo_p == NULL) rimosso = 0; else { rimosso = 1; /* se nodo_p non ha figlio sx */ if (nodo_p->sx_p == NULL) { /* se nodo_p si trova in cima all'albero */ if (nodo_p == **radice_p) /* il figlio destro del nodo diventa la radice */ **radice_p = nodo_p->dx_p; /* altrimenti se il codice da rimuovere è minore di quello del padre */ else if (strcmp(codice_vino, padre_p->codice_vino) < 0) /* il figlio destro del nodo_p, diventa figlio sinistro del padre */ padre_p->sx_p = nodo_p->dx_p; else /* il figlio destro del nodo_p, diventa figlio destro del padre */ padre_p->dx_p = nodo_p->dx_p; } /* altrimenti, se nodo_p non ha figlio destro */ else if (nodo_p->dx_p == NULL) { /* se nodo_p si trova in cima all'albero */ if (nodo_p == **radice_p) /* il figlio sinistro del nodo diventa la radice */ **radice_p = nodo_p->sx_p; /* altrimenti, se il codice da rimuovere è minore di quello del padre */ else if (strcmp(codice_vino, padre_p->codice_vino) < 0) /* il figlio sinistro del nodo_p diventa figlio sinistro del padre */ padre_p->sx_p = nodo_p->sx_p; else /* il figlio sinistro del nodo_p diventa figlio destro del padre */ padre_p->dx_p = nodo_p->sx_p; } /* altrimenti, se il nodo_p ha entrambi i figli */ else { /* sost_p prende l'indirizzo contenuto in nodo_p */ sost_p = nodo_p; /* ad ogni iterazione del ciclo, padre_p prende l'indirizzo di nodo_p e nodo_p prende */ /* l'indirizzo del figlio destro; il ciclo termina quando nodo_p non ha figlio destro */ for (padre_p = sost_p, nodo_p = sost_p->sx_p; (nodo_p->dx_p != NULL); padre_p = nodo_p, nodo_p = nodo_p->dx_p); /* sostuzione del codice del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_CODICE); i++) sost_p->codice_vino[i] = nodo_p->codice_vino[i]; /* sostituzione del nome del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_NOME); i++) sost_p->nome_vino[i] = nodo_p->nome_vino[i]; /* sostuzione dell'anno del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_ANNO_PRODUZIONE); i++) sost_p->anno_vino[i] = nodo_p->anno_vino[i]; /* sostituzione del luogo del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_LUOGO_PRODUZIONE); i++) sost_p->anno_vino[i] = nodo_p->anno_vino[i]; /* se padre_p e sost_p puntano allo stesso nodo */ if (padre_p == sost_p) /* il figlio sinistro del nodo_p diventa figlio sinistro del padre_p */ padre_p->sx_p = nodo_p->sx_p; else /* il figlio sinistro del nodo_p diventa figlio destro del padre_p */ padre_p->dx_p = nodo_p->sx_p; } /* il nodo puntato da nodo_p viene rimosso dalla memoria */ free(nodo_p); } return(rimosso); } /* funzione per la stampa dei vini in base al codice */ void stampa_codice(nodo_albero_bin_t *nodo_p) { if (nodo_p != NULL) { stampa_codice(nodo_p->sx_p); printf("%s %s %s %s\n", nodo_p->nome_vino, nodo_p->codice_vino, nodo_p->anno_vino, nodo_p->luogo_vino); stampa_codice(nodo_p->dx_p); } } void stampa_vini(nodo_albero_bin_t *radice_p, int numero_vini, int scelta_ordinamento) { vino_t vini[numero_vini]; /* array per l'ordinamento */ /* trasferimento dei vini dall'albero in un array */ inserisci_vini_in_array(radice_p, vini, 0); switch(scelta_ordinamento) { case 1: /* ordina i vini in base al nome */ quicksort_nome(vini, 0, numero_vini - 1); break; case 3: /* ordina i vini in base all'anno */ quicksort_anno(vini, 0, numero_vini - 1); break; case 4: /* ordina i vini in base al luogo */ quicksort_luogo(vini, 0, numero_vini - 1); break; } stampa_array(numero_vini, vini); } /* funzione per il trasferimento dei vini dall'albero in un array */ void inserisci_vini_in_array(nodo_albero_bin_t *nodo_p, vino_t *vini, int i) { if (nodo_p->codice_vino != NULL) { inserisci_vini_in_array(nodo_p->sx_p, vini, i); strcpy(vini[i].nome_vino, nodo_p->nome_vino); strcpy(vini[i].codice_vino, nodo_p->codice_vino); strcpy(vini[i].anno_vino, nodo_p->anno_vino); strcpy(vini[i].luogo_vino, nodo_p->luogo_vino); i = i + 1; inserisci_vini_in_array(nodo_p->dx_p, vini, i); } } void quicksort_nome(vino_t a[], int sx, int dx) { int i, j; /* variabili di lavoro */ vino_t tmp, /* variabile usata per lo scambio */ pivot; /* puntatore all'elemento che fungera' da pivot */ /* si sceglie come pivot il valore centrale e si attua una tri-partizione */ /* scambiando gli elementi in modo che nella porzione a destra del pivot vi */ /* siano elementi maggiori del pivot e nella porzione sinistra quelli minori */ for (pivot = a[(sx + dx) / 2], i = sx, j = dx; (i <= j);) { while (strcmp(a[i].nome_vino, pivot.nome_vino) == -1) i++; while (strcmp(a[j].nome_vino, pivot.nome_vino) == 1) j--; if (i <= j) { if (i < j) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; } i++; j--; } } /* si invoca ricorsivamente la funzione sulle porzioni sinistra e destra */ if (sx < j) quicksort_nome(a, sx, j); if (i < dx) quicksort_nome(a, i, dx); } void quicksort_anno(vino_t a[], int sx, int dx) { int i, j; /* variabili di lavoro */ vino_t tmp, /* variabile usata per lo scambio */ pivot; /* puntatore all'elemento che fungera' da pivot */ /* si sceglie come pivot il valore centrale e si attua una tri-partizione */ /* scambiando gli elementi in modo che nella porzione a destra del pivot vi */ /* siano elementi maggiori del pivot e nella porzione sinistra quelli minori */ for (pivot = a[(sx + dx) / 2], i = sx, j = dx; (i <= j);) { while (strcmp(a[i].anno_vino, pivot.anno_vino) == -1) i++; while (strcmp(a[j].anno_vino, pivot.anno_vino) == 1) j--; if (i <= j) { if (i < j) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; } i++; j--; } } /* si invoca ricorsivamente la funzione sulle porzioni sinistra e destra */ if (sx < j) quicksort_anno(a, sx, j); if (i < dx) quicksort_anno(a, i, dx); } void quicksort_luogo(vino_t a[], int sx, int dx) { int i, j; /* variabili di lavoro */ vino_t tmp, /* variabile usata per lo scambio */ pivot; /* puntatore all'elemento che fungera' da pivot */ /* si sceglie come pivot il valore centrale e si attua una tri-partizione */ /* scambiando gli elementi in modo che nella porzione a destra del pivot vi */ /* siano elementi maggiori del pivot e nella porzione sinistra quelli minori */ for (pivot = a[(sx + dx) / 2], i = sx, j = dx; (i <= j);) { while (strcmp(a[i].luogo_vino, pivot.luogo_vino) == -1) i++; while (strcmp(a[j].luogo_vino, pivot.luogo_vino) == 1) j--; if (i <= j) { if (i < j) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; } i++; j--; } } /*Si invoca ricorsivamente la funzione sulle porzioni sinistra e destra*/ if (sx < j) quicksort_luogo(a, sx, j); if (i < dx) quicksort_luogo(a, i, dx); } void stampa_array(int numero_vini, vino_t *vini) { int i; /*Vengono stampati gli elementi ordinati*/ for(i = 0; i < numero_vini; i++) printf("\n%20s %4s %4s %s", vini[i].nome_vino, vini[i].codice_vino, vini[i].anno_vino, vini[i].luogo_vino); }'; /* se il luogo di produzione del vino ha più caratteri del previsto */ if ((carattere_acquisito != '\n') && (controllo_errori == 0)) printf("I luoghi che superano i %d caratteri sono stati abbreviati!\n", (LUNGHEZZA_LUOGO_PRODUZIONE - 1)); /* inserimento del vino nell'albero ordinato secondo il codice */ esito = inserisci_in_albero_bin(&radice_p, codice_vino, nome_vino, anno_vino, luogo_vino); /* se l'inserimento non è andato a buon fine */ if (esito == 0) { printf("\nIl vino con codice \"%s\" non è stato inserito perchè già presente nella lista!\n", codice_vino); /* decrementa il numero dei vini del numero di inserimenti falliti */ *numero_vini = *numero_vini - 1; } } return (controllo_errori); } /* Algoritmo per l'inserimento di un vino nell'albero binario ordinato secondo il codice */ int inserisci_in_albero_bin(nodo_albero_bin_t ***radice_p, /* lavoro: puntatore al puntatore alla radice dell'albero */ char codice_vino[], /* input: codice del vino da inserire */ char nome_vino[], /* input: nome del vino da inserire */ char anno_vino[], /* input: anno di produzione del vino da inserire */ char luogo_vino[]) /* input: luogo di produzione del vino da inserire */ { int inserito, /* output: esito dell'inserimento */ i; /* lavoro: indice per i cicli for */ nodo_albero_bin_t *nodo_p, /* lavoro: puntatore ad un nodo */ *padre_p, /* lavoro: puntatore al padre del nodo_p */ *nuovo_p; /* lavoro: puntatore al nodo che conterrà il nuovo vino */ /* nodo_p e padre_p vengono inizializzati con l'indirizzo della radice e ad ogni */ /* iterazione padre_p prende l'indirizzo di nodo_p.nodo_p prende l'indirizzo del */ /* suo figlio sx o dx a seconda che il codice da inserire sia < o >= al codice */ /* puntato da nodo_p.Il ciclo termina quando nodo_p punta a NULL oppure ad un */ /* elemento che contiene un codice uguale a quello da inserire. */ for (nodo_p = padre_p = **radice_p; ((nodo_p != NULL) && (strcmp(nodo_p->codice_vino, codice_vino) != 0)); padre_p = nodo_p, nodo_p = (strcmp(codice_vino, nodo_p->codice_vino) < 0)? nodo_p->sx_p: nodo_p->dx_p); /* il vino non verrà inserito se era già presente, ovvero se nodo_p non punta a NULL */ if (nodo_p != NULL) inserito = 0; else { inserito = 1; /* viene allocata memoria per il nuovo nodo */ nuovo_p = (nodo_albero_bin_t *)malloc(sizeof(nodo_albero_bin_t)); /* inserimento del codice del vino */ for (i = 0; (i < LUNGHEZZA_CODICE); i++) nuovo_p->codice_vino[i] = codice_vino[i]; /* inserimento del nome del vino */ for (i = 0; (i < LUNGHEZZA_NOME); i++) nuovo_p->nome_vino[i] = nome_vino[i]; /* inserimento dell'anno di produzione del vino */ for (i = 0; (i < LUNGHEZZA_ANNO_PRODUZIONE); i++) nuovo_p->anno_vino[i] = anno_vino[i]; /* inserimento del luogo di produzione del vino */ for (i = 0; (i < LUNGHEZZA_LUOGO_PRODUZIONE); i++) nuovo_p->luogo_vino[i] = luogo_vino[i]; /* i puntatori vengono inizializzati a NULL */ nuovo_p->sx_p = nuovo_p->dx_p = NULL; /* se il nodo si trova in cima all'albero diventa la radice */ if (nodo_p == **radice_p) **radice_p = nuovo_p; /* se il codice inserito è inferiore a quello contenuto nel nodo padre */ else if (strcmp(codice_vino, padre_p->codice_vino) < 0) /* il nuovo nodo diventa figlio sinistro */ padre_p->sx_p = nuovo_p; else /* il nuovo nodo diventa figlio destro */ padre_p->dx_p = nuovo_p; } /* viene restituito il valore di esito dell'inserimento */ return(inserito); } /* Funzione per l'inserimento di un nuovo vino */ int inserisci_nuovo_vino(nodo_albero_bin_t **radice_p) /* lavoro: puntatore alla radice dell'albero */ { char nome_vino[LUNGHEZZA_NOME], /* input: nome del vino da inserire */ codice_vino[LUNGHEZZA_CODICE], /* input: codice del vino da inserire */ anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], /* input: anno di produzione del vino da inserire */ luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE], /* input: luogo di produzione del vino da inserire */ carattere_acquisito = '~'; /* lavoro: variabile usata per acquisizioni e controlli */ int inserito = 0, /* output: esito dell'inserimento */ controllo_errori, /* lavoro: variabile di controllo */ i; /* lavoro: indice per i cicli for */ /* acquisizione del codice del vino da inserire */ printf("\nScrivere il codice del vino da inserire: "); /* non esce dal ciclo se il codice inserito da tastiera è troppo corto */ do { controllo_errori = 0; carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_CODICE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ') && (controllo_errori == 0)); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) codice_vino[i] = carattere_acquisito; else { i--; printf("\nIl codice deve contenere %d caratteri alfanumerici!\n", (LUNGHEZZA_CODICE - 1)); printf("\nRiscrivere il codice del vino: "); } /* se il codice contiene caratteri non alfanumerici */ if (codice_vino[i] < '0' || (codice_vino[i] > '9' && codice_vino[i] < 'A') || (codice_vino[i] > 'Z' && codice_vino[i] < 'a') || codice_vino[i] > 'z') { controllo_errori = 1; printf("\nRiscrivere il codice del vino: "); } } codice_vino[i] = 'Nel file allegato vi è il codice di un programma che gestisce un database di vini. Il mio problema è che ricevo un errore di segmentazione entrando nella funzione "inserisci_in_albero_bin". E' da un pò di giorni che stò cercando una soluzione ma non riesco a venirne a capo...qualcuno saprebbe aiutarmi??/******************************************************************/ /* Programma per manipolare un file contenente una lista di vini. */ /* Michele Petrocchi Matricola 256507 */ /******************************************************************/ /***********************/ /* inclusione librerie */ /***********************/ #include <stdio.h> #include <stdlib.h> #include <string.h> /*************************************/ /* Dichiarazione costanti simboliche */ /*************************************/ #define LUNGHEZZA_NOME 51 /* lunghezza della stringa del nome del vino */ #define LUNGHEZZA_CODICE 5 /* lunghezza della stringa del codice del vino */ #define LUNGHEZZA_ANNO_PRODUZIONE 5 /* lunghezza della stringa dell'anno di produzione del vino */ #define LUNGHEZZA_LUOGO_PRODUZIONE 51 /* lunghezza della stringa del luogo di produzione del vino */ #define PERCORSO_FILE "./file_vini" /* percorso del file di output */ /************************/ /* Defibizione dei tipi */ /************************/ typedef struct nodo_albero_bin { char nome_vino[LUNGHEZZA_NOME], /* nome del vino */ codice_vino[LUNGHEZZA_CODICE], /* codice del vino */ anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], /* anno di produzione del vino */ luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE]; /* luogo di produzione del vino */ struct nodo_albero_bin *sx_p, *dx_p; } nodo_albero_bin_t; typedef struct vino { char nome_vino[LUNGHEZZA_NOME], /* nome del vino */ codice_vino[LUNGHEZZA_CODICE], /* codice del vino */ anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], /* anno di produzione del vino */ luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE]; /* luogo di produzione del vino */ } vino_t; /********************************/ /* Dichiarazione delle funzioni */ /********************************/ int controllo_correttezza_file(nodo_albero_bin_t **, FILE *, int *); int inserisci_in_albero_bin(nodo_albero_bin_t ***, char[], char[], char[], char[]); int inserisci_nuovo_vino(nodo_albero_bin_t **); int rimuovi_vino(nodo_albero_bin_t **); int rimuovi_da_albero_bin(nodo_albero_bin_t ***, char[]); void stampa_codice(nodo_albero_bin_t *); void stampa_vini(nodo_albero_bin_t *, int, int); void inserisci_vini_in_array(nodo_albero_bin_t *, vino_t [], int); void quicksort_nome(vino_t [], int, int); void quicksort_anno(vino_t [], int, int); void quicksort_luogo(vino_t [], int, int); void stampa_array(int, vino_t *); /******************************/ /* Definizione delle funzioni */ /******************************/ int main (int argc, /* numero stringhe acquisite lancio comandi */ char *argv[]) /* stringhe acqusite dal lancio comandi */ { int esito = 0, esito_ordinamento = 0, esito_pulizia = 1, esito_pulizia_ordinamento = 1, scelta_utente = 0, scelta_ordinamento = 0, rimosso = 0, numero_vini = 0, controllo = 0; FILE *input; /* file da dove preleverò la lista dei vini */ nodo_albero_bin_t *radice_p = NULL; /* lavoro: puntatore alla radice dell'albero */ /* specifichiamo il file di input, quindi deve essere 1 il numero degli argomenti */ if(argc > 1) { /* apriamo il file specificato */ input = fopen(argv[1],"r"); /* se il file specificato esiste */ if (input != NULL) { /* acquisisci il numero di vini */ esito = fscanf(input, "%d", &numero_vini); /* se il numero di vini non è valido */ if (esito != 1 || numero_vini < 0) printf("Lettura del numero di vini non riuscita.\n\n"); else controllo = controllo_correttezza_file(&radice_p, input, &numero_vini); /* chiudere il file di input */ fclose(input); /* se non si sono verificati errori */ if (controllo != 1) { do { do { printf("\nL'utente digiti:"); printf("\n 1-Se si vuole procedere nell'inserimento di un nuovo vino"); printf("\n 2-Se si vuole procedere nella cancellazione di un altro"); printf("\n 3-Se si vuole visualizzare la lista con i vini inseriti"); printf("\n 4-Se si vuole uscire dal programma"); printf("\nPremere Invio per confermare.\n"); printf("\n"); /* pulizia del buffer della scanf */ esito_pulizia = scanf("\n"); esito = scanf("%d", &scelta_utente); while (getchar() != '\n'); } while ((scelta_utente < 1) || (scelta_utente > 4) || (esito != 1) || (esito_pulizia != 0)); switch (scelta_utente) { case 1: esito = inserisci_nuovo_vino(&radice_p); if (esito == 1) /* incrementa il numero di vini */ numero_vini++; printf(" (premere Invio per tornare al menù)\n"); while (getchar() != '\n'); break; case 2: rimosso = rimuovi_vino(&radice_p); /* se la rimozione è andata a buon fine */ if (rimosso == 1) /* decremento il numero di vini */ numero_vini--; printf(" (premere Invio per tornare al menù)\n"); while (getchar() != '\n'); break; case 3: do { printf("\nL'utente scelga l'ordine di visualizzaione dei vini:"); printf("\n 1-Nome"); printf("\n 2-Codice"); printf("\n 3-Luogo di produzione"); printf("\n 4-Anno di produzione"); printf("\nPremere Invio per confermare.\n"); printf("\n"); /* pulizia del buffer della scanf */ esito_pulizia_ordinamento = scanf("\n"); esito_ordinamento = scanf("%d", &scelta_ordinamento); while (getchar() != '\n'); } while ((scelta_utente < 1) || (scelta_utente > 4) || (esito_ordinamento != 1) || (esito_pulizia_ordinamento != 0)); /* visualizzare la lista dei vini inseriti */ printf("\n%d vini inseriti:\n", numero_vini); if (scelta_ordinamento == 2) /* stampa i vini in base al codice */ stampa_codice(radice_p); else stampa_vini(radice_p, numero_vini, scelta_ordinamento); printf("\n"); printf("(premere Invio per tornare al menù)\n"); while (getchar() != '\n'); break; case 4: /* se l'utente decide di uscire stampiamo un messaggio di saluto */ printf("\nGrazie per aver utilizzato questo programma!"); printf("\n\n"); break; } } while ((scelta_utente != 4)); } } else/* se il file specificato è uguale a NULL e quindi inesistente */ printf("\nIl file specificato non esiste!\n"); } else { /* se non è stato inserito il parametro di lancio del file */ printf("\nNon è stato immesso il nome del file da dove importare i dati riguardanti i vini!"); printf("\nrilanciare il programma con queste specifiche:"); printf("\n./<nome_eseguibile> <nome_file_input>\n"); printf("\nIl file può essere generato tramite il programma che viene lanciato con ./genera"); printf("\n(per la compilazione il comando è make genera_vini!)\n"); printf("\n(se il file è nella dir. di lavoro basta specificarne il nome!)\n\n"); } return(0); } int controllo_correttezza_file(nodo_albero_bin_t **radice_p, FILE * input, int *numero_vini) { int esito, controllo_errori = 0, i, j; char nome_vino[LUNGHEZZA_NOME], codice_vino[LUNGHEZZA_CODICE], anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE], carattere_acquisito = '~'; /* lavoro: variabile utilizzata */ /* per acquisizioni e controlli */ /* il ciclo acquisce i vini uno ad uno dal file e li inserisce nella struttura dati */ for (i = 0; ((i < *numero_vini) && (controllo_errori == 0)); i++) { /* scorro il file fino a trovare il carattere successivo */ while (carattere_acquisito != '\n') carattere_acquisito = getc(input); /* acquisizione del nome del vino */ for (j = 0, carattere_acquisito = '~'; ((j < (LUNGHEZZA_NOME - 1)) && (carattere_acquisito != ' ') && (carattere_acquisito != '\n') && (controllo_errori == 0)); j++) { carattere_acquisito = getc(input); if ((carattere_acquisito != ' ') && (carattere_acquisito != '\n')) nome_vino[j] = carattere_acquisito; else j--; } nome_vino[j] = '{parsed_message}'; /* se il nome del vino ha più caratteri del previsto */ if (carattere_acquisito != ' ') printf("I nomi che superano i %d caratteri sono stati abbreviati!\n", (LUNGHEZZA_NOME - 1)); /* spostati in avanti nel file in avanti fino ad arrivare all'inizio del codice */ while (carattere_acquisito != ' ') carattere_acquisito = getc(input); /* acquisizione del codice del vino */ for (j = 0; ((j < (LUNGHEZZA_CODICE - 1)) && (controllo_errori == 0)); j++) { codice_vino[j] = getc(input); /* se il codice vino ha meno caratteri del previsto */ if (codice_vino[j] == ' ') { printf("I codici dei vini devono contenere %d caratteri!\n", (LUNGHEZZA_CODICE - 1)); controllo_errori = 1; } /* se il codice contiene caratteri non alfanumerici */ else if (codice_vino[j] < '0' || (codice_vino[j] > '9' && codice_vino[j] < 'A') || (codice_vino[j] > 'Z' && codice_vino[j] < 'a') || codice_vino[j] > 'z') { printf("I codici dei vini possono contenere solo caratteri alfanumerici!\n"); /* forza la chiusura del programma */ controllo_errori = 1; } } codice_vino[j] = '{parsed_message}'; carattere_acquisito = getc(input); /* spostati in avanti nel file fino ad arrivare all'inizio dell'anno di produzione */ while (carattere_acquisito != ' ') carattere_acquisito = getc(input); /* acquisizione dell'anno di produzione */ for (j = 0, carattere_acquisito = '~'; ((j < (LUNGHEZZA_ANNO_PRODUZIONE - 1)) && (controllo_errori == 0)); j++) { anno_vino[j] = getc(input); /* se l'anno del vino ha meno caratteri del previsto */ if (anno_vino[j] == ' ') { printf("L'anno di produzione dei vini devono contenere %d caratteri!\n", (LUNGHEZZA_ANNO_PRODUZIONE - 1)); controllo_errori = 1; } /* se l'anno contiene caratteri non numerici */ else if (anno_vino[j] < '0' || anno_vino[j] > '9' ) { printf("Gli anni dei vini possono contenere solo caratteri numerici!\n"); /* forza la chiusura del programma */ controllo_errori = 1; } } anno_vino[j] = '{parsed_message}'; carattere_acquisito = getc(input); /* spostati in avanti nel file in avanti fino ad arrivare all'inizio del luogo di produzione */ while (carattere_acquisito != ' ') carattere_acquisito = getc(input); /* acquisizione del luogo di produzione del vino */ for (j = 0, carattere_acquisito = '~'; ((j < (LUNGHEZZA_LUOGO_PRODUZIONE - 1)) && (carattere_acquisito != ' ') && (carattere_acquisito != '\n') && (controllo_errori == 0)); j++) { carattere_acquisito = getc(input); if ((carattere_acquisito != ' ') && (carattere_acquisito != '\n')) luogo_vino[j] = carattere_acquisito; else j--; } luogo_vino[j] = '{parsed_message}'; /* se il luogo di produzione del vino ha più caratteri del previsto */ if ((carattere_acquisito != '\n') && (controllo_errori == 0)) printf("I luoghi che superano i %d caratteri sono stati abbreviati!\n", (LUNGHEZZA_LUOGO_PRODUZIONE - 1)); /* inserimento del vino nell'albero ordinato secondo il codice */ esito = inserisci_in_albero_bin(&radice_p, codice_vino, nome_vino, anno_vino, luogo_vino); /* se l'inserimento non è andato a buon fine */ if (esito == 0) { printf("\nIl vino con codice \"%s\" non è stato inserito perchè già presente nella lista!\n", codice_vino); /* decrementa il numero dei vini del numero di inserimenti falliti */ *numero_vini = *numero_vini - 1; } } return (controllo_errori); } /* Algoritmo per l'inserimento di un vino nell'albero binario ordinato secondo il codice */ int inserisci_in_albero_bin(nodo_albero_bin_t ***radice_p, /* lavoro: puntatore al puntatore alla radice dell'albero */ char codice_vino[], /* input: codice del vino da inserire */ char nome_vino[], /* input: nome del vino da inserire */ char anno_vino[], /* input: anno di produzione del vino da inserire */ char luogo_vino[]) /* input: luogo di produzione del vino da inserire */ { int inserito, /* output: esito dell'inserimento */ i; /* lavoro: indice per i cicli for */ nodo_albero_bin_t *nodo_p, /* lavoro: puntatore ad un nodo */ *padre_p, /* lavoro: puntatore al padre del nodo_p */ *nuovo_p; /* lavoro: puntatore al nodo che conterrà il nuovo vino */ /* nodo_p e padre_p vengono inizializzati con l'indirizzo della radice e ad ogni */ /* iterazione padre_p prende l'indirizzo di nodo_p.nodo_p prende l'indirizzo del */ /* suo figlio sx o dx a seconda che il codice da inserire sia < o >= al codice */ /* puntato da nodo_p.Il ciclo termina quando nodo_p punta a NULL oppure ad un */ /* elemento che contiene un codice uguale a quello da inserire. */ for (nodo_p = padre_p = **radice_p; ((nodo_p != NULL) && (strcmp(nodo_p->codice_vino, codice_vino) != 0)); padre_p = nodo_p, nodo_p = (strcmp(codice_vino, nodo_p->codice_vino) < 0)? nodo_p->sx_p: nodo_p->dx_p); /* il vino non verrà inserito se era già presente, ovvero se nodo_p non punta a NULL */ if (nodo_p != NULL) inserito = 0; else { inserito = 1; /* viene allocata memoria per il nuovo nodo */ nuovo_p = (nodo_albero_bin_t *)malloc(sizeof(nodo_albero_bin_t)); /* inserimento del codice del vino */ for (i = 0; (i < LUNGHEZZA_CODICE); i++) nuovo_p->codice_vino[i] = codice_vino[i]; /* inserimento del nome del vino */ for (i = 0; (i < LUNGHEZZA_NOME); i++) nuovo_p->nome_vino[i] = nome_vino[i]; /* inserimento dell'anno di produzione del vino */ for (i = 0; (i < LUNGHEZZA_ANNO_PRODUZIONE); i++) nuovo_p->anno_vino[i] = anno_vino[i]; /* inserimento del luogo di produzione del vino */ for (i = 0; (i < LUNGHEZZA_LUOGO_PRODUZIONE); i++) nuovo_p->luogo_vino[i] = luogo_vino[i]; /* i puntatori vengono inizializzati a NULL */ nuovo_p->sx_p = nuovo_p->dx_p = NULL; /* se il nodo si trova in cima all'albero diventa la radice */ if (nodo_p == **radice_p) **radice_p = nuovo_p; /* se il codice inserito è inferiore a quello contenuto nel nodo padre */ else if (strcmp(codice_vino, padre_p->codice_vino) < 0) /* il nuovo nodo diventa figlio sinistro */ padre_p->sx_p = nuovo_p; else /* il nuovo nodo diventa figlio destro */ padre_p->dx_p = nuovo_p; } /* viene restituito il valore di esito dell'inserimento */ return(inserito); } /* Funzione per l'inserimento di un nuovo vino */ int inserisci_nuovo_vino(nodo_albero_bin_t **radice_p) /* lavoro: puntatore alla radice dell'albero */ { char nome_vino[LUNGHEZZA_NOME], /* input: nome del vino da inserire */ codice_vino[LUNGHEZZA_CODICE], /* input: codice del vino da inserire */ anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], /* input: anno di produzione del vino da inserire */ luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE], /* input: luogo di produzione del vino da inserire */ carattere_acquisito = '~'; /* lavoro: variabile usata per acquisizioni e controlli */ int inserito = 0, /* output: esito dell'inserimento */ controllo_errori, /* lavoro: variabile di controllo */ i; /* lavoro: indice per i cicli for */ /* acquisizione del codice del vino da inserire */ printf("\nScrivere il codice del vino da inserire: "); /* non esce dal ciclo se il codice inserito da tastiera è troppo corto */ do { controllo_errori = 0; carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_CODICE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ') && (controllo_errori == 0)); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) codice_vino[i] = carattere_acquisito; else { i--; printf("\nIl codice deve contenere %d caratteri alfanumerici!\n", (LUNGHEZZA_CODICE - 1)); printf("\nRiscrivere il codice del vino: "); } /* se il codice contiene caratteri non alfanumerici */ if (codice_vino[i] < '0' || (codice_vino[i] > '9' && codice_vino[i] < 'A') || (codice_vino[i] > 'Z' && codice_vino[i] < 'a') || codice_vino[i] > 'z') { controllo_errori = 1; printf("\nRiscrivere il codice del vino: "); } } codice_vino[i] = '{parsed_message}'; } while ((strlen(codice_vino) != (LUNGHEZZA_CODICE - 1)) || (controllo_errori == 1)); carattere_acquisito = getchar(); /* se l'utente ha inserito un codice troppo lungo */ if (carattere_acquisito != '\n') /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); /* acquisizione del nome del vino da inserire */ /* non esce dal ciclo se l'utente non inserisce nessun nome */ do { printf("Scrivere il nome del vino da inserire: "); carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_NOME - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ')); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) nome_vino[i] = carattere_acquisito; else i--; } nome_vino[i] = '{parsed_message}'; /* se l'utente ha inserito un nome troppo lungo */ if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) { printf("\nIl nome è stato abbreviato a %d caratteri!\n\n", (LUNGHEZZA_NOME - 1)); /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); } } while (strlen(nome_vino) == 0); /* acquisizione dell'anno di produzione del vino da inserire */ printf("Scrivere l'anno di produzione del vino da inserire: "); /* non esce dal ciclo se l'anno inserito da tastiera è troppo corto */ do { controllo_errori = 0; carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_ANNO_PRODUZIONE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ') && (controllo_errori == 0)); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) anno_vino[i] = carattere_acquisito; else { i--; printf("\nL'anno deve contenere %d caratteri numerici!\n", (LUNGHEZZA_ANNO_PRODUZIONE - 1)); printf("\nRiscrivere l'anno di produzione del vino: "); } /* se l'anno contiene caratteri non numerici */ if (anno_vino[i] < '0' || anno_vino[i] > '9') controllo_errori = 1; } anno_vino[i] = '{parsed_message}'; } while ((strlen(anno_vino) != (LUNGHEZZA_ANNO_PRODUZIONE - 1)) || (controllo_errori == 1)); carattere_acquisito = getchar(); /* se l'utente ha inserito un anno troppo lungo */ if (carattere_acquisito != '\n') /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); /* acquisizione del luogo di produzione del vino da inserire */ /* non esce dal ciclo se l'utente non inserisce nessun luogo */ do { printf("Scrivere il luogo di produzione del vino da inserire: "); carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_LUOGO_PRODUZIONE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ')); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) luogo_vino[i] = carattere_acquisito; else i--; } luogo_vino[i] = '{parsed_message}'; /* se l'utente ha inserito un luogo troppo lungo */ if (carattere_acquisito != '\n') { printf("\nIl luogo è stato abbreviato a %d caratteri!\n\n", (LUNGHEZZA_LUOGO_PRODUZIONE - 1)); /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); } } while (strlen(luogo_vino) == 0); /* inserimento del vino nell'albero */ inserito = inserisci_in_albero_bin(&radice_p, codice_vino, nome_vino, anno_vino, luogo_vino); /* se l'inserimento è andato a buon fine */ if (inserito != 1) printf("\nVino \"%s\" già presente!", codice_vino); else printf("\nIl vino è stato inserito."); /* viene restituito l'esito dell'inserimento */ return (inserito); } int rimuovi_vino(nodo_albero_bin_t **radice_p) /* lavoro: puntatore alla radice dell'albero */ { char codice_vino[LUNGHEZZA_CODICE], /* input: codice del vino da rimuovere */ carattere_acquisito = '~'; /* lavoro: variabile usata per acquisizioni e controlli */ int rimosso = 0, /* output: esito rimozione */ controllo_errori, /* lavoro: variabile di controllo */ i; /* lavoro: indice per i cicli */ /* acquisizione del codice del vino da rimuovere */ printf("\nScrivere il codice del vino da rimuovere: "); /* non esce dal ciclo se l'utente non inserisce un codice corretto */ do { controllo_errori = 0; carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_CODICE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ') && (controllo_errori == 0)); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) codice_vino[i] = carattere_acquisito; else { i--; printf("\nIl codice deve contenere %d caratteri alfanumerici!\n", (LUNGHEZZA_CODICE - 1)); printf("\nRiscrivere il codice del vino: "); } /* se il codice contiene caratteri non alfanumerici */ if (codice_vino[i] < '0' || (codice_vino[i] > '9' && codice_vino[i] < 'A') || (codice_vino[i] > 'Z' && codice_vino[i] < 'a') || codice_vino[i] > 'z') { controllo_errori = 1; printf("\nRiscrivere il codice del vino: "); } } codice_vino[i] = '{parsed_message}'; } while ((strlen(codice_vino) != (LUNGHEZZA_CODICE - 1)) || (controllo_errori == 1)); carattere_acquisito = getchar(); /* se l'utente ha inserito un codice troppo lungo */ if (carattere_acquisito != '\n') /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); /* rimozione del vino dall'albero */ rimosso = rimuovi_da_albero_bin(&radice_p, codice_vino); if (rimosso == 1) printf("\nIl vino è stato rimosso!"); else printf("\nIl vino non è presente nella lista!"); /* viene restituito l'esito della rimozione */ return (rimosso); } /* Algoritmo per la rimozione di un vino dall'albero binario */ int rimuovi_da_albero_bin(nodo_albero_bin_t ***radice_p, /* lavoro: puntatore al puntatore alla radice dell'albero */ char codice_vino[]) /* input: codice del vino da rimuovere */ { int rimosso, /* output: esito della rimozione */ i; /* lavoro: contatore per i cicli for */ nodo_albero_bin_t *nodo_p, /* lavoro: puntatore a un nodo */ *padre_p, /* lavoro: padre di nodo_p */ *sost_p; /* lavoro: sostituto di nodo_p */ /* nodo_p e padre_p vengono inizializzati con l'indirizzo della radice e ad ogni */ /* iterazione padre_p prende l'indirizzo di nodo_p.nodo_p prende l'indirizzo del */ /* suo figlio sx o dx a seconda che il codice da inserire sia < o >= al codice */ /* puntato da nodo_p.Il ciclo termina quando nodo_p punta a NULL oppure ad un */ /* elemento che contiene un codice uguale a quello da rimuovere. */ for (nodo_p = padre_p = **radice_p; ((nodo_p != NULL) && (strcmp(nodo_p->codice_vino,codice_vino) != 0)); padre_p = nodo_p, nodo_p = (strcmp(codice_vino,nodo_p->codice_vino) < 0)? nodo_p->sx_p: nodo_p->dx_p); /* il vino non verrà rimosso se non era presente, ovvero se nodo_p punta a NULL */ if (nodo_p == NULL) rimosso = 0; else { rimosso = 1; /* se nodo_p non ha figlio sx */ if (nodo_p->sx_p == NULL) { /* se nodo_p si trova in cima all'albero */ if (nodo_p == **radice_p) /* il figlio destro del nodo diventa la radice */ **radice_p = nodo_p->dx_p; /* altrimenti se il codice da rimuovere è minore di quello del padre */ else if (strcmp(codice_vino, padre_p->codice_vino) < 0) /* il figlio destro del nodo_p, diventa figlio sinistro del padre */ padre_p->sx_p = nodo_p->dx_p; else /* il figlio destro del nodo_p, diventa figlio destro del padre */ padre_p->dx_p = nodo_p->dx_p; } /* altrimenti, se nodo_p non ha figlio destro */ else if (nodo_p->dx_p == NULL) { /* se nodo_p si trova in cima all'albero */ if (nodo_p == **radice_p) /* il figlio sinistro del nodo diventa la radice */ **radice_p = nodo_p->sx_p; /* altrimenti, se il codice da rimuovere è minore di quello del padre */ else if (strcmp(codice_vino, padre_p->codice_vino) < 0) /* il figlio sinistro del nodo_p diventa figlio sinistro del padre */ padre_p->sx_p = nodo_p->sx_p; else /* il figlio sinistro del nodo_p diventa figlio destro del padre */ padre_p->dx_p = nodo_p->sx_p; } /* altrimenti, se il nodo_p ha entrambi i figli */ else { /* sost_p prende l'indirizzo contenuto in nodo_p */ sost_p = nodo_p; /* ad ogni iterazione del ciclo, padre_p prende l'indirizzo di nodo_p e nodo_p prende */ /* l'indirizzo del figlio destro; il ciclo termina quando nodo_p non ha figlio destro */ for (padre_p = sost_p, nodo_p = sost_p->sx_p; (nodo_p->dx_p != NULL); padre_p = nodo_p, nodo_p = nodo_p->dx_p); /* sostuzione del codice del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_CODICE); i++) sost_p->codice_vino[i] = nodo_p->codice_vino[i]; /* sostituzione del nome del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_NOME); i++) sost_p->nome_vino[i] = nodo_p->nome_vino[i]; /* sostuzione dell'anno del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_ANNO_PRODUZIONE); i++) sost_p->anno_vino[i] = nodo_p->anno_vino[i]; /* sostituzione del luogo del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_LUOGO_PRODUZIONE); i++) sost_p->anno_vino[i] = nodo_p->anno_vino[i]; /* se padre_p e sost_p puntano allo stesso nodo */ if (padre_p == sost_p) /* il figlio sinistro del nodo_p diventa figlio sinistro del padre_p */ padre_p->sx_p = nodo_p->sx_p; else /* il figlio sinistro del nodo_p diventa figlio destro del padre_p */ padre_p->dx_p = nodo_p->sx_p; } /* il nodo puntato da nodo_p viene rimosso dalla memoria */ free(nodo_p); } return(rimosso); } /* funzione per la stampa dei vini in base al codice */ void stampa_codice(nodo_albero_bin_t *nodo_p) { if (nodo_p != NULL) { stampa_codice(nodo_p->sx_p); printf("%s %s %s %s\n", nodo_p->nome_vino, nodo_p->codice_vino, nodo_p->anno_vino, nodo_p->luogo_vino); stampa_codice(nodo_p->dx_p); } } void stampa_vini(nodo_albero_bin_t *radice_p, int numero_vini, int scelta_ordinamento) { vino_t vini[numero_vini]; /* array per l'ordinamento */ /* trasferimento dei vini dall'albero in un array */ inserisci_vini_in_array(radice_p, vini, 0); switch(scelta_ordinamento) { case 1: /* ordina i vini in base al nome */ quicksort_nome(vini, 0, numero_vini - 1); break; case 3: /* ordina i vini in base all'anno */ quicksort_anno(vini, 0, numero_vini - 1); break; case 4: /* ordina i vini in base al luogo */ quicksort_luogo(vini, 0, numero_vini - 1); break; } stampa_array(numero_vini, vini); } /* funzione per il trasferimento dei vini dall'albero in un array */ void inserisci_vini_in_array(nodo_albero_bin_t *nodo_p, vino_t *vini, int i) { if (nodo_p->codice_vino != NULL) { inserisci_vini_in_array(nodo_p->sx_p, vini, i); strcpy(vini[i].nome_vino, nodo_p->nome_vino); strcpy(vini[i].codice_vino, nodo_p->codice_vino); strcpy(vini[i].anno_vino, nodo_p->anno_vino); strcpy(vini[i].luogo_vino, nodo_p->luogo_vino); i = i + 1; inserisci_vini_in_array(nodo_p->dx_p, vini, i); } } void quicksort_nome(vino_t a[], int sx, int dx) { int i, j; /* variabili di lavoro */ vino_t tmp, /* variabile usata per lo scambio */ pivot; /* puntatore all'elemento che fungera' da pivot */ /* si sceglie come pivot il valore centrale e si attua una tri-partizione */ /* scambiando gli elementi in modo che nella porzione a destra del pivot vi */ /* siano elementi maggiori del pivot e nella porzione sinistra quelli minori */ for (pivot = a[(sx + dx) / 2], i = sx, j = dx; (i <= j);) { while (strcmp(a[i].nome_vino, pivot.nome_vino) == -1) i++; while (strcmp(a[j].nome_vino, pivot.nome_vino) == 1) j--; if (i <= j) { if (i < j) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; } i++; j--; } } /* si invoca ricorsivamente la funzione sulle porzioni sinistra e destra */ if (sx < j) quicksort_nome(a, sx, j); if (i < dx) quicksort_nome(a, i, dx); } void quicksort_anno(vino_t a[], int sx, int dx) { int i, j; /* variabili di lavoro */ vino_t tmp, /* variabile usata per lo scambio */ pivot; /* puntatore all'elemento che fungera' da pivot */ /* si sceglie come pivot il valore centrale e si attua una tri-partizione */ /* scambiando gli elementi in modo che nella porzione a destra del pivot vi */ /* siano elementi maggiori del pivot e nella porzione sinistra quelli minori */ for (pivot = a[(sx + dx) / 2], i = sx, j = dx; (i <= j);) { while (strcmp(a[i].anno_vino, pivot.anno_vino) == -1) i++; while (strcmp(a[j].anno_vino, pivot.anno_vino) == 1) j--; if (i <= j) { if (i < j) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; } i++; j--; } } /* si invoca ricorsivamente la funzione sulle porzioni sinistra e destra */ if (sx < j) quicksort_anno(a, sx, j); if (i < dx) quicksort_anno(a, i, dx); } void quicksort_luogo(vino_t a[], int sx, int dx) { int i, j; /* variabili di lavoro */ vino_t tmp, /* variabile usata per lo scambio */ pivot; /* puntatore all'elemento che fungera' da pivot */ /* si sceglie come pivot il valore centrale e si attua una tri-partizione */ /* scambiando gli elementi in modo che nella porzione a destra del pivot vi */ /* siano elementi maggiori del pivot e nella porzione sinistra quelli minori */ for (pivot = a[(sx + dx) / 2], i = sx, j = dx; (i <= j);) { while (strcmp(a[i].luogo_vino, pivot.luogo_vino) == -1) i++; while (strcmp(a[j].luogo_vino, pivot.luogo_vino) == 1) j--; if (i <= j) { if (i < j) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; } i++; j--; } } /*Si invoca ricorsivamente la funzione sulle porzioni sinistra e destra*/ if (sx < j) quicksort_luogo(a, sx, j); if (i < dx) quicksort_luogo(a, i, dx); } void stampa_array(int numero_vini, vino_t *vini) { int i; /*Vengono stampati gli elementi ordinati*/ for(i = 0; i < numero_vini; i++) printf("\n%20s %4s %4s %s", vini[i].nome_vino, vini[i].codice_vino, vini[i].anno_vino, vini[i].luogo_vino); }'; } while ((strlen(codice_vino) != (LUNGHEZZA_CODICE - 1)) || (controllo_errori == 1)); carattere_acquisito = getchar(); /* se l'utente ha inserito un codice troppo lungo */ if (carattere_acquisito != '\n') /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); /* acquisizione del nome del vino da inserire */ /* non esce dal ciclo se l'utente non inserisce nessun nome */ do { printf("Scrivere il nome del vino da inserire: "); carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_NOME - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ')); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) nome_vino[i] = carattere_acquisito; else i--; } nome_vino[i] = 'Nel file allegato vi è il codice di un programma che gestisce un database di vini. Il mio problema è che ricevo un errore di segmentazione entrando nella funzione "inserisci_in_albero_bin". E' da un pò di giorni che stò cercando una soluzione ma non riesco a venirne a capo...qualcuno saprebbe aiutarmi??/******************************************************************/ /* Programma per manipolare un file contenente una lista di vini. */ /* Michele Petrocchi Matricola 256507 */ /******************************************************************/ /***********************/ /* inclusione librerie */ /***********************/ #include <stdio.h> #include <stdlib.h> #include <string.h> /*************************************/ /* Dichiarazione costanti simboliche */ /*************************************/ #define LUNGHEZZA_NOME 51 /* lunghezza della stringa del nome del vino */ #define LUNGHEZZA_CODICE 5 /* lunghezza della stringa del codice del vino */ #define LUNGHEZZA_ANNO_PRODUZIONE 5 /* lunghezza della stringa dell'anno di produzione del vino */ #define LUNGHEZZA_LUOGO_PRODUZIONE 51 /* lunghezza della stringa del luogo di produzione del vino */ #define PERCORSO_FILE "./file_vini" /* percorso del file di output */ /************************/ /* Defibizione dei tipi */ /************************/ typedef struct nodo_albero_bin { char nome_vino[LUNGHEZZA_NOME], /* nome del vino */ codice_vino[LUNGHEZZA_CODICE], /* codice del vino */ anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], /* anno di produzione del vino */ luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE]; /* luogo di produzione del vino */ struct nodo_albero_bin *sx_p, *dx_p; } nodo_albero_bin_t; typedef struct vino { char nome_vino[LUNGHEZZA_NOME], /* nome del vino */ codice_vino[LUNGHEZZA_CODICE], /* codice del vino */ anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], /* anno di produzione del vino */ luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE]; /* luogo di produzione del vino */ } vino_t; /********************************/ /* Dichiarazione delle funzioni */ /********************************/ int controllo_correttezza_file(nodo_albero_bin_t **, FILE *, int *); int inserisci_in_albero_bin(nodo_albero_bin_t ***, char[], char[], char[], char[]); int inserisci_nuovo_vino(nodo_albero_bin_t **); int rimuovi_vino(nodo_albero_bin_t **); int rimuovi_da_albero_bin(nodo_albero_bin_t ***, char[]); void stampa_codice(nodo_albero_bin_t *); void stampa_vini(nodo_albero_bin_t *, int, int); void inserisci_vini_in_array(nodo_albero_bin_t *, vino_t [], int); void quicksort_nome(vino_t [], int, int); void quicksort_anno(vino_t [], int, int); void quicksort_luogo(vino_t [], int, int); void stampa_array(int, vino_t *); /******************************/ /* Definizione delle funzioni */ /******************************/ int main (int argc, /* numero stringhe acquisite lancio comandi */ char *argv[]) /* stringhe acqusite dal lancio comandi */ { int esito = 0, esito_ordinamento = 0, esito_pulizia = 1, esito_pulizia_ordinamento = 1, scelta_utente = 0, scelta_ordinamento = 0, rimosso = 0, numero_vini = 0, controllo = 0; FILE *input; /* file da dove preleverò la lista dei vini */ nodo_albero_bin_t *radice_p = NULL; /* lavoro: puntatore alla radice dell'albero */ /* specifichiamo il file di input, quindi deve essere 1 il numero degli argomenti */ if(argc > 1) { /* apriamo il file specificato */ input = fopen(argv[1],"r"); /* se il file specificato esiste */ if (input != NULL) { /* acquisisci il numero di vini */ esito = fscanf(input, "%d", &numero_vini); /* se il numero di vini non è valido */ if (esito != 1 || numero_vini < 0) printf("Lettura del numero di vini non riuscita.\n\n"); else controllo = controllo_correttezza_file(&radice_p, input, &numero_vini); /* chiudere il file di input */ fclose(input); /* se non si sono verificati errori */ if (controllo != 1) { do { do { printf("\nL'utente digiti:"); printf("\n 1-Se si vuole procedere nell'inserimento di un nuovo vino"); printf("\n 2-Se si vuole procedere nella cancellazione di un altro"); printf("\n 3-Se si vuole visualizzare la lista con i vini inseriti"); printf("\n 4-Se si vuole uscire dal programma"); printf("\nPremere Invio per confermare.\n"); printf("\n"); /* pulizia del buffer della scanf */ esito_pulizia = scanf("\n"); esito = scanf("%d", &scelta_utente); while (getchar() != '\n'); } while ((scelta_utente < 1) || (scelta_utente > 4) || (esito != 1) || (esito_pulizia != 0)); switch (scelta_utente) { case 1: esito = inserisci_nuovo_vino(&radice_p); if (esito == 1) /* incrementa il numero di vini */ numero_vini++; printf(" (premere Invio per tornare al menù)\n"); while (getchar() != '\n'); break; case 2: rimosso = rimuovi_vino(&radice_p); /* se la rimozione è andata a buon fine */ if (rimosso == 1) /* decremento il numero di vini */ numero_vini--; printf(" (premere Invio per tornare al menù)\n"); while (getchar() != '\n'); break; case 3: do { printf("\nL'utente scelga l'ordine di visualizzaione dei vini:"); printf("\n 1-Nome"); printf("\n 2-Codice"); printf("\n 3-Luogo di produzione"); printf("\n 4-Anno di produzione"); printf("\nPremere Invio per confermare.\n"); printf("\n"); /* pulizia del buffer della scanf */ esito_pulizia_ordinamento = scanf("\n"); esito_ordinamento = scanf("%d", &scelta_ordinamento); while (getchar() != '\n'); } while ((scelta_utente < 1) || (scelta_utente > 4) || (esito_ordinamento != 1) || (esito_pulizia_ordinamento != 0)); /* visualizzare la lista dei vini inseriti */ printf("\n%d vini inseriti:\n", numero_vini); if (scelta_ordinamento == 2) /* stampa i vini in base al codice */ stampa_codice(radice_p); else stampa_vini(radice_p, numero_vini, scelta_ordinamento); printf("\n"); printf("(premere Invio per tornare al menù)\n"); while (getchar() != '\n'); break; case 4: /* se l'utente decide di uscire stampiamo un messaggio di saluto */ printf("\nGrazie per aver utilizzato questo programma!"); printf("\n\n"); break; } } while ((scelta_utente != 4)); } } else/* se il file specificato è uguale a NULL e quindi inesistente */ printf("\nIl file specificato non esiste!\n"); } else { /* se non è stato inserito il parametro di lancio del file */ printf("\nNon è stato immesso il nome del file da dove importare i dati riguardanti i vini!"); printf("\nrilanciare il programma con queste specifiche:"); printf("\n./<nome_eseguibile> <nome_file_input>\n"); printf("\nIl file può essere generato tramite il programma che viene lanciato con ./genera"); printf("\n(per la compilazione il comando è make genera_vini!)\n"); printf("\n(se il file è nella dir. di lavoro basta specificarne il nome!)\n\n"); } return(0); } int controllo_correttezza_file(nodo_albero_bin_t **radice_p, FILE * input, int *numero_vini) { int esito, controllo_errori = 0, i, j; char nome_vino[LUNGHEZZA_NOME], codice_vino[LUNGHEZZA_CODICE], anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE], carattere_acquisito = '~'; /* lavoro: variabile utilizzata */ /* per acquisizioni e controlli */ /* il ciclo acquisce i vini uno ad uno dal file e li inserisce nella struttura dati */ for (i = 0; ((i < *numero_vini) && (controllo_errori == 0)); i++) { /* scorro il file fino a trovare il carattere successivo */ while (carattere_acquisito != '\n') carattere_acquisito = getc(input); /* acquisizione del nome del vino */ for (j = 0, carattere_acquisito = '~'; ((j < (LUNGHEZZA_NOME - 1)) && (carattere_acquisito != ' ') && (carattere_acquisito != '\n') && (controllo_errori == 0)); j++) { carattere_acquisito = getc(input); if ((carattere_acquisito != ' ') && (carattere_acquisito != '\n')) nome_vino[j] = carattere_acquisito; else j--; } nome_vino[j] = '{parsed_message}'; /* se il nome del vino ha più caratteri del previsto */ if (carattere_acquisito != ' ') printf("I nomi che superano i %d caratteri sono stati abbreviati!\n", (LUNGHEZZA_NOME - 1)); /* spostati in avanti nel file in avanti fino ad arrivare all'inizio del codice */ while (carattere_acquisito != ' ') carattere_acquisito = getc(input); /* acquisizione del codice del vino */ for (j = 0; ((j < (LUNGHEZZA_CODICE - 1)) && (controllo_errori == 0)); j++) { codice_vino[j] = getc(input); /* se il codice vino ha meno caratteri del previsto */ if (codice_vino[j] == ' ') { printf("I codici dei vini devono contenere %d caratteri!\n", (LUNGHEZZA_CODICE - 1)); controllo_errori = 1; } /* se il codice contiene caratteri non alfanumerici */ else if (codice_vino[j] < '0' || (codice_vino[j] > '9' && codice_vino[j] < 'A') || (codice_vino[j] > 'Z' && codice_vino[j] < 'a') || codice_vino[j] > 'z') { printf("I codici dei vini possono contenere solo caratteri alfanumerici!\n"); /* forza la chiusura del programma */ controllo_errori = 1; } } codice_vino[j] = '{parsed_message}'; carattere_acquisito = getc(input); /* spostati in avanti nel file fino ad arrivare all'inizio dell'anno di produzione */ while (carattere_acquisito != ' ') carattere_acquisito = getc(input); /* acquisizione dell'anno di produzione */ for (j = 0, carattere_acquisito = '~'; ((j < (LUNGHEZZA_ANNO_PRODUZIONE - 1)) && (controllo_errori == 0)); j++) { anno_vino[j] = getc(input); /* se l'anno del vino ha meno caratteri del previsto */ if (anno_vino[j] == ' ') { printf("L'anno di produzione dei vini devono contenere %d caratteri!\n", (LUNGHEZZA_ANNO_PRODUZIONE - 1)); controllo_errori = 1; } /* se l'anno contiene caratteri non numerici */ else if (anno_vino[j] < '0' || anno_vino[j] > '9' ) { printf("Gli anni dei vini possono contenere solo caratteri numerici!\n"); /* forza la chiusura del programma */ controllo_errori = 1; } } anno_vino[j] = '{parsed_message}'; carattere_acquisito = getc(input); /* spostati in avanti nel file in avanti fino ad arrivare all'inizio del luogo di produzione */ while (carattere_acquisito != ' ') carattere_acquisito = getc(input); /* acquisizione del luogo di produzione del vino */ for (j = 0, carattere_acquisito = '~'; ((j < (LUNGHEZZA_LUOGO_PRODUZIONE - 1)) && (carattere_acquisito != ' ') && (carattere_acquisito != '\n') && (controllo_errori == 0)); j++) { carattere_acquisito = getc(input); if ((carattere_acquisito != ' ') && (carattere_acquisito != '\n')) luogo_vino[j] = carattere_acquisito; else j--; } luogo_vino[j] = '{parsed_message}'; /* se il luogo di produzione del vino ha più caratteri del previsto */ if ((carattere_acquisito != '\n') && (controllo_errori == 0)) printf("I luoghi che superano i %d caratteri sono stati abbreviati!\n", (LUNGHEZZA_LUOGO_PRODUZIONE - 1)); /* inserimento del vino nell'albero ordinato secondo il codice */ esito = inserisci_in_albero_bin(&radice_p, codice_vino, nome_vino, anno_vino, luogo_vino); /* se l'inserimento non è andato a buon fine */ if (esito == 0) { printf("\nIl vino con codice \"%s\" non è stato inserito perchè già presente nella lista!\n", codice_vino); /* decrementa il numero dei vini del numero di inserimenti falliti */ *numero_vini = *numero_vini - 1; } } return (controllo_errori); } /* Algoritmo per l'inserimento di un vino nell'albero binario ordinato secondo il codice */ int inserisci_in_albero_bin(nodo_albero_bin_t ***radice_p, /* lavoro: puntatore al puntatore alla radice dell'albero */ char codice_vino[], /* input: codice del vino da inserire */ char nome_vino[], /* input: nome del vino da inserire */ char anno_vino[], /* input: anno di produzione del vino da inserire */ char luogo_vino[]) /* input: luogo di produzione del vino da inserire */ { int inserito, /* output: esito dell'inserimento */ i; /* lavoro: indice per i cicli for */ nodo_albero_bin_t *nodo_p, /* lavoro: puntatore ad un nodo */ *padre_p, /* lavoro: puntatore al padre del nodo_p */ *nuovo_p; /* lavoro: puntatore al nodo che conterrà il nuovo vino */ /* nodo_p e padre_p vengono inizializzati con l'indirizzo della radice e ad ogni */ /* iterazione padre_p prende l'indirizzo di nodo_p.nodo_p prende l'indirizzo del */ /* suo figlio sx o dx a seconda che il codice da inserire sia < o >= al codice */ /* puntato da nodo_p.Il ciclo termina quando nodo_p punta a NULL oppure ad un */ /* elemento che contiene un codice uguale a quello da inserire. */ for (nodo_p = padre_p = **radice_p; ((nodo_p != NULL) && (strcmp(nodo_p->codice_vino, codice_vino) != 0)); padre_p = nodo_p, nodo_p = (strcmp(codice_vino, nodo_p->codice_vino) < 0)? nodo_p->sx_p: nodo_p->dx_p); /* il vino non verrà inserito se era già presente, ovvero se nodo_p non punta a NULL */ if (nodo_p != NULL) inserito = 0; else { inserito = 1; /* viene allocata memoria per il nuovo nodo */ nuovo_p = (nodo_albero_bin_t *)malloc(sizeof(nodo_albero_bin_t)); /* inserimento del codice del vino */ for (i = 0; (i < LUNGHEZZA_CODICE); i++) nuovo_p->codice_vino[i] = codice_vino[i]; /* inserimento del nome del vino */ for (i = 0; (i < LUNGHEZZA_NOME); i++) nuovo_p->nome_vino[i] = nome_vino[i]; /* inserimento dell'anno di produzione del vino */ for (i = 0; (i < LUNGHEZZA_ANNO_PRODUZIONE); i++) nuovo_p->anno_vino[i] = anno_vino[i]; /* inserimento del luogo di produzione del vino */ for (i = 0; (i < LUNGHEZZA_LUOGO_PRODUZIONE); i++) nuovo_p->luogo_vino[i] = luogo_vino[i]; /* i puntatori vengono inizializzati a NULL */ nuovo_p->sx_p = nuovo_p->dx_p = NULL; /* se il nodo si trova in cima all'albero diventa la radice */ if (nodo_p == **radice_p) **radice_p = nuovo_p; /* se il codice inserito è inferiore a quello contenuto nel nodo padre */ else if (strcmp(codice_vino, padre_p->codice_vino) < 0) /* il nuovo nodo diventa figlio sinistro */ padre_p->sx_p = nuovo_p; else /* il nuovo nodo diventa figlio destro */ padre_p->dx_p = nuovo_p; } /* viene restituito il valore di esito dell'inserimento */ return(inserito); } /* Funzione per l'inserimento di un nuovo vino */ int inserisci_nuovo_vino(nodo_albero_bin_t **radice_p) /* lavoro: puntatore alla radice dell'albero */ { char nome_vino[LUNGHEZZA_NOME], /* input: nome del vino da inserire */ codice_vino[LUNGHEZZA_CODICE], /* input: codice del vino da inserire */ anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], /* input: anno di produzione del vino da inserire */ luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE], /* input: luogo di produzione del vino da inserire */ carattere_acquisito = '~'; /* lavoro: variabile usata per acquisizioni e controlli */ int inserito = 0, /* output: esito dell'inserimento */ controllo_errori, /* lavoro: variabile di controllo */ i; /* lavoro: indice per i cicli for */ /* acquisizione del codice del vino da inserire */ printf("\nScrivere il codice del vino da inserire: "); /* non esce dal ciclo se il codice inserito da tastiera è troppo corto */ do { controllo_errori = 0; carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_CODICE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ') && (controllo_errori == 0)); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) codice_vino[i] = carattere_acquisito; else { i--; printf("\nIl codice deve contenere %d caratteri alfanumerici!\n", (LUNGHEZZA_CODICE - 1)); printf("\nRiscrivere il codice del vino: "); } /* se il codice contiene caratteri non alfanumerici */ if (codice_vino[i] < '0' || (codice_vino[i] > '9' && codice_vino[i] < 'A') || (codice_vino[i] > 'Z' && codice_vino[i] < 'a') || codice_vino[i] > 'z') { controllo_errori = 1; printf("\nRiscrivere il codice del vino: "); } } codice_vino[i] = '{parsed_message}'; } while ((strlen(codice_vino) != (LUNGHEZZA_CODICE - 1)) || (controllo_errori == 1)); carattere_acquisito = getchar(); /* se l'utente ha inserito un codice troppo lungo */ if (carattere_acquisito != '\n') /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); /* acquisizione del nome del vino da inserire */ /* non esce dal ciclo se l'utente non inserisce nessun nome */ do { printf("Scrivere il nome del vino da inserire: "); carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_NOME - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ')); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) nome_vino[i] = carattere_acquisito; else i--; } nome_vino[i] = '{parsed_message}'; /* se l'utente ha inserito un nome troppo lungo */ if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) { printf("\nIl nome è stato abbreviato a %d caratteri!\n\n", (LUNGHEZZA_NOME - 1)); /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); } } while (strlen(nome_vino) == 0); /* acquisizione dell'anno di produzione del vino da inserire */ printf("Scrivere l'anno di produzione del vino da inserire: "); /* non esce dal ciclo se l'anno inserito da tastiera è troppo corto */ do { controllo_errori = 0; carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_ANNO_PRODUZIONE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ') && (controllo_errori == 0)); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) anno_vino[i] = carattere_acquisito; else { i--; printf("\nL'anno deve contenere %d caratteri numerici!\n", (LUNGHEZZA_ANNO_PRODUZIONE - 1)); printf("\nRiscrivere l'anno di produzione del vino: "); } /* se l'anno contiene caratteri non numerici */ if (anno_vino[i] < '0' || anno_vino[i] > '9') controllo_errori = 1; } anno_vino[i] = '{parsed_message}'; } while ((strlen(anno_vino) != (LUNGHEZZA_ANNO_PRODUZIONE - 1)) || (controllo_errori == 1)); carattere_acquisito = getchar(); /* se l'utente ha inserito un anno troppo lungo */ if (carattere_acquisito != '\n') /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); /* acquisizione del luogo di produzione del vino da inserire */ /* non esce dal ciclo se l'utente non inserisce nessun luogo */ do { printf("Scrivere il luogo di produzione del vino da inserire: "); carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_LUOGO_PRODUZIONE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ')); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) luogo_vino[i] = carattere_acquisito; else i--; } luogo_vino[i] = '{parsed_message}'; /* se l'utente ha inserito un luogo troppo lungo */ if (carattere_acquisito != '\n') { printf("\nIl luogo è stato abbreviato a %d caratteri!\n\n", (LUNGHEZZA_LUOGO_PRODUZIONE - 1)); /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); } } while (strlen(luogo_vino) == 0); /* inserimento del vino nell'albero */ inserito = inserisci_in_albero_bin(&radice_p, codice_vino, nome_vino, anno_vino, luogo_vino); /* se l'inserimento è andato a buon fine */ if (inserito != 1) printf("\nVino \"%s\" già presente!", codice_vino); else printf("\nIl vino è stato inserito."); /* viene restituito l'esito dell'inserimento */ return (inserito); } int rimuovi_vino(nodo_albero_bin_t **radice_p) /* lavoro: puntatore alla radice dell'albero */ { char codice_vino[LUNGHEZZA_CODICE], /* input: codice del vino da rimuovere */ carattere_acquisito = '~'; /* lavoro: variabile usata per acquisizioni e controlli */ int rimosso = 0, /* output: esito rimozione */ controllo_errori, /* lavoro: variabile di controllo */ i; /* lavoro: indice per i cicli */ /* acquisizione del codice del vino da rimuovere */ printf("\nScrivere il codice del vino da rimuovere: "); /* non esce dal ciclo se l'utente non inserisce un codice corretto */ do { controllo_errori = 0; carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_CODICE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ') && (controllo_errori == 0)); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) codice_vino[i] = carattere_acquisito; else { i--; printf("\nIl codice deve contenere %d caratteri alfanumerici!\n", (LUNGHEZZA_CODICE - 1)); printf("\nRiscrivere il codice del vino: "); } /* se il codice contiene caratteri non alfanumerici */ if (codice_vino[i] < '0' || (codice_vino[i] > '9' && codice_vino[i] < 'A') || (codice_vino[i] > 'Z' && codice_vino[i] < 'a') || codice_vino[i] > 'z') { controllo_errori = 1; printf("\nRiscrivere il codice del vino: "); } } codice_vino[i] = '{parsed_message}'; } while ((strlen(codice_vino) != (LUNGHEZZA_CODICE - 1)) || (controllo_errori == 1)); carattere_acquisito = getchar(); /* se l'utente ha inserito un codice troppo lungo */ if (carattere_acquisito != '\n') /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); /* rimozione del vino dall'albero */ rimosso = rimuovi_da_albero_bin(&radice_p, codice_vino); if (rimosso == 1) printf("\nIl vino è stato rimosso!"); else printf("\nIl vino non è presente nella lista!"); /* viene restituito l'esito della rimozione */ return (rimosso); } /* Algoritmo per la rimozione di un vino dall'albero binario */ int rimuovi_da_albero_bin(nodo_albero_bin_t ***radice_p, /* lavoro: puntatore al puntatore alla radice dell'albero */ char codice_vino[]) /* input: codice del vino da rimuovere */ { int rimosso, /* output: esito della rimozione */ i; /* lavoro: contatore per i cicli for */ nodo_albero_bin_t *nodo_p, /* lavoro: puntatore a un nodo */ *padre_p, /* lavoro: padre di nodo_p */ *sost_p; /* lavoro: sostituto di nodo_p */ /* nodo_p e padre_p vengono inizializzati con l'indirizzo della radice e ad ogni */ /* iterazione padre_p prende l'indirizzo di nodo_p.nodo_p prende l'indirizzo del */ /* suo figlio sx o dx a seconda che il codice da inserire sia < o >= al codice */ /* puntato da nodo_p.Il ciclo termina quando nodo_p punta a NULL oppure ad un */ /* elemento che contiene un codice uguale a quello da rimuovere. */ for (nodo_p = padre_p = **radice_p; ((nodo_p != NULL) && (strcmp(nodo_p->codice_vino,codice_vino) != 0)); padre_p = nodo_p, nodo_p = (strcmp(codice_vino,nodo_p->codice_vino) < 0)? nodo_p->sx_p: nodo_p->dx_p); /* il vino non verrà rimosso se non era presente, ovvero se nodo_p punta a NULL */ if (nodo_p == NULL) rimosso = 0; else { rimosso = 1; /* se nodo_p non ha figlio sx */ if (nodo_p->sx_p == NULL) { /* se nodo_p si trova in cima all'albero */ if (nodo_p == **radice_p) /* il figlio destro del nodo diventa la radice */ **radice_p = nodo_p->dx_p; /* altrimenti se il codice da rimuovere è minore di quello del padre */ else if (strcmp(codice_vino, padre_p->codice_vino) < 0) /* il figlio destro del nodo_p, diventa figlio sinistro del padre */ padre_p->sx_p = nodo_p->dx_p; else /* il figlio destro del nodo_p, diventa figlio destro del padre */ padre_p->dx_p = nodo_p->dx_p; } /* altrimenti, se nodo_p non ha figlio destro */ else if (nodo_p->dx_p == NULL) { /* se nodo_p si trova in cima all'albero */ if (nodo_p == **radice_p) /* il figlio sinistro del nodo diventa la radice */ **radice_p = nodo_p->sx_p; /* altrimenti, se il codice da rimuovere è minore di quello del padre */ else if (strcmp(codice_vino, padre_p->codice_vino) < 0) /* il figlio sinistro del nodo_p diventa figlio sinistro del padre */ padre_p->sx_p = nodo_p->sx_p; else /* il figlio sinistro del nodo_p diventa figlio destro del padre */ padre_p->dx_p = nodo_p->sx_p; } /* altrimenti, se il nodo_p ha entrambi i figli */ else { /* sost_p prende l'indirizzo contenuto in nodo_p */ sost_p = nodo_p; /* ad ogni iterazione del ciclo, padre_p prende l'indirizzo di nodo_p e nodo_p prende */ /* l'indirizzo del figlio destro; il ciclo termina quando nodo_p non ha figlio destro */ for (padre_p = sost_p, nodo_p = sost_p->sx_p; (nodo_p->dx_p != NULL); padre_p = nodo_p, nodo_p = nodo_p->dx_p); /* sostuzione del codice del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_CODICE); i++) sost_p->codice_vino[i] = nodo_p->codice_vino[i]; /* sostituzione del nome del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_NOME); i++) sost_p->nome_vino[i] = nodo_p->nome_vino[i]; /* sostuzione dell'anno del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_ANNO_PRODUZIONE); i++) sost_p->anno_vino[i] = nodo_p->anno_vino[i]; /* sostituzione del luogo del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_LUOGO_PRODUZIONE); i++) sost_p->anno_vino[i] = nodo_p->anno_vino[i]; /* se padre_p e sost_p puntano allo stesso nodo */ if (padre_p == sost_p) /* il figlio sinistro del nodo_p diventa figlio sinistro del padre_p */ padre_p->sx_p = nodo_p->sx_p; else /* il figlio sinistro del nodo_p diventa figlio destro del padre_p */ padre_p->dx_p = nodo_p->sx_p; } /* il nodo puntato da nodo_p viene rimosso dalla memoria */ free(nodo_p); } return(rimosso); } /* funzione per la stampa dei vini in base al codice */ void stampa_codice(nodo_albero_bin_t *nodo_p) { if (nodo_p != NULL) { stampa_codice(nodo_p->sx_p); printf("%s %s %s %s\n", nodo_p->nome_vino, nodo_p->codice_vino, nodo_p->anno_vino, nodo_p->luogo_vino); stampa_codice(nodo_p->dx_p); } } void stampa_vini(nodo_albero_bin_t *radice_p, int numero_vini, int scelta_ordinamento) { vino_t vini[numero_vini]; /* array per l'ordinamento */ /* trasferimento dei vini dall'albero in un array */ inserisci_vini_in_array(radice_p, vini, 0); switch(scelta_ordinamento) { case 1: /* ordina i vini in base al nome */ quicksort_nome(vini, 0, numero_vini - 1); break; case 3: /* ordina i vini in base all'anno */ quicksort_anno(vini, 0, numero_vini - 1); break; case 4: /* ordina i vini in base al luogo */ quicksort_luogo(vini, 0, numero_vini - 1); break; } stampa_array(numero_vini, vini); } /* funzione per il trasferimento dei vini dall'albero in un array */ void inserisci_vini_in_array(nodo_albero_bin_t *nodo_p, vino_t *vini, int i) { if (nodo_p->codice_vino != NULL) { inserisci_vini_in_array(nodo_p->sx_p, vini, i); strcpy(vini[i].nome_vino, nodo_p->nome_vino); strcpy(vini[i].codice_vino, nodo_p->codice_vino); strcpy(vini[i].anno_vino, nodo_p->anno_vino); strcpy(vini[i].luogo_vino, nodo_p->luogo_vino); i = i + 1; inserisci_vini_in_array(nodo_p->dx_p, vini, i); } } void quicksort_nome(vino_t a[], int sx, int dx) { int i, j; /* variabili di lavoro */ vino_t tmp, /* variabile usata per lo scambio */ pivot; /* puntatore all'elemento che fungera' da pivot */ /* si sceglie come pivot il valore centrale e si attua una tri-partizione */ /* scambiando gli elementi in modo che nella porzione a destra del pivot vi */ /* siano elementi maggiori del pivot e nella porzione sinistra quelli minori */ for (pivot = a[(sx + dx) / 2], i = sx, j = dx; (i <= j);) { while (strcmp(a[i].nome_vino, pivot.nome_vino) == -1) i++; while (strcmp(a[j].nome_vino, pivot.nome_vino) == 1) j--; if (i <= j) { if (i < j) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; } i++; j--; } } /* si invoca ricorsivamente la funzione sulle porzioni sinistra e destra */ if (sx < j) quicksort_nome(a, sx, j); if (i < dx) quicksort_nome(a, i, dx); } void quicksort_anno(vino_t a[], int sx, int dx) { int i, j; /* variabili di lavoro */ vino_t tmp, /* variabile usata per lo scambio */ pivot; /* puntatore all'elemento che fungera' da pivot */ /* si sceglie come pivot il valore centrale e si attua una tri-partizione */ /* scambiando gli elementi in modo che nella porzione a destra del pivot vi */ /* siano elementi maggiori del pivot e nella porzione sinistra quelli minori */ for (pivot = a[(sx + dx) / 2], i = sx, j = dx; (i <= j);) { while (strcmp(a[i].anno_vino, pivot.anno_vino) == -1) i++; while (strcmp(a[j].anno_vino, pivot.anno_vino) == 1) j--; if (i <= j) { if (i < j) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; } i++; j--; } } /* si invoca ricorsivamente la funzione sulle porzioni sinistra e destra */ if (sx < j) quicksort_anno(a, sx, j); if (i < dx) quicksort_anno(a, i, dx); } void quicksort_luogo(vino_t a[], int sx, int dx) { int i, j; /* variabili di lavoro */ vino_t tmp, /* variabile usata per lo scambio */ pivot; /* puntatore all'elemento che fungera' da pivot */ /* si sceglie come pivot il valore centrale e si attua una tri-partizione */ /* scambiando gli elementi in modo che nella porzione a destra del pivot vi */ /* siano elementi maggiori del pivot e nella porzione sinistra quelli minori */ for (pivot = a[(sx + dx) / 2], i = sx, j = dx; (i <= j);) { while (strcmp(a[i].luogo_vino, pivot.luogo_vino) == -1) i++; while (strcmp(a[j].luogo_vino, pivot.luogo_vino) == 1) j--; if (i <= j) { if (i < j) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; } i++; j--; } } /*Si invoca ricorsivamente la funzione sulle porzioni sinistra e destra*/ if (sx < j) quicksort_luogo(a, sx, j); if (i < dx) quicksort_luogo(a, i, dx); } void stampa_array(int numero_vini, vino_t *vini) { int i; /*Vengono stampati gli elementi ordinati*/ for(i = 0; i < numero_vini; i++) printf("\n%20s %4s %4s %s", vini[i].nome_vino, vini[i].codice_vino, vini[i].anno_vino, vini[i].luogo_vino); }'; /* se l'utente ha inserito un nome troppo lungo */ if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) { printf("\nIl nome è stato abbreviato a %d caratteri!\n\n", (LUNGHEZZA_NOME - 1)); /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); } } while (strlen(nome_vino) == 0); /* acquisizione dell'anno di produzione del vino da inserire */ printf("Scrivere l'anno di produzione del vino da inserire: "); /* non esce dal ciclo se l'anno inserito da tastiera è troppo corto */ do { controllo_errori = 0; carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_ANNO_PRODUZIONE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ') && (controllo_errori == 0)); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) anno_vino[i] = carattere_acquisito; else { i--; printf("\nL'anno deve contenere %d caratteri numerici!\n", (LUNGHEZZA_ANNO_PRODUZIONE - 1)); printf("\nRiscrivere l'anno di produzione del vino: "); } /* se l'anno contiene caratteri non numerici */ if (anno_vino[i] < '0' || anno_vino[i] > '9') controllo_errori = 1; } anno_vino[i] = 'Nel file allegato vi è il codice di un programma che gestisce un database di vini. Il mio problema è che ricevo un errore di segmentazione entrando nella funzione "inserisci_in_albero_bin". E' da un pò di giorni che stò cercando una soluzione ma non riesco a venirne a capo...qualcuno saprebbe aiutarmi??/******************************************************************/ /* Programma per manipolare un file contenente una lista di vini. */ /* Michele Petrocchi Matricola 256507 */ /******************************************************************/ /***********************/ /* inclusione librerie */ /***********************/ #include <stdio.h> #include <stdlib.h> #include <string.h> /*************************************/ /* Dichiarazione costanti simboliche */ /*************************************/ #define LUNGHEZZA_NOME 51 /* lunghezza della stringa del nome del vino */ #define LUNGHEZZA_CODICE 5 /* lunghezza della stringa del codice del vino */ #define LUNGHEZZA_ANNO_PRODUZIONE 5 /* lunghezza della stringa dell'anno di produzione del vino */ #define LUNGHEZZA_LUOGO_PRODUZIONE 51 /* lunghezza della stringa del luogo di produzione del vino */ #define PERCORSO_FILE "./file_vini" /* percorso del file di output */ /************************/ /* Defibizione dei tipi */ /************************/ typedef struct nodo_albero_bin { char nome_vino[LUNGHEZZA_NOME], /* nome del vino */ codice_vino[LUNGHEZZA_CODICE], /* codice del vino */ anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], /* anno di produzione del vino */ luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE]; /* luogo di produzione del vino */ struct nodo_albero_bin *sx_p, *dx_p; } nodo_albero_bin_t; typedef struct vino { char nome_vino[LUNGHEZZA_NOME], /* nome del vino */ codice_vino[LUNGHEZZA_CODICE], /* codice del vino */ anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], /* anno di produzione del vino */ luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE]; /* luogo di produzione del vino */ } vino_t; /********************************/ /* Dichiarazione delle funzioni */ /********************************/ int controllo_correttezza_file(nodo_albero_bin_t **, FILE *, int *); int inserisci_in_albero_bin(nodo_albero_bin_t ***, char[], char[], char[], char[]); int inserisci_nuovo_vino(nodo_albero_bin_t **); int rimuovi_vino(nodo_albero_bin_t **); int rimuovi_da_albero_bin(nodo_albero_bin_t ***, char[]); void stampa_codice(nodo_albero_bin_t *); void stampa_vini(nodo_albero_bin_t *, int, int); void inserisci_vini_in_array(nodo_albero_bin_t *, vino_t [], int); void quicksort_nome(vino_t [], int, int); void quicksort_anno(vino_t [], int, int); void quicksort_luogo(vino_t [], int, int); void stampa_array(int, vino_t *); /******************************/ /* Definizione delle funzioni */ /******************************/ int main (int argc, /* numero stringhe acquisite lancio comandi */ char *argv[]) /* stringhe acqusite dal lancio comandi */ { int esito = 0, esito_ordinamento = 0, esito_pulizia = 1, esito_pulizia_ordinamento = 1, scelta_utente = 0, scelta_ordinamento = 0, rimosso = 0, numero_vini = 0, controllo = 0; FILE *input; /* file da dove preleverò la lista dei vini */ nodo_albero_bin_t *radice_p = NULL; /* lavoro: puntatore alla radice dell'albero */ /* specifichiamo il file di input, quindi deve essere 1 il numero degli argomenti */ if(argc > 1) { /* apriamo il file specificato */ input = fopen(argv[1],"r"); /* se il file specificato esiste */ if (input != NULL) { /* acquisisci il numero di vini */ esito = fscanf(input, "%d", &numero_vini); /* se il numero di vini non è valido */ if (esito != 1 || numero_vini < 0) printf("Lettura del numero di vini non riuscita.\n\n"); else controllo = controllo_correttezza_file(&radice_p, input, &numero_vini); /* chiudere il file di input */ fclose(input); /* se non si sono verificati errori */ if (controllo != 1) { do { do { printf("\nL'utente digiti:"); printf("\n 1-Se si vuole procedere nell'inserimento di un nuovo vino"); printf("\n 2-Se si vuole procedere nella cancellazione di un altro"); printf("\n 3-Se si vuole visualizzare la lista con i vini inseriti"); printf("\n 4-Se si vuole uscire dal programma"); printf("\nPremere Invio per confermare.\n"); printf("\n"); /* pulizia del buffer della scanf */ esito_pulizia = scanf("\n"); esito = scanf("%d", &scelta_utente); while (getchar() != '\n'); } while ((scelta_utente < 1) || (scelta_utente > 4) || (esito != 1) || (esito_pulizia != 0)); switch (scelta_utente) { case 1: esito = inserisci_nuovo_vino(&radice_p); if (esito == 1) /* incrementa il numero di vini */ numero_vini++; printf(" (premere Invio per tornare al menù)\n"); while (getchar() != '\n'); break; case 2: rimosso = rimuovi_vino(&radice_p); /* se la rimozione è andata a buon fine */ if (rimosso == 1) /* decremento il numero di vini */ numero_vini--; printf(" (premere Invio per tornare al menù)\n"); while (getchar() != '\n'); break; case 3: do { printf("\nL'utente scelga l'ordine di visualizzaione dei vini:"); printf("\n 1-Nome"); printf("\n 2-Codice"); printf("\n 3-Luogo di produzione"); printf("\n 4-Anno di produzione"); printf("\nPremere Invio per confermare.\n"); printf("\n"); /* pulizia del buffer della scanf */ esito_pulizia_ordinamento = scanf("\n"); esito_ordinamento = scanf("%d", &scelta_ordinamento); while (getchar() != '\n'); } while ((scelta_utente < 1) || (scelta_utente > 4) || (esito_ordinamento != 1) || (esito_pulizia_ordinamento != 0)); /* visualizzare la lista dei vini inseriti */ printf("\n%d vini inseriti:\n", numero_vini); if (scelta_ordinamento == 2) /* stampa i vini in base al codice */ stampa_codice(radice_p); else stampa_vini(radice_p, numero_vini, scelta_ordinamento); printf("\n"); printf("(premere Invio per tornare al menù)\n"); while (getchar() != '\n'); break; case 4: /* se l'utente decide di uscire stampiamo un messaggio di saluto */ printf("\nGrazie per aver utilizzato questo programma!"); printf("\n\n"); break; } } while ((scelta_utente != 4)); } } else/* se il file specificato è uguale a NULL e quindi inesistente */ printf("\nIl file specificato non esiste!\n"); } else { /* se non è stato inserito il parametro di lancio del file */ printf("\nNon è stato immesso il nome del file da dove importare i dati riguardanti i vini!"); printf("\nrilanciare il programma con queste specifiche:"); printf("\n./<nome_eseguibile> <nome_file_input>\n"); printf("\nIl file può essere generato tramite il programma che viene lanciato con ./genera"); printf("\n(per la compilazione il comando è make genera_vini!)\n"); printf("\n(se il file è nella dir. di lavoro basta specificarne il nome!)\n\n"); } return(0); } int controllo_correttezza_file(nodo_albero_bin_t **radice_p, FILE * input, int *numero_vini) { int esito, controllo_errori = 0, i, j; char nome_vino[LUNGHEZZA_NOME], codice_vino[LUNGHEZZA_CODICE], anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE], carattere_acquisito = '~'; /* lavoro: variabile utilizzata */ /* per acquisizioni e controlli */ /* il ciclo acquisce i vini uno ad uno dal file e li inserisce nella struttura dati */ for (i = 0; ((i < *numero_vini) && (controllo_errori == 0)); i++) { /* scorro il file fino a trovare il carattere successivo */ while (carattere_acquisito != '\n') carattere_acquisito = getc(input); /* acquisizione del nome del vino */ for (j = 0, carattere_acquisito = '~'; ((j < (LUNGHEZZA_NOME - 1)) && (carattere_acquisito != ' ') && (carattere_acquisito != '\n') && (controllo_errori == 0)); j++) { carattere_acquisito = getc(input); if ((carattere_acquisito != ' ') && (carattere_acquisito != '\n')) nome_vino[j] = carattere_acquisito; else j--; } nome_vino[j] = '{parsed_message}'; /* se il nome del vino ha più caratteri del previsto */ if (carattere_acquisito != ' ') printf("I nomi che superano i %d caratteri sono stati abbreviati!\n", (LUNGHEZZA_NOME - 1)); /* spostati in avanti nel file in avanti fino ad arrivare all'inizio del codice */ while (carattere_acquisito != ' ') carattere_acquisito = getc(input); /* acquisizione del codice del vino */ for (j = 0; ((j < (LUNGHEZZA_CODICE - 1)) && (controllo_errori == 0)); j++) { codice_vino[j] = getc(input); /* se il codice vino ha meno caratteri del previsto */ if (codice_vino[j] == ' ') { printf("I codici dei vini devono contenere %d caratteri!\n", (LUNGHEZZA_CODICE - 1)); controllo_errori = 1; } /* se il codice contiene caratteri non alfanumerici */ else if (codice_vino[j] < '0' || (codice_vino[j] > '9' && codice_vino[j] < 'A') || (codice_vino[j] > 'Z' && codice_vino[j] < 'a') || codice_vino[j] > 'z') { printf("I codici dei vini possono contenere solo caratteri alfanumerici!\n"); /* forza la chiusura del programma */ controllo_errori = 1; } } codice_vino[j] = '{parsed_message}'; carattere_acquisito = getc(input); /* spostati in avanti nel file fino ad arrivare all'inizio dell'anno di produzione */ while (carattere_acquisito != ' ') carattere_acquisito = getc(input); /* acquisizione dell'anno di produzione */ for (j = 0, carattere_acquisito = '~'; ((j < (LUNGHEZZA_ANNO_PRODUZIONE - 1)) && (controllo_errori == 0)); j++) { anno_vino[j] = getc(input); /* se l'anno del vino ha meno caratteri del previsto */ if (anno_vino[j] == ' ') { printf("L'anno di produzione dei vini devono contenere %d caratteri!\n", (LUNGHEZZA_ANNO_PRODUZIONE - 1)); controllo_errori = 1; } /* se l'anno contiene caratteri non numerici */ else if (anno_vino[j] < '0' || anno_vino[j] > '9' ) { printf("Gli anni dei vini possono contenere solo caratteri numerici!\n"); /* forza la chiusura del programma */ controllo_errori = 1; } } anno_vino[j] = '{parsed_message}'; carattere_acquisito = getc(input); /* spostati in avanti nel file in avanti fino ad arrivare all'inizio del luogo di produzione */ while (carattere_acquisito != ' ') carattere_acquisito = getc(input); /* acquisizione del luogo di produzione del vino */ for (j = 0, carattere_acquisito = '~'; ((j < (LUNGHEZZA_LUOGO_PRODUZIONE - 1)) && (carattere_acquisito != ' ') && (carattere_acquisito != '\n') && (controllo_errori == 0)); j++) { carattere_acquisito = getc(input); if ((carattere_acquisito != ' ') && (carattere_acquisito != '\n')) luogo_vino[j] = carattere_acquisito; else j--; } luogo_vino[j] = '{parsed_message}'; /* se il luogo di produzione del vino ha più caratteri del previsto */ if ((carattere_acquisito != '\n') && (controllo_errori == 0)) printf("I luoghi che superano i %d caratteri sono stati abbreviati!\n", (LUNGHEZZA_LUOGO_PRODUZIONE - 1)); /* inserimento del vino nell'albero ordinato secondo il codice */ esito = inserisci_in_albero_bin(&radice_p, codice_vino, nome_vino, anno_vino, luogo_vino); /* se l'inserimento non è andato a buon fine */ if (esito == 0) { printf("\nIl vino con codice \"%s\" non è stato inserito perchè già presente nella lista!\n", codice_vino); /* decrementa il numero dei vini del numero di inserimenti falliti */ *numero_vini = *numero_vini - 1; } } return (controllo_errori); } /* Algoritmo per l'inserimento di un vino nell'albero binario ordinato secondo il codice */ int inserisci_in_albero_bin(nodo_albero_bin_t ***radice_p, /* lavoro: puntatore al puntatore alla radice dell'albero */ char codice_vino[], /* input: codice del vino da inserire */ char nome_vino[], /* input: nome del vino da inserire */ char anno_vino[], /* input: anno di produzione del vino da inserire */ char luogo_vino[]) /* input: luogo di produzione del vino da inserire */ { int inserito, /* output: esito dell'inserimento */ i; /* lavoro: indice per i cicli for */ nodo_albero_bin_t *nodo_p, /* lavoro: puntatore ad un nodo */ *padre_p, /* lavoro: puntatore al padre del nodo_p */ *nuovo_p; /* lavoro: puntatore al nodo che conterrà il nuovo vino */ /* nodo_p e padre_p vengono inizializzati con l'indirizzo della radice e ad ogni */ /* iterazione padre_p prende l'indirizzo di nodo_p.nodo_p prende l'indirizzo del */ /* suo figlio sx o dx a seconda che il codice da inserire sia < o >= al codice */ /* puntato da nodo_p.Il ciclo termina quando nodo_p punta a NULL oppure ad un */ /* elemento che contiene un codice uguale a quello da inserire. */ for (nodo_p = padre_p = **radice_p; ((nodo_p != NULL) && (strcmp(nodo_p->codice_vino, codice_vino) != 0)); padre_p = nodo_p, nodo_p = (strcmp(codice_vino, nodo_p->codice_vino) < 0)? nodo_p->sx_p: nodo_p->dx_p); /* il vino non verrà inserito se era già presente, ovvero se nodo_p non punta a NULL */ if (nodo_p != NULL) inserito = 0; else { inserito = 1; /* viene allocata memoria per il nuovo nodo */ nuovo_p = (nodo_albero_bin_t *)malloc(sizeof(nodo_albero_bin_t)); /* inserimento del codice del vino */ for (i = 0; (i < LUNGHEZZA_CODICE); i++) nuovo_p->codice_vino[i] = codice_vino[i]; /* inserimento del nome del vino */ for (i = 0; (i < LUNGHEZZA_NOME); i++) nuovo_p->nome_vino[i] = nome_vino[i]; /* inserimento dell'anno di produzione del vino */ for (i = 0; (i < LUNGHEZZA_ANNO_PRODUZIONE); i++) nuovo_p->anno_vino[i] = anno_vino[i]; /* inserimento del luogo di produzione del vino */ for (i = 0; (i < LUNGHEZZA_LUOGO_PRODUZIONE); i++) nuovo_p->luogo_vino[i] = luogo_vino[i]; /* i puntatori vengono inizializzati a NULL */ nuovo_p->sx_p = nuovo_p->dx_p = NULL; /* se il nodo si trova in cima all'albero diventa la radice */ if (nodo_p == **radice_p) **radice_p = nuovo_p; /* se il codice inserito è inferiore a quello contenuto nel nodo padre */ else if (strcmp(codice_vino, padre_p->codice_vino) < 0) /* il nuovo nodo diventa figlio sinistro */ padre_p->sx_p = nuovo_p; else /* il nuovo nodo diventa figlio destro */ padre_p->dx_p = nuovo_p; } /* viene restituito il valore di esito dell'inserimento */ return(inserito); } /* Funzione per l'inserimento di un nuovo vino */ int inserisci_nuovo_vino(nodo_albero_bin_t **radice_p) /* lavoro: puntatore alla radice dell'albero */ { char nome_vino[LUNGHEZZA_NOME], /* input: nome del vino da inserire */ codice_vino[LUNGHEZZA_CODICE], /* input: codice del vino da inserire */ anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], /* input: anno di produzione del vino da inserire */ luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE], /* input: luogo di produzione del vino da inserire */ carattere_acquisito = '~'; /* lavoro: variabile usata per acquisizioni e controlli */ int inserito = 0, /* output: esito dell'inserimento */ controllo_errori, /* lavoro: variabile di controllo */ i; /* lavoro: indice per i cicli for */ /* acquisizione del codice del vino da inserire */ printf("\nScrivere il codice del vino da inserire: "); /* non esce dal ciclo se il codice inserito da tastiera è troppo corto */ do { controllo_errori = 0; carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_CODICE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ') && (controllo_errori == 0)); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) codice_vino[i] = carattere_acquisito; else { i--; printf("\nIl codice deve contenere %d caratteri alfanumerici!\n", (LUNGHEZZA_CODICE - 1)); printf("\nRiscrivere il codice del vino: "); } /* se il codice contiene caratteri non alfanumerici */ if (codice_vino[i] < '0' || (codice_vino[i] > '9' && codice_vino[i] < 'A') || (codice_vino[i] > 'Z' && codice_vino[i] < 'a') || codice_vino[i] > 'z') { controllo_errori = 1; printf("\nRiscrivere il codice del vino: "); } } codice_vino[i] = '{parsed_message}'; } while ((strlen(codice_vino) != (LUNGHEZZA_CODICE - 1)) || (controllo_errori == 1)); carattere_acquisito = getchar(); /* se l'utente ha inserito un codice troppo lungo */ if (carattere_acquisito != '\n') /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); /* acquisizione del nome del vino da inserire */ /* non esce dal ciclo se l'utente non inserisce nessun nome */ do { printf("Scrivere il nome del vino da inserire: "); carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_NOME - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ')); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) nome_vino[i] = carattere_acquisito; else i--; } nome_vino[i] = '{parsed_message}'; /* se l'utente ha inserito un nome troppo lungo */ if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) { printf("\nIl nome è stato abbreviato a %d caratteri!\n\n", (LUNGHEZZA_NOME - 1)); /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); } } while (strlen(nome_vino) == 0); /* acquisizione dell'anno di produzione del vino da inserire */ printf("Scrivere l'anno di produzione del vino da inserire: "); /* non esce dal ciclo se l'anno inserito da tastiera è troppo corto */ do { controllo_errori = 0; carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_ANNO_PRODUZIONE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ') && (controllo_errori == 0)); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) anno_vino[i] = carattere_acquisito; else { i--; printf("\nL'anno deve contenere %d caratteri numerici!\n", (LUNGHEZZA_ANNO_PRODUZIONE - 1)); printf("\nRiscrivere l'anno di produzione del vino: "); } /* se l'anno contiene caratteri non numerici */ if (anno_vino[i] < '0' || anno_vino[i] > '9') controllo_errori = 1; } anno_vino[i] = '{parsed_message}'; } while ((strlen(anno_vino) != (LUNGHEZZA_ANNO_PRODUZIONE - 1)) || (controllo_errori == 1)); carattere_acquisito = getchar(); /* se l'utente ha inserito un anno troppo lungo */ if (carattere_acquisito != '\n') /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); /* acquisizione del luogo di produzione del vino da inserire */ /* non esce dal ciclo se l'utente non inserisce nessun luogo */ do { printf("Scrivere il luogo di produzione del vino da inserire: "); carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_LUOGO_PRODUZIONE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ')); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) luogo_vino[i] = carattere_acquisito; else i--; } luogo_vino[i] = '{parsed_message}'; /* se l'utente ha inserito un luogo troppo lungo */ if (carattere_acquisito != '\n') { printf("\nIl luogo è stato abbreviato a %d caratteri!\n\n", (LUNGHEZZA_LUOGO_PRODUZIONE - 1)); /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); } } while (strlen(luogo_vino) == 0); /* inserimento del vino nell'albero */ inserito = inserisci_in_albero_bin(&radice_p, codice_vino, nome_vino, anno_vino, luogo_vino); /* se l'inserimento è andato a buon fine */ if (inserito != 1) printf("\nVino \"%s\" già presente!", codice_vino); else printf("\nIl vino è stato inserito."); /* viene restituito l'esito dell'inserimento */ return (inserito); } int rimuovi_vino(nodo_albero_bin_t **radice_p) /* lavoro: puntatore alla radice dell'albero */ { char codice_vino[LUNGHEZZA_CODICE], /* input: codice del vino da rimuovere */ carattere_acquisito = '~'; /* lavoro: variabile usata per acquisizioni e controlli */ int rimosso = 0, /* output: esito rimozione */ controllo_errori, /* lavoro: variabile di controllo */ i; /* lavoro: indice per i cicli */ /* acquisizione del codice del vino da rimuovere */ printf("\nScrivere il codice del vino da rimuovere: "); /* non esce dal ciclo se l'utente non inserisce un codice corretto */ do { controllo_errori = 0; carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_CODICE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ') && (controllo_errori == 0)); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) codice_vino[i] = carattere_acquisito; else { i--; printf("\nIl codice deve contenere %d caratteri alfanumerici!\n", (LUNGHEZZA_CODICE - 1)); printf("\nRiscrivere il codice del vino: "); } /* se il codice contiene caratteri non alfanumerici */ if (codice_vino[i] < '0' || (codice_vino[i] > '9' && codice_vino[i] < 'A') || (codice_vino[i] > 'Z' && codice_vino[i] < 'a') || codice_vino[i] > 'z') { controllo_errori = 1; printf("\nRiscrivere il codice del vino: "); } } codice_vino[i] = '{parsed_message}'; } while ((strlen(codice_vino) != (LUNGHEZZA_CODICE - 1)) || (controllo_errori == 1)); carattere_acquisito = getchar(); /* se l'utente ha inserito un codice troppo lungo */ if (carattere_acquisito != '\n') /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); /* rimozione del vino dall'albero */ rimosso = rimuovi_da_albero_bin(&radice_p, codice_vino); if (rimosso == 1) printf("\nIl vino è stato rimosso!"); else printf("\nIl vino non è presente nella lista!"); /* viene restituito l'esito della rimozione */ return (rimosso); } /* Algoritmo per la rimozione di un vino dall'albero binario */ int rimuovi_da_albero_bin(nodo_albero_bin_t ***radice_p, /* lavoro: puntatore al puntatore alla radice dell'albero */ char codice_vino[]) /* input: codice del vino da rimuovere */ { int rimosso, /* output: esito della rimozione */ i; /* lavoro: contatore per i cicli for */ nodo_albero_bin_t *nodo_p, /* lavoro: puntatore a un nodo */ *padre_p, /* lavoro: padre di nodo_p */ *sost_p; /* lavoro: sostituto di nodo_p */ /* nodo_p e padre_p vengono inizializzati con l'indirizzo della radice e ad ogni */ /* iterazione padre_p prende l'indirizzo di nodo_p.nodo_p prende l'indirizzo del */ /* suo figlio sx o dx a seconda che il codice da inserire sia < o >= al codice */ /* puntato da nodo_p.Il ciclo termina quando nodo_p punta a NULL oppure ad un */ /* elemento che contiene un codice uguale a quello da rimuovere. */ for (nodo_p = padre_p = **radice_p; ((nodo_p != NULL) && (strcmp(nodo_p->codice_vino,codice_vino) != 0)); padre_p = nodo_p, nodo_p = (strcmp(codice_vino,nodo_p->codice_vino) < 0)? nodo_p->sx_p: nodo_p->dx_p); /* il vino non verrà rimosso se non era presente, ovvero se nodo_p punta a NULL */ if (nodo_p == NULL) rimosso = 0; else { rimosso = 1; /* se nodo_p non ha figlio sx */ if (nodo_p->sx_p == NULL) { /* se nodo_p si trova in cima all'albero */ if (nodo_p == **radice_p) /* il figlio destro del nodo diventa la radice */ **radice_p = nodo_p->dx_p; /* altrimenti se il codice da rimuovere è minore di quello del padre */ else if (strcmp(codice_vino, padre_p->codice_vino) < 0) /* il figlio destro del nodo_p, diventa figlio sinistro del padre */ padre_p->sx_p = nodo_p->dx_p; else /* il figlio destro del nodo_p, diventa figlio destro del padre */ padre_p->dx_p = nodo_p->dx_p; } /* altrimenti, se nodo_p non ha figlio destro */ else if (nodo_p->dx_p == NULL) { /* se nodo_p si trova in cima all'albero */ if (nodo_p == **radice_p) /* il figlio sinistro del nodo diventa la radice */ **radice_p = nodo_p->sx_p; /* altrimenti, se il codice da rimuovere è minore di quello del padre */ else if (strcmp(codice_vino, padre_p->codice_vino) < 0) /* il figlio sinistro del nodo_p diventa figlio sinistro del padre */ padre_p->sx_p = nodo_p->sx_p; else /* il figlio sinistro del nodo_p diventa figlio destro del padre */ padre_p->dx_p = nodo_p->sx_p; } /* altrimenti, se il nodo_p ha entrambi i figli */ else { /* sost_p prende l'indirizzo contenuto in nodo_p */ sost_p = nodo_p; /* ad ogni iterazione del ciclo, padre_p prende l'indirizzo di nodo_p e nodo_p prende */ /* l'indirizzo del figlio destro; il ciclo termina quando nodo_p non ha figlio destro */ for (padre_p = sost_p, nodo_p = sost_p->sx_p; (nodo_p->dx_p != NULL); padre_p = nodo_p, nodo_p = nodo_p->dx_p); /* sostuzione del codice del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_CODICE); i++) sost_p->codice_vino[i] = nodo_p->codice_vino[i]; /* sostituzione del nome del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_NOME); i++) sost_p->nome_vino[i] = nodo_p->nome_vino[i]; /* sostuzione dell'anno del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_ANNO_PRODUZIONE); i++) sost_p->anno_vino[i] = nodo_p->anno_vino[i]; /* sostituzione del luogo del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_LUOGO_PRODUZIONE); i++) sost_p->anno_vino[i] = nodo_p->anno_vino[i]; /* se padre_p e sost_p puntano allo stesso nodo */ if (padre_p == sost_p) /* il figlio sinistro del nodo_p diventa figlio sinistro del padre_p */ padre_p->sx_p = nodo_p->sx_p; else /* il figlio sinistro del nodo_p diventa figlio destro del padre_p */ padre_p->dx_p = nodo_p->sx_p; } /* il nodo puntato da nodo_p viene rimosso dalla memoria */ free(nodo_p); } return(rimosso); } /* funzione per la stampa dei vini in base al codice */ void stampa_codice(nodo_albero_bin_t *nodo_p) { if (nodo_p != NULL) { stampa_codice(nodo_p->sx_p); printf("%s %s %s %s\n", nodo_p->nome_vino, nodo_p->codice_vino, nodo_p->anno_vino, nodo_p->luogo_vino); stampa_codice(nodo_p->dx_p); } } void stampa_vini(nodo_albero_bin_t *radice_p, int numero_vini, int scelta_ordinamento) { vino_t vini[numero_vini]; /* array per l'ordinamento */ /* trasferimento dei vini dall'albero in un array */ inserisci_vini_in_array(radice_p, vini, 0); switch(scelta_ordinamento) { case 1: /* ordina i vini in base al nome */ quicksort_nome(vini, 0, numero_vini - 1); break; case 3: /* ordina i vini in base all'anno */ quicksort_anno(vini, 0, numero_vini - 1); break; case 4: /* ordina i vini in base al luogo */ quicksort_luogo(vini, 0, numero_vini - 1); break; } stampa_array(numero_vini, vini); } /* funzione per il trasferimento dei vini dall'albero in un array */ void inserisci_vini_in_array(nodo_albero_bin_t *nodo_p, vino_t *vini, int i) { if (nodo_p->codice_vino != NULL) { inserisci_vini_in_array(nodo_p->sx_p, vini, i); strcpy(vini[i].nome_vino, nodo_p->nome_vino); strcpy(vini[i].codice_vino, nodo_p->codice_vino); strcpy(vini[i].anno_vino, nodo_p->anno_vino); strcpy(vini[i].luogo_vino, nodo_p->luogo_vino); i = i + 1; inserisci_vini_in_array(nodo_p->dx_p, vini, i); } } void quicksort_nome(vino_t a[], int sx, int dx) { int i, j; /* variabili di lavoro */ vino_t tmp, /* variabile usata per lo scambio */ pivot; /* puntatore all'elemento che fungera' da pivot */ /* si sceglie come pivot il valore centrale e si attua una tri-partizione */ /* scambiando gli elementi in modo che nella porzione a destra del pivot vi */ /* siano elementi maggiori del pivot e nella porzione sinistra quelli minori */ for (pivot = a[(sx + dx) / 2], i = sx, j = dx; (i <= j);) { while (strcmp(a[i].nome_vino, pivot.nome_vino) == -1) i++; while (strcmp(a[j].nome_vino, pivot.nome_vino) == 1) j--; if (i <= j) { if (i < j) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; } i++; j--; } } /* si invoca ricorsivamente la funzione sulle porzioni sinistra e destra */ if (sx < j) quicksort_nome(a, sx, j); if (i < dx) quicksort_nome(a, i, dx); } void quicksort_anno(vino_t a[], int sx, int dx) { int i, j; /* variabili di lavoro */ vino_t tmp, /* variabile usata per lo scambio */ pivot; /* puntatore all'elemento che fungera' da pivot */ /* si sceglie come pivot il valore centrale e si attua una tri-partizione */ /* scambiando gli elementi in modo che nella porzione a destra del pivot vi */ /* siano elementi maggiori del pivot e nella porzione sinistra quelli minori */ for (pivot = a[(sx + dx) / 2], i = sx, j = dx; (i <= j);) { while (strcmp(a[i].anno_vino, pivot.anno_vino) == -1) i++; while (strcmp(a[j].anno_vino, pivot.anno_vino) == 1) j--; if (i <= j) { if (i < j) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; } i++; j--; } } /* si invoca ricorsivamente la funzione sulle porzioni sinistra e destra */ if (sx < j) quicksort_anno(a, sx, j); if (i < dx) quicksort_anno(a, i, dx); } void quicksort_luogo(vino_t a[], int sx, int dx) { int i, j; /* variabili di lavoro */ vino_t tmp, /* variabile usata per lo scambio */ pivot; /* puntatore all'elemento che fungera' da pivot */ /* si sceglie come pivot il valore centrale e si attua una tri-partizione */ /* scambiando gli elementi in modo che nella porzione a destra del pivot vi */ /* siano elementi maggiori del pivot e nella porzione sinistra quelli minori */ for (pivot = a[(sx + dx) / 2], i = sx, j = dx; (i <= j);) { while (strcmp(a[i].luogo_vino, pivot.luogo_vino) == -1) i++; while (strcmp(a[j].luogo_vino, pivot.luogo_vino) == 1) j--; if (i <= j) { if (i < j) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; } i++; j--; } } /*Si invoca ricorsivamente la funzione sulle porzioni sinistra e destra*/ if (sx < j) quicksort_luogo(a, sx, j); if (i < dx) quicksort_luogo(a, i, dx); } void stampa_array(int numero_vini, vino_t *vini) { int i; /*Vengono stampati gli elementi ordinati*/ for(i = 0; i < numero_vini; i++) printf("\n%20s %4s %4s %s", vini[i].nome_vino, vini[i].codice_vino, vini[i].anno_vino, vini[i].luogo_vino); }'; } while ((strlen(anno_vino) != (LUNGHEZZA_ANNO_PRODUZIONE - 1)) || (controllo_errori == 1)); carattere_acquisito = getchar(); /* se l'utente ha inserito un anno troppo lungo */ if (carattere_acquisito != '\n') /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); /* acquisizione del luogo di produzione del vino da inserire */ /* non esce dal ciclo se l'utente non inserisce nessun luogo */ do { printf("Scrivere il luogo di produzione del vino da inserire: "); carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_LUOGO_PRODUZIONE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ')); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) luogo_vino[i] = carattere_acquisito; else i--; } luogo_vino[i] = 'Nel file allegato vi è il codice di un programma che gestisce un database di vini. Il mio problema è che ricevo un errore di segmentazione entrando nella funzione "inserisci_in_albero_bin". E' da un pò di giorni che stò cercando una soluzione ma non riesco a venirne a capo...qualcuno saprebbe aiutarmi??/******************************************************************/ /* Programma per manipolare un file contenente una lista di vini. */ /* Michele Petrocchi Matricola 256507 */ /******************************************************************/ /***********************/ /* inclusione librerie */ /***********************/ #include <stdio.h> #include <stdlib.h> #include <string.h> /*************************************/ /* Dichiarazione costanti simboliche */ /*************************************/ #define LUNGHEZZA_NOME 51 /* lunghezza della stringa del nome del vino */ #define LUNGHEZZA_CODICE 5 /* lunghezza della stringa del codice del vino */ #define LUNGHEZZA_ANNO_PRODUZIONE 5 /* lunghezza della stringa dell'anno di produzione del vino */ #define LUNGHEZZA_LUOGO_PRODUZIONE 51 /* lunghezza della stringa del luogo di produzione del vino */ #define PERCORSO_FILE "./file_vini" /* percorso del file di output */ /************************/ /* Defibizione dei tipi */ /************************/ typedef struct nodo_albero_bin { char nome_vino[LUNGHEZZA_NOME], /* nome del vino */ codice_vino[LUNGHEZZA_CODICE], /* codice del vino */ anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], /* anno di produzione del vino */ luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE]; /* luogo di produzione del vino */ struct nodo_albero_bin *sx_p, *dx_p; } nodo_albero_bin_t; typedef struct vino { char nome_vino[LUNGHEZZA_NOME], /* nome del vino */ codice_vino[LUNGHEZZA_CODICE], /* codice del vino */ anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], /* anno di produzione del vino */ luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE]; /* luogo di produzione del vino */ } vino_t; /********************************/ /* Dichiarazione delle funzioni */ /********************************/ int controllo_correttezza_file(nodo_albero_bin_t **, FILE *, int *); int inserisci_in_albero_bin(nodo_albero_bin_t ***, char[], char[], char[], char[]); int inserisci_nuovo_vino(nodo_albero_bin_t **); int rimuovi_vino(nodo_albero_bin_t **); int rimuovi_da_albero_bin(nodo_albero_bin_t ***, char[]); void stampa_codice(nodo_albero_bin_t *); void stampa_vini(nodo_albero_bin_t *, int, int); void inserisci_vini_in_array(nodo_albero_bin_t *, vino_t [], int); void quicksort_nome(vino_t [], int, int); void quicksort_anno(vino_t [], int, int); void quicksort_luogo(vino_t [], int, int); void stampa_array(int, vino_t *); /******************************/ /* Definizione delle funzioni */ /******************************/ int main (int argc, /* numero stringhe acquisite lancio comandi */ char *argv[]) /* stringhe acqusite dal lancio comandi */ { int esito = 0, esito_ordinamento = 0, esito_pulizia = 1, esito_pulizia_ordinamento = 1, scelta_utente = 0, scelta_ordinamento = 0, rimosso = 0, numero_vini = 0, controllo = 0; FILE *input; /* file da dove preleverò la lista dei vini */ nodo_albero_bin_t *radice_p = NULL; /* lavoro: puntatore alla radice dell'albero */ /* specifichiamo il file di input, quindi deve essere 1 il numero degli argomenti */ if(argc > 1) { /* apriamo il file specificato */ input = fopen(argv[1],"r"); /* se il file specificato esiste */ if (input != NULL) { /* acquisisci il numero di vini */ esito = fscanf(input, "%d", &numero_vini); /* se il numero di vini non è valido */ if (esito != 1 || numero_vini < 0) printf("Lettura del numero di vini non riuscita.\n\n"); else controllo = controllo_correttezza_file(&radice_p, input, &numero_vini); /* chiudere il file di input */ fclose(input); /* se non si sono verificati errori */ if (controllo != 1) { do { do { printf("\nL'utente digiti:"); printf("\n 1-Se si vuole procedere nell'inserimento di un nuovo vino"); printf("\n 2-Se si vuole procedere nella cancellazione di un altro"); printf("\n 3-Se si vuole visualizzare la lista con i vini inseriti"); printf("\n 4-Se si vuole uscire dal programma"); printf("\nPremere Invio per confermare.\n"); printf("\n"); /* pulizia del buffer della scanf */ esito_pulizia = scanf("\n"); esito = scanf("%d", &scelta_utente); while (getchar() != '\n'); } while ((scelta_utente < 1) || (scelta_utente > 4) || (esito != 1) || (esito_pulizia != 0)); switch (scelta_utente) { case 1: esito = inserisci_nuovo_vino(&radice_p); if (esito == 1) /* incrementa il numero di vini */ numero_vini++; printf(" (premere Invio per tornare al menù)\n"); while (getchar() != '\n'); break; case 2: rimosso = rimuovi_vino(&radice_p); /* se la rimozione è andata a buon fine */ if (rimosso == 1) /* decremento il numero di vini */ numero_vini--; printf(" (premere Invio per tornare al menù)\n"); while (getchar() != '\n'); break; case 3: do { printf("\nL'utente scelga l'ordine di visualizzaione dei vini:"); printf("\n 1-Nome"); printf("\n 2-Codice"); printf("\n 3-Luogo di produzione"); printf("\n 4-Anno di produzione"); printf("\nPremere Invio per confermare.\n"); printf("\n"); /* pulizia del buffer della scanf */ esito_pulizia_ordinamento = scanf("\n"); esito_ordinamento = scanf("%d", &scelta_ordinamento); while (getchar() != '\n'); } while ((scelta_utente < 1) || (scelta_utente > 4) || (esito_ordinamento != 1) || (esito_pulizia_ordinamento != 0)); /* visualizzare la lista dei vini inseriti */ printf("\n%d vini inseriti:\n", numero_vini); if (scelta_ordinamento == 2) /* stampa i vini in base al codice */ stampa_codice(radice_p); else stampa_vini(radice_p, numero_vini, scelta_ordinamento); printf("\n"); printf("(premere Invio per tornare al menù)\n"); while (getchar() != '\n'); break; case 4: /* se l'utente decide di uscire stampiamo un messaggio di saluto */ printf("\nGrazie per aver utilizzato questo programma!"); printf("\n\n"); break; } } while ((scelta_utente != 4)); } } else/* se il file specificato è uguale a NULL e quindi inesistente */ printf("\nIl file specificato non esiste!\n"); } else { /* se non è stato inserito il parametro di lancio del file */ printf("\nNon è stato immesso il nome del file da dove importare i dati riguardanti i vini!"); printf("\nrilanciare il programma con queste specifiche:"); printf("\n./<nome_eseguibile> <nome_file_input>\n"); printf("\nIl file può essere generato tramite il programma che viene lanciato con ./genera"); printf("\n(per la compilazione il comando è make genera_vini!)\n"); printf("\n(se il file è nella dir. di lavoro basta specificarne il nome!)\n\n"); } return(0); } int controllo_correttezza_file(nodo_albero_bin_t **radice_p, FILE * input, int *numero_vini) { int esito, controllo_errori = 0, i, j; char nome_vino[LUNGHEZZA_NOME], codice_vino[LUNGHEZZA_CODICE], anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE], carattere_acquisito = '~'; /* lavoro: variabile utilizzata */ /* per acquisizioni e controlli */ /* il ciclo acquisce i vini uno ad uno dal file e li inserisce nella struttura dati */ for (i = 0; ((i < *numero_vini) && (controllo_errori == 0)); i++) { /* scorro il file fino a trovare il carattere successivo */ while (carattere_acquisito != '\n') carattere_acquisito = getc(input); /* acquisizione del nome del vino */ for (j = 0, carattere_acquisito = '~'; ((j < (LUNGHEZZA_NOME - 1)) && (carattere_acquisito != ' ') && (carattere_acquisito != '\n') && (controllo_errori == 0)); j++) { carattere_acquisito = getc(input); if ((carattere_acquisito != ' ') && (carattere_acquisito != '\n')) nome_vino[j] = carattere_acquisito; else j--; } nome_vino[j] = '{parsed_message}'; /* se il nome del vino ha più caratteri del previsto */ if (carattere_acquisito != ' ') printf("I nomi che superano i %d caratteri sono stati abbreviati!\n", (LUNGHEZZA_NOME - 1)); /* spostati in avanti nel file in avanti fino ad arrivare all'inizio del codice */ while (carattere_acquisito != ' ') carattere_acquisito = getc(input); /* acquisizione del codice del vino */ for (j = 0; ((j < (LUNGHEZZA_CODICE - 1)) && (controllo_errori == 0)); j++) { codice_vino[j] = getc(input); /* se il codice vino ha meno caratteri del previsto */ if (codice_vino[j] == ' ') { printf("I codici dei vini devono contenere %d caratteri!\n", (LUNGHEZZA_CODICE - 1)); controllo_errori = 1; } /* se il codice contiene caratteri non alfanumerici */ else if (codice_vino[j] < '0' || (codice_vino[j] > '9' && codice_vino[j] < 'A') || (codice_vino[j] > 'Z' && codice_vino[j] < 'a') || codice_vino[j] > 'z') { printf("I codici dei vini possono contenere solo caratteri alfanumerici!\n"); /* forza la chiusura del programma */ controllo_errori = 1; } } codice_vino[j] = '{parsed_message}'; carattere_acquisito = getc(input); /* spostati in avanti nel file fino ad arrivare all'inizio dell'anno di produzione */ while (carattere_acquisito != ' ') carattere_acquisito = getc(input); /* acquisizione dell'anno di produzione */ for (j = 0, carattere_acquisito = '~'; ((j < (LUNGHEZZA_ANNO_PRODUZIONE - 1)) && (controllo_errori == 0)); j++) { anno_vino[j] = getc(input); /* se l'anno del vino ha meno caratteri del previsto */ if (anno_vino[j] == ' ') { printf("L'anno di produzione dei vini devono contenere %d caratteri!\n", (LUNGHEZZA_ANNO_PRODUZIONE - 1)); controllo_errori = 1; } /* se l'anno contiene caratteri non numerici */ else if (anno_vino[j] < '0' || anno_vino[j] > '9' ) { printf("Gli anni dei vini possono contenere solo caratteri numerici!\n"); /* forza la chiusura del programma */ controllo_errori = 1; } } anno_vino[j] = '{parsed_message}'; carattere_acquisito = getc(input); /* spostati in avanti nel file in avanti fino ad arrivare all'inizio del luogo di produzione */ while (carattere_acquisito != ' ') carattere_acquisito = getc(input); /* acquisizione del luogo di produzione del vino */ for (j = 0, carattere_acquisito = '~'; ((j < (LUNGHEZZA_LUOGO_PRODUZIONE - 1)) && (carattere_acquisito != ' ') && (carattere_acquisito != '\n') && (controllo_errori == 0)); j++) { carattere_acquisito = getc(input); if ((carattere_acquisito != ' ') && (carattere_acquisito != '\n')) luogo_vino[j] = carattere_acquisito; else j--; } luogo_vino[j] = '{parsed_message}'; /* se il luogo di produzione del vino ha più caratteri del previsto */ if ((carattere_acquisito != '\n') && (controllo_errori == 0)) printf("I luoghi che superano i %d caratteri sono stati abbreviati!\n", (LUNGHEZZA_LUOGO_PRODUZIONE - 1)); /* inserimento del vino nell'albero ordinato secondo il codice */ esito = inserisci_in_albero_bin(&radice_p, codice_vino, nome_vino, anno_vino, luogo_vino); /* se l'inserimento non è andato a buon fine */ if (esito == 0) { printf("\nIl vino con codice \"%s\" non è stato inserito perchè già presente nella lista!\n", codice_vino); /* decrementa il numero dei vini del numero di inserimenti falliti */ *numero_vini = *numero_vini - 1; } } return (controllo_errori); } /* Algoritmo per l'inserimento di un vino nell'albero binario ordinato secondo il codice */ int inserisci_in_albero_bin(nodo_albero_bin_t ***radice_p, /* lavoro: puntatore al puntatore alla radice dell'albero */ char codice_vino[], /* input: codice del vino da inserire */ char nome_vino[], /* input: nome del vino da inserire */ char anno_vino[], /* input: anno di produzione del vino da inserire */ char luogo_vino[]) /* input: luogo di produzione del vino da inserire */ { int inserito, /* output: esito dell'inserimento */ i; /* lavoro: indice per i cicli for */ nodo_albero_bin_t *nodo_p, /* lavoro: puntatore ad un nodo */ *padre_p, /* lavoro: puntatore al padre del nodo_p */ *nuovo_p; /* lavoro: puntatore al nodo che conterrà il nuovo vino */ /* nodo_p e padre_p vengono inizializzati con l'indirizzo della radice e ad ogni */ /* iterazione padre_p prende l'indirizzo di nodo_p.nodo_p prende l'indirizzo del */ /* suo figlio sx o dx a seconda che il codice da inserire sia < o >= al codice */ /* puntato da nodo_p.Il ciclo termina quando nodo_p punta a NULL oppure ad un */ /* elemento che contiene un codice uguale a quello da inserire. */ for (nodo_p = padre_p = **radice_p; ((nodo_p != NULL) && (strcmp(nodo_p->codice_vino, codice_vino) != 0)); padre_p = nodo_p, nodo_p = (strcmp(codice_vino, nodo_p->codice_vino) < 0)? nodo_p->sx_p: nodo_p->dx_p); /* il vino non verrà inserito se era già presente, ovvero se nodo_p non punta a NULL */ if (nodo_p != NULL) inserito = 0; else { inserito = 1; /* viene allocata memoria per il nuovo nodo */ nuovo_p = (nodo_albero_bin_t *)malloc(sizeof(nodo_albero_bin_t)); /* inserimento del codice del vino */ for (i = 0; (i < LUNGHEZZA_CODICE); i++) nuovo_p->codice_vino[i] = codice_vino[i]; /* inserimento del nome del vino */ for (i = 0; (i < LUNGHEZZA_NOME); i++) nuovo_p->nome_vino[i] = nome_vino[i]; /* inserimento dell'anno di produzione del vino */ for (i = 0; (i < LUNGHEZZA_ANNO_PRODUZIONE); i++) nuovo_p->anno_vino[i] = anno_vino[i]; /* inserimento del luogo di produzione del vino */ for (i = 0; (i < LUNGHEZZA_LUOGO_PRODUZIONE); i++) nuovo_p->luogo_vino[i] = luogo_vino[i]; /* i puntatori vengono inizializzati a NULL */ nuovo_p->sx_p = nuovo_p->dx_p = NULL; /* se il nodo si trova in cima all'albero diventa la radice */ if (nodo_p == **radice_p) **radice_p = nuovo_p; /* se il codice inserito è inferiore a quello contenuto nel nodo padre */ else if (strcmp(codice_vino, padre_p->codice_vino) < 0) /* il nuovo nodo diventa figlio sinistro */ padre_p->sx_p = nuovo_p; else /* il nuovo nodo diventa figlio destro */ padre_p->dx_p = nuovo_p; } /* viene restituito il valore di esito dell'inserimento */ return(inserito); } /* Funzione per l'inserimento di un nuovo vino */ int inserisci_nuovo_vino(nodo_albero_bin_t **radice_p) /* lavoro: puntatore alla radice dell'albero */ { char nome_vino[LUNGHEZZA_NOME], /* input: nome del vino da inserire */ codice_vino[LUNGHEZZA_CODICE], /* input: codice del vino da inserire */ anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], /* input: anno di produzione del vino da inserire */ luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE], /* input: luogo di produzione del vino da inserire */ carattere_acquisito = '~'; /* lavoro: variabile usata per acquisizioni e controlli */ int inserito = 0, /* output: esito dell'inserimento */ controllo_errori, /* lavoro: variabile di controllo */ i; /* lavoro: indice per i cicli for */ /* acquisizione del codice del vino da inserire */ printf("\nScrivere il codice del vino da inserire: "); /* non esce dal ciclo se il codice inserito da tastiera è troppo corto */ do { controllo_errori = 0; carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_CODICE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ') && (controllo_errori == 0)); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) codice_vino[i] = carattere_acquisito; else { i--; printf("\nIl codice deve contenere %d caratteri alfanumerici!\n", (LUNGHEZZA_CODICE - 1)); printf("\nRiscrivere il codice del vino: "); } /* se il codice contiene caratteri non alfanumerici */ if (codice_vino[i] < '0' || (codice_vino[i] > '9' && codice_vino[i] < 'A') || (codice_vino[i] > 'Z' && codice_vino[i] < 'a') || codice_vino[i] > 'z') { controllo_errori = 1; printf("\nRiscrivere il codice del vino: "); } } codice_vino[i] = '{parsed_message}'; } while ((strlen(codice_vino) != (LUNGHEZZA_CODICE - 1)) || (controllo_errori == 1)); carattere_acquisito = getchar(); /* se l'utente ha inserito un codice troppo lungo */ if (carattere_acquisito != '\n') /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); /* acquisizione del nome del vino da inserire */ /* non esce dal ciclo se l'utente non inserisce nessun nome */ do { printf("Scrivere il nome del vino da inserire: "); carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_NOME - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ')); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) nome_vino[i] = carattere_acquisito; else i--; } nome_vino[i] = '{parsed_message}'; /* se l'utente ha inserito un nome troppo lungo */ if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) { printf("\nIl nome è stato abbreviato a %d caratteri!\n\n", (LUNGHEZZA_NOME - 1)); /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); } } while (strlen(nome_vino) == 0); /* acquisizione dell'anno di produzione del vino da inserire */ printf("Scrivere l'anno di produzione del vino da inserire: "); /* non esce dal ciclo se l'anno inserito da tastiera è troppo corto */ do { controllo_errori = 0; carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_ANNO_PRODUZIONE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ') && (controllo_errori == 0)); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) anno_vino[i] = carattere_acquisito; else { i--; printf("\nL'anno deve contenere %d caratteri numerici!\n", (LUNGHEZZA_ANNO_PRODUZIONE - 1)); printf("\nRiscrivere l'anno di produzione del vino: "); } /* se l'anno contiene caratteri non numerici */ if (anno_vino[i] < '0' || anno_vino[i] > '9') controllo_errori = 1; } anno_vino[i] = '{parsed_message}'; } while ((strlen(anno_vino) != (LUNGHEZZA_ANNO_PRODUZIONE - 1)) || (controllo_errori == 1)); carattere_acquisito = getchar(); /* se l'utente ha inserito un anno troppo lungo */ if (carattere_acquisito != '\n') /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); /* acquisizione del luogo di produzione del vino da inserire */ /* non esce dal ciclo se l'utente non inserisce nessun luogo */ do { printf("Scrivere il luogo di produzione del vino da inserire: "); carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_LUOGO_PRODUZIONE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ')); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) luogo_vino[i] = carattere_acquisito; else i--; } luogo_vino[i] = '{parsed_message}'; /* se l'utente ha inserito un luogo troppo lungo */ if (carattere_acquisito != '\n') { printf("\nIl luogo è stato abbreviato a %d caratteri!\n\n", (LUNGHEZZA_LUOGO_PRODUZIONE - 1)); /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); } } while (strlen(luogo_vino) == 0); /* inserimento del vino nell'albero */ inserito = inserisci_in_albero_bin(&radice_p, codice_vino, nome_vino, anno_vino, luogo_vino); /* se l'inserimento è andato a buon fine */ if (inserito != 1) printf("\nVino \"%s\" già presente!", codice_vino); else printf("\nIl vino è stato inserito."); /* viene restituito l'esito dell'inserimento */ return (inserito); } int rimuovi_vino(nodo_albero_bin_t **radice_p) /* lavoro: puntatore alla radice dell'albero */ { char codice_vino[LUNGHEZZA_CODICE], /* input: codice del vino da rimuovere */ carattere_acquisito = '~'; /* lavoro: variabile usata per acquisizioni e controlli */ int rimosso = 0, /* output: esito rimozione */ controllo_errori, /* lavoro: variabile di controllo */ i; /* lavoro: indice per i cicli */ /* acquisizione del codice del vino da rimuovere */ printf("\nScrivere il codice del vino da rimuovere: "); /* non esce dal ciclo se l'utente non inserisce un codice corretto */ do { controllo_errori = 0; carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_CODICE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ') && (controllo_errori == 0)); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) codice_vino[i] = carattere_acquisito; else { i--; printf("\nIl codice deve contenere %d caratteri alfanumerici!\n", (LUNGHEZZA_CODICE - 1)); printf("\nRiscrivere il codice del vino: "); } /* se il codice contiene caratteri non alfanumerici */ if (codice_vino[i] < '0' || (codice_vino[i] > '9' && codice_vino[i] < 'A') || (codice_vino[i] > 'Z' && codice_vino[i] < 'a') || codice_vino[i] > 'z') { controllo_errori = 1; printf("\nRiscrivere il codice del vino: "); } } codice_vino[i] = '{parsed_message}'; } while ((strlen(codice_vino) != (LUNGHEZZA_CODICE - 1)) || (controllo_errori == 1)); carattere_acquisito = getchar(); /* se l'utente ha inserito un codice troppo lungo */ if (carattere_acquisito != '\n') /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); /* rimozione del vino dall'albero */ rimosso = rimuovi_da_albero_bin(&radice_p, codice_vino); if (rimosso == 1) printf("\nIl vino è stato rimosso!"); else printf("\nIl vino non è presente nella lista!"); /* viene restituito l'esito della rimozione */ return (rimosso); } /* Algoritmo per la rimozione di un vino dall'albero binario */ int rimuovi_da_albero_bin(nodo_albero_bin_t ***radice_p, /* lavoro: puntatore al puntatore alla radice dell'albero */ char codice_vino[]) /* input: codice del vino da rimuovere */ { int rimosso, /* output: esito della rimozione */ i; /* lavoro: contatore per i cicli for */ nodo_albero_bin_t *nodo_p, /* lavoro: puntatore a un nodo */ *padre_p, /* lavoro: padre di nodo_p */ *sost_p; /* lavoro: sostituto di nodo_p */ /* nodo_p e padre_p vengono inizializzati con l'indirizzo della radice e ad ogni */ /* iterazione padre_p prende l'indirizzo di nodo_p.nodo_p prende l'indirizzo del */ /* suo figlio sx o dx a seconda che il codice da inserire sia < o >= al codice */ /* puntato da nodo_p.Il ciclo termina quando nodo_p punta a NULL oppure ad un */ /* elemento che contiene un codice uguale a quello da rimuovere. */ for (nodo_p = padre_p = **radice_p; ((nodo_p != NULL) && (strcmp(nodo_p->codice_vino,codice_vino) != 0)); padre_p = nodo_p, nodo_p = (strcmp(codice_vino,nodo_p->codice_vino) < 0)? nodo_p->sx_p: nodo_p->dx_p); /* il vino non verrà rimosso se non era presente, ovvero se nodo_p punta a NULL */ if (nodo_p == NULL) rimosso = 0; else { rimosso = 1; /* se nodo_p non ha figlio sx */ if (nodo_p->sx_p == NULL) { /* se nodo_p si trova in cima all'albero */ if (nodo_p == **radice_p) /* il figlio destro del nodo diventa la radice */ **radice_p = nodo_p->dx_p; /* altrimenti se il codice da rimuovere è minore di quello del padre */ else if (strcmp(codice_vino, padre_p->codice_vino) < 0) /* il figlio destro del nodo_p, diventa figlio sinistro del padre */ padre_p->sx_p = nodo_p->dx_p; else /* il figlio destro del nodo_p, diventa figlio destro del padre */ padre_p->dx_p = nodo_p->dx_p; } /* altrimenti, se nodo_p non ha figlio destro */ else if (nodo_p->dx_p == NULL) { /* se nodo_p si trova in cima all'albero */ if (nodo_p == **radice_p) /* il figlio sinistro del nodo diventa la radice */ **radice_p = nodo_p->sx_p; /* altrimenti, se il codice da rimuovere è minore di quello del padre */ else if (strcmp(codice_vino, padre_p->codice_vino) < 0) /* il figlio sinistro del nodo_p diventa figlio sinistro del padre */ padre_p->sx_p = nodo_p->sx_p; else /* il figlio sinistro del nodo_p diventa figlio destro del padre */ padre_p->dx_p = nodo_p->sx_p; } /* altrimenti, se il nodo_p ha entrambi i figli */ else { /* sost_p prende l'indirizzo contenuto in nodo_p */ sost_p = nodo_p; /* ad ogni iterazione del ciclo, padre_p prende l'indirizzo di nodo_p e nodo_p prende */ /* l'indirizzo del figlio destro; il ciclo termina quando nodo_p non ha figlio destro */ for (padre_p = sost_p, nodo_p = sost_p->sx_p; (nodo_p->dx_p != NULL); padre_p = nodo_p, nodo_p = nodo_p->dx_p); /* sostuzione del codice del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_CODICE); i++) sost_p->codice_vino[i] = nodo_p->codice_vino[i]; /* sostituzione del nome del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_NOME); i++) sost_p->nome_vino[i] = nodo_p->nome_vino[i]; /* sostuzione dell'anno del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_ANNO_PRODUZIONE); i++) sost_p->anno_vino[i] = nodo_p->anno_vino[i]; /* sostituzione del luogo del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_LUOGO_PRODUZIONE); i++) sost_p->anno_vino[i] = nodo_p->anno_vino[i]; /* se padre_p e sost_p puntano allo stesso nodo */ if (padre_p == sost_p) /* il figlio sinistro del nodo_p diventa figlio sinistro del padre_p */ padre_p->sx_p = nodo_p->sx_p; else /* il figlio sinistro del nodo_p diventa figlio destro del padre_p */ padre_p->dx_p = nodo_p->sx_p; } /* il nodo puntato da nodo_p viene rimosso dalla memoria */ free(nodo_p); } return(rimosso); } /* funzione per la stampa dei vini in base al codice */ void stampa_codice(nodo_albero_bin_t *nodo_p) { if (nodo_p != NULL) { stampa_codice(nodo_p->sx_p); printf("%s %s %s %s\n", nodo_p->nome_vino, nodo_p->codice_vino, nodo_p->anno_vino, nodo_p->luogo_vino); stampa_codice(nodo_p->dx_p); } } void stampa_vini(nodo_albero_bin_t *radice_p, int numero_vini, int scelta_ordinamento) { vino_t vini[numero_vini]; /* array per l'ordinamento */ /* trasferimento dei vini dall'albero in un array */ inserisci_vini_in_array(radice_p, vini, 0); switch(scelta_ordinamento) { case 1: /* ordina i vini in base al nome */ quicksort_nome(vini, 0, numero_vini - 1); break; case 3: /* ordina i vini in base all'anno */ quicksort_anno(vini, 0, numero_vini - 1); break; case 4: /* ordina i vini in base al luogo */ quicksort_luogo(vini, 0, numero_vini - 1); break; } stampa_array(numero_vini, vini); } /* funzione per il trasferimento dei vini dall'albero in un array */ void inserisci_vini_in_array(nodo_albero_bin_t *nodo_p, vino_t *vini, int i) { if (nodo_p->codice_vino != NULL) { inserisci_vini_in_array(nodo_p->sx_p, vini, i); strcpy(vini[i].nome_vino, nodo_p->nome_vino); strcpy(vini[i].codice_vino, nodo_p->codice_vino); strcpy(vini[i].anno_vino, nodo_p->anno_vino); strcpy(vini[i].luogo_vino, nodo_p->luogo_vino); i = i + 1; inserisci_vini_in_array(nodo_p->dx_p, vini, i); } } void quicksort_nome(vino_t a[], int sx, int dx) { int i, j; /* variabili di lavoro */ vino_t tmp, /* variabile usata per lo scambio */ pivot; /* puntatore all'elemento che fungera' da pivot */ /* si sceglie come pivot il valore centrale e si attua una tri-partizione */ /* scambiando gli elementi in modo che nella porzione a destra del pivot vi */ /* siano elementi maggiori del pivot e nella porzione sinistra quelli minori */ for (pivot = a[(sx + dx) / 2], i = sx, j = dx; (i <= j);) { while (strcmp(a[i].nome_vino, pivot.nome_vino) == -1) i++; while (strcmp(a[j].nome_vino, pivot.nome_vino) == 1) j--; if (i <= j) { if (i < j) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; } i++; j--; } } /* si invoca ricorsivamente la funzione sulle porzioni sinistra e destra */ if (sx < j) quicksort_nome(a, sx, j); if (i < dx) quicksort_nome(a, i, dx); } void quicksort_anno(vino_t a[], int sx, int dx) { int i, j; /* variabili di lavoro */ vino_t tmp, /* variabile usata per lo scambio */ pivot; /* puntatore all'elemento che fungera' da pivot */ /* si sceglie come pivot il valore centrale e si attua una tri-partizione */ /* scambiando gli elementi in modo che nella porzione a destra del pivot vi */ /* siano elementi maggiori del pivot e nella porzione sinistra quelli minori */ for (pivot = a[(sx + dx) / 2], i = sx, j = dx; (i <= j);) { while (strcmp(a[i].anno_vino, pivot.anno_vino) == -1) i++; while (strcmp(a[j].anno_vino, pivot.anno_vino) == 1) j--; if (i <= j) { if (i < j) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; } i++; j--; } } /* si invoca ricorsivamente la funzione sulle porzioni sinistra e destra */ if (sx < j) quicksort_anno(a, sx, j); if (i < dx) quicksort_anno(a, i, dx); } void quicksort_luogo(vino_t a[], int sx, int dx) { int i, j; /* variabili di lavoro */ vino_t tmp, /* variabile usata per lo scambio */ pivot; /* puntatore all'elemento che fungera' da pivot */ /* si sceglie come pivot il valore centrale e si attua una tri-partizione */ /* scambiando gli elementi in modo che nella porzione a destra del pivot vi */ /* siano elementi maggiori del pivot e nella porzione sinistra quelli minori */ for (pivot = a[(sx + dx) / 2], i = sx, j = dx; (i <= j);) { while (strcmp(a[i].luogo_vino, pivot.luogo_vino) == -1) i++; while (strcmp(a[j].luogo_vino, pivot.luogo_vino) == 1) j--; if (i <= j) { if (i < j) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; } i++; j--; } } /*Si invoca ricorsivamente la funzione sulle porzioni sinistra e destra*/ if (sx < j) quicksort_luogo(a, sx, j); if (i < dx) quicksort_luogo(a, i, dx); } void stampa_array(int numero_vini, vino_t *vini) { int i; /*Vengono stampati gli elementi ordinati*/ for(i = 0; i < numero_vini; i++) printf("\n%20s %4s %4s %s", vini[i].nome_vino, vini[i].codice_vino, vini[i].anno_vino, vini[i].luogo_vino); }'; /* se l'utente ha inserito un luogo troppo lungo */ if (carattere_acquisito != '\n') { printf("\nIl luogo è stato abbreviato a %d caratteri!\n\n", (LUNGHEZZA_LUOGO_PRODUZIONE - 1)); /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); } } while (strlen(luogo_vino) == 0); /* inserimento del vino nell'albero */ inserito = inserisci_in_albero_bin(&radice_p, codice_vino, nome_vino, anno_vino, luogo_vino); /* se l'inserimento è andato a buon fine */ if (inserito != 1) printf("\nVino \"%s\" già presente!", codice_vino); else printf("\nIl vino è stato inserito."); /* viene restituito l'esito dell'inserimento */ return (inserito); } int rimuovi_vino(nodo_albero_bin_t **radice_p) /* lavoro: puntatore alla radice dell'albero */ { char codice_vino[LUNGHEZZA_CODICE], /* input: codice del vino da rimuovere */ carattere_acquisito = '~'; /* lavoro: variabile usata per acquisizioni e controlli */ int rimosso = 0, /* output: esito rimozione */ controllo_errori, /* lavoro: variabile di controllo */ i; /* lavoro: indice per i cicli */ /* acquisizione del codice del vino da rimuovere */ printf("\nScrivere il codice del vino da rimuovere: "); /* non esce dal ciclo se l'utente non inserisce un codice corretto */ do { controllo_errori = 0; carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_CODICE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ') && (controllo_errori == 0)); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) codice_vino[i] = carattere_acquisito; else { i--; printf("\nIl codice deve contenere %d caratteri alfanumerici!\n", (LUNGHEZZA_CODICE - 1)); printf("\nRiscrivere il codice del vino: "); } /* se il codice contiene caratteri non alfanumerici */ if (codice_vino[i] < '0' || (codice_vino[i] > '9' && codice_vino[i] < 'A') || (codice_vino[i] > 'Z' && codice_vino[i] < 'a') || codice_vino[i] > 'z') { controllo_errori = 1; printf("\nRiscrivere il codice del vino: "); } } codice_vino[i] = 'Nel file allegato vi è il codice di un programma che gestisce un database di vini. Il mio problema è che ricevo un errore di segmentazione entrando nella funzione "inserisci_in_albero_bin". E' da un pò di giorni che stò cercando una soluzione ma non riesco a venirne a capo...qualcuno saprebbe aiutarmi??/******************************************************************/ /* Programma per manipolare un file contenente una lista di vini. */ /* Michele Petrocchi Matricola 256507 */ /******************************************************************/ /***********************/ /* inclusione librerie */ /***********************/ #include <stdio.h> #include <stdlib.h> #include <string.h> /*************************************/ /* Dichiarazione costanti simboliche */ /*************************************/ #define LUNGHEZZA_NOME 51 /* lunghezza della stringa del nome del vino */ #define LUNGHEZZA_CODICE 5 /* lunghezza della stringa del codice del vino */ #define LUNGHEZZA_ANNO_PRODUZIONE 5 /* lunghezza della stringa dell'anno di produzione del vino */ #define LUNGHEZZA_LUOGO_PRODUZIONE 51 /* lunghezza della stringa del luogo di produzione del vino */ #define PERCORSO_FILE "./file_vini" /* percorso del file di output */ /************************/ /* Defibizione dei tipi */ /************************/ typedef struct nodo_albero_bin { char nome_vino[LUNGHEZZA_NOME], /* nome del vino */ codice_vino[LUNGHEZZA_CODICE], /* codice del vino */ anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], /* anno di produzione del vino */ luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE]; /* luogo di produzione del vino */ struct nodo_albero_bin *sx_p, *dx_p; } nodo_albero_bin_t; typedef struct vino { char nome_vino[LUNGHEZZA_NOME], /* nome del vino */ codice_vino[LUNGHEZZA_CODICE], /* codice del vino */ anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], /* anno di produzione del vino */ luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE]; /* luogo di produzione del vino */ } vino_t; /********************************/ /* Dichiarazione delle funzioni */ /********************************/ int controllo_correttezza_file(nodo_albero_bin_t **, FILE *, int *); int inserisci_in_albero_bin(nodo_albero_bin_t ***, char[], char[], char[], char[]); int inserisci_nuovo_vino(nodo_albero_bin_t **); int rimuovi_vino(nodo_albero_bin_t **); int rimuovi_da_albero_bin(nodo_albero_bin_t ***, char[]); void stampa_codice(nodo_albero_bin_t *); void stampa_vini(nodo_albero_bin_t *, int, int); void inserisci_vini_in_array(nodo_albero_bin_t *, vino_t [], int); void quicksort_nome(vino_t [], int, int); void quicksort_anno(vino_t [], int, int); void quicksort_luogo(vino_t [], int, int); void stampa_array(int, vino_t *); /******************************/ /* Definizione delle funzioni */ /******************************/ int main (int argc, /* numero stringhe acquisite lancio comandi */ char *argv[]) /* stringhe acqusite dal lancio comandi */ { int esito = 0, esito_ordinamento = 0, esito_pulizia = 1, esito_pulizia_ordinamento = 1, scelta_utente = 0, scelta_ordinamento = 0, rimosso = 0, numero_vini = 0, controllo = 0; FILE *input; /* file da dove preleverò la lista dei vini */ nodo_albero_bin_t *radice_p = NULL; /* lavoro: puntatore alla radice dell'albero */ /* specifichiamo il file di input, quindi deve essere 1 il numero degli argomenti */ if(argc > 1) { /* apriamo il file specificato */ input = fopen(argv[1],"r"); /* se il file specificato esiste */ if (input != NULL) { /* acquisisci il numero di vini */ esito = fscanf(input, "%d", &numero_vini); /* se il numero di vini non è valido */ if (esito != 1 || numero_vini < 0) printf("Lettura del numero di vini non riuscita.\n\n"); else controllo = controllo_correttezza_file(&radice_p, input, &numero_vini); /* chiudere il file di input */ fclose(input); /* se non si sono verificati errori */ if (controllo != 1) { do { do { printf("\nL'utente digiti:"); printf("\n 1-Se si vuole procedere nell'inserimento di un nuovo vino"); printf("\n 2-Se si vuole procedere nella cancellazione di un altro"); printf("\n 3-Se si vuole visualizzare la lista con i vini inseriti"); printf("\n 4-Se si vuole uscire dal programma"); printf("\nPremere Invio per confermare.\n"); printf("\n"); /* pulizia del buffer della scanf */ esito_pulizia = scanf("\n"); esito = scanf("%d", &scelta_utente); while (getchar() != '\n'); } while ((scelta_utente < 1) || (scelta_utente > 4) || (esito != 1) || (esito_pulizia != 0)); switch (scelta_utente) { case 1: esito = inserisci_nuovo_vino(&radice_p); if (esito == 1) /* incrementa il numero di vini */ numero_vini++; printf(" (premere Invio per tornare al menù)\n"); while (getchar() != '\n'); break; case 2: rimosso = rimuovi_vino(&radice_p); /* se la rimozione è andata a buon fine */ if (rimosso == 1) /* decremento il numero di vini */ numero_vini--; printf(" (premere Invio per tornare al menù)\n"); while (getchar() != '\n'); break; case 3: do { printf("\nL'utente scelga l'ordine di visualizzaione dei vini:"); printf("\n 1-Nome"); printf("\n 2-Codice"); printf("\n 3-Luogo di produzione"); printf("\n 4-Anno di produzione"); printf("\nPremere Invio per confermare.\n"); printf("\n"); /* pulizia del buffer della scanf */ esito_pulizia_ordinamento = scanf("\n"); esito_ordinamento = scanf("%d", &scelta_ordinamento); while (getchar() != '\n'); } while ((scelta_utente < 1) || (scelta_utente > 4) || (esito_ordinamento != 1) || (esito_pulizia_ordinamento != 0)); /* visualizzare la lista dei vini inseriti */ printf("\n%d vini inseriti:\n", numero_vini); if (scelta_ordinamento == 2) /* stampa i vini in base al codice */ stampa_codice(radice_p); else stampa_vini(radice_p, numero_vini, scelta_ordinamento); printf("\n"); printf("(premere Invio per tornare al menù)\n"); while (getchar() != '\n'); break; case 4: /* se l'utente decide di uscire stampiamo un messaggio di saluto */ printf("\nGrazie per aver utilizzato questo programma!"); printf("\n\n"); break; } } while ((scelta_utente != 4)); } } else/* se il file specificato è uguale a NULL e quindi inesistente */ printf("\nIl file specificato non esiste!\n"); } else { /* se non è stato inserito il parametro di lancio del file */ printf("\nNon è stato immesso il nome del file da dove importare i dati riguardanti i vini!"); printf("\nrilanciare il programma con queste specifiche:"); printf("\n./<nome_eseguibile> <nome_file_input>\n"); printf("\nIl file può essere generato tramite il programma che viene lanciato con ./genera"); printf("\n(per la compilazione il comando è make genera_vini!)\n"); printf("\n(se il file è nella dir. di lavoro basta specificarne il nome!)\n\n"); } return(0); } int controllo_correttezza_file(nodo_albero_bin_t **radice_p, FILE * input, int *numero_vini) { int esito, controllo_errori = 0, i, j; char nome_vino[LUNGHEZZA_NOME], codice_vino[LUNGHEZZA_CODICE], anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE], carattere_acquisito = '~'; /* lavoro: variabile utilizzata */ /* per acquisizioni e controlli */ /* il ciclo acquisce i vini uno ad uno dal file e li inserisce nella struttura dati */ for (i = 0; ((i < *numero_vini) && (controllo_errori == 0)); i++) { /* scorro il file fino a trovare il carattere successivo */ while (carattere_acquisito != '\n') carattere_acquisito = getc(input); /* acquisizione del nome del vino */ for (j = 0, carattere_acquisito = '~'; ((j < (LUNGHEZZA_NOME - 1)) && (carattere_acquisito != ' ') && (carattere_acquisito != '\n') && (controllo_errori == 0)); j++) { carattere_acquisito = getc(input); if ((carattere_acquisito != ' ') && (carattere_acquisito != '\n')) nome_vino[j] = carattere_acquisito; else j--; } nome_vino[j] = '{parsed_message}'; /* se il nome del vino ha più caratteri del previsto */ if (carattere_acquisito != ' ') printf("I nomi che superano i %d caratteri sono stati abbreviati!\n", (LUNGHEZZA_NOME - 1)); /* spostati in avanti nel file in avanti fino ad arrivare all'inizio del codice */ while (carattere_acquisito != ' ') carattere_acquisito = getc(input); /* acquisizione del codice del vino */ for (j = 0; ((j < (LUNGHEZZA_CODICE - 1)) && (controllo_errori == 0)); j++) { codice_vino[j] = getc(input); /* se il codice vino ha meno caratteri del previsto */ if (codice_vino[j] == ' ') { printf("I codici dei vini devono contenere %d caratteri!\n", (LUNGHEZZA_CODICE - 1)); controllo_errori = 1; } /* se il codice contiene caratteri non alfanumerici */ else if (codice_vino[j] < '0' || (codice_vino[j] > '9' && codice_vino[j] < 'A') || (codice_vino[j] > 'Z' && codice_vino[j] < 'a') || codice_vino[j] > 'z') { printf("I codici dei vini possono contenere solo caratteri alfanumerici!\n"); /* forza la chiusura del programma */ controllo_errori = 1; } } codice_vino[j] = '{parsed_message}'; carattere_acquisito = getc(input); /* spostati in avanti nel file fino ad arrivare all'inizio dell'anno di produzione */ while (carattere_acquisito != ' ') carattere_acquisito = getc(input); /* acquisizione dell'anno di produzione */ for (j = 0, carattere_acquisito = '~'; ((j < (LUNGHEZZA_ANNO_PRODUZIONE - 1)) && (controllo_errori == 0)); j++) { anno_vino[j] = getc(input); /* se l'anno del vino ha meno caratteri del previsto */ if (anno_vino[j] == ' ') { printf("L'anno di produzione dei vini devono contenere %d caratteri!\n", (LUNGHEZZA_ANNO_PRODUZIONE - 1)); controllo_errori = 1; } /* se l'anno contiene caratteri non numerici */ else if (anno_vino[j] < '0' || anno_vino[j] > '9' ) { printf("Gli anni dei vini possono contenere solo caratteri numerici!\n"); /* forza la chiusura del programma */ controllo_errori = 1; } } anno_vino[j] = '{parsed_message}'; carattere_acquisito = getc(input); /* spostati in avanti nel file in avanti fino ad arrivare all'inizio del luogo di produzione */ while (carattere_acquisito != ' ') carattere_acquisito = getc(input); /* acquisizione del luogo di produzione del vino */ for (j = 0, carattere_acquisito = '~'; ((j < (LUNGHEZZA_LUOGO_PRODUZIONE - 1)) && (carattere_acquisito != ' ') && (carattere_acquisito != '\n') && (controllo_errori == 0)); j++) { carattere_acquisito = getc(input); if ((carattere_acquisito != ' ') && (carattere_acquisito != '\n')) luogo_vino[j] = carattere_acquisito; else j--; } luogo_vino[j] = '{parsed_message}'; /* se il luogo di produzione del vino ha più caratteri del previsto */ if ((carattere_acquisito != '\n') && (controllo_errori == 0)) printf("I luoghi che superano i %d caratteri sono stati abbreviati!\n", (LUNGHEZZA_LUOGO_PRODUZIONE - 1)); /* inserimento del vino nell'albero ordinato secondo il codice */ esito = inserisci_in_albero_bin(&radice_p, codice_vino, nome_vino, anno_vino, luogo_vino); /* se l'inserimento non è andato a buon fine */ if (esito == 0) { printf("\nIl vino con codice \"%s\" non è stato inserito perchè già presente nella lista!\n", codice_vino); /* decrementa il numero dei vini del numero di inserimenti falliti */ *numero_vini = *numero_vini - 1; } } return (controllo_errori); } /* Algoritmo per l'inserimento di un vino nell'albero binario ordinato secondo il codice */ int inserisci_in_albero_bin(nodo_albero_bin_t ***radice_p, /* lavoro: puntatore al puntatore alla radice dell'albero */ char codice_vino[], /* input: codice del vino da inserire */ char nome_vino[], /* input: nome del vino da inserire */ char anno_vino[], /* input: anno di produzione del vino da inserire */ char luogo_vino[]) /* input: luogo di produzione del vino da inserire */ { int inserito, /* output: esito dell'inserimento */ i; /* lavoro: indice per i cicli for */ nodo_albero_bin_t *nodo_p, /* lavoro: puntatore ad un nodo */ *padre_p, /* lavoro: puntatore al padre del nodo_p */ *nuovo_p; /* lavoro: puntatore al nodo che conterrà il nuovo vino */ /* nodo_p e padre_p vengono inizializzati con l'indirizzo della radice e ad ogni */ /* iterazione padre_p prende l'indirizzo di nodo_p.nodo_p prende l'indirizzo del */ /* suo figlio sx o dx a seconda che il codice da inserire sia < o >= al codice */ /* puntato da nodo_p.Il ciclo termina quando nodo_p punta a NULL oppure ad un */ /* elemento che contiene un codice uguale a quello da inserire. */ for (nodo_p = padre_p = **radice_p; ((nodo_p != NULL) && (strcmp(nodo_p->codice_vino, codice_vino) != 0)); padre_p = nodo_p, nodo_p = (strcmp(codice_vino, nodo_p->codice_vino) < 0)? nodo_p->sx_p: nodo_p->dx_p); /* il vino non verrà inserito se era già presente, ovvero se nodo_p non punta a NULL */ if (nodo_p != NULL) inserito = 0; else { inserito = 1; /* viene allocata memoria per il nuovo nodo */ nuovo_p = (nodo_albero_bin_t *)malloc(sizeof(nodo_albero_bin_t)); /* inserimento del codice del vino */ for (i = 0; (i < LUNGHEZZA_CODICE); i++) nuovo_p->codice_vino[i] = codice_vino[i]; /* inserimento del nome del vino */ for (i = 0; (i < LUNGHEZZA_NOME); i++) nuovo_p->nome_vino[i] = nome_vino[i]; /* inserimento dell'anno di produzione del vino */ for (i = 0; (i < LUNGHEZZA_ANNO_PRODUZIONE); i++) nuovo_p->anno_vino[i] = anno_vino[i]; /* inserimento del luogo di produzione del vino */ for (i = 0; (i < LUNGHEZZA_LUOGO_PRODUZIONE); i++) nuovo_p->luogo_vino[i] = luogo_vino[i]; /* i puntatori vengono inizializzati a NULL */ nuovo_p->sx_p = nuovo_p->dx_p = NULL; /* se il nodo si trova in cima all'albero diventa la radice */ if (nodo_p == **radice_p) **radice_p = nuovo_p; /* se il codice inserito è inferiore a quello contenuto nel nodo padre */ else if (strcmp(codice_vino, padre_p->codice_vino) < 0) /* il nuovo nodo diventa figlio sinistro */ padre_p->sx_p = nuovo_p; else /* il nuovo nodo diventa figlio destro */ padre_p->dx_p = nuovo_p; } /* viene restituito il valore di esito dell'inserimento */ return(inserito); } /* Funzione per l'inserimento di un nuovo vino */ int inserisci_nuovo_vino(nodo_albero_bin_t **radice_p) /* lavoro: puntatore alla radice dell'albero */ { char nome_vino[LUNGHEZZA_NOME], /* input: nome del vino da inserire */ codice_vino[LUNGHEZZA_CODICE], /* input: codice del vino da inserire */ anno_vino[LUNGHEZZA_ANNO_PRODUZIONE], /* input: anno di produzione del vino da inserire */ luogo_vino[LUNGHEZZA_LUOGO_PRODUZIONE], /* input: luogo di produzione del vino da inserire */ carattere_acquisito = '~'; /* lavoro: variabile usata per acquisizioni e controlli */ int inserito = 0, /* output: esito dell'inserimento */ controllo_errori, /* lavoro: variabile di controllo */ i; /* lavoro: indice per i cicli for */ /* acquisizione del codice del vino da inserire */ printf("\nScrivere il codice del vino da inserire: "); /* non esce dal ciclo se il codice inserito da tastiera è troppo corto */ do { controllo_errori = 0; carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_CODICE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ') && (controllo_errori == 0)); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) codice_vino[i] = carattere_acquisito; else { i--; printf("\nIl codice deve contenere %d caratteri alfanumerici!\n", (LUNGHEZZA_CODICE - 1)); printf("\nRiscrivere il codice del vino: "); } /* se il codice contiene caratteri non alfanumerici */ if (codice_vino[i] < '0' || (codice_vino[i] > '9' && codice_vino[i] < 'A') || (codice_vino[i] > 'Z' && codice_vino[i] < 'a') || codice_vino[i] > 'z') { controllo_errori = 1; printf("\nRiscrivere il codice del vino: "); } } codice_vino[i] = '{parsed_message}'; } while ((strlen(codice_vino) != (LUNGHEZZA_CODICE - 1)) || (controllo_errori == 1)); carattere_acquisito = getchar(); /* se l'utente ha inserito un codice troppo lungo */ if (carattere_acquisito != '\n') /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); /* acquisizione del nome del vino da inserire */ /* non esce dal ciclo se l'utente non inserisce nessun nome */ do { printf("Scrivere il nome del vino da inserire: "); carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_NOME - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ')); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) nome_vino[i] = carattere_acquisito; else i--; } nome_vino[i] = '{parsed_message}'; /* se l'utente ha inserito un nome troppo lungo */ if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) { printf("\nIl nome è stato abbreviato a %d caratteri!\n\n", (LUNGHEZZA_NOME - 1)); /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); } } while (strlen(nome_vino) == 0); /* acquisizione dell'anno di produzione del vino da inserire */ printf("Scrivere l'anno di produzione del vino da inserire: "); /* non esce dal ciclo se l'anno inserito da tastiera è troppo corto */ do { controllo_errori = 0; carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_ANNO_PRODUZIONE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ') && (controllo_errori == 0)); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) anno_vino[i] = carattere_acquisito; else { i--; printf("\nL'anno deve contenere %d caratteri numerici!\n", (LUNGHEZZA_ANNO_PRODUZIONE - 1)); printf("\nRiscrivere l'anno di produzione del vino: "); } /* se l'anno contiene caratteri non numerici */ if (anno_vino[i] < '0' || anno_vino[i] > '9') controllo_errori = 1; } anno_vino[i] = '{parsed_message}'; } while ((strlen(anno_vino) != (LUNGHEZZA_ANNO_PRODUZIONE - 1)) || (controllo_errori == 1)); carattere_acquisito = getchar(); /* se l'utente ha inserito un anno troppo lungo */ if (carattere_acquisito != '\n') /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); /* acquisizione del luogo di produzione del vino da inserire */ /* non esce dal ciclo se l'utente non inserisce nessun luogo */ do { printf("Scrivere il luogo di produzione del vino da inserire: "); carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_LUOGO_PRODUZIONE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ')); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) luogo_vino[i] = carattere_acquisito; else i--; } luogo_vino[i] = '{parsed_message}'; /* se l'utente ha inserito un luogo troppo lungo */ if (carattere_acquisito != '\n') { printf("\nIl luogo è stato abbreviato a %d caratteri!\n\n", (LUNGHEZZA_LUOGO_PRODUZIONE - 1)); /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); } } while (strlen(luogo_vino) == 0); /* inserimento del vino nell'albero */ inserito = inserisci_in_albero_bin(&radice_p, codice_vino, nome_vino, anno_vino, luogo_vino); /* se l'inserimento è andato a buon fine */ if (inserito != 1) printf("\nVino \"%s\" già presente!", codice_vino); else printf("\nIl vino è stato inserito."); /* viene restituito l'esito dell'inserimento */ return (inserito); } int rimuovi_vino(nodo_albero_bin_t **radice_p) /* lavoro: puntatore alla radice dell'albero */ { char codice_vino[LUNGHEZZA_CODICE], /* input: codice del vino da rimuovere */ carattere_acquisito = '~'; /* lavoro: variabile usata per acquisizioni e controlli */ int rimosso = 0, /* output: esito rimozione */ controllo_errori, /* lavoro: variabile di controllo */ i; /* lavoro: indice per i cicli */ /* acquisizione del codice del vino da rimuovere */ printf("\nScrivere il codice del vino da rimuovere: "); /* non esce dal ciclo se l'utente non inserisce un codice corretto */ do { controllo_errori = 0; carattere_acquisito = '~'; for (i = 0; ((i < (LUNGHEZZA_CODICE - 1)) && (carattere_acquisito != '\n') && (carattere_acquisito != ' ') && (controllo_errori == 0)); i++) { carattere_acquisito = getchar(); if ((carattere_acquisito != '\n') && (carattere_acquisito != ' ')) codice_vino[i] = carattere_acquisito; else { i--; printf("\nIl codice deve contenere %d caratteri alfanumerici!\n", (LUNGHEZZA_CODICE - 1)); printf("\nRiscrivere il codice del vino: "); } /* se il codice contiene caratteri non alfanumerici */ if (codice_vino[i] < '0' || (codice_vino[i] > '9' && codice_vino[i] < 'A') || (codice_vino[i] > 'Z' && codice_vino[i] < 'a') || codice_vino[i] > 'z') { controllo_errori = 1; printf("\nRiscrivere il codice del vino: "); } } codice_vino[i] = '{parsed_message}'; } while ((strlen(codice_vino) != (LUNGHEZZA_CODICE - 1)) || (controllo_errori == 1)); carattere_acquisito = getchar(); /* se l'utente ha inserito un codice troppo lungo */ if (carattere_acquisito != '\n') /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); /* rimozione del vino dall'albero */ rimosso = rimuovi_da_albero_bin(&radice_p, codice_vino); if (rimosso == 1) printf("\nIl vino è stato rimosso!"); else printf("\nIl vino non è presente nella lista!"); /* viene restituito l'esito della rimozione */ return (rimosso); } /* Algoritmo per la rimozione di un vino dall'albero binario */ int rimuovi_da_albero_bin(nodo_albero_bin_t ***radice_p, /* lavoro: puntatore al puntatore alla radice dell'albero */ char codice_vino[]) /* input: codice del vino da rimuovere */ { int rimosso, /* output: esito della rimozione */ i; /* lavoro: contatore per i cicli for */ nodo_albero_bin_t *nodo_p, /* lavoro: puntatore a un nodo */ *padre_p, /* lavoro: padre di nodo_p */ *sost_p; /* lavoro: sostituto di nodo_p */ /* nodo_p e padre_p vengono inizializzati con l'indirizzo della radice e ad ogni */ /* iterazione padre_p prende l'indirizzo di nodo_p.nodo_p prende l'indirizzo del */ /* suo figlio sx o dx a seconda che il codice da inserire sia < o >= al codice */ /* puntato da nodo_p.Il ciclo termina quando nodo_p punta a NULL oppure ad un */ /* elemento che contiene un codice uguale a quello da rimuovere. */ for (nodo_p = padre_p = **radice_p; ((nodo_p != NULL) && (strcmp(nodo_p->codice_vino,codice_vino) != 0)); padre_p = nodo_p, nodo_p = (strcmp(codice_vino,nodo_p->codice_vino) < 0)? nodo_p->sx_p: nodo_p->dx_p); /* il vino non verrà rimosso se non era presente, ovvero se nodo_p punta a NULL */ if (nodo_p == NULL) rimosso = 0; else { rimosso = 1; /* se nodo_p non ha figlio sx */ if (nodo_p->sx_p == NULL) { /* se nodo_p si trova in cima all'albero */ if (nodo_p == **radice_p) /* il figlio destro del nodo diventa la radice */ **radice_p = nodo_p->dx_p; /* altrimenti se il codice da rimuovere è minore di quello del padre */ else if (strcmp(codice_vino, padre_p->codice_vino) < 0) /* il figlio destro del nodo_p, diventa figlio sinistro del padre */ padre_p->sx_p = nodo_p->dx_p; else /* il figlio destro del nodo_p, diventa figlio destro del padre */ padre_p->dx_p = nodo_p->dx_p; } /* altrimenti, se nodo_p non ha figlio destro */ else if (nodo_p->dx_p == NULL) { /* se nodo_p si trova in cima all'albero */ if (nodo_p == **radice_p) /* il figlio sinistro del nodo diventa la radice */ **radice_p = nodo_p->sx_p; /* altrimenti, se il codice da rimuovere è minore di quello del padre */ else if (strcmp(codice_vino, padre_p->codice_vino) < 0) /* il figlio sinistro del nodo_p diventa figlio sinistro del padre */ padre_p->sx_p = nodo_p->sx_p; else /* il figlio sinistro del nodo_p diventa figlio destro del padre */ padre_p->dx_p = nodo_p->sx_p; } /* altrimenti, se il nodo_p ha entrambi i figli */ else { /* sost_p prende l'indirizzo contenuto in nodo_p */ sost_p = nodo_p; /* ad ogni iterazione del ciclo, padre_p prende l'indirizzo di nodo_p e nodo_p prende */ /* l'indirizzo del figlio destro; il ciclo termina quando nodo_p non ha figlio destro */ for (padre_p = sost_p, nodo_p = sost_p->sx_p; (nodo_p->dx_p != NULL); padre_p = nodo_p, nodo_p = nodo_p->dx_p); /* sostuzione del codice del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_CODICE); i++) sost_p->codice_vino[i] = nodo_p->codice_vino[i]; /* sostituzione del nome del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_NOME); i++) sost_p->nome_vino[i] = nodo_p->nome_vino[i]; /* sostuzione dell'anno del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_ANNO_PRODUZIONE); i++) sost_p->anno_vino[i] = nodo_p->anno_vino[i]; /* sostituzione del luogo del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_LUOGO_PRODUZIONE); i++) sost_p->anno_vino[i] = nodo_p->anno_vino[i]; /* se padre_p e sost_p puntano allo stesso nodo */ if (padre_p == sost_p) /* il figlio sinistro del nodo_p diventa figlio sinistro del padre_p */ padre_p->sx_p = nodo_p->sx_p; else /* il figlio sinistro del nodo_p diventa figlio destro del padre_p */ padre_p->dx_p = nodo_p->sx_p; } /* il nodo puntato da nodo_p viene rimosso dalla memoria */ free(nodo_p); } return(rimosso); } /* funzione per la stampa dei vini in base al codice */ void stampa_codice(nodo_albero_bin_t *nodo_p) { if (nodo_p != NULL) { stampa_codice(nodo_p->sx_p); printf("%s %s %s %s\n", nodo_p->nome_vino, nodo_p->codice_vino, nodo_p->anno_vino, nodo_p->luogo_vino); stampa_codice(nodo_p->dx_p); } } void stampa_vini(nodo_albero_bin_t *radice_p, int numero_vini, int scelta_ordinamento) { vino_t vini[numero_vini]; /* array per l'ordinamento */ /* trasferimento dei vini dall'albero in un array */ inserisci_vini_in_array(radice_p, vini, 0); switch(scelta_ordinamento) { case 1: /* ordina i vini in base al nome */ quicksort_nome(vini, 0, numero_vini - 1); break; case 3: /* ordina i vini in base all'anno */ quicksort_anno(vini, 0, numero_vini - 1); break; case 4: /* ordina i vini in base al luogo */ quicksort_luogo(vini, 0, numero_vini - 1); break; } stampa_array(numero_vini, vini); } /* funzione per il trasferimento dei vini dall'albero in un array */ void inserisci_vini_in_array(nodo_albero_bin_t *nodo_p, vino_t *vini, int i) { if (nodo_p->codice_vino != NULL) { inserisci_vini_in_array(nodo_p->sx_p, vini, i); strcpy(vini[i].nome_vino, nodo_p->nome_vino); strcpy(vini[i].codice_vino, nodo_p->codice_vino); strcpy(vini[i].anno_vino, nodo_p->anno_vino); strcpy(vini[i].luogo_vino, nodo_p->luogo_vino); i = i + 1; inserisci_vini_in_array(nodo_p->dx_p, vini, i); } } void quicksort_nome(vino_t a[], int sx, int dx) { int i, j; /* variabili di lavoro */ vino_t tmp, /* variabile usata per lo scambio */ pivot; /* puntatore all'elemento che fungera' da pivot */ /* si sceglie come pivot il valore centrale e si attua una tri-partizione */ /* scambiando gli elementi in modo che nella porzione a destra del pivot vi */ /* siano elementi maggiori del pivot e nella porzione sinistra quelli minori */ for (pivot = a[(sx + dx) / 2], i = sx, j = dx; (i <= j);) { while (strcmp(a[i].nome_vino, pivot.nome_vino) == -1) i++; while (strcmp(a[j].nome_vino, pivot.nome_vino) == 1) j--; if (i <= j) { if (i < j) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; } i++; j--; } } /* si invoca ricorsivamente la funzione sulle porzioni sinistra e destra */ if (sx < j) quicksort_nome(a, sx, j); if (i < dx) quicksort_nome(a, i, dx); } void quicksort_anno(vino_t a[], int sx, int dx) { int i, j; /* variabili di lavoro */ vino_t tmp, /* variabile usata per lo scambio */ pivot; /* puntatore all'elemento che fungera' da pivot */ /* si sceglie come pivot il valore centrale e si attua una tri-partizione */ /* scambiando gli elementi in modo che nella porzione a destra del pivot vi */ /* siano elementi maggiori del pivot e nella porzione sinistra quelli minori */ for (pivot = a[(sx + dx) / 2], i = sx, j = dx; (i <= j);) { while (strcmp(a[i].anno_vino, pivot.anno_vino) == -1) i++; while (strcmp(a[j].anno_vino, pivot.anno_vino) == 1) j--; if (i <= j) { if (i < j) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; } i++; j--; } } /* si invoca ricorsivamente la funzione sulle porzioni sinistra e destra */ if (sx < j) quicksort_anno(a, sx, j); if (i < dx) quicksort_anno(a, i, dx); } void quicksort_luogo(vino_t a[], int sx, int dx) { int i, j; /* variabili di lavoro */ vino_t tmp, /* variabile usata per lo scambio */ pivot; /* puntatore all'elemento che fungera' da pivot */ /* si sceglie come pivot il valore centrale e si attua una tri-partizione */ /* scambiando gli elementi in modo che nella porzione a destra del pivot vi */ /* siano elementi maggiori del pivot e nella porzione sinistra quelli minori */ for (pivot = a[(sx + dx) / 2], i = sx, j = dx; (i <= j);) { while (strcmp(a[i].luogo_vino, pivot.luogo_vino) == -1) i++; while (strcmp(a[j].luogo_vino, pivot.luogo_vino) == 1) j--; if (i <= j) { if (i < j) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; } i++; j--; } } /*Si invoca ricorsivamente la funzione sulle porzioni sinistra e destra*/ if (sx < j) quicksort_luogo(a, sx, j); if (i < dx) quicksort_luogo(a, i, dx); } void stampa_array(int numero_vini, vino_t *vini) { int i; /*Vengono stampati gli elementi ordinati*/ for(i = 0; i < numero_vini; i++) printf("\n%20s %4s %4s %s", vini[i].nome_vino, vini[i].codice_vino, vini[i].anno_vino, vini[i].luogo_vino); }'; } while ((strlen(codice_vino) != (LUNGHEZZA_CODICE - 1)) || (controllo_errori == 1)); carattere_acquisito = getchar(); /* se l'utente ha inserito un codice troppo lungo */ if (carattere_acquisito != '\n') /* ripulisci il file stdin */ while (carattere_acquisito != '\n') carattere_acquisito = getchar(); /* rimozione del vino dall'albero */ rimosso = rimuovi_da_albero_bin(&radice_p, codice_vino); if (rimosso == 1) printf("\nIl vino è stato rimosso!"); else printf("\nIl vino non è presente nella lista!"); /* viene restituito l'esito della rimozione */ return (rimosso); } /* Algoritmo per la rimozione di un vino dall'albero binario */ int rimuovi_da_albero_bin(nodo_albero_bin_t ***radice_p, /* lavoro: puntatore al puntatore alla radice dell'albero */ char codice_vino[]) /* input: codice del vino da rimuovere */ { int rimosso, /* output: esito della rimozione */ i; /* lavoro: contatore per i cicli for */ nodo_albero_bin_t *nodo_p, /* lavoro: puntatore a un nodo */ *padre_p, /* lavoro: padre di nodo_p */ *sost_p; /* lavoro: sostituto di nodo_p */ /* nodo_p e padre_p vengono inizializzati con l'indirizzo della radice e ad ogni */ /* iterazione padre_p prende l'indirizzo di nodo_p.nodo_p prende l'indirizzo del */ /* suo figlio sx o dx a seconda che il codice da inserire sia < o >= al codice */ /* puntato da nodo_p.Il ciclo termina quando nodo_p punta a NULL oppure ad un */ /* elemento che contiene un codice uguale a quello da rimuovere. */ for (nodo_p = padre_p = **radice_p; ((nodo_p != NULL) && (strcmp(nodo_p->codice_vino,codice_vino) != 0)); padre_p = nodo_p, nodo_p = (strcmp(codice_vino,nodo_p->codice_vino) < 0)? nodo_p->sx_p: nodo_p->dx_p); /* il vino non verrà rimosso se non era presente, ovvero se nodo_p punta a NULL */ if (nodo_p == NULL) rimosso = 0; else { rimosso = 1; /* se nodo_p non ha figlio sx */ if (nodo_p->sx_p == NULL) { /* se nodo_p si trova in cima all'albero */ if (nodo_p == **radice_p) /* il figlio destro del nodo diventa la radice */ **radice_p = nodo_p->dx_p; /* altrimenti se il codice da rimuovere è minore di quello del padre */ else if (strcmp(codice_vino, padre_p->codice_vino) < 0) /* il figlio destro del nodo_p, diventa figlio sinistro del padre */ padre_p->sx_p = nodo_p->dx_p; else /* il figlio destro del nodo_p, diventa figlio destro del padre */ padre_p->dx_p = nodo_p->dx_p; } /* altrimenti, se nodo_p non ha figlio destro */ else if (nodo_p->dx_p == NULL) { /* se nodo_p si trova in cima all'albero */ if (nodo_p == **radice_p) /* il figlio sinistro del nodo diventa la radice */ **radice_p = nodo_p->sx_p; /* altrimenti, se il codice da rimuovere è minore di quello del padre */ else if (strcmp(codice_vino, padre_p->codice_vino) < 0) /* il figlio sinistro del nodo_p diventa figlio sinistro del padre */ padre_p->sx_p = nodo_p->sx_p; else /* il figlio sinistro del nodo_p diventa figlio destro del padre */ padre_p->dx_p = nodo_p->sx_p; } /* altrimenti, se il nodo_p ha entrambi i figli */ else { /* sost_p prende l'indirizzo contenuto in nodo_p */ sost_p = nodo_p; /* ad ogni iterazione del ciclo, padre_p prende l'indirizzo di nodo_p e nodo_p prende */ /* l'indirizzo del figlio destro; il ciclo termina quando nodo_p non ha figlio destro */ for (padre_p = sost_p, nodo_p = sost_p->sx_p; (nodo_p->dx_p != NULL); padre_p = nodo_p, nodo_p = nodo_p->dx_p); /* sostuzione del codice del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_CODICE); i++) sost_p->codice_vino[i] = nodo_p->codice_vino[i]; /* sostituzione del nome del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_NOME); i++) sost_p->nome_vino[i] = nodo_p->nome_vino[i]; /* sostuzione dell'anno del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_ANNO_PRODUZIONE); i++) sost_p->anno_vino[i] = nodo_p->anno_vino[i]; /* sostituzione del luogo del nodo sost_p con quello del nodo_p */ for (i = 0; (i < LUNGHEZZA_LUOGO_PRODUZIONE); i++) sost_p->anno_vino[i] = nodo_p->anno_vino[i]; /* se padre_p e sost_p puntano allo stesso nodo */ if (padre_p == sost_p) /* il figlio sinistro del nodo_p diventa figlio sinistro del padre_p */ padre_p->sx_p = nodo_p->sx_p; else /* il figlio sinistro del nodo_p diventa figlio destro del padre_p */ padre_p->dx_p = nodo_p->sx_p; } /* il nodo puntato da nodo_p viene rimosso dalla memoria */ free(nodo_p); } return(rimosso); } /* funzione per la stampa dei vini in base al codice */ void stampa_codice(nodo_albero_bin_t *nodo_p) { if (nodo_p != NULL) { stampa_codice(nodo_p->sx_p); printf("%s %s %s %s\n", nodo_p->nome_vino, nodo_p->codice_vino, nodo_p->anno_vino, nodo_p->luogo_vino); stampa_codice(nodo_p->dx_p); } } void stampa_vini(nodo_albero_bin_t *radice_p, int numero_vini, int scelta_ordinamento) { vino_t vini[numero_vini]; /* array per l'ordinamento */ /* trasferimento dei vini dall'albero in un array */ inserisci_vini_in_array(radice_p, vini, 0); switch(scelta_ordinamento) { case 1: /* ordina i vini in base al nome */ quicksort_nome(vini, 0, numero_vini - 1); break; case 3: /* ordina i vini in base all'anno */ quicksort_anno(vini, 0, numero_vini - 1); break; case 4: /* ordina i vini in base al luogo */ quicksort_luogo(vini, 0, numero_vini - 1); break; } stampa_array(numero_vini, vini); } /* funzione per il trasferimento dei vini dall'albero in un array */ void inserisci_vini_in_array(nodo_albero_bin_t *nodo_p, vino_t *vini, int i) { if (nodo_p->codice_vino != NULL) { inserisci_vini_in_array(nodo_p->sx_p, vini, i); strcpy(vini[i].nome_vino, nodo_p->nome_vino); strcpy(vini[i].codice_vino, nodo_p->codice_vino); strcpy(vini[i].anno_vino, nodo_p->anno_vino); strcpy(vini[i].luogo_vino, nodo_p->luogo_vino); i = i + 1; inserisci_vini_in_array(nodo_p->dx_p, vini, i); } } void quicksort_nome(vino_t a[], int sx, int dx) { int i, j; /* variabili di lavoro */ vino_t tmp, /* variabile usata per lo scambio */ pivot; /* puntatore all'elemento che fungera' da pivot */ /* si sceglie come pivot il valore centrale e si attua una tri-partizione */ /* scambiando gli elementi in modo che nella porzione a destra del pivot vi */ /* siano elementi maggiori del pivot e nella porzione sinistra quelli minori */ for (pivot = a[(sx + dx) / 2], i = sx, j = dx; (i <= j);) { while (strcmp(a[i].nome_vino, pivot.nome_vino) == -1) i++; while (strcmp(a[j].nome_vino, pivot.nome_vino) == 1) j--; if (i <= j) { if (i < j) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; } i++; j--; } } /* si invoca ricorsivamente la funzione sulle porzioni sinistra e destra */ if (sx < j) quicksort_nome(a, sx, j); if (i < dx) quicksort_nome(a, i, dx); } void quicksort_anno(vino_t a[], int sx, int dx) { int i, j; /* variabili di lavoro */ vino_t tmp, /* variabile usata per lo scambio */ pivot; /* puntatore all'elemento che fungera' da pivot */ /* si sceglie come pivot il valore centrale e si attua una tri-partizione */ /* scambiando gli elementi in modo che nella porzione a destra del pivot vi */ /* siano elementi maggiori del pivot e nella porzione sinistra quelli minori */ for (pivot = a[(sx + dx) / 2], i = sx, j = dx; (i <= j);) { while (strcmp(a[i].anno_vino, pivot.anno_vino) == -1) i++; while (strcmp(a[j].anno_vino, pivot.anno_vino) == 1) j--; if (i <= j) { if (i < j) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; } i++; j--; } } /* si invoca ricorsivamente la funzione sulle porzioni sinistra e destra */ if (sx < j) quicksort_anno(a, sx, j); if (i < dx) quicksort_anno(a, i, dx); } void quicksort_luogo(vino_t a[], int sx, int dx) { int i, j; /* variabili di lavoro */ vino_t tmp, /* variabile usata per lo scambio */ pivot; /* puntatore all'elemento che fungera' da pivot */ /* si sceglie come pivot il valore centrale e si attua una tri-partizione */ /* scambiando gli elementi in modo che nella porzione a destra del pivot vi */ /* siano elementi maggiori del pivot e nella porzione sinistra quelli minori */ for (pivot = a[(sx + dx) / 2], i = sx, j = dx; (i <= j);) { while (strcmp(a[i].luogo_vino, pivot.luogo_vino) == -1) i++; while (strcmp(a[j].luogo_vino, pivot.luogo_vino) == 1) j--; if (i <= j) { if (i < j) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; } i++; j--; } } /*Si invoca ricorsivamente la funzione sulle porzioni sinistra e destra*/ if (sx < j) quicksort_luogo(a, sx, j); if (i < dx) quicksort_luogo(a, i, dx); } void stampa_array(int numero_vini, vino_t *vini) { int i; /*Vengono stampati gli elementi ordinati*/ for(i = 0; i < numero_vini; i++) printf("\n%20s %4s %4s %s", vini[i].nome_vino, vini[i].codice_vino, vini[i].anno_vino, vini[i].luogo_vino); }
Ultima modifica effettuata da mik_91 27/01/14 17:39
aaa