Visualizzazione dei risultati da 1 a 8 su 8

Discussione: [C] lista nomi

  1. #1

    [C] lista nomi

    Salve.
    Sto tentando di elaborare un programma che:
    - prenda in input dei nomi
    - li inserisca in ordine alfabetico in una lista
    -stampi la lista dei nomi inseriti.

    Il compilatore però, dopo aver preso il secondo nome, mi dà segmentation fault; perché?

    codice:
     
    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    
    struct lista{
    	char nome[15];
    	struct lista *nextptr;
    };
    typedef struct lista lista_al;
    
    /*prototipi*/
    lista_al *my_alloc(void);
    void insert_el(lista_al **sptr);
    int disordine(char *ial, char *sal);
    void stampa_lista(lista_al *sptr);
    
    
    int main(){
    	int cntr=0;
    	lista_al *head=NULL; //all'inizio non ci sono nodi
    	insert_el(&head);
    	do{
    		printf("Per inserire altri elementi,1 to go on, -1 to exit\n");
    	    scanf("%d",&cntr);
    	    if(cntr!=-1)
    	    insert_el(&head);
    	}while(cntr!=-1);
    	stampa_lista(head);
    
    
    
    	return 0;
    }
    
    /*definizioni di funzione*/
    lista_al *my_alloc(){
    	lista_al *p;
    	p=(lista_al*)malloc(sizeof(lista_al));
    	if(p==NULL){
    	   printf("Errore nell'allocazione della memoria.\n");
    	   exit(-1);
        }
    	return p;
    }
    
    
    void insert_el(lista_al **sptr){
    	lista_al *newptr,*scanptr=NULL,*previousPtr=NULL;
    	static int j=0;
    	int i;
    	++j; //contatore numero di elementi inseriti;
    	printf("Inserisci nome alunno:\n");
    	if(*sptr==NULL){
    	   *sptr=my_alloc();
    	   scanf("%s",(*sptr)->nome);
    	   (*sptr)->nextptr=NULL;
    	   printf("Nome primo alunno inserito correttamente\n");
    	   return ;
        }
        else{
    		i=0;
    		newptr=my_alloc();
    		scanf("%s",newptr->nome);
    		newptr->nextptr=NULL;
    		scanptr=*sptr;     //la scansione parte dalla testa della lista
    		while((scanptr!=NULL)&&(disordine(newptr->nome,scanptr->nome))) {    //finché non termina la lista, o ha trovato un elemento
    		                                                                     //successivo a quello da inserire
    		previousPtr=scanptr;
    		scanptr=scanptr->nextptr;                                            //continua la scansione
    		++i;
    	    }
    	    newptr->nextptr=scanptr;
    	    previousPtr->nextptr=newptr;
    	    if((i+1)==j)                                                        //se ho passato in rassegna tutti gli elementi della lista
    	    scanptr->nextptr=NULL;                                              //e non ho trovato un nome che venga dopo quello da inserire
    	                                                                        //allora il nome appena inserito è l'ultimo della lista
    	    printf("Elemento %d inserito correttamente.\n",j);
    	    return ;
    	}
    
    }
    
    
    
    
    
    int disordine(char *ial, char *sal){
    	int cntr=strcmp(ial,sal);        //ial=alunno da inserire; sal= alunno da passare in Scansione
    	if(cntr>0)                       //se l'alunno da inserire viene dopo quello appena esaminato
    	return 0;
    	else return 1;
    }
    
    
    
    void stampa_lista(lista_al *sptr){
    	lista_al *scanptr;
    	for(scanptr=sptr;scanptr!=NULL;scanptr=scanptr->nextptr)
    	printf("%s-->",scanptr->nome);
    	return;
    }

  2. #2
    Utente di HTML.it
    Registrato dal
    Jul 2008
    Messaggi
    1,326
    Provavi a dereferenziare puntatori NULL. In rosso le modifiche. Le stringhe vengono ordinate in ordine alfabetico inverso, non so se era questa la tua intenzione; se vuoi il contrario, basta negare la seconda condizione del while. Comunque ti ho corretto solo l'errore, ma ci sarebbero una serie di altre cose da aggiustare come il fatto che non deallochi lo spazio allocato dinamicamente... scrivi una funzione per la deallocazione. Attento anche al buffer overflow a cui vai incontro se qualcuno inserisce un nome più lungo di 15 caratteri.

    PS: non è il compilatore che dà segmentation fault, ma il sistema operativo dopo che il processo, una volta avviato il programma, riceve il segnale SIGSEGV (se stai su Linux). E non è nemmeno il compilatore a "prendere il nome": il compilatore compila soltanto, è l'esecuzione del programma a fare tutto il resto.

    codice:
    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    
    struct lista{
    	char nome[15];
    	struct lista *nextptr;
    };
    typedef struct lista lista_al;
    
    /*prototipi*/
    lista_al *my_alloc(void);
    void insert_el(lista_al **sptr);
    int disordine(char *ial, char *sal);
    void stampa_lista(lista_al *sptr);
    
    
    int main(){
    	int cntr=0;
    	lista_al *head=NULL; //all'inizio non ci sono nodi
    	insert_el(&head);
    	do{
    		printf("Per inserire altri elementi,1 to go on, -1 to exit\n");
    	    scanf("%d",&cntr);
    	    if(cntr!=-1)
    	    insert_el(&head);
    	}while(cntr!=-1);
    	stampa_lista(head);
    
    
    
    	return 0;
    }
    
    /*definizioni di funzione*/
    lista_al *my_alloc(){
    	lista_al *p;
    	p=(lista_al*)malloc(sizeof(lista_al));
    	if(p==NULL){
    	   printf("Errore nell'allocazione della memoria.\n");
    	   exit(-1);
        }
    	return p;
    }
    
    
    void insert_el(lista_al **sptr){
    	lista_al *newptr,*scanptr=NULL,*previousPtr=NULL;
    	static int j=0;
    	int i;
    	++j; //contatore numero di elementi inseriti;
    	printf("Inserisci nome alunno:\n");
    	if(*sptr==NULL){
    	   *sptr=my_alloc();
    	   scanf("%s",(*sptr)->nome);
    	   (*sptr)->nextptr=NULL;
    	   printf("Nome primo alunno inserito correttamente\n");
    	   return ;
        }
        else{
    		i=0;
    		newptr=my_alloc();
    		scanf("%s",newptr->nome);
    		newptr->nextptr=NULL;
    		scanptr=*sptr;     //la scansione parte dalla testa della lista
    		while((scanptr!=NULL)&&(disordine(newptr->nome,scanptr->nome))) {    //finché non termina la lista, o ha trovato un elemento
    		                                                                     //successivo a quello da inserire
    		previousPtr=scanptr;
    		scanptr=scanptr->nextptr;                                            //continua la scansione
    		++i;
    	    }
    
    	    newptr->nextptr=scanptr;
    	    if (i == 0) { /* l'inserimento è avvenuto in testa, quindi va aggiornato *sptr */
    	      *sptr = newptr;
    	    } else { /* altrimenti è avvenuto nel mezzo */
    	      previousPtr->nextptr=newptr;
    	    }
    
    	    printf("Elemento %d inserito correttamente.\n",j);
    	    return ;
    	}
    
    }
    
    
    
    
    
    int disordine(char *ial, char *sal){
    	int cntr=strcmp(ial,sal);        //ial=alunno da inserire; sal= alunno da passare in Scansione
    	if(cntr>0)                       //se l'alunno da inserire viene dopo quello appena esaminato
    	return 0;
    	else return 1;
    }
    
    
    
    void stampa_lista(lista_al *sptr){
    	lista_al *scanptr;
    	for(scanptr=sptr;scanptr!=NULL;scanptr=scanptr->nextptr)
    	printf("%s-->",scanptr->nome);
    	return;
    }
    every day above ground is a good one

  3. #3
    Ti ringrazio innanzitutto per aver avuto la pazienza e il coraggio di leggere quello scempio.

    Vediamo se ho capito dov'era l'errore.
    -L'errore nasceva dal fatto che non avevo considerato il caso in cui il nome appena inserito dovesse essere messo in testa alla lista; in questa situazione non sarebbe stato eseguito alcun ciclo while, e avrei fatto puntare previousPtr a NULL; giusto?

    -Per quanto riguarda la de-allocazione, mi confermi che è consigliabile eseguirla non appena non si ha più bisogno di accedere ad un'area di memoria e ai dati in essa contenuti?
    -Nel mio caso è sufficiente invocare un " free(head); " prima del return nel main?

    -Per il rischio buffer-overflow è sufficiente utilizzare fscanf+sscanf al posto di scanf, giusto?

    -Sulle operazioni che ho attribuito-nella fretta- al compilatore, stendiamo pure un velo pietoso!

  4. #4
    Utente di HTML.it
    Registrato dal
    Jul 2008
    Messaggi
    1,326
    Originariamente inviato da franzSPECIAL
    Vediamo se ho capito dov'era l'errore.
    -L'errore nasceva dal fatto che non avevo considerato il caso in cui il nome appena inserito dovesse essere messo in testa alla lista; in questa situazione non sarebbe stato eseguito alcun ciclo while, e avrei fatto puntare previousPtr a NULL; giusto?
    Una sorgente di errore era esattamente questa; l'altra l'avevi invece col puntatore scanptr quando il ciclo while veniva, invece, eseguito fino a che non risultasse proprio scanptr == NULL (cioè di fatto quando l'inserimento era da fare in coda): in quel caso, le istruzioni

    codice:
    	    if((i+1)==j)
    	    scanptr->nextptr=NULL;
    facevano fallire tutto con meravigliosa potenza

    Originariamente inviato da franzSPECIAL
    -Per quanto riguarda la de-allocazione, mi confermi che è consigliabile eseguirla non appena non si ha più bisogno di accedere ad un'area di memoria e ai dati in essa contenuti?
    Sì. In realtà nel tuo programma, dopo la stampa della lista, termini subito l'esecuzione quindi non ci sarebbe stretta necessità di deallocare la memoria "a mano" in quanto lo farebbe il sistema operativo una volta terminato il processo, ma è buona norma non trascurare mai questo aspetto perché produce cattive abitudini, programmi trashware e il linguaggio di programmazione Java.

    Originariamente inviato da franzSPECIAL
    -Nel mio caso è sufficiente invocare un " free(head); " prima del return nel main?
    No, così deallocheresti lo spazio soltanto per il puntatore alla testa della lista... dalla testa devi scorrere tutta la lista e deallocare nodo per nodo, e questo lo devi fare tu perché la funzione free() della libreria standard di certo non sa che quel puntatore che gli passi è la testa di una lista

    Originariamente inviato da franzSPECIAL
    -Per il rischio buffer-overflow è sufficiente utilizzare fscanf+sscanf al posto di scanf, giusto?
    In quel caso va bene una fgets(), se non sai come si usa leggi qui. Fai attenzione perché la fgets() aggiunge automaticamente il carattere di newline alla fine della stringa, quindi una lettura appropriata nel tuo caso sarebbe

    codice:
    fgets(newptr->nome, sizeof(newptr->nome), stdin);
    newptr->nome[strlen(newptr->nome) - 1] = '\0';
    every day above ground is a good one

  5. #5
    Sì, effettivamente non aveva alcuna utilità far puntare l'ultimo elemento della lista a NULL!
    Grazie per l'aiuto!

  6. #6
    Utente di HTML.it
    Registrato dal
    May 2008
    Messaggi
    475
    ...ma è buona norma non trascurare mai questo aspetto perché produce cattive abitudini, programmi trashware e il linguaggio di programmazione Java.


    Ti prego posso metterla come firma!?!? Ovviamente mettendo l'autore
    "Let him who has understanding reckon the number of the beast, for it is a human number.
    Its number is rw-rw-rw-."

  7. #7
    Utente di HTML.it L'avatar di Alex'87
    Registrato dal
    Aug 2001
    residenza
    Verona
    Messaggi
    5,802
    Originariamente inviato da YuYevon
    ma è buona norma non trascurare mai questo aspetto perché produce cattive abitudini, programmi trashware e il linguaggio di programmazione Java.
    SpringSource Certified Spring Professional | Pivotal Certified Enterprise Integration Specialist
    Di questo libro e degli altri (blog personale di recensioni libri) | ​NO M.P. TECNICI

  8. #8
    Utente di HTML.it
    Registrato dal
    Jul 2008
    Messaggi
    1,326
    LOL fai pure ;D
    every day above ground is a good one

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.