Lettura file C

Ryuzaky*
Dopo aver aperto un file di test in lettura come faccio a sapere se questo è vuoto o meno ?
Ho provato in questo modo :

fp=fopen("nomefile.txt","r");

if(fp==NULL){
                printf("Il file di testo è vuoto");
               }
else {
       Istruzioni programma;
       }


dove fp è il puntatore assegnato al file, ma non entra mai nell'if, anche se il testo è vuoto :? dov'è che sbaglio ?

Inoltre, quando provo a copiare un file di testo (vuoto) in un altro file di testo creato dal programma mi stampa simboli a caso nel nuovo file come "1/4" o "Æ".

Risposte
yoshiharu
"Ryuzaky*":
Dopo aver aperto un file di test in lettura come faccio a sapere se questo è vuoto o meno ?
Ho provato in questo modo :

fp=fopen("nomefile.txt","r");

if(fp==NULL){
                printf("Il file di testo è vuoto");
               }
else {
       Istruzioni programma;
       }


dove fp è il puntatore assegnato al file, ma non entra mai nell'if, anche se il testo è vuoto :? dov'è che sbaglio ?


Occhio che fopen() ritorna NULL solo se non riesce ad aprire il file.
Se e' vuoto e lo apre restituisce un puntatore non nullo, a prescindere da quello che c'e' scritto nel file.
Per vedere se il file e' vuoto o meno puoi sempre provare a leggere, se restituisce subito EOF allora e' vuoto.

Ryuzaky*
"yoshiharu":

Per vedere se il file e' vuoto o meno puoi sempre provare a leggere, se restituisce subito EOF allora e' vuoto.


scusa, come faccio a vedere se restituisce subito EOF ?
dovrei copiare il contenuto del file in una stringa e poi verificare se strlen è uguale a 0 ?

yoshiharu
"Ryuzaky*":

scusa, come faccio a vedere se restituisce subito EOF ?
dovrei copiare il contenuto del file in una stringa e poi verificare se strlen è uguale a 0 ?


Visto che parlavi di file di testo, prova con fgetc(). Se restituisce EOF il file e' vuoto.
Non e' che sia una soluzione molto pulita, pero' c'e' da dire che in genere, a meno di necessita' particolari, non ti serve di sapere se il file e' vuoto in anticipo, visto che la condizione di non EOF la puoi controllare volta per volta quando lo leggi.

Ryuzaky*
Per impostare che il programma non funzioni se il file è vuoto devo "imporre" quindi che fgetc()!=EOF ?
Grazie mille !

yoshiharu
"Ryuzaky*":
Per impostare che il programma non funzioni se il file è vuoto devo "imporre" quindi che fgetc()!=EOF ?


Se per esempio leggi il file carattere per carattere con un loop, usi la condizione che non sia la fine del file, in questo modo
  while((c=fgetc(file))!=EOF) {
      ...
  }


in questo modo il loop si blocca quando arriva alla fine del file, ma non parte nemmeno se non ci sono caratteri nel file.


Ho un'altra domanda, leggendo degli interi (sempre da file di testo) separati da più spazi o piu righe con la fscanf %d questa funzione passa automaticamente al successivo numero ?


A me le funzioni della famiglia *scanf() hanno sempre dato problemi, meglio IMHO leggere riga per riga (tipo con fgets(), o magari getline() ) e poi usare strtok per leggere la riga appena letta token per token, convertendo poi ogni singolo token in un numero con le funzioni adeguate a seconda del tipo di dato numerico che ti aspetti.
scanf() invece e' un po' particolare per quanto riguarda la lettura di spazi e simili, per cui delle volte, a seconda di quello che devi fare, si dimostra talvolta non proprio adeguata, secondo me...

Ryuzaky*
Il fatto è che la fgets mi ha causato parecchi problemi inserendola in un ciclo di lettura, alla prima iterazione di un for contenente printf e chiamata ad altre funzioni mi eseguiva le printf ma non le funzioni..
Mi spiego meglio: usando la fgets all'interno di un ciclo for la prima iterazione del ciclo mi eseguiva solamente le printf mentre dalla seconda in poi andava tutto "liscio". Con la fscanf non ho questo problema invece. Mi han detto che l'errore è dovuto al fatto che la fgets è lettura non formattata (che significa poi di preciso lettura formattata e come può aver influenzato il ciclo ? )

yoshiharu
"Ryuzaky*":

Mi spiego meglio: usando la fgets all'interno di un ciclo for la prima iterazione del ciclo mi eseguiva solamente le printf mentre dalla seconda in poi andava tutto "liscio". Con la fscanf non ho questo problema invece. Mi han detto che l'errore è dovuto al fatto che la fgets è lettura non formattata (che significa poi di preciso lettura formattata e come può aver influenzato il ciclo ? )


Non ci ho capito molto (overstatement :-) ).
Puoi postare il pezzo di codice incriminato, con un esempio dell'input caratteristico che causava questo problema?
"Formattato" si riferisce a quello che fa printf() o scanf(), che usano le stringhe di formato per descrivere l'input/output che ti aspetti. Tipo "%s" o "%d" etc.
Ma non capisco neanche io cosa c'entri col ciclo, magari era il resto delle operazioni che causavano qualche intoppo?

Ryuzaky*
void estrazione(char parola[], char parolaOutput[]);
void elaborazione(char par[]);

main(){
       char parola[N], parolaOutput[N];
       int r,i=0;
       printf("Quante parole si vogliono elaborare ?\n");
       scanf("%d", &r);

       for(i=0;i<r;i++){
                        printf("iterazione n. %d: Inserire la parola :",i);
                        /*gets(parola);*/
                        scanf("%s", parola);
                        estrazione(parola,parolaOutput);
                        printf("Primo passo di elaborazione : %s\n", parolaOutput);
                        elaborazione(parolaOutput);
                        printf("Secondo passo elaborazione : %s\n\n", parolaOutput);
                        }
        system("pause");
       }


Questo è il main del codice, la gets è messa come commento sostituita dalla scanf perchè mi causava, appunto, quel problema.. grazie dell'aiuto :)

(P.S. la printf con "iterazione n." l'ho inserita appunto per verificare quale iterazione non andasse)

yoshiharu
"Ryuzaky*":
main(){
       ...
       printf("Quante parole si vogliono elaborare ?\n");
       scanf("%d", &r);

       for(i=0;i<r;i++){
                        printf("iterazione n. %d: Inserire la parola :",i);
                        /*gets(parola);*/
                        scanf("%s", parola);
                           ...
                        }

       }



A parte che dovresti preferire fgets() a gets(), il problema qui e' causato dal fatto che il primo scanf() (quello fuori dal loop) legge l'input _fino_ al primo whitespace. Quindi, quando inserisci il numero e poi dai newline, rimane un '\n' pendente, che viene intercettato dal primo fgets() o scanf(). Se c'e' scanf, i whitespace prima del "%d" dovrebbero essere scartati automaticamente, per cui tutto sembra andare bene. Mentre fgets() ritorna appena trova un '\n', con una stringa vuota.
Ripeto che secondo me il modo piu' pratico e' quello di usare una fgets() seguita da strtok(), oppure, se l'input e' particolarmente semplice (come nel caso del primo scanf()) usare sscanf() invece di strtok(), che di da' anche la conversione automatica, per esempio.
Tra l'altro, e' noto che scanf() ha anche dei sottili problemi di sicurezza, oltre a quelli di usabilita'.

Ryuzaky*
Scusa, in che senso problemi di "sicurezza" ?

yoshiharu
"Ryuzaky*":
Scusa, in che senso problemi di "sicurezza" ?


Per esempio (ipersemplifico):

    char r[SIZE];
    scanf("%s",r);


continua a leggere anche se l'utente inserisce piu' caratteri di quanti ne possa ospitare il buffer.
Sfruttando questo fenomeno e' possibile sovrascrivere con schifezza a piacere il codice che segue la locazione dell'array, per esempio con codice arbitrario. So che e' stato usato in passato.

Vedi per esempio questo, laddove trovi anche delle info interessanti sui problemi che puo' dare scanf.

Ryuzaky*
Capito, quindi un modo di rimediare al problema precedente sarebbe quello di mettere una gets a vuoto.
In ogni caso non capisco l'uso di sscanf dopo fgets. Dal momento che la fgets legge una stringa pari alla dimensione del buffer, usare di seguito la sscanf per ottenere la medesima stringa ha poco senso ! o no ?
Forse intendevi dire di leggere, prima riga inclusa, con la fgets e in seguito fare una sscanf(%d), dalla stringa per ottenere il numero di elementi nel vettore in questo caso sarebbe comunque risolto il problema del \n vacante !
Immagino che la scanf si riveli piu utile nel caso in cui l'input sia da tastiera.
Per caso anche la printf crea problemi del genere ? sto avendo un problema molto simile a quello descritto da te con la scanf. Nel senso che la stampa non si ferma quando finisce il buffer. Grazie mille ancora per l'aiuto e gli utilissimi suggerimenti.

yoshiharu
"Ryuzaky*":
Capito, quindi un modo di rimediare al problema precedente sarebbe quello di mettere una gets a vuoto.


Volendo puoi anche fare cosi', ma mi sembra un po' (tanto) brutto.
Usa direttamente la fgets(), che e' meglio di gets(), e poi puoi usare anche sscanf().


In ogni caso non capisco l'uso di sscanf dopo fgets. Dal momento che la fgets legge una stringa pari alla dimensione del buffer, usare di seguito la sscanf per ottenere la medesima stringa ha poco senso ! o no ?
Forse intendevi dire di leggere, prima riga inclusa, con la fgets e in seguito fare una sscanf(%d), dalla stringa per ottenere il numero di elementi nel vettore in questo caso sarebbe comunque risolto il problema del \n vacante !


L'idioma e' sempre quello: prima fai una fgets(), per riempire un buffer, e ti becchi pure il newline. Poi sscanf(), per parsare la stringa, con un formato fisso, perche' e' quello che ti aspetti. Non e' un passaggio inutile, perche' fgets() serve solo per acquisire l'input, sscanf() "se lo lavora". Se l'input e' piu' complesso, magari variabile, e' meglio usare strtok() invece, ma e' un altro discorso.


Per caso anche la printf crea problemi del genere ? sto avendo un problema molto simile a quello descritto da te con la scanf. Nel senso che la stampa non si ferma quando finisce il buffer.


Non conoscendo i dettagli e' uno sparo nel buio, ma non e' che ti sei dimenticato di terminare la stringa con un '\0'?

Ryuzaky*
No :/ ho posto il problema in un altro post, se puoi darci un occhiata il link è questo : http://www.matematicamente.it/forum/post593129.html#p593129 :wink:

yoshiharu
"Ryuzaky*":
No :/ ho posto il problema in un altro post, se puoi darci un occhiata il link è questo : http://www.matematicamente.it/forum/post593129.html#p593129 :wink:


Controlla quello che ti ha scritto Rggb (il suo post e' seguente al tuo al quale sto rispondendo).
Secondo me ha individuato il problema. Prova a scrivere i caratteri uno per uno, invece che in stringa, incluso il carattere laddove dovrebbe esserci un terminatore.

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.