[C]copia di un file
Ciao a tutti...sono nuovamente a scrivere su queste forum perchè questi programmi in C mi creano non pochi problemi...Allora mi trovo ad affrontare un problema riguardante la copia di un file. In linea generale riesco a capire cosa sta facendo questo programma.
Devo prendere in input i nomi dei file su cui voglio lavorare, guardo se i file in questione non sono nulli ( if ((fpOUT=fopen(nomeOUT, "w"))==NULL) perchè se fossero nulli non posso proseguire con il mio programma, se non sono nulli allora procedo alla copia dei file.
Infide chiudo entrambi i file con la sintassi [ fclose(fpIN); fclose(fpOUT)];. Premetto che questi programmi in classe non sono stati spiegati come avrebbero dovuto, ma sono stati esercizi di vera copiatura dopo averci accennatto qualche istruzione base. Mi interesserebbe capire un po' meglio cosa fanno le singole istruzioni, se possibile, perchè non mi basta riuscire a capire l'algoritmo generale ma devo lavorare bene sul codice. Grazie mille per la disponibilità.
Devo prendere in input i nomi dei file su cui voglio lavorare, guardo se i file in questione non sono nulli ( if ((fpOUT=fopen(nomeOUT, "w"))==NULL) perchè se fossero nulli non posso proseguire con il mio programma, se non sono nulli allora procedo alla copia dei file.
Infide chiudo entrambi i file con la sintassi [ fclose(fpIN); fclose(fpOUT)];. Premetto che questi programmi in classe non sono stati spiegati come avrebbero dovuto, ma sono stati esercizi di vera copiatura dopo averci accennatto qualche istruzione base. Mi interesserebbe capire un po' meglio cosa fanno le singole istruzioni, se possibile, perchè non mi basta riuscire a capire l'algoritmo generale ma devo lavorare bene sul codice. Grazie mille per la disponibilità.
#include <stdio.h> #include <stdlib.h> void filecopy(FILE *, FILE *); int main(void) { FILE *fpIN; FILE *fpOUT; char nomeIN[20]; char nomeOUT[20]; printf("Nome del file di Input ? "); scanf("%s", nomeIN); printf("Nome del file di Output ? "); scanf("%s", nomeOUT); if ((fpOUT=fopen(nomeOUT, "w"))==NULL) { printf("\nImpossibile aprire il file %s\n",nomeOUT); exit(1); } if ((fpIN=fopen(nomeIN, "r"))==NULL) { printf("\nImpossibile aprire il file %s\n",nomeIN); exit(1); } else { filecopy(fpIN, fpOUT); fclose(fpIN); fclose(fpOUT); } return 0; } /*void filecopy(FILE *inFile, FILE *outFile) { while(!feof(inFile)) { fputc(fgetc(inFile),outFile); } return; }*/ [size=18]void filecopy(FILE *inFile, FILE *outFile) { int c; while((c = getc(inFile)) != EOF) { putc(c,outFile); } return; }[/size] /*void filecopy(FILE *inFile, FILE *outFile) { int c; while((fscanf(inFile, "%c", &c))>0) fprintf(outFile, "%c", c); return; }*/[color=indigo][/color]
Risposte
Ci sono diverse cose da cambiare o migliorare nel tuo programma. Visto che le istruzioni non ti sono del tutto chiare cercherò di commentarlo quasi riga per riga.
Anche se molti compilatori lo accettano, lo standard C accetta solo le seguenti due versioni (o codici equivalenti):
Il codice è corretto ma l'uso di scanf per la lettura di stringhe è fortemente sconsigliato. Questa funzione non ha infatti modo di verificare i limiti della stringa. Più sicura è la forma:
in cui la dimensione della stringa è stata passata alla funzione. Più in generale sarebbe meglio fare uso di una funzione come fgets oppure utilizzare gli argomenti passati al programma da linea di comando.
Non c'è motivo di chiamare exit(1) per terminare la funzione. È sufficiente usare la normale istruzione per uscire da una funzione: return 1 è infatti equivalente. Inoltre è spesso consigliabile separare l'assegnazione del valore ad una variabile e il successivo test per verificare il suo valore. Infine, stai aprendo i file in modalità testuale. Può andare bene se si tratta di file di testo, ma non in generale. Sarebbe stato quindi meglio scrivere:
Trovo più intuitivo aprire prima il file da cui effettui la lettura che quello da cui scrivi. Se infatti non esiste un file di lettura, non ha neanche senso creare quello su cui scrivi. Inoltre, ti sei dimenticata di chiudere il file di output nel caso in cui quello di input non sia stato aperto. Ovviamente ontinuano a valere anche le indicazioni precedenti.
Per eliminare del codice che non usi, NON usare i commenti. Il metodo più sicuro è
I commenti infatti non vengono nidificati. Se avessi quindi un commento all'interno della tua funzione, elimineresti solo il codice prima di quel commento.
Immagino che delle tante funzioni io debba commentare l'unica non commentata.
A parte il return inutile non c'è molto da commentare. Esegui un ciclo fino a quando ci sono caratteri da leggere. Quello con fprintf e fscanf è invece sbagliato (sono funzioni da usare per altri scopi) e fputs e fgetc sono equivalenti a putc e getc. La differenza c'è, ma probabilmente non sei in grado di capirla per il momento.
Ci sono cose più precise su cui hai dubbi? Vorresti per esempio vedere implementazioni diverse della copia?
int main(void)
Anche se molti compilatori lo accettano, lo standard C accetta solo le seguenti due versioni (o codici equivalenti):
int main() int main(int argc, char *argv[])
printf("Nome del file di Input ? "); scanf("%s", nomeIN); printf("Nome del file di Output ? "); scanf("%s", nomeOUT);
Il codice è corretto ma l'uso di scanf per la lettura di stringhe è fortemente sconsigliato. Questa funzione non ha infatti modo di verificare i limiti della stringa. Più sicura è la forma:
scanf("%20s", nomeIN);
in cui la dimensione della stringa è stata passata alla funzione. Più in generale sarebbe meglio fare uso di una funzione come fgets oppure utilizzare gli argomenti passati al programma da linea di comando.
if ((fpOUT=fopen(nomeOUT, "w"))==NULL) { printf("\nImpossibile aprire il file %s\n",nomeOUT); exit(1); }
Non c'è motivo di chiamare exit(1) per terminare la funzione. È sufficiente usare la normale istruzione per uscire da una funzione: return 1 è infatti equivalente. Inoltre è spesso consigliabile separare l'assegnazione del valore ad una variabile e il successivo test per verificare il suo valore. Infine, stai aprendo i file in modalità testuale. Può andare bene se si tratta di file di testo, ma non in generale. Sarebbe stato quindi meglio scrivere:
fpOUT = fopen(nomeOut, "wb"); if (NULL == fpOUT) { fprintf(stderr, "\nImpossibile aprire il file %s\n", nomeOUT); return 1; }
if ((fpIN=fopen(nomeIN, "r"))==NULL) { printf("\nImpossibile aprire il file %s\n",nomeIN); exit(1); } else { filecopy(fpIN, fpOUT); fclose(fpIN); fclose(fpOUT); }
Trovo più intuitivo aprire prima il file da cui effettui la lettura che quello da cui scrivi. Se infatti non esiste un file di lettura, non ha neanche senso creare quello su cui scrivi. Inoltre, ti sei dimenticata di chiudere il file di output nel caso in cui quello di input non sia stato aperto. Ovviamente ontinuano a valere anche le indicazioni precedenti.
fpIN = fopen(nomeIN, "rb"); if (NULL == fpIN) { fprintf(stderr, "\nImpossibile aprire il file %s\n", nomeIN); fclose(fpOUT); return 1; } filecopy(fpIN, fpOUT); fclose(fpIN); fclose(fpOUT); return 0;
Per eliminare del codice che non usi, NON usare i commenti. Il metodo più sicuro è
#if 0 /* codice da eliminare.. */ #endif
I commenti infatti non vengono nidificati. Se avessi quindi un commento all'interno della tua funzione, elimineresti solo il codice prima di quel commento.
Immagino che delle tante funzioni io debba commentare l'unica non commentata.
void filecopy(FILE *inFile, FILE *outFile) { int c; while((c = getc(inFile)) != EOF) { putc(c, outFile); } return; }
A parte il return inutile non c'è molto da commentare. Esegui un ciclo fino a quando ci sono caratteri da leggere. Quello con fprintf e fscanf è invece sbagliato (sono funzioni da usare per altri scopi) e fputs e fgetc sono equivalenti a putc e getc. La differenza c'è, ma probabilmente non sei in grado di capirla per il momento.
Ci sono cose più precise su cui hai dubbi? Vorresti per esempio vedere implementazioni diverse della copia?
Grazie mille per la risposta...Ma allora mi viene da pensare che il professore con questi codici ci complica solo la vita!!!Ora do un'occhiata con calma a tutto il programma e se avessi dei problemi(sicuramente gli avrò) ti chiedo sicuramente. Grazie ancora per la tua risposta!