Buonasera a tutti. Sto studiando gli stream e le varie funzioni per leggere dai file e scriverci, ma ci sono cose che non ho capito, ed essendo autodidatta, non ho nessuno a cui chiedere, per cui spero abbiate la pazienza di darmi una mano. Da quello che ho capito, lo stream è una sorta di ponte tra l’elaboratore e le periferiche, su cui viaggiano i byte. Se non ho capito male, quando viene aperto un file, in base alla modalità di apertura, i dati vengono allocati in una porzione dinamica della RAM, in celle contigue, come avviene per i vettori, e un puntatore a questa area permette di leggerne/modificarne il contenuto. Se, per esempio, viene creato un file di testo in cui scrivere i dati ricevuti in input dalla tastiera, la porzione di memoria viene di volta in volta aumentata, per poter memorizzare i dati ricevuti, fino ad un massimo di circa 2 GB (ftell, che restituisce la posizione del puntatore, restituisce un long, ossia un numero a 32 bit, che può essere positivo o negativo, ma poiché un indice non può avere valore negativo, desumo che possa assumere al massimo il valore di 2.147.483.647 ossia il limite positivo di un long). Solo quando lo stream viene chiuso, i dati vengono scritti effettivamente sul file e la memoria liberata. Quando apro un file di testo in lettura, l’uso della funzione fgetc restituisce il carattere nella posizione corrente del puntatore e al tempo stesso sposta il puntatore sulla posizione successiva, per cui se ho il testo “questa e’ una prova”, quando nella condizione del ciclo while viene chiamata fgetc per inizializzare una variabile char, la prima volta legge la lettera ‘q’ e si sposta sulla lettera ‘u’, alla seconda iterazione legge la lettera ‘u’ e si sposta sulla lettera ‘e’ e così via fino a raggiungere l’EOF. A questo punto quando viene letto il byte, viene restituito il valore EOF, il ciclo viene interrotto e il puntatore resta dov’è. Il puntatore si sposta un byte alla volta perché lo stream è stato avviato su un file di testo e, con la chiamata alla funzione fgetc, viene letto un carattere per volta, ossia un byte per volta.
Le cose che avete letto fino ad ora sono in parte mie deduzioni, quindi potrebbero essere del tutto errate.
Ora veniamo a quello che succede con un file di testo in lettura/scrittura (modalità di apertura “r+”). Supponiamo che voglia prendere il testo precedente, ossia “questa e’ una prova”, leggere i singoli caratteri, e se il carattere è minuscolo convertirlo in maiuscolo. Ad ogni chiamata di fgetc il puntatore, dopo la lettura del byte, viene spostato sul byte successivo, per cui quando viene verificato il carattere, il puntatore è già sulla posizione successiva. Per modificare il carattere quindi sarà necessario spostare il puntatore indietro di una posizione e rendere maiuscolo il carattere con la chiamata a fputc. Anche fputc sposta il puntatore di una posizione dopo aver inserito il carattere, per cui penso che si dovrebbe verificare questa situazione:
*******************(consultare il file TraceTable.jpg allegato, grazie)********************
E così dovrebbe andare fino alla fine. Il problema è che dopo la seconda iterazione fgetc non restituisce la lettera ‘e’, ma continua a restituire all’infinito la lettera ‘u’.
L’esempio sul testo inserisce una nuova chiamata alla funzione fseek subito dopo la chiamata alla funzione fputc:
fseek(testo, 0L, SEEK_CUR); //riposiziona per la lettura
il commento è quello inserito nel codice sul testo. In effetti con questa istruzione il testo viene letto e modificato correttamente. Tuttavia mi sembra che questa istruzione non faccia altro che confermare la posizione corrente del puntatore (SEEK_CUR indica la posizione corrente del puntatore, mentre l’offset è impostato su zero, quindi in pratica non sembra spostare nulla). Cosa non ho capito? Non vale rispondere "Tutto"
Grazie anticipatamente a tutti quelli che vorranno dedicarmi un po' del loro tempo, e scusate per la lunghezza del post, ma ho bisogno di un riscontro.
Aggiungo il codice del programma e le immagini dell'output del programma, con la chiamata alla seconda fseek e senza la chiamata alla seconda fseek:
#include <stdio.h>
#include <ctype.h> //contiene la definizione di islower
#include <string.h> //contiene la definizione di strlen
void Visualizza(FILE *);
main()
{
FILE *testo = fopen("[IndirizzoDelFile]", "r+");
if(testo == NULL)
{
printf("Errore nella apertura del file");
getch();
exit(-1);
}
char c;
int i = 0;
while((c = fgetc(testo)) != EOF)
{
printf("\ninizio iterazione [%2d], posizione puntatore: %ld, valore di c: %c", i, ftell(testo), c);
if(isupper(c))
{
fseek(testo, ftell(testo) - 1, SEEK_SET);
printf("\ndopo prima fseek [%2d], posizione puntatore: %ld, valore di c: %c", i, ftell(testo), c);
fputc(tolower(c), testo);
printf("\ndopo fputc [%2d], posizione puntatore: %ld, valore di c: %c", i, ftell(testo), c);
//fseek(testo, 0, SEEK_CUR); //??????
printf("\nfine iterazione [%2d], posizione puntatore: %ld, valore di c: %c", i, ftell(testo), c);
printf("\n");
}
else
{
printf("\n");
}
i++;//commenta se si decommenta l'istruzione 29
if(i > 18)//commenta se si decommenta l'istruzione 29
break;//commenta se si decommenta l'istruzione 29
}
Visualizza(testo);
char lettere[30];
fseek(testo, 0L, SEEK_SET);//resetta la posizione del puntatore
fgets(lettere, 30, testo);//legge la stringa dal file memorizzandola nel buffer
printf("\n");
for(i = 0; i < strlen(lettere); i++)
{
printf("[%2d]", i);
}
printf("\n");
for(i = 0; i < strlen(lettere); i++)
{
printf("%4c", lettere[i]);
}
fclose(testo);
printf("\n\n");
getch();
}
void Visualizza(FILE *file)
{
char c;
fseek(file, 0, SEEK_SET);
while((c = fgetc(file)) != EOF)
{
printf("%c", c);
}
}
Allegati: