[RISOLTO] errore di segmentazione

Linguaggi di programmazione: php, perl, python, C, bash e tutti gli altri.
Scrivi risposta
GiuliaC_
Prode Principiante
Messaggi: 13
Iscrizione: giovedì 27 agosto 2015, 11:59
Desktop: ubuntu
Distribuzione: Ubuntu 14.04.2 LTS x86_64
Sesso: Femminile

[RISOLTO] errore di segmentazione

Messaggio da GiuliaC_ »

ciao. sono nuova in questo forum e mi sto preparando per l'esame di programmazione in C e non è decisamente il mio forte. :( :muro:

ho scritto il primo punto di 3 della consegna di un esame passato, ma mi dà appunto un errore di segmentazione.
la consegna è:
si definisca una funzione double* leggiSequenza(char* nomeFile, int*size) in grado di aprire il file nomeFile(parametro IN), leggere la prima riga contenente il numero di elementi che seguono e poi la sequenza di numeri in virgola mobile. i numeri devono essere inseriti in un vettore allocato all'interno della funzione e fornito all'esterno tramite il valore di ritorno della funzione. i valori negativi devono essere cambiati di segno in modo che la sequenza ritornata contenga solo valori positivi. il numero di elementi letti (quindi la dimensione di seq) o -1 in caso di errore viene fornito nel parametro (OUTPUT) size.
per quanto riguarda il MAIN la consegna è:
prendere da riga di comando il nome di un file contenente il numero di elementi ed una sequenza di numeri in virgola mobile.

Codice: Seleziona tutto

  #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    
    double* leggiSequenza (char* nomeFile, int* size)
    {	
    	FILE* fp;
    	fp=fopen("nomeFile","r");
    	
    	if (!fp)
    	{
    		printf("ERRORE nell' aprire il file %s in lettura\n",nomeFile);
    		exit;
    	}
    
    	const int MAX = 100;
    	int numletti;
    	int numelem;
    	double* seq=NULL;
    	int i;
    	double num;
    	
    
    	numletti=fscanf(fp,"%d",&numelem);
    	printf("%d\n",numelem);
    	
    	if (numletti>1)
    	{
    		printf("formato file errato\n");
    		exit;
    	}
    
    	seq=(double*)malloc(numelem*sizeof(double));
    	
    	while (!feof(fp))
    	{		
    		fscanf(fp,"%lf",&num);
    		if (num<0)
    		{
    			num=-num;
    		}
    		seq[i]=num;
    		i++;
    	}
    
    	*size=i;
    	return seq;
    
    }
    
    int main(int argc, char** argv)
    {
    	int size=0;
    	int i;
    
    	double sequenza;
    
    	sequenza=*leggiSequenza(argv[1],&size);
    
    	for (i=0;i<size;i++)
    		printf("%lf",sequenza+i);
    
    	printf("\n");
    }
sicuramente all'interno del codice ci saranno imprecisione, accetto volentieri consigli :) ;)
grazie in anticipo.
Ultima modifica di GiuliaC_ il martedì 8 settembre 2015, 11:04, modificato 1 volta in totale.
Avatar utente
Dclaudio1990
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 624
Iscrizione: sabato 11 aprile 2015, 14:31
Distribuzione: openSUSE
Sesso: Maschile
Località: Roma

Re: errore di segmentazione

Messaggio da Dclaudio1990 »

Quando valorizzi sequenza usi l'operatore unario che non serve a nulla se non a pasticciare, dovrebbe causare lui il SIGSEGV.
Ciao :ciao:
"Io penso, dunque sono, ossia esisto."
-René Descartes
nameless95
Prode Principiante
Messaggi: 31
Iscrizione: lunedì 9 maggio 2011, 16:41
Desktop: XFCE 4.10
Distribuzione: Xubuntu 14.04 LTS
Sesso: Maschile

Re: errore di segmentazione

Messaggio da nameless95 »

