Linguaggio C: stream, fseek e varie

di il
8 risposte

Linguaggio C: stream, fseek e varie

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:
7328_f0f5eed29dfa5692711171914f6adf61.jpg
7328_f0f5eed29dfa5692711171914f6adf61.jpg

8 Risposte

  • Re: Linguaggio C: stream, fseek e varie

    Non ho letto tutto (non avevo tanto tempo) ma la questione dei file in modifica in C è un po' contorta. Quello che devi scrivere è semplicemente
    
    		if (isupper(c))
    		{
    			fseek(testo, ftell(testo) - 1, SEEK_SET);
    			fputc(tolower(c), testo);
    			fseek(testo, ftell(testo), SEEK_SET);
    		}
    
    e la ultima fseek è necessario per effettuare lo switch tra scrittura e lettura.

    Sicuramente non avrai letto la documentazione (anche se autodidatta, anzi soprattutto, DEVI leggere la documentazione di ciò che usi)

    http://www.cplusplus.com/reference/cstdio/fseek

    in cui potrai leggere

    On streams open for update (read+write), a call to fseek allows to switch between reading and writing.
  • Re: Linguaggio C: stream, fseek e varie

    oregon ha scritto:


    Non ho letto tutto (non avevo tanto tempo) ma la questione dei file in modifica in C è un po' contorta. Quello che devi scrivere è semplicemente
    
    		if (isupper(c))
    		{
    			fseek(testo, ftell(testo) - 1, SEEK_SET);
    			fputc(tolower(c), testo);
    			fseek(testo, ftell(testo), SEEK_SET);
    		}
    
    e la ultima fseek è necessario per effettuare lo switch tra scrittura e lettura.

    Sicuramente non avrai letto la documentazione (anche se autodidatta, anzi soprattutto, DEVI leggere la documentazione di ciò che usi)

    http://www.cplusplus.com/reference/cstdio/fseek

    in cui potrai leggere

    On streams open for update (read+write), a call to fseek allows to switch between reading and writing.
    Grazie per la risposta ed il link alla documentazione. Avevo letto questo

    https://digilander.libero.it/uzappi/C/librerie/funzioni/fseek.html

    ma chiaramente non era sufficiente, oltre al fatto che questo particolare sul testo non era scritto, eppure non mi pare di poco conto. Comunque il link è finito tra i preferiti e sarà la mia futura fonte di informazioni. Grazie ancora.
  • Re: Linguaggio C: stream, fseek e varie

    Ok ... comunque tieni presente che la gestione dei puntatori ai dati nei file aperti in modifica in modo "testo" non è privo di potenziali problemi.

    Questo tipo di gestione è invece adatta ai file aperti in modalità "binaria" (rb+)
  • Re: Linguaggio C: stream, fseek e varie

    oregon ha scritto:


    Ok ... comunque tieni presente che la gestione dei puntatori ai dati nei file aperti in modifica in modo "testo" non è privo di potenziali problemi.

    Questo tipo di gestione è invece adatta ai file aperti in modalità "binaria" (rb+)
    ok, grazie, lo terrò presente. Ne approfitto per chiederti ancora una cosa. Sto utilizzando Dev C++, ma noto che l'IntelliSense non è proprio il massimo, forse dipende da qualche settaggio. Ho scritto qualcosina in C#, utilizzando Visual Studio Express 2010 e l'IntelliSense di quel IDE è davvero fenomenale. In Dev C++lo trovo abbastanza limitato, nel senso che in Visual Studio viene fornita una breve descrizione dello scopo della funzione e dei parametri, il che rende anche meno complicato l'uso della funzione stessa. Con Dev C++ invece mi sembra che sia necessario conoscere a memoria la firma delle funzioni e lo scopo dei parametri, oltre a mancare una funzionalità di completamento della digitazione del codice. E' un problema di impostazioni, oppure l'IntelliSense del Dev C++ funziona proprio così?
  • Re: Linguaggio C: stream, fseek e varie

    Perché non usi Visual Studio anche per il C/C++?
  • Re: Linguaggio C: stream, fseek e varie

    Andrea Quaglia ha scritto:


    Perché non usi Visual Studio anche per il C/C++?
    perché potrebbe essere utile conoscere più di un IDE e perché voglio trovarmi nelle stesse difficoltà/condizioni in cui si trova chi lo utilizza. Poi, conoscendo a malapena Dev C++, potrebbe essere un mio limite non saperlo sfruttare a dovere
  • Re: Linguaggio C: stream, fseek e varie

    DevC++ è un prodotto vecchio, molto semplice (per questo utilizzato) ma proprio per questo molto limitato. Ti sconsiglio vivamente di usarlo.

    Usa tranquillamente Visual Studio per il C/C++ anche se un po' più complesso, dopo un po' impari ad usarlo (almeno per quello che ti serve) e noti le differenze.

    Tuttavia, non ti fidare ciecamente dell'intellisense e studia sempre la documentazione delle funzioni prima di usarle.
  • Re: Linguaggio C: stream, fseek e varie

    oregon ha scritto:


    DevC++ è un prodotto vecchio, molto semplice (per questo utilizzato) ma proprio per questo molto limitato. Ti sconsiglio vivamente di usarlo.

    Usa tranquillamente Visual Studio per il C/C++ anche se un po' più complesso, dopo un po' impari ad usarlo (almeno per quello che ti serve) e noti le differenze.

    Tuttavia, non ti fidare ciecamente dell'intellisense e studia sempre la documentazione delle funzioni prima di usarle.
    va bene, e grazie ancora per i consigli
Devi accedere o registrarti per scrivere nel forum
8 risposte