Domanda sulle liste in C

di il
21 risposte

Domanda sulle liste in C

Ciao a tutti.
Avrei una domanda sulle liste, in particolare sul modo di inserimento di più numeri in una lista tramite una funzione (e non nel main).
Vi posto il mio codice:
#include <stdio.h>
#include <stdlib.h>
#define CLS system("cls")

struct fila {
	int num;
	struct fila *next;
};

void inserisci(struct fila **p);
void header()
{
	printf("\n\n1 - inserisci");
	printf("\n\n2 - stampa");
}

int main()
{
	struct fila *testa;
	struct fila *prec;
	struct fila *temp;
	struct fila *elimina;
	int i = 0, scelta;
	while(1)
	{
		header();
		scelta = getch();
		switch(scelta)
		{
			case '1':
				CLS;
				inserisci(&testa);
				CLS;
				break;
			case '2':
				CLS;
				temp = testa;
				while(temp != NULL)
				{
					printf("\n\nNumero inserito: %d", temp->num);
					temp = temp->next;
				}
				puts("");
				break;
			default:
				CLS;
				printf("Errore.\n");
				break;
		}
	}
	
	
	system("pause");
	return 0;
} 

void inserisci(struct fila **p)
{
	int numero, i;
	struct fila *nuovo;
	
	nuovo = (struct fila *)malloc(sizeof(struct fila));
	printf("\n\nUtente, inserisci un numero :" );
	scanf("%d", &numero);
	nuovo->num = numero;
	nuovo->next = *p;
	*p = nuovo;
	
}
E' giusto un programmino per inserire numeri e stamparli... ma crasha dopo averli stampati.
Avete idea del motivo per cui lo fa?

Grazie in anticipo

