[C] Esercizio con lista

di il
10 risposte

[C] Esercizio con lista

Ciao ragazzi. In poche parole l'esercizio che devo svolgere consiste nell'inserire dei dati presi da file in una struttura dati (io ho scelto di usare una lista), inserire un nuovo elemento da tastiera, cancellare un elemento da tastiera e ordinare gli elementi secondo una delle quattro chiavi che ho scritto sotto.
Il file che uso contiene questo:
Barolo 19E2 2011 Asti
Chianti 48K1 2009 Siena
Amarone 68A5 2010 Verona
Gravner 39U4 2006 Udine
Valentini 57L3 2012 Chieti
Il formato del file sarebbe: nome_vino, id_bottiglia, anno_produzione, luogo_imbottigliamento.

Premettendo che sono ancora piuttosto scarso in programmazione, ho trovato un problema piuttosto fastidioso che non riesco a risolvere. Praticamente quando vado a inserire un nuovo elemento, anche se questo esiste già nella lista, viene inserito lo stesso e invece non dovrebbe. Quindi la prima cosa che ho pensato è che il controllo che dovrebbe impedirlo non funzioni. Tuttavia, anche con l'aiuto di un amico decisamente più esperto di me, non siamo ancora riusciti a trovare l'errore. C'è qualcuno che può aiutarmi?
Il codice che ho scritto finora è questo:

/* Inclusione librerie */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

/* Definizione delle costanti simboliche */
#define DIM_NOME 70	/* Definizione della costante per la dimensione del nome del vino */
#define DIM_ID 20	/* Definizione della costante per la dimensione dell'id del vino */
#define DIM_ANNO 20	/* Definizione della costante per la dimensione dell'anno di produzione del vino */
#define DIM_LUOGO 70	/* Definizione della costante per la dimensione del luogo di imbottigliamento del vino */

/* Definizione della struttura dati */
typedef struct lista
{
	char nome_vino[DIM_NOME+1];
	char id_bott[DIM_ID+1];
	char anno_prod[DIM_ANNO+1];
	char luogo_imb[DIM_LUOGO+1];
	struct lista *succ_p;
}lista_t;

/* Dichiarazione delle funzioni */
int inserisci_in_lista(lista_t **,
			char [],
			char [],
			char [],
			char []);