Dopo un'occhiata superficiale, direi che l'errore più evidente è quel "nomeFile" nella fopen (alla riga 9) tra virgolette. nomeFile è una variabile che contiene il nome del file al quale vuoi accedere. Attraverso l'uso delle virgolette invece tenti di accedere ad un file chiamato, per l'appunto "nomeFile".
Avatar utente
Dclaudio1990
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 624
Iscrizione: sabato 11 aprile 2015, 14:31
Distribuzione: openSUSE
Sesso: Maschile
Località: Roma

Re: errore di segmentazione

Messaggio da Dclaudio1990 »

Anche quello è un errore ma non credo che sia lui il responsabile dell'errore di segmentazione di memoria.
In teoria se non trova il file lo crea..
"Io penso, dunque sono, ossia esisto."
-René Descartes
nameless95
Prode Principiante
Messaggi: 31
Iscrizione: lunedì 9 maggio 2011, 16:41
Desktop: XFCE 4.10
Distribuzione: Xubuntu 14.04 LTS
Sesso: Maschile

Re: errore di segmentazione

Messaggio da nameless95 »

In seguito andrà a leggere su quel file inesistente, è lì che verrà generato l'errore di segmentazione.

Ovviamente parlo dall'alto della mia ignoranza e inesperienza, quindi è molto probabile un mio errore.
Avatar utente
Dclaudio1990
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 624
Iscrizione: sabato 11 aprile 2015, 14:31
Distribuzione: openSUSE
Sesso: Maschile
Località: Roma

Re: errore di segmentazione

Messaggio da Dclaudio1990 »

Il file esiste... in teoria come ho gia detto se non ricordo male se non trova alcun file prova a crearlo se al processo è concesso.
"Io penso, dunque sono, ossia esisto."
-René Descartes
Avatar utente
M_A_W_ 1968
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 856
Iscrizione: venerdì 15 febbraio 2013, 3:57
Desktop: KDE
Distribuzione: SuSE
Sesso: Maschile
Località: Un luogo geometrico
Contatti:

Re: errore di segmentazione

Messaggio da M_A_W_ 1968 »

La maggior parte degli errori sono dovuti ad una inopinata confusione tra due variabili numletti e numelem, non necessarie e conflittuali. Inoltre è errata l'invocazione della fopen, come già notato, ed è errata la specificazione di sequenza nel main(). Vi sono poi altri errori minori e di stile.

Allo scopo di creare uno stimolo positivo alla riflessione, propongo una possibile soluzione, ampiamente accettabile dal punto di vista didattico, che vuole suggerire agli studenti gli idiomi più ragionevoli e solidi da usare per le varie operazioni. fscanf() è deprecata, ad esempio.

La soluzione è volutamente incompleta: è necessario verificare effettivamente il numero di valori letti da file, ad esempio, confrontandolo col valore letto in intestazione e gestendo i casi di errore (troppi valori o troppo pochi). Occorre inoltre aggiungere un controllo sul numero di parametri passati da command line, e gestire eventuali errori in tale senso.

Codice: Seleziona tutto

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUFSIZE 128

double *leggiSequenza(char *nomeFile, int *size)
{
    double *seq;
    char buff[BUFSIZE];
    int numletti;
    FILE *fp;
    *size = 0; /* Meglio non affidarne l'inizializzazione al main() */

    fp = fopen(nomeFile, "r");
    if (NULL == fp)
    {
        printf("ERRORE nell'aprire il file %s in lettura!\n", nomeFile);
        *size = -1;
        return NULL;
        /*exit(1);*/
    }

    fgets(buff, BUFSIZE, fp);
    numletti = strtod(buff, NULL);
    printf("Elementi presenti nel file: %d\n", numletti);

    if (numletti < 1)
    {
        printf("Formato file errato!\n");
        *size = -1;
        fclose(fp);
        return NULL;
        /*exit(1);*/
    }

    seq = (double *)malloc(numletti * sizeof(double));
    if (NULL == seq)
    {
        printf("Errore di allocazione!\n");
        *size = -1;
        fclose(fp);
        return NULL;
        /*exit(1);*/
    }

    while (fgets(buff, BUFSIZE, fp) != NULL)
    {
        seq[*size] = strtod(buff, NULL);
        *size += 1;
    }

    fclose(fp);
    return seq;
}

