PDA

View Full Version : [C] Problema di segmentation fault durante l'esecuzione


Balop
09-12-2011, 19:12
Ciao a tutti, ho fatto un semplice programmino il quale legge una per una le righe di un file, vede se c'è la stessa riga nel secondo file, se non c'è la inserisce in un terzo file vuoto.
Insomma in pratica fa file1 - file2 = file3

Solo che ho un piccolo problema con la memoria, cioè che il file1 non lo posso fare più di 507 righe...
Se lo faccio più grande mi dà errore dopo appunto 507 righe restituendomi:
if ((stream2 = fopen(da_togliere, "rt")) == NULL)
printf(".....");

cioè io cambio di dimensioni il file1 e mi dà errore al file2... :confused:
eccovi il codice:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_BUF 15

int main()
{
char *unique= "Unique.txt";
char *da_togliere= "da togliere.txt";
char *buoni= "buoni.txt";
char *c= (char *) malloc((MAX_BUF * sizeof(char *)) + 1);
char *c2= (char *) malloc((MAX_BUF * sizeof(char *)) + 1);

/* dichiara lo stream e il prototipo della funzione fopen */
FILE *stream1, *stream2, *stream3, *fopen();

/* apre lo stream del file */
stream1 = fopen(unique, "rt");
stream3 = fopen(buoni, "wt");

// apro i files
if ((stream1 = fopen(unique, "rt")) == NULL)
printf("Non posso aprire il file %s\n", unique);
if ((stream3 = fopen(buoni, "wt")) == NULL)
printf("Non posso aprire il file %s\n", buoni);

// comincio la scansione dall'inizio del file "da_togliere"
while (!feof(stream1)){
int i= 1;
// if (!fgets(c, 3, stream1)) printf("");
fgets(c, 100, stream1);
// apro il file "unique"
stream2 = fopen(da_togliere, "rt");
if ((stream2 = fopen(da_togliere, "rt")) == NULL)
printf("Non posso aprire il file %s\n", da_togliere);

while (!feof(stream2)){
fgets(c2, 100, stream2);
if (strcmp(c, c2) == 0) {
i=0;
break;
}
}
if (i==1){
fputs(c, stream3);
printf("%s", c); //per vedere a video quello che fa
}
}

fflush(stream1);
fclose(stream1);
fflush(stream2);
fclose(stream2);
fflush(stream3);
fclose(stream3);
}


senza la malloc, dichiarando c e c2 [100000..] è sempre la stessa cosa, al massimo se metto un numero troppo grande mi dà segment fault in fase di compilazione..
anche se metto fgets(c2, 100000, stream2); è sempre lo stesso... :help:

GByTe87
09-12-2011, 19:19
1: Come fa a darti segfault in fase di compilazione? :confused:
2: Dichiari c2 come array contenente 16 char e poi fai fgets di 100? :confused:
3: perchè dichiari "char * fopen()"? fopen() è funzione contenuta nella stdlib, ti basta includere stdlib.h

Balop
09-12-2011, 19:31
1: Come fa a darti segfault in fase di compilazione? :confused:
2: Dichiari c2 come array contenente 16 char e poi fai fgets di 100? :confused:
3: perchè dichiari "char * fopen()"? fopen() è funzione contenuta nella stdlib, ti basta includere stdlib.h

1- No scusa era un altro errore, ma nel caso dichiarassi char c[1000.....].
2- quel valore di MAX_BUF è solo l'ultimo di una serie di tentativi..
3- hai ragione, ma comunque non è quello il problema perchè è ininfluente.. sinceramente era moltissimo tempo che non usavo l'input da file, quel pezzo l'ho copiato da un sito che l'aveva scritto così e non l'ho più tolto..

WarDuck
10-12-2011, 09:02
Aggiungo che apri più volte gli stream (inutilmente).


..
/* apre lo stream del file */
stream1 = fopen(unique, "rt");
stream3 = fopen(buoni, "wt");

// apro i files
if ((stream1 = fopen(unique, "rt")) == NULL)
printf("Non posso aprire il file %s\n", unique);
if ((stream3 = fopen(buoni, "wt")) == NULL)
printf("Non posso aprire il file %s\n", buoni);
..
stream2 = fopen(da_togliere, "rt");
if ((stream2 = fopen(da_togliere, "rt")) == NULL)
printf("Non posso aprire il file %s\n", da_togliere);
..


Basta mantenere solo la seconda (la variante con l'IF).

1- No scusa era un altro errore, ma nel caso dichiarassi char c[1000.....].


Non puoi allocare staticamente più di TOT bytes, in quanto esiste un limite finito per lo stack.


2- quel valore di MAX_BUF è solo l'ultimo di una serie di tentativi..


Andare a tentativi senza capire quello che stai facendo non è il massimo.

Il modo corretto per allocare le stringhe c e c2 è:


variabile = malloc( SIZE );


Dove SIZE è espresso in bytes (quindi non hai bisogno del sizeof se stai usando caratteri ASCII).

Si può discutere su quanto dev'essere grande SIZE per contenere la riga ed eventualmente il terminatore, questa è una cosa che dipende dai tuoi files.

In ogni caso NON tenerti stretto.

Quando fai FGETS, usa al posto di 100 la define che hai utilizzato, meno 1.


#define SIZE 1024

char *c = malloc( SIZE );
..
fgets(c, SIZE-1, stream);
..


Per definizione FGETS si ferma quando incontra una new-line.

Intanto prova a sistemare queste cose, poi vediamo se c'è qualcos'altro che non va.

Balop
10-12-2011, 09:49
Aggiungo che apri più volte gli stream (inutilmente).


..
/* apre lo stream del file */
stream1 = fopen(unique, "rt");
stream3 = fopen(buoni, "wt");

// apro i files
if ((stream1 = fopen(unique, "rt")) == NULL)
printf("Non posso aprire il file %s\n", unique);
if ((stream3 = fopen(buoni, "wt")) == NULL)
printf("Non posso aprire il file %s\n", buoni);
..
stream2 = fopen(da_togliere, "rt");
if ((stream2 = fopen(da_togliere, "rt")) == NULL)
printf("Non posso aprire il file %s\n", da_togliere);
..


Basta mantenere solo la seconda (la variante con l'IF).

Facendo questo sono salito a poter inserire nel file1 1018 righe...


Non puoi allocare staticamente più di TOT bytes, in quanto esiste un limite finito per lo stack.



Andare a tentativi senza capire quello che stai facendo non è il massimo.

Il modo corretto per allocare le stringhe c e c2 è:


variabile = malloc( SIZE );


Dove SIZE è espresso in bytes (quindi non hai bisogno del sizeof se stai usando caratteri ASCII).

Si può discutere su quanto dev'essere grande SIZE per contenere la riga ed eventualmente il terminatore, questa è una cosa che dipende dai tuoi files.

In ogni caso NON tenerti stretto.

Quando fai FGETS, usa al posto di 100 la define che hai utilizzato, meno 1.


#define SIZE 1024

char *c = malloc( SIZE );
..
fgets(c, SIZE-1, stream);
..


Per definizione FGETS si ferma quando incontra una new-line.

Intanto prova a sistemare queste cose, poi vediamo se c'è qualcos'altro che non va.
inizialmente le stringhe le avevo allocate con la malloc (anche se avevo usato SIZEOF * MAX_BUF)
il discorso dell'allocazione con c[] e c2[] era solo una prova che avevo fatto per vedere se cambiava qualcosa, ma come per gli altri tentativi non cambia niente, sia in positivo che in negativo, si ferma allo stesso identico punto..

la cosa che non capisco è che le righe sono corte, cioè contengono al massimo 20 caratteri + la newline, meno si di più no...
solo che ci sono molte righe nei file, quindi per questo il problema non dovrebbero essere c e c2, perchè tanto non devono memorizzare chissà che frasi chilometriche...
ho provato a mettere il fflush(stream2) fuori dal ciclo while dello stream2 ma sempre lo stesso..

la cosa cuoriosa è che il file2 (quello denominato "da togliere" e associato allo stream2) non ha problemi di dimensioni, posso mettergli anche 60000 righe..
invece se nel file1 (denominato "unique" e associato allo stream1) metto più di 1018 righe mi dà errore che "non può aprire il file2", non mi dà errore su se stesso.....

WarDuck
10-12-2011, 10:23
Il problema secondo me è che ad ogni passo del ciclo while apri lo stream2 senza chiuderlo dopo aver finito la lettura (nello stesso ciclo).

Se hai molte righe in stream1 apri tanti descrittori quante sono le righe.

Se non chiudi il descrittore, potresti arrivare a saturare il numero massimo di descrittori aperti supportati dal SO.

Ora le cose sono 2:


Chiudi stream2 all'interno del ciclo dopo averlo usato
Apri stream2 una volta sola, così come hai fatto per gli altri stream e usi qualche funzione per resettare lo stream ad ogni ciclo di lettura (forse fseek fa al caso tuo)


La soluzione 1 è quella più immediata.

La soluzione 2 sarebbe anche più efficiente credo, perché eviti di creare ad ogni ciclo un nuovo descrittore.

PS: posta il codice modificato.

Balop
10-12-2011, 10:43
Il problema secondo me è che ad ogni passo del ciclo while apri lo stream2 senza chiuderlo dopo aver finito la lettura (nello stesso ciclo).

Se hai molte righe in stream1 apri tanti descrittori quante sono le righe.

Se non chiudi il descrittore, potresti arrivare a saturare il numero massimo di descrittori aperti supportati dal SO.

Ora le cose sono 2:


Chiudi stream2 all'interno del ciclo dopo averlo usato
Apri stream2 una volta sola, così come hai fatto per gli altri stream e usi qualche funzione per resettare lo stream ad ogni ciclo di lettura (forse fseek fa al caso tuo)


La soluzione 1 è quella più immediata.

La soluzione 2 sarebbe anche più efficiente credo, perché eviti di creare ad ogni ciclo un nuovo descrittore.

PS: posta il codice modificato.
lo stream2 lo riaprivo ogni volta perchè altrimenti non funzionava bene il programma (non conoscevo la funzione che mi hai detto ora..), quindi riaprendolo ogni volta ricomincia la ricerca sempre dall'inizio.. avevo pensato di mettere la funziona fflush lì alla fine del ciclo while ma non la funzione fclose!! in questo modo sembra funzionare anche se ci sta un po a terminare l'ultima riga e mette un doppione (cosa che avevo visto pure prima ma di secondaria importanza..), anche se comunque ci sta un bel po, ora vedo come funziona la fseek e apro lo stream fuori, dovrebbe risultare più veloce il programma... ti faccio sapere.. intanto grazie :)

Balop
10-12-2011, 12:16
ok, ora il programma funziona quasi perfettamente, tranne che l'ultima riga la scrive 2 volte.. e non capisco perchè..

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_BUF 1024

int main()
{
char *unique= "Unique.txt";
char *da_togliere= "da togliere.txt";
char *buoni= "buoni.txt";
char *c= (char *) malloc(MAX_BUF);
char *c2= (char *) malloc(MAX_BUF);
int num=0;

/* dichiara lo stream e il prototipo della funzione fopen */
FILE *stream1, *stream2, *stream3;

/* apre lo stream del file
stream1 = fopen(unique, "rt");
stream3 = fopen(buoni, "wt");
*/
// apro i files
if ((stream1 = fopen(unique, "rt")) == NULL)
printf("Non posso aprire il file %s\n", unique);
if ((stream3 = fopen(buoni, "wt")) == NULL)
printf("Non posso aprire il file %s\n", buoni);
if ((stream2 = fopen(da_togliere, "rt")) == NULL)
printf("Non posso aprire il file %s\n", da_togliere);
// comincio la scansione dall'inizio del file "da_togliere"
while (!feof(stream1)){
int i=0;
// if (!fgets(c, 3, stream1)) printf("");
fgets(c, MAX_BUF - 1, stream1);
while (!feof(stream2)){
fgets(c2, MAX_BUF - 1, stream2);
if (strcmp(c, c2) == 0) {
i=0;
break;
}
else i=1;
}
if (i==1){
num++;
fputs(c, stream3);
// putc('\n', stream2);
printf("%s", c);
}
(void) fseek(stream2, 0L, SEEK_SET);
}
fflush(stream1);
fclose(stream1);
fflush(stream2);
fclose(stream2);
fflush(stream3);
fclose(stream3);
printf("Numero di righe: %d\n", num);
getchar();
}

all'inizio del primo ciclo while ho aggiunto la dichiarazione i=0 per evitare che restasse in qualche modo memorizzata con il valore 1.. invece niente.. l'ultima riga viene sempre duplicata.. l'ultimo aiutino?? :rolleyes:

Edit: come non detto, su windows funziona perfettamente.. =)