/* Definizione delle funzioni */
/* Definizione della funzione main */
int main(void)
{
	/* Dichiarazione delle variabili locali */
	int operazione;			/* Variabile che contiene la scelta dell'utente */
	int file_caricato;		/* Variabile che contiene 0 se si deve ancora caricare il file, 1 se è già stato caricato */
	int esegui_altre_operazioni;	/* Variabile che se contiene 1 permette l'esucezione di ulteriori informazioni, altrimenti termina il programma */
	int controllo;			/* Variabile che controlla quando si raggiunge la fine del file */
	int inserito; 			/* Variabile che controlla se l'inserimento è avvenuto oppure no */
	int inserito1;			/* Variabile che controlla se l'inserimento del nuovo vino è avvenuto oppure no */
	char nome_vino[DIM_NOME+1];	/* Input: nome del vino */
	char id_bott[DIM_ID+1];		/* Input: id del vino */
	char anno_prod[DIM_ANNO+1];	/* Input: anno di produzione del vino */
	char luogo_imb[DIM_LUOGO+1];	/* Input: luogo di imbottigliamento del vino */
	FILE *file_input;		/* Puntatore al file */
	lista_t *testa_p;		/* Dichiarazione della testa della struttura dati */
	
	/* Inizializzo */
	file_caricato = 0;

	/* Inizializzo la testa della struttura = NULL */
	testa_p = NULL;


	/* Eseguo fino a che l'utente non decide di uscire dal programma */
	do
	{
		/* Interfaccia del programma: contiene informazioni generali e il menù con le possibili operazioni */
		printf("\n");
		printf("Benvenuti nel programma.\n");
		printf("Menù operazioni disponibili:\n");
		printf("-Inserire i dati da file nella struttura apposita: premere '1';\n");
		printf("-Inserire i dati relativi ad un nuovo vino: premere '2';\n");
		printf("-Rimuovere un vino esistente e i dati ad esso correlati: premere '3';\n");
		printf("-Ordinare la struttura dati in base ad una delle chiavi: premere '4';\n");
		
		/* Acquisizione dell'operazione scelta dall'utente */	
		scanf("%d",
			&operazione);

		/* Se l'utente sceglie di inserire i dati nella struttura */
		if (operazione == 1)
		{	
			/* Il file viene caricato solamente se file_caricato = 0 */
			if (file_caricato == 0)
			{
				file_caricato++;
	
				/* Apro il file in lettura */
				file_input = fopen ("input.txt",
							"r");

				/* Se non posso aprire il file mando un messaggio di errore */
				if (file_input == 0)
					printf("Impossibile caricare il file.\n");
				else
					printf("Il file è stato caricato con successo.\n");

				/* Leggo i dati e li inserisco nella struttura fino alla fine del file */
				do
				{
					/* La funzione fscanf restituirà EOF quando avrà raggiunto la fine del file */
					controllo = fscanf(file_input,
							"%s %s %s %s",
							nome_vino,
							id_bott,
							anno_prod,
							luogo_imb);

					
					/* Controllo che la variabile sia diversa da EOF per evitare che venga inserito due volte l'ultimo elemento */
					if (controllo != EOF)
					{
						inserito = inserisci_in_lista(&testa_p, 
										nome_vino,
										id_bott,
										anno_prod,
										luogo_imb);

						if (inserito == 1)
						{
							/* Stampo i dati nel caso l'utente voglia inserirne di nuovi, rimuoverne esistenti, o ordinarli */
							printf("\n%s %s %s %s",
									nome_vino,
									id_bott,
									anno_prod,
									luogo_imb);
						}
					}				

				} while(controllo != EOF);

				/* Chiudo il file */
				fclose(file_input);

				/* Chiedo se l'utente vuole compiere altre operazioni */
				printf("\n\nEseguire ulteriori operazioni? Digitare '1' in caso affermativo, '2' in caso negativo\n");
				scanf("%d",
					&esegui_altre_operazioni);	
			}
			else
			{
				printf("Il file è già stato caricato.\n");
			}
			
		}
		
		/* Se l'utente sceglie di inserire dei nuovi dati da tastiera */
		if ((operazione == 2) && (file_caricato != 0))
		{

			/* Acquisisco il nome del vino */
			printf("Digitare il nome del vino che si vuole inserire.\n");
			scanf("%s",
				nome_vino);

			/* Acquisisco l'id del vino */
			printf("Digitare l'id del vino che si vuole inserire.\n");
			scanf("%s",
				id_bott);

			/* Acquisisco l'anno di produzione del vino */
			printf("Digitare l'anno di produzione del vino che si vuole inserire.\n");
			scanf("%s",
				anno_prod);
			
			/* Acquisisco il luogo di imbottigliamento del vino */
			printf("Digitare il luogo di imbottigliamento del vino che si vuole inserire.\n");
			scanf("%s",
				luogo_imb);

			/* Invoco la funzione per inserire i dati nella struttura */
			inserito1 = inserisci_in_lista(&testa_p,
							nome_vino,
							id_bott,
							anno_prod,
							luogo_imb);

			/* Se la funzione ritorna 1 significa che i dati sono stati inseriti, in tal caso... */
			if (inserito1 == 1)
			{	
				/* Messaggio di conferma */			
				printf("\nI seguenti dati:\n%s %s %s %s\nsono stati inseriti con successo.\n",
													nome_vino,
													id_bott,
													anno_prod,
													luogo_imb);
			}
		
			/* Chiedo se l'utente vuole compiere altre operazioni */			
			printf("\n\nEseguire ulteriori operazioni? Digitare '1' in caso affermativo, '2' in caso negativo\n");
			scanf("%d",
				&esegui_altre_operazioni);	
			
		}
	
		if ((operazione == 3) && (file_caricato != 0))
		{
			printf("da fare");
		}

		if (operazione == 4)
		{
			printf("da fare");
		}

	} while (esegui_altre_operazioni == 1);

	/*Messaggio conclusivo */	
	printf("Grazie per aver utilizzato il programma.\n");

	return(0);
}