int main(int argc, char **argv)
{
    double *sequenza;
    int size;
    int i;

    sequenza = leggiSequenza(argv[1], &size);

    if(NULL != sequenza)
    {
        for (i = 0; i < size; ++i)
        {
            printf("%2d) %lf\n", i+1, sequenza[i]);
        }
        free(sequenza);
    }
    puts("");

    return 0;
}
Sì, un blog ce l'ho perfino io: gli è che mi manca il tempo...

"...in una società che sembra sempre più spaventata dai problemi troppo articolati e che rigetta come un corpo estraneo ogni elemento di complessità, sapremo ancora come utilizzare il parere degli esperti?"
nameless95
Prode Principiante
Messaggi: 31
Iscrizione: lunedì 9 maggio 2011, 16:41
Desktop: XFCE 4.10
Distribuzione: Xubuntu 14.04 LTS
Sesso: Maschile

Re: errore di segmentazione

Messaggio da nameless95 »

@M_A_W_1968: Ti ringrazio per gli ottimi spunti dati dal tuo stralcio di codice. Lo trovo molto interessante.
GiuliaC_
Prode Principiante
Messaggi: 13
Iscrizione: giovedì 27 agosto 2015, 11:59
Desktop: ubuntu
Distribuzione: Ubuntu 14.04.2 LTS x86_64
Sesso: Femminile

Re: errore di segmentazione

Messaggio da GiuliaC_ »

