Problema con le liste in C: funzione di inserimento

di il
10 risposte

Problema con le liste in C: funzione di inserimento

Ciao a tutti, e Buon Anno.

Allora, il problema che ho nasce dal fatto che ho sempre utilizzato un certo modo per inserire valori in una lista, ovvero richiamo la funzione di inserimento facendo passare l'indirizzo della testa della lista e un puntatore chiamato, ad esempio, "nuovo", che mi permetteva di creare un nuovo nodo.

Quindi il mio solito codice era questo:

struct lista {
      int valore;
      struct lista *next;
};

int main()
{
/*Codice.....*/
       struct lista *testa, *nuovo = NULL;
       printf("\n1 - Inserisci");
       printf("\n2 - Stampa");
       scelta = getch();
       switch(scelta)
       {
              case '1':
              inserimento(&testa, nuovo);
              break;
      /*Eccetera....*/


}

void inserimento(struct lista **head, *newElem)
{
     int num;

    printf("\nInserisci valore: ");
    scanf("%d", &num);
    newElem->valore = num;
    newElem->next = *head;
    *head = newElem;
}
E così funzionava benissimo. Ora però sto provando alcuni esami passati, dato che ho l'esame fra 1 settimana all'Università, e mi chiede di implementare una funzione di inserimento passando soltanto la "testa" senza la & commerciale. Inoltre, il tipo di dato non è più void inserimento ma int inserimento, di conseguenza ho capito che dovrò returnare qualcosa. Questo qualcosa suppongo sia la nuova testa, ma ho provato e non funziona (Warning: return makes integer from pointer without a cast).

Il codice è:
#include <stdio.h>
#include <stdlib.h>
#define CLS system("cls")   //so che è brutto, ma non ho voglia ogni volta di scrivere system("cls")...

struct lista {
	int valore;
	struct lista *next;
};

int inserisci(struct lista *head, struct lista *newElem);
void stampa(struct lista *head);


int main()
{
	struct lista *testa, *nuovo;
	int scelta, scelta2;
	
	while(1)
	{
		printf("\n1 - Inserisci");
		printf("\n2 - Stampa");
		scelta = getch();
		switch(scelta)
		{
			case '1':
				CLS;
				testa =inserisci(testa, nuovo);  //Mi da' lo stesso errore anche qui.
				CLS;
				break;
			case '2':
				CLS;
				stampa(testa);
				printf("\nPremi un tasto per tornare al menu...\n");
				scelta2 = getch();
				CLS;
			default:
				CLS;
				printf("\nErrore: carattere non valido.\n");
				printf("\nPremi un tasto per tornare al menu...\n");
				scelta2 = getch();
				CLS;
				break;
		}
	}
				
}

int inserisci(struct lista *head, struct lista *newElem)
{
	int numero;
	
	printf("\nInserisci un numero: ");
	scanf("%d", &numero);
	newElem->valore = numero;
	newElem->next = head;
	head = newElem;
	
	return head;   //L'errore è in questo punto. Il programma viene eseguito, ma crasha quando
                             //inserisco qualcosa.
}

void stampa(struct lista *head)
{
	struct lista *temp = NULL;
	temp = head;
	while(temp != NULL)
	{
		printf("\nValore inserito: %d", temp->valore);
		temp = temp->next;
	}
}
Mi sapreste spiegare il perché non funzioni? Io questo metodo non l'ho mai utilizzato e mi trovo un po' in difficoltà...

10 Risposte

  • Re: Problema con le liste in C: funzione di inserimento

    Sorvolando su tutta una serie di cose che non ho capito nel tuo codice (es. dove viene allocato 'nuovo'?), per "eliminare" il & dovresti scrivere una funzione di questo tipo:
    struct lista *inserisci(struct lista *head, struct lista *newElem);
    Mi sembra poco elegante (e senza senso) che ti venga richiesto di utilizzare un int come valore di ritorno; ad ogni modo potresti eventualmente fare un cast.
  • Re: Problema con le liste in C: funzione di inserimento

    Ciao
    Allora, per l'allocazione hai ragione, me l'ero completamente dimenticata (e mi succede sempre ). A parte questo, ora funziona; tuttavia, nel momento della stampa, mi mostra gli elementi inseriti ma poi il programma crasha.
    Mi dicevi del cast... Mi spiegheresti come dovrei utilizzarlo per favore? Perché non capisco proprio dove sia il problema, a questo punto...
  • Re: Problema con le liste in C: funzione di inserimento

    Ah, un'altra cosa. Nella funzione di stampa mi sono scordato di mettere la & commerciale al momento della chiamata e il doppio puntatore nella funzione, ma anche dopo la correzione mi crasha...
  • Re: Problema con le liste in C: funzione di inserimento

    nel momento della stampa, mi mostra gli elementi inseriti ma poi il programma crasha
    Il motivo è molto semplice: come fa a riconoscere la fine della lista se non hai caricato NULL nel campo next del primo elemento inserito?
    Nella funzione di stampa mi sono scordato di mettere la & commerciale al momento della chiamata e il doppio puntatore nella funzione, ma anche dopo la correzione mi crasha...
    I puntatori non sono un qualcosa da provare così, una & commerciale di qua, un ** di là: la modifica che hai descritto in realtà non cambia niente nel tuo caso, ti da solo la possibilità di modificare il contenuto di 'testa' che però nella funzione di stampa non è richiesto.
  • Re: Problema con le liste in C: funzione di inserimento

    Allora, per la stampa okay, hai ragione.
    Però non capisco la prima parte del commento: cosa vuoi dire con: "Il motivo è molto semplice: come fa a riconoscere la fine della lista se non hai caricato NULL nel campo next del primo elemento inserito?"

    Sto seguendo il modo in cui ho sempre inserito in lista, non ho capito cosa intendi dire... Non ho mai messo NULL nel campo next del primo elemento, e non so capisco nemmeno la sua utilità (forse vuoi dire che deve essere inizializzato? In questo caso va bene, ma ha sempre funzionato tutto correttamente).
    Inoltre, i due Warning ci sono ancora in questi due punti:

    int main()
    {
    ...
    testa = inserimento(testa, nuovo);
    }

    int *inserimento(struct lista *head, struct lista *newElem)
    {
    ...
    return head;
    }
  • Re: Problema con le liste in C: funzione di inserimento

    Sto seguendo il modo in cui ho sempre inserito in lista, non ho capito cosa intendi dire... Non ho mai messo NULL nel campo next del primo elemento, e non so capisco nemmeno la sua utilità (forse vuoi dire che deve essere inizializzato? In questo caso va bene, ma ha sempre funzionato tutto correttamente).
    Analizza con un debugger la funzione di stampa e vedi cosa succede quando arrivi sull'ultimo elemento, oppure stampa anche il valore di 'next' oltre al valore di 'valore') e capirai il perchè del crash:
       while(temp != NULL)
       {
          printf("\nValore inserito: %d", temp->valore);
          printf("\nPuntatore prossimo elemento: %d", (int)temp->next);
          temp = temp->next;
       }
    

    Invece per il warning devi fare un cast, che trovi spiegato in vari posti, es.
    int main()
    {
    ...
    testa = (struct lista *)inserimento(testa, nuovo);
    }
    
    int *inserimento(struct lista *head, struct lista *newElem)
    {
    ...
    return (int)head;
    }
    In pratica tratta il puntatore come se fosse un int.
    Comunque io sconsiglio questa modifica perchè non ha alcun senso!
  • Re: Problema con le liste in C: funzione di inserimento

    Ho guardato un paio di cose sul cast, e nella prima parte funziona bene. Mi genera altri warning quando faccio il return, ma a parte questo l'errore è un altro: inserisco i valori, li stampo, ma poi crasha alla fine.
    La stampa si sviluppa così, se presumiamo che l'utente inserisca come valori: 1, 2, 3, 4:

    Valore: 4
    Prossimo valore: 3

    Valore: 3
    Prossimo valore: 2

    Valore: 2
    Prossimo valore: 1

    Valore: 1
    Crash del programma. Per cui sembra che non punti a NULL, ma non capisco proprio come correggere.

    Il codice ora è questo:
    #include <stdio.h>
    #include <stdlib.h>
    #define CLS system("cls")
    
    struct lista {
    	int valore;
    	struct lista *next;
    };
    
    int *inserisci(struct lista *head, struct lista *newElem);
    void stampa(struct lista **head);
    
    
    int main()
    {
    	struct lista *testa = NULL, *nuovo = NULL;
    	int scelta, scelta2;
    	
    	while(1)
    	{
    		printf("\n1 - Inserisci");
    		printf("\n2 - Stampa");
    		scelta = getch();
    		switch(scelta)
    		{
    			case '1':
    				CLS;
    				testa = (struct lista*)inserisci(testa, nuovo);
    				CLS;
    				break;
    			case '2':
    				CLS;
    				stampa(&testa);
    				printf("\nPremi un tasto per tornare al menu...\n");
    				scelta2 = getch();
    				CLS;
    				break;
    			default:
    				CLS;
    				printf("\nErrore: carattere non valido.\n");
    				printf("\nPremi un tasto per tornare al menu...\n");
    				scelta2 = getch();
    				CLS;
    				break;
    		}
    	}
    				
    }
    
    int *inserisci(struct lista *head, struct lista *newElem)
    {
    	int numero;
    	newElem = (struct lista*)malloc(sizeof(struct lista));
    	printf("\nInserisci un numero: ");
    	scanf("%d", &numero);
    	newElem->valore = numero;
    	newElem->next = head;
    	head = newElem;
    	
    	return head;    //non ho messo return (int)head perché mi genera altri Warning 
    }
    
    void stampa(struct lista **head)
    {
    	struct lista *temp = NULL;
    	temp = *head;
    	while(temp != NULL)
    	{
    		printf("\nValore inserito: %d", temp->valore);
    		printf("\nValore next: %d\n", (int)temp->next->valore);
    		temp = temp->next;
    	}
    }
    
    Se hai voglia di aiutarmi giusto in quest'ultima cosa te ne sarei infinitamente grato...
  • Re: Problema con le liste in C: funzione di inserimento

    Per tutti gli inserimenti successivi al primo, come puntatore alla testa passi il valore di ritorno della precedente chiamata alla funzione inserisci(); per il primo inserimento, invece, passi un puntatore non inizializzato, quindi ti manca una inizializzazione a NULL.
  • Re: Problema con le liste in C: funzione di inserimento

    Come non inizializzato? Li ho inizializzati tutti... Quale sarebbe quello non inizializzato?
  • Re: Problema con le liste in C: funzione di inserimento

    Tutto risolto: il problema riguardava la stampa del valore successivo a quello considerato. Non capisco bene il motivo di questo errore, ma tramite dei flag ho capito che era quello. Ti ringrazio per la disponibilità
    Buone feste!
Devi accedere o registrarti per scrivere nel forum
10 risposte