/* Definizione della funzione di inserimento dati in lista */
int inserisci_in_lista(lista_t **testa_p,
				char nome_vino[],
				char id_bott[],
				char anno_prod[],
				char luogo_imb[])
{
	/* Dichiarazione delle variabili locali */
	int inserito,		/* Output: ritorna 1 se l'inserimento ha avuto successo, 0 in caso contrario */
		i,		/* Contatore per l'array nome_vino */
		j,		/* Contatore per l'array id_bott */
		k,		/* Contatore per l'array anno_prod */
		l;		/* Contatore per l'array luogo_imb */
	lista_t *elem_p,
		*prec_p,
		*nuovo_p;

	/* Ciclo che controlla se l'id del vino che viene inserito esiste già */
	for (elem_p = prec_p = *testa_p;
		((elem_p != NULL) && (strcmp(elem_p->id_bott, id_bott) < 0));
		prec_p = elem_p, elem_p = elem_p->succ_p);
	
	/* Se l'id è già presente */
	if ((elem_p != NULL) && (strcmp(elem_p->id_bott, id_bott) == 0))
	{
		/* L'inserimento non avviene */
		inserito = 0;
		
		/* Messaggio di errore */	
		printf("Dati non inseriti.\n");
	}
	/* Altrimenti */
	else 
	{
		/* L'inserimento avviene */
		inserito = 1;

		/* Alloco memoria per il nuovo elemento che conterrà il nuovo vino */
		nuovo_p = (lista_t *)malloc(sizeof(lista_t));
		
		/* Inserisco nel nuovo elemento un puntatore all'array nuovo_vino */
		for (i = 0; 
			i <= DIM_NOME+1;
			i++);
		{
			nuovo_p->nome_vino[i] = nome_vino[i];
		} 
		
		/* Inserisco nel nuovo elemento un puntatore all'array id_bott */
		for (j = 0;
			j <= DIM_ID+1;
			j++);
		{
			nuovo_p->id_bott[j] = id_bott[j];
		}

		/* Inserisco nel nuovo elemento un puntatore all'array anno_prod */
		for (k = 0;
			k <= DIM_ANNO+1;
			k++);
		{
			nuovo_p->anno_prod[k] = anno_prod[k];
		}
		
		/* Inserisco nel nuovo elemento un puntatore all'array luogo_imb */
		for (l = 0;
			l <= DIM_LUOGO+1;
			l++);
		{
			nuovo_p->luogo_imb[l] = luogo_imb[l];
		}

		/* L'indirizzo dell'elemento successivo al nuovo elemento è quello corrente */
		nuovo_p->succ_p = elem_p;

		/* Se l'elemento è uguale alla testa */
		if (elem_p == *testa_p)

			/* Il nuovo elemento diventa la testa */
			*testa_p = nuovo_p;
		
		/* Altrimenti */
		else
			/* Il nuovo elemento diventa l'elemento successivo del precedente */
			prec_p->succ_p = nuovo_p;
	}
	return(inserito);
}
Grazie in anticipo.

10 Risposte

  • Re: [C] Esercizio con lista

    Ciao ragazzi, non voglio mettere pressione a nessuno, ma noto che molti thread hanno ricevuto risposte mentre il mio ancora niente.
    Purtroppo questo esercizio devo consegnarlo entro sabato 1° febbraio, quindi non mi rimane molto tempo.

    Qualsiasi tipo di aiuto andrebbe bene.
    Grazie in anticipo.
  • Re: [C] Esercizio con lista

    Il problema, se non ho capito male, è concentrato in queste frasi

    Praticamente quando vado a inserire un nuovo elemento, anche se questo esiste già nella lista, viene inserito lo stesso e invece non dovrebbe. Quindi la prima cosa che ho pensato è che il controllo che dovrebbe impedirlo non funzioni.

    Ma il controllo di cui parli, nel codice, qual è?
  • Re: [C] Esercizio con lista

    La funzione inserimento è questa:
    /* Definizione della funzione di inserimento dati in lista */
    int inserisci_in_lista(lista_t **testa_p,
                char nome_vino[],
                char id_bott[],
                char anno_prod[],
                char luogo_imb[])
    {
       /* Dichiarazione delle variabili locali */
       int inserito,      /* Output: ritorna 1 se l'inserimento ha avuto successo, 0 in caso contrario */
          i,      /* Contatore per l'array nome_vino */
          j,      /* Contatore per l'array id_bott */
          k,      /* Contatore per l'array anno_prod */
          l;      /* Contatore per l'array luogo_imb */
       lista_t *elem_p,
          *prec_p,
          *nuovo_p;
    
       /* Ciclo che controlla se l'id del vino che viene inserito esiste già */
       for (elem_p = prec_p = *testa_p;
          ((elem_p != NULL) && (strcmp(elem_p->id_bott, id_bott) < 0));
          prec_p = elem_p, elem_p = elem_p->succ_p);
       
       /* Se l'id è già presente */
       if ((elem_p != NULL) && (strcmp(elem_p->id_bott, id_bott) == 0))
       {
          /* L'inserimento non avviene */
          inserito = 0;
          
          /* Messaggio di errore */   
          printf("Dati non inseriti.\n");
       }
       /* Altrimenti */
       else 
       {
          /* L'inserimento avviene */
          inserito = 1;
    
          /* Alloco memoria per il nuovo elemento che conterrà il nuovo vino */
          nuovo_p = (lista_t *)malloc(sizeof(lista_t));
          
          /* Inserisco nel nuovo elemento un puntatore all'array nuovo_vino */
          for (i = 0; 
             i <= DIM_NOME+1;
             i++);
          {
             nuovo_p->nome_vino[i] = nome_vino[i];
          } 
          
          /* Inserisco nel nuovo elemento un puntatore all'array id_bott */
          for (j = 0;
             j <= DIM_ID+1;
             j++);
          {
             nuovo_p->id_bott[j] = id_bott[j];
          }
    
          /* Inserisco nel nuovo elemento un puntatore all'array anno_prod */
          for (k = 0;
             k <= DIM_ANNO+1;
             k++);
          {
             nuovo_p->anno_prod[k] = anno_prod[k];
          }
          
          /* Inserisco nel nuovo elemento un puntatore all'array luogo_imb */
          for (l = 0;
             l <= DIM_LUOGO+1;
             l++);
          {
             nuovo_p->luogo_imb[l] = luogo_imb[l];
          }
    
          /* L'indirizzo dell'elemento successivo al nuovo elemento è quello corrente */
          nuovo_p->succ_p = elem_p;
    
          /* Se l'elemento è uguale alla testa */
          if (elem_p == *testa_p)
    
             /* Il nuovo elemento diventa la testa */
             *testa_p = nuovo_p;
          
          /* Altrimenti */
          else
             /* Il nuovo elemento diventa l'elemento successivo del precedente */
             prec_p->succ_p = nuovo_p;
       }
       return(inserito);
    }
    Il controllo in teoria sarebbe questo:
       /* Ciclo che controlla se l'id del vino che viene inserito esiste già */
       for (elem_p = prec_p = *testa_p;
          ((elem_p != NULL) && (strcmp(elem_p->id_bott, id_bott) < 0));
          prec_p = elem_p, elem_p = elem_p->succ_p);
    che è subito dopo seguito dall'If:
       /* Se l'id è già presente */
       if ((elem_p != NULL) && (strcmp(elem_p->id_bott, id_bott) == 0))
       {
          /* L'inserimento non avviene */
          inserito = 0;
          
          /* Messaggio di errore */   
          printf("Dati non inseriti.\n");
       }
       /* Altrimenti */
       else ...
  • Re: [C] Esercizio con lista

    Hai messo un breakpoint in questa if

    if ((elem_p != NULL) && (strcmp(elem_p->id_bott, id_bott) == 0))

    ed eseguito il programma in debugging inserendo un codice già esistente?

    Quando l'esecuzione si ferma in quella linea, quanto valgono

    elem_p
    elem_p->id_bott
    id_bott
  • Re: [C] Esercizio con lista

    Non vorrei far la figura dello scemo, ma essendo che sono ancora inesperto anche col debugger, come si fa a mettere un breakpoint in quella riga di preciso?

    Ho letto che il formato sarebbe:
    break filesorgente: numerolinea,

    Usando GDB ho provato con
    break new.c: 260
    ma non funziona

    new.c sarebbe il nome del file
    e 260 sarebbe la riga numero 260 nel codice
    dove sbaglio?

    Grazie per l'aiuto oregon.
  • Re: [C] Esercizio con lista

    Va bene ... l'ho fatto io e ho visto che nella lista non ci sono i dati.

    Quindi il problema è da cercare nella funzione di inserimento.

    Ho visto che il problema è in questi cicli, ad esempio questo (ma controllali tutti)
    
          /* Inserisco nel nuovo elemento un puntatore all'array nuovo_vino */
          for (i = 0; 
             i <= DIM_NOME+1;
             i++)         ///  <----------- ATTENZIONE !!!
          {
             nuovo_p->nome_vino[i] = nome_vino[i];
          } 
    
    in cui avevi inserito un ; nella linea segnata con ATTENZIONE

    In quel modo la copia dei dati non avveniva.

    Ma mi chiedo perché mai utilizzi la for e non una semplice chiamata alla funzione strcpy

    strcpy(nuovo_p->nome_vino, nome_vino);

    (o alla strncpy)
  • Re: [C] Esercizio con lista

    Grazie mille oregon, mi hai risolto il problema.
    Nel frattempo ho fatto anche la funzione per rimuovere un elemento, e sia quella che l'inserimento funzionano alla perfezione.

    Rimane l'ordinamento e poi ho finito l'esercizio.
    Nel caso incontrassi ulteriori problemi, non esiterò a chiedere qui, visto la impeccabile competenza!
  • Re: [C] Esercizio con lista

    Di nulla ... ciao
  • Re: [C] Esercizio con lista

    Ciao ragazzi, come immaginavo sto trovando difficoltà nel creare la funzione per ordinare la lista.

    Spiego meglio ciò che devo fare:
    -Stampare a monitor l'elenco ordinato dei dati sulla base di una delle 4 chiavi, a scelta dell'utente.

    Tenendo conto che la lista ha questo aspetto:
    Barolo 19E2 2011 Asti
    Chianti 48K1 2009 Siena
    Amarone 68A5 2010 Verona
    Gravner 39U4 2006 Udine
    Valentini 57L3 2012 Chieti
    dove le chiavi sono chiaramente: nome_vino, id_bottiglia, anno_produzione, luogo_imbottigliamento.

    Per adesso ho creato questa parte nella funzione main:
    if ((operazione == 4) && (file_caricato != 0))
    		{
    			/*Acquisisco la chiave scelta dall'utente */
    			printf("Digitare la chiave secondo la quale si desidera ordinare gli elementi:\n");
    			printf("(Scelte disponibili: nome, id, anno, luogo)\n");
    			scanf("%s",
    				scelta);
    
    			/* Uso uno switch per suddividere i casi di ordinamento */
    			switch(scelta)
    			{
    				case 'nome':
    				ordinamento();
    				break;
    
    				case 'id':
    				ordinamento();
    				break;
    				
    				case 'anno':
    				ordinamento();
    				break;
    				
    				case 'luogo':
    				ordinamento();
    				break;
    			}
    
    			/* Chiedo se l'utente vuole compiere altre operazioni */			
    			printf("\n\nEseguire ulteriori operazioni? Digitare '1' in caso affermativo, '2' in caso negativo\n");
    			scanf("%d",
    				&esegui_altre_operazioni);
    		}
    
    Mancano ancora i dati da passare in input alla funzione per ordinare, ma immagino siano *testa_p (puntatore alla testa della lista) e una delle chiavi a seconda di quale case si verifica.

    Detto questo, non ho veramente idea su come implementare questa funzione e qualunque tipo di aiuto è ben accetto.
    Mentre attendo risposte sarò comunque qua a ragionarci su.
    Grazie in anticipo.
  • Re: [C] Esercizio con lista

    Nuovo argomento, nuovo thread ...
Devi accedere o registrarti per scrivere nel forum
10 risposte