M_A_W_ 1968 [url=http://forum.ubuntu-it.org/viewtopic.php?p=4796566#p4796566][img]http://forum.ubuntu-it.org/images/icons/icona-cita.gif[/img][/url] ha scritto:La maggior parte degli errori sono dovuti ad una inopinata confusione tra due variabili numletti e numelem, non necessarie e conflittuali. Inoltre è errata l'invocazione della fopen, come già notato, ed è errata la specificazione di sequenza nel main(). Vi sono poi altri errori minori e di stile.

Allo scopo di creare uno stimolo positivo alla riflessione, propongo una possibile soluzione, ampiamente accettabile dal punto di vista didattico, che vuole suggerire agli studenti gli idiomi più ragionevoli e solidi da usare per le varie operazioni. fscanf() è deprecata, ad esempio.

La soluzione è volutamente incompleta: è necessario verificare effettivamente il numero di valori letti da file, ad esempio, confrontandolo col valore letto in intestazione e gestendo i casi di errore (troppi valori o troppo pochi). Occorre inoltre aggiungere un controllo sul numero di parametri passati da command line, e gestire eventuali errori in tale senso.

Codice: Seleziona tutto

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUFSIZE 128

double *leggiSequenza(char *nomeFile, int *size)
{
    double *seq;
    char buff[BUFSIZE];
    int numletti;
    FILE *fp;
    *size = 0; /* Meglio non affidarne l'inizializzazione al main() */

    fp = fopen(nomeFile, "r");
    if (NULL == fp)
    {
        printf("ERRORE nell'aprire il file %s in lettura!\n", nomeFile);
        *size = -1;
        return NULL;
        /*exit(1);*/
    }

    fgets(buff, BUFSIZE, fp);
    numletti = strtod(buff, NULL);
    printf("Elementi presenti nel file: %d\n", numletti);

    if (numletti < 1)
    {
        printf("Formato file errato!\n");
        *size = -1;
        fclose(fp);
        return NULL;
        /*exit(1);*/
    }

    seq = (double *)malloc(numletti * sizeof(double));
    if (NULL == seq)
    {
        printf("Errore di allocazione!\n");
        *size = -1;
        fclose(fp);
        return NULL;
        /*exit(1);*/
    }

    while (fgets(buff, BUFSIZE, fp) != NULL)
    {
        seq[*size] = strtod(buff, NULL);
        *size += 1;
    }

    fclose(fp);
    return seq;
}

int main(int argc, char **argv)
{
    double *sequenza;
    int size;
    int i;

    sequenza = leggiSequenza(argv[1], &size);

    if(NULL != sequenza)
    {
        for (i = 0; i < size; ++i)
        {
            printf("%2d) %lf\n", i+1, sequenza[i]);
        }
        free(sequenza);
    }
    puts("");

    return 0;
}

Se nel file i numeri (dopo il primo che indica il numero di elementi) sono scritti tutti nella stessa riga, separati dallo spazio, fgets(buff,BUFSIZE,fp) non mi legge ogni singolo numero, ma tutta la riga di numeri e quindi non inserisco ogni numero nella sequenza?!
spero di essermi spiegata :(
nameless95
Prode Principiante
Messaggi: 31
Iscrizione: lunedì 9 maggio 2011, 16:41
Desktop: XFCE 4.10
Distribuzione: Xubuntu 14.04 LTS
Sesso: Maschile

Re: errore di segmentazione

Messaggio da nameless95 »

Sì, ti sei spiegata perfettamente.
La funzione fgets legge al più BUFSIZE -1 byte (seguendo l'esempio fornito da M_A_W_1968).
Nel caso in cui la suddetta funzione incontri un carattere di newline (\n), prima di aver raggiunto il limite dei BUFSIZE -1 byte leggibili, interrompe la lettura in corrispondenza del '\n'.
A QUESTO indirizzo puoi trovare una descrizione sicuramente più dettagliata di quella da me fornita per quanto riguarda la funzione fgets.

Se il file di input è organizzato nell'ultimo modo da te descritto, fgets non è, a mio avviso, la funzione più adatta ai tuoi scopi.
GiuliaC_
Prode Principiante
Messaggi: 13
Iscrizione: giovedì 27 agosto 2015, 11:59
Desktop: ubuntu
Distribuzione: Ubuntu 14.04.2 LTS x86_64
Sesso: Femminile

Re: errore di segmentazione

Messaggio da GiuliaC_ »

nameless95 [url=http://forum.ubuntu-it.org/viewtopic.php?p=4796603#p4796603][img]http://forum.ubuntu-it.org/images/icons/icona-cita.gif[/img][/url] ha scritto:Sì, ti sei spiegata perfettamente.
La funzione fgets legge al più BUFSIZE -1 byte (seguendo l'esempio fornito da M_A_W_1968).
Nel caso in cui la suddetta funzione incontri un carattere di newline (\n), prima di aver raggiunto il limite dei BUFSIZE -1 byte leggibili, interrompe la lettura in corrispondenza del '\n'.
A QUESTO indirizzo puoi trovare una descrizione sicuramente più dettagliata di quella da me fornita per quanto riguarda la funzione fgets.

Se il file di input è organizzato nell'ultimo modo da te descritto, fgets non è, a mio avviso, la funzione più adatta ai tuoi scopi.

quindi mi chiedo se per caso esiste un modo di imporre come limite nel fgets, ad esempio, la dimensione del numero, o qualcosa del genere? troppo astratto? :o
Avatar utente
M_A_W_ 1968
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 856
Iscrizione: venerdì 15 febbraio 2013, 3:57
Desktop: KDE
Distribuzione: SuSE
Sesso: Maschile
Località: Un luogo geometrico
Contatti:

Re: errore di segmentazione

Messaggio da M_A_W_ 1968 »

La funzione fgets() è sempre la Via Regia nelle letture da file ASCII, come caso particolare del principio generale del buffering in lettura: si dovrebbe sempre leggere la più ampia porzione possibile di file in memoria in una volta sola (idealmente l'intero file con una singola lettura), compatibilmente con altre condizioni funzionali, poiché le operazioni di I/O su memorie di massa elettromeccaniche sono inerentemente le più lente in assoluto, assieme alle comunicazioni remote su canale seriale. Tutto ciò a prescindere dai servizi offerti dal file system e dal SO in generale, che in realtà realizzano esattamente tale principio ed a più livelli: dall'elettronica di controllo a bordo del disco rigido, al buffering hardware del controller sulla motherboard, fino ai vari livelli di buffering del SO.

Nel caso in cui il formato del file consista, in modo piuttosto anomalo, in un singolo record i cui campi contengono l'intera serie numerica, si deve solo apportare una banalissima modifica al loop di lettura, dopo aver piazzato la seguente comoda #define in testa:

Codice: Seleziona tutto

#define SEPS " ,;\t"

Il loop di lettura si modifica come segue:

Codice: Seleziona tutto

    if (fgets(buff, BUFSIZE, fp) != NULL)
    {
        char *p = strtok(buff, SEPS);
        while (NULL != p)
        {
            seq[*size] = strtod(p, NULL);
            *size += 1;
            p = strtok(NULL, SEPS);
        }
    }
L'accoppiata fgets() + strtok() costituisce il vero e proprio swiss army knife della programmazione in C, il principe di tutti gli strumenti per la lettura di dati da file testuali delimited di qualsivoglia formato, superata unicamente dall'uso di file binari e quindi di record definiti tramite struct con allineamento al byte, letti e scritti in blocco (anche multiplo) con una singola operazione low level.
Sì, un blog ce l'ho perfino io: gli è che mi manca il tempo...

"...in una società che sembra sempre più spaventata dai problemi troppo articolati e che rigetta come un corpo estraneo ogni elemento di complessità, sapremo ancora come utilizzare il parere degli esperti?"
GiuliaC_
Prode Principiante
Messaggi: 13
Iscrizione: giovedì 27 agosto 2015, 11:59
Desktop: ubuntu
Distribuzione: Ubuntu 14.04.2 LTS x86_64
Sesso: Femminile

Re: errore di segmentazione

Messaggio da GiuliaC_ »

M_A_W_ 1968 [url=http://forum.ubuntu-it.org/viewtopic.php?p=4796617#p4796617][img]http://forum.ubuntu-it.org/images/icons/icona-cita.gif[/img][/url] ha scritto:La funzione fgets() è sempre la Via Regia nelle letture da file ASCII, come caso particolare del principio generale del buffering in lettura: si dovrebbe sempre leggere la più ampia porzione possibile di file in memoria in una volta sola (idealmente l'intero file con una singola lettura), compatibilmente con altre condizioni funzionali, poiché le operazioni di I/O su memorie di massa elettromeccaniche sono inerentemente le più lente in assoluto, assieme alle comunicazioni remote su canale seriale. Tutto ciò a prescindere dai servizi offerti dal file system e dal SO in generale, che in realtà realizzano esattamente tale principio ed a più livelli: dall'elettronica di controllo a bordo del disco rigido, al buffering hardware del controller sulla motherboard, fino ai vari livelli di buffering del SO.

Nel caso in cui il formato del file consista, in modo piuttosto anomalo, in un singolo record i cui campi contengono l'intera serie numerica, si deve solo apportare una banalissima modifica al loop di lettura, dopo aver piazzato la seguente comoda #define in testa:

Codice: Seleziona tutto

#define SEPS " ,;\t"

Il loop di lettura si modifica come segue:

Codice: Seleziona tutto

    if (fgets(buff, BUFSIZE, fp) != NULL)
    {
        char *p = strtok(buff, SEPS);
        while (NULL != p)
        {
            seq[*size] = strtod(p, NULL);
            *size += 1;
            p = strtok(NULL, SEPS);
        }
    }
L'accoppiata fgets() + strtok() costituisce il vero e proprio swiss army knife della programmazione in C, il principe di tutti gli strumenti per la lettura di dati da file testuali delimited di qualsivoglia formato, superata unicamente dall'uso di file binari e quindi di record definiti tramite struct con allineamento al byte, letti e scritti in blocco (anche multiplo) con una singola operazione low level.
sto un po' impazzendo..
dato che il livello si sta alzando un po' troppo rispetto a ciò che ha fatto il prof a lezione, ho scritto un file in cui i numeri sono scritti uno sotto l'altro.
mi legge la prima riga , stampando il numero di elementi e poi "Segmentation fault (core dumped)" :muro: :muro: :muro:
purtroppo questo passaggio mi serve per procedere con gli altri punti dell'esercizio :cry:
chiedo perdono
Avatar utente
M_A_W_ 1968
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 856
Iscrizione: venerdì 15 febbraio 2013, 3:57
Desktop: KDE
Distribuzione: SuSE
Sesso: Maschile
Località: Un luogo geometrico
Contatti:

Re: errore di segmentazione

Messaggio da M_A_W_ 1968 »

Hai copiato e compilato esattamente il codice che ti ho fornito?
Questo è il risultato che ottengo io, dopo aver creato il file di dati nel formato richiesto.

Codice: Seleziona tutto

Y:\>compile giuliac.c
Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
giuliac.c:
Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland

Y:\>type giuliac.dat
12
3.14159272
1.41421356
1.25992104
0.03030303
0.83867056
0.88294759
4.23410650
0.96402758
0.00137174
5.20287346
3.83067056
2.25902194

Y:\>giuliac giuliac.dat
Elementi presenti nel file: 12
 1) 3.141593
 2) 1.414214
 3) 1.259921
 4) 0.030303
 5) 0.838671
 6) 0.882948
 7) 4.234107
 8) 0.964028
 9) 0.001372