21 Risposte

  • Re: Domanda sulle liste in C

    A posto, anche questa volta ce l'ho fatta da solo
    PS: Non avevo inizializzato *testa a NULL, lol
  • Re: Domanda sulle liste in C

    Spesso vedo che nell'implementazione degli esercizi scolastici si fa un utilizzo "allegro" della malloc(), ovvero:
    - non viene mai controllato se effettivamente la malloc() non abbia ritornato NULL;
    - non viene mai chiamata la free().
    Può darsi che questo non dia problemi nei semplici programmini che vengono richiesti e che quindi il professore chiuda un occhio su queste mancanze; in ogni caso a me sembrano degli errori molto gravi.
  • Re: Domanda sulle liste in C

    candaluar ha scritto:


    Spesso vedo che nell'implementazione degli esercizi scolastici si fa un utilizzo "allegro" della malloc(), ovvero:
    - non viene mai controllato se effettivamente la malloc() non abbia ritornato NULL;
    - non viene mai chiamata la free().
    Può darsi che questo non dia problemi nei semplici programmini che vengono richiesti e che quindi il professore chiuda un occhio su queste mancanze; in ogni caso a me sembrano degli errori molto gravi.
    Dipende di che corso si tratta; se ad esempio si tratta di algoritmi e strutture dati, il controllo degli errori viene volutamente trascurato per concentrarsi di più sull'algoritmo. Se invece si tratta di un corso dove effettivamente l'obbiettivo è imparare il c, allora sì, sono degli errori.

    ciao
  • Re: Domanda sulle liste in C

    Tranquillo, nel 99.99% dei casi puoi tranquillamente evitare di controllare se la malloc ritorna null oppure no.

    Il motivo e' semplice: a meno di casi estrenamente rari, un programma correttamente proggettato alloca una quantita' finita di memoria. E tale quantita' e' inferiore alla memoria installata. Se il programma dovesse allocare tutta la memoria disponibile, saresti in presenza di 'memory leak'. In questo caso, pero', non avresti piu' un limite massimo di memoria allocata, e controllare se una malloc e' fallita, sarebbe solo come spegnere un incendio con un bicchiere.

    In altre parole, avresti un problema ben piu' grave da risolvere.

    Esistono programmi che cercano di sfruttare tutta la mem disponibile, ma sono casi molto rari e molto specialistici, ben lontani dalla progettazione software normale.

    per quanto riguarda la chiamata della free, anche qui il motivo e' semplice: il programma deve solo fare qualcosa e poi terminare. Al termine, sara' il s. o. a ricuperare tutta la memoria allocata.

    La gestione della memoria, invece, e' estremamente importante in quelle applicazioni che devono rimanere attive per molto tempo (ore, giorni o anche anni). In questo caso, la sua gestione e' una parte estremamente complessa da implementare. Non e' solo 'chiamare la free', ma anche quando.

    inoltre, malloc e free sono operazioni che richiedono molto tempo per essere eseguite, perche' devono accedere al s. o. Per questo motivo, si cerca di usarle il meno possibile.

    La materia 'allocazione della memoria' e' molto complessa, ha mille sfaccettature.
  • Re: Domanda sulle liste in C

    Unica cosa ELIMINA "system("cls")" è orrendo non si può vedere....per di piu in una definizione!
    
    void gotoxy (short x,short y)
    {
        COORD coord = {x, y};
        HANDLE hconsole  = GetStdHandle(STD_OUTPUT_HANDLE);
        if (hconsole == INVALID_HANDLE_VALUE) return;
        SetConsoleCursorPosition (hconsole,coord );
    }
    
    void cls()
    {
        CONSOLE_SCREEN_BUFFER_INFO csbi;
        const COORD startCoords = {0,0};
        DWORD dummy;
        HANDLE hconsole  = GetStdHandle(STD_OUTPUT_HANDLE);
        if (hconsole == INVALID_HANDLE_VALUE) return;
        GetConsoleScreenBufferInfo(hconsole,&csbi);
        FillConsoleOutputAttribute(hconsole,0,csbi.dwSize.X * csbi.dwSize.Y,startCoords,&dummy);
        FillConsoleOutputCharacter(hconsole,' ',csbi.dwSize.X * csbi.dwSize.Y,startCoords,&dummy);
        gotoxy(0,0);
    }
    
  • Re: Domanda sulle liste in C

    Ciao a tutti.
    In effetti me lo dimentico sempre il controllo del NULL, anche se gli danno molta importanza (colpa mia, devo ancora smanettarci un po' prima).
    Per quanto riguarda il CLS, non capisco perché possa essere così "brutto"... Anzi, io mi ci trovo anche meglio...
  • Re: Domanda sulle liste in C

    Ignorare i possibili errori non è un bel modo di lavorare: anche se è molto difficile che una malloc() fallisca è bene abituarsi fin da subito a controllarne il valore di ritorno e a pensare ad una sua gestione.
    Se poi non ci si abitua a pensare alla free() non si fa altro che aumentare le probabilità che successive malloc() falliscano.
    Se questi aspetti fanno paura allora è meglio scegliere un linguaggio di più alto livello come ad esempio Java o C#.
    Per concludere, non vorrei mai lavorare in team con uno sviluppatore che richiama funzioni senza gestirne i possibili casi di errore.
  • Re: Domanda sulle liste in C

    Giovani
    Gia' il fatto di considerare java e c# linguaggi ad alto livello perche' utilizzano il gc dimostra la giovinezza.
    Il gc non e' un panacea: riduce un po' la complessita' nella gestione della memoria, ma non la elimina. Anzi, la falsa sicurezza dats dalla presenza di un gc puo' portare a problemi anche peggiori che non la sua assenza. Ad esempio un uso eccessivo del gc ha conseguenza devastanti.

    Anche la gestione degli errori e' una problematica estremamente complessa: non deve essere troppo puntuale, per non appesantire troppo il codice e la sua mantenibilita', non deve esserectroppo blanda per non trattare errori facili da risolvere.

    Per avere una visione del perche' di certe scelte serve molta, ma molta esperienza. E buone competenze.

    Qundi, giovane programmatore, non credere a quello che ho scritto, ma pensaci bene, e studia il problema, fatti una tsbella dei pro e dei contro oltre a possibili soluzioni e vedrai che arriverai alle stesse conclusioni.
  • Re: Domanda sulle liste in C

    Per quanto riguarda il CLS, non capisco perché possa essere così "brutto"... Anzi, io mi ci trovo anche meglio...
    Semplicemente perchè lanci il programma "cls" all'interno del tuo programma per cancellare la console.Come se per fare la somma di due variabili dovessi lanciare una applicazione esterna,ridicolo.
    è un metodo LLLLLLLLento e programmaticamente inutile.
    Usa il cls pappa pronta postato.Poi un domani capirai di piu,anche su come funziona.

    Rimango anche io dell'idea di usare sempre la free per ogni malloc richiamata.
    Il controllo va sempre fatto perchè non è detto che ci sia un'heap infinito,dipende dalle impostazioni di sistema,quindi le probabilità che falliscano sono molto maggiori dello 0.01% .
  • Re: Domanda sulle liste in C

    vbextreme ha scritto:


    ...
    Rimango anche io dell'idea di usare sempre la free per ogni malloc richiamata.
    Il controllo va sempre fatto perchè non è detto che ci sia un'heap infinito,dipende dalle impostazioni di sistema,quindi le probabilità che falliscano sono molto maggiori dello 0.01% .
    Mio giovane entusiasta, la tua affermazone, benche' ragionevolmente corretta, richiede delle delle condizioni al contorno che sono ben specifiche. E tali condizioni non sono sempre disponibili.

    Ma a voler essere pignoli: e' solo l'allocazione della memoria che deve essere controllata?
    O, oltra alla memoria che e' finita (da cui l'heap non potra' mai essere infinito) ci sono altre risorse che andrebbero controlate?

    Io ne ho in mente almenu una, ovvia. Ed almeno un'altra, molto meno ovvia....
  • Re: Domanda sulle liste in C

    Gia' il fatto di considerare java e c# linguaggi ad alto livello perche' utilizzano il gc dimostra la giovinezza.
    Il gc non e' un panacea: riduce un po' la complessita' nella gestione della memoria, ma non la elimina. Anzi, la falsa sicurezza dats dalla presenza di un gc puo' portare a problemi anche peggiori che non la sua assenza. Ad esempio un uso eccessivo del gc ha conseguenza devastanti.
    Grazie per il giovane
    Non dico che l'utilizzo del gc automaticamente rende lo sviluppo più semplice; penso però che la gestione degli errori con l'utilizzo delle eccezioni semplifica di molto la vita (ammesso di saperla utilizzare!) e quindi, dal punto di vista educativo, sia più semplice per lo studente.
    Anche la gestione degli errori e' una problematica estremamente complessa: non deve essere troppo puntuale, per non appesantire troppo il codice e la sua mantenibilita', non deve esserectroppo blanda per non trattare errori facili da risolvere.
    Quindi una tua applicazione se la malloc() ritorna NULL semplicemente si lascia crashare al primo utilizzo del puntatore?
  • Re: Domanda sulle liste in C

    Una malloc che ritorna NULL e' un sintomo di un problema ben piu' rognoso: un memory leak.
    Ed e' questo da risolvere.

    Intanto eliminiamo subito il caso in cui l'applicazione alloca troppa memoria fin dalla sua partenza: questo caso viene risolto gia' in fase di sviluppo.

    Il caso rognoso e' quando il memory leak e' lento: ci possono volere ore o giorni per iniziare a vedere degli effetti (troppa memoria allocata dall'applicazione, ma ancora inferiore alla memoria disponibile nel sistema)

    Ma andiamo con ordine: perche' una malloc ritorna NULL? Perche' non ha piu' memoria disponibile.
    Ma come funziona una malloc?
    A grandi linee funziona cosi':

    1) l'applicazione parte con una certa quantita' di memoria assegnata dal SO.
    2) l'applicazione inizia a fare le sue elaborazioni e vengono chiamate le malloc. Quando una malloc non ha piu' memoria disponibile tra quella assegnata, richiede al S.O. un nuovo blocco di memoria.
    3) questo processo continua finche' il S.O. ha a disposzione memoria libera.
    4) quando l'applicazione ha allocata sutta la memoria di sistema, e il S.O non ne ha piu', ritorna NULL.

    Ma a questo punto tutto il compiuter e' in uno stato disastroso: oltre alla tua applicazione, ci sono anche altre applicazioni che stanno girando, che richiedono e rilasciano memoria in continuazione, c'e' il S.O. il buffer a supporto della lettura/scrittura file, la gestione della memoria virtuale, i thread, i servizi di rete, l'interfaccia grafica, ...

    In questo stato, non e' solo la tua applicazione che non funziona, ma l'intero sistema: puo' non funzionare piu' l'interfaccia grafica, non puoi piu' lanciare una console, il traffico di rete si ferma per mancanza di risorse,...

    Se la macchina e' accessibile solo da remoto, potrebbe non essere piu' raggiungibile..
    Spesso l'unica soluzione in tali situazioni e' quella di spegnere e riaccentere il computer.

    Allora che si fa?
    L'approccio standard, in attesa di capire dove sta' il memory leak e' quello di aggiungere un controllo, all'interno dell'applicazione, che si assicura che l'applicazione stessa non allochi piu' di tot memoria, superata la quale la quale l'aplicazione viene abortita e si sfruttano i dei meccanismi automatici di riavvio.

    In C c'e' la possibilita' anche di impostare un handler per gestire la situazione di "out of memory", ma spesso la sua attivazione arriva troppo tardi, percche' intanto il sistema e' gia' diventato instabile.

    Quindi, il passo successivo e' cercare di capire il responsabile del memory leak.
    Raramente si trova in 5 minuti. Spesso e' subdolo e serve fare un sacco di tentativi, aggiungendo controlli su controlli in vari punti del codice, per capire dove si trova il responsabile.

    E' un lavoro lento e' complicato: e spesso richiede l'utilzzo di strumenti come i memory profiler che sono anche loro abbastanza complicati da utilizzare: si deve conoscere esattamente come funziona l'applicazione, tutte le sue componenti, ...

    Un lavoraccio

    Ora e' un po' piu' chiaro?
  • Re: Domanda sulle liste in C

    Se il tuo programma si impianta il cliente ti chiama piuttosto arrabbiato e non è bello, soprattutto se non è colpa tua! Molto meglio segnalare il problema con un messaggio di "Memoria esaurita"; così come quando apri un file su disco verifichi che questo sia stato aperto e se non ci riesci segnali "Impossibile aprire file xxx" dando modo così all'utente di verificare se, ad esempio, ha i permessi per utilizzare questo file.
    Se l'utente ha problemi sul suo pc, il nostro software deve comunque adottare tutte le sicurezze per essere "utilizzabile".
    Se poi tu credi che sia meglio crashare spiegando all'utente che c'è un memory leak, rispetto il tuo pensiero.
  • Re: Domanda sulle liste in C

    Si scusa non infinito,ma decisamente enorme,naturalmente in base ai bit del microprocessore e altri piccoli dettagli.
    Ma questo vale per quasi tutte le macchine,in altre magari si usa solo la memoria fisica e non quella virtuale,in questi casi ricevere un NULL è assai probabile.
    è anche difficile stabilire se avremo abbastanza memoria per l'applicazione o dopo quanto tempo tornerà disponibile.
    Pertanto in via puramente teorica potremmo scrivere:
    
    char* mem = NULL;
    while ( !(mem = malloc(1000000000)) ) Sleep(1000); 
    
    Ovvio che se è la nostra applicazione a "succhiare" tutta la memoria la riga di codice appena scritta finirà per innescare un loop infinito.
    Quindi ci sono molte variabili in gioco,ma secondo me la prima cosa da imparare è che ad ogni malloc deve corrispondere una free.Sempre e comunque.
    Usare anche un briciolo di programmazione difensiva quale può essere il controllo del NULL allora sicuramente non guasta.Anche perchè non mi sembra di star parlando di applicazioni critiche o quant'altro.
    Siamo molto ai livelli di base e quindi va seguita la strada piu classica e corretta.
    Io ne ho in mente almenu una, ovvia. Ed almeno un'altra, molto meno ovvia...
    Ovvero?
Devi accedere o registrarti per scrivere nel forum
21 risposte