Newsgroup: it.comp.lang.c
Titolo: Un chiarimento su fflush()

Sto cercando di padroneggiare al meglio le fgets(),fflush(),fputs(),...
ma ancora sono lontano :)
Voglio leggere un file, usando la bufferizzazione e stampare le righe
numerate a schermo.
Ma ho un paio di problemi
a) la numerazione e' scorretta
b) sia con fflush() che senza il programma sembra comportarsi allo
   stesso modo
========FILE DA LEGGERE ========
a b c d        k
1 2 3 4
aa bb cc dd
11 22 33 44
===============================
=========== CODICE ===========
#include<stdio.h>
#define BUFFER 12
int main(int argc,char *argv[]){
	FILE *fp;
	char a[BUFFER];
	int i=0;
 
	if (argc != 2){
		fputs("USO:./a.out nome_file\n",stdout);
		exit(1);
	}
 
	fp=fopen("file.dat","r");
	while(fgets(a,BUFFER,fp)){
		printf("%d :%s",++i,a);
		fflush(fp);
	}
	fclose(fp);
	return 0;
}
 
=============================
In uscita io credevo di ottenere una cosa del tipo:
1 :a b c d
2 :1 2 3 4
3 :aa bb cc dd
4 :11 22 33 44
Invece ho:
 
/tmp$ cc -Wall prova.c 
/tmp$ ./a.out 
1 :a b c d    2 :     k
3 :1 2 3 4
4 :aa bb cc dd5 :
6 :11 22 33 447 :
8 :
La *k* mi compare pur essendo fuori dal buffer di lettura, cosa sbaglio?
Effettivamente il buffer di lettura legge BUFFER-1 caratteri, e k viene
letto alla chiamata successiva di fgets(), ma l'uso di fflush() non
dovrebbe eliminare la k?
Grazie

 dovrebbe eliminare la k?
Stai usando fflush() su uno stream in lettura. Questo genera un 
comportamento non definito dallo standard. Ergo, *non farlo*. fflush() 
si usa solo su uno stream di output.

 }
come ti hanno gia' detto non usare flush sollo stdin.
cmq cosi' come fai le righe che hanno un input piu' lungo e una serie di
spazi finali verranno lette e stampate con gli stessi spazi ... se vuoi
cerca di fare il tailing degli spazi finali se non ti servono ...
ciao

 come ti hanno gia' detto non usare flush sollo stdin.
Non era lo stdin, era un altro file in lettura, ma naturalmente il 
discorso di non usare fflush() (con due 'f') si applica lo stesso.


A gia' dimenticavo la storia dello stdin, ma allora per pulire un buffer
in ingresso non si hanno delle funzioni? devo scrivere tutto io?
cmq un piccolo passettino avanti l'ho fatto:
========= CODICE ============
 
#include<stdio.h>
#include<string.h>
#define BUFFER 12
int main(){
	FILE *fp;
	char a[BUFFER];
	int j,i=0;
	int flag=0;
 
	fp=fopen("file.dat","r");
	while(fgets(a,BUFFER,fp)){
		for (j=0;j<BUFFER;j++){
			if(a[j] != '\n'){
				if (flag == 0){
					printf("%d: %c",++i,a[j]);
					flag=1;
				}
				else{
					printf("%c",a[j]);
				}
			}
			else{
				printf("\n");
				flag=0;
				break;
			}
		}
	}
 
	fclose(fp);
	return 0;
}
===============================
Ma non sono soddisfatto perche' il codice mi sembra poco leggibile, e
perche la k me la trovo sempre dietro
/tmp$ cc -W -Wall -g prova.c
/tmp$ ./a.out
1: a b c d        k
2: 1 2 3 4
3: aa bb cc dd
4: 11 22 33 44
Ho dato una spulciata a man fread che proprio cio' che fa per me, ma
ottengo solo pasticci
I codice di prima mi pare una vera porcata, cosi' ho buttato giu'
un'altra implementazione, che mi sembra stilisticamente piu' corretta,
ma che non funziona correttamente:
============= codice ================
#include<stdio.h>
#define BUFFER 12
int main(){
	FILE *fp;
	char a[BUFFER];
	int i=0;
 
	fp=fopen("file.dat","r");
 
	while(fread(a,sizeof(char),BUFFER,fp) > 0){
		i++;
		printf("%d: ",i);
		fwrite(a,sizeof(char),BUFFER,stdout);
		if (a[11] != '\n'){
			while(fgetc(fp) !='\n'){} /* sposto il puntatore del file fino */ 
						  /* a dopo k, almeno cosi' credo */
		}
		printf("\n");
	}
 
	fclose(fp);
	return 0;
}
===========================================
cio' che ottengo e':
/tmp$ cc -W -Wall -g prova.c
/tmp$ ./a.out
1: a b c d
2: 1 2 3 4
aa b
3: 11 22 33 44
Ricordo che file.dat e':


 in ingresso non si hanno delle funzioni? devo scrivere tutto io?
Non e' una questiona che riguarda solo stdin, ma tutti gli stream in 
lettura.
Se con 'pulire un buffer in ingresso' intendi scartare tutti i caratteri 
che rimangono nella riga, la risposta e' si', devi preoccupartene tu.
Comunque non e' molto difficile: se scopri che l'ultimo carattere letto 
non e' '\n', ti basta continuare a chiamare fgetc() finche' non lo 
trovi. A questo punto sei arrivato alla riga successiva.

 1 :a b c d    2 :     k
Giusto. La prima fgets legge 11 caratteri (quindi non tutta la riga). La
printf non contiene  il newline finale e quindi  alla seconda iterazione
la stringa  viene stampata sulla  stessa riga. La secondo fgets  legge a
partire dalla posizione in cui si  era fermata (quindi 11 caratteri dopo
l'inizio del file) e questa volta  si ferma perche` ha raggiunto la fine
della linea.
Poi, come hai notato, la fflush non serve a nulla in questo caso perche`
non scrivi nulla.  fflush fa in modo che il  buffer di scrittura interno
alla libreria C venga svuotato ad  inviato al sistema operativo (che poi
in ogni caso attua le proprie politiche di buffering).
In genere si legge tutta la riga  e si fa poi il parsing del buffer. Nel
tuo caso, pero`, si puo` semplicemente fare una cosa del genere:
while(fgets(a, BUFFER, fp)) {
        /* E` stata letta tutta la riga? */
        if (strchr(buf, '\n') == NULL) {
                /* Salto il resto della riga corrente */
                while(fgets(fp) != '\n')
                        ;
        }
        ....
}
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
Dicono che  il cane sia  il miglior  amico dell'uomo. Secondo me  non e`
vero. Quanti dei vostri amici avete fatto castrare, recentemente?

Il Thu, 14 Aug 2003 16:25:44 GMT, -=M=M=-@
cippa.lippa.net
 fece sapere che:
Grazie a tutti per l'aiuto ed i suggerimenti :)
ho sistemato il codice, pero' ottengo una cattiva formattazzione in
uscita, cioe' a seconda della dimensione della stringa e del buffer di
lettura dato che uso una funzione printf("...%s\n",...) posso avere in
uscita piu' escape '\n'.
Che ho risolto serenamente usando la strchr() che non conoscevo.
Posto per l'ultima volta il codice, per avere ulteriori suggerimenti e
correzioni riguardo alla leggibilita ed all'efficenza
#include<stdio.h>
#include<string.h> 
#define BUFFER 12
 
int main(int argc,char *argv[]){
        FILE *fp;
        char a[BUFFER];
        int i = 0;
 
        if (argc != 2){
                fputs("USO:./a.out nome_file\n",stderr);
		exit(0);
        }
 
        fp=fopen(argv[1],"r");
        while(fgets(a,BUFFER,fp)){
		/* effettu un bel check come mi e' stato suggerito */
		if(strchr(a,'\n') == NULL){
			while(fgetc(fp) !='\n'){}
		}
		/* faccio dei controlli su \n per aver un
		 * output correttamente formattato */
		if (strchr(a,'\n') == NULL){
			printf("%d :%s\n",++i,a);
		}
		else{
			printf("%d :%s",++i,a);
		}
        }
        fclose(fp);
        return 0;
}
-- 
...uno dei progetti iniziali di Linus era un programma che doveva 
cambiare una riga di AAAA in BBBB e viceversa. Questo in seguito
divento' Linux.
			The Linux Users'Guide Beta Version 1

                }
char *p;
...
while(fgets(a, BUFFER, fp)) {
        if ((p = strchr(a, '\n')) == NULL) {
                while(fgetc(fp) !='\n') {}
        } else
                *p = '\0';
        printf("%d :%s\n", ++i, a);
}
Cosi`  effettui  una  ricerca  sola  sulla  stringa  (e`  un  operazione
abbastanza dispendiosa). Se il newline viene  trovato (p != NULL) allora
viene sovrascritto. In questo modo ti basta una sola printf.
Kronos
-- 
Home: 
http://kronoz.cjb.net
Il piu` bel momento dell'amore e` quando ci si illude che duri per 
sempre; il piu` brutto, quando ci si accorge che dura da troppo.