10) 5.202873
11) 3.830671
12) 2.259022
Sì, un blog ce l'ho perfino io: gli è che mi manca il tempo...

"...in una società che sembra sempre più spaventata dai problemi troppo articolati e che rigetta come un corpo estraneo ogni elemento di complessità, sapremo ancora come utilizzare il parere degli esperti?"
GiuliaC_
Prode Principiante
Messaggi: 13
Iscrizione: giovedì 27 agosto 2015, 11:59
Desktop: ubuntu
Distribuzione: Ubuntu 14.04.2 LTS x86_64
Sesso: Femminile

Re: errore di segmentazione

Messaggio da GiuliaC_ »

M_A_W_ 1968 [url=http://forum.ubuntu-it.org/viewtopic.php?p=4796637#p4796637][img]http://forum.ubuntu-it.org/images/icons/icona-cita.gif[/img][/url] ha scritto:Hai copiato e compilato esattamente il codice che ti ho fornito?
Questo è il risultato che ottengo io, dopo aver creato il file di dati nel formato richiesto.

Codice: Seleziona tutto

Y:\>compile giuliac.c
Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
giuliac.c:
Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland

Y:\>type giuliac.dat
12
3.14159272
1.41421356
1.25992104
0.03030303
0.83867056
0.88294759
4.23410650
0.96402758
0.00137174
5.20287346
3.83067056
2.25902194

Y:\>giuliac giuliac.dat
Elementi presenti nel file: 12
 1) 3.141593
 2) 1.414214
 3) 1.259921
 4) 0.030303
 5) 0.838671
 6) 0.882948
 7) 4.234107
 8) 0.964028
 9) 0.001372
10) 5.202873
11) 3.830671
12) 2.259022
correttissimo :birra: facendo prove su prove prima, poi avevo dimenticato un "!=NULL" ..
GRAZIE GRAZIE GRAZIE!! gentilissimo
Avatar utente
Dclaudio1990
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 624
Iscrizione: sabato 11 aprile 2015, 14:31
Distribuzione: openSUSE
Sesso: Maschile
Località: Roma

Re: errore di segmentazione

Messaggio da Dclaudio1990 »

Metti [Risolto] al titolo.
Ciao :ciao:
"Io penso, dunque sono, ossia esisto."
-René Descartes
Scrivi risposta

Ritorna a “Programmazione”

Chi c’è in linea

Visualizzano questa sezione: Rafbor, steff e 10 ospiti