libri-javascript-python

La funzione fgets in C svolge un ruolo fondamentale nel processo di lettura delle stringhe da un file. È particolarmente utile quando si desidera leggere una riga intera di testo da un file di testo. La sua sintassi è la seguente:

char *fgets(char *stringa, int lun, FILE *fp);

Dove:

  • stringa è un puntatore a un’area di memoria in cui verrà memorizzata la stringa letta.
  • lun rappresenta il numero massimo di caratteri che possono essere letti dalla stringa.
  • fp è un puntatore al file da cui leggere la stringa, restituito dalla funzione fopen.

Quindi la funzione legge una riga intera dal file puntato da fp e la memorizza nella locazione di memoria puntata da stringa. È importante notare che lun indica il numero massimo di caratteri da leggere, e viene solitamente impostato in modo che non si superi la dimensione dell’array di stringa. La lettura si ferma quando viene raggiunta la fine della riga o quando viene letto il numero massimo di caratteri specificato, inclusi i caratteri di spazio vuoto.

La funzione restituisce un puntatore alla stringa letta. In caso di errore o se viene raggiunta la fine del file, restituisce NULL.

Esempio di utilizzo di fgets in C

In questo primo esempio realizziamo un programma che apre un file di testo chiamato “testo.txt”, legge ogni riga utilizzando fgets e la stampa a schermo.

Ricordiamo che fgets include il carattere di nuova riga (\n) nel buffer se c’è spazio sufficiente. Potremmo voler rimuovere questo carattere se non è desiderato.

#include <stdio.h>

int main() {
    FILE *file;
    char buffer[100];

    file = fopen("testo.txt", "r");
    if (file == NULL) {
        printf("Impossibile aprire il file.\n");
        return 1;
    }

    while (fgets(buffer, 100, file) != NULL) {
        printf("%s", buffer);
    }

    fclose(file);

    return 0;
}

Ecco una spiegazione dettagliata delle parti principali del codice che legge e stampa il contenuto di un file di testo chiamato “testo.txt” in C.

  1. FILE *file;: Dichiarazione di un puntatore a FILE, che è il tipo di dati utilizzato da C per rappresentare file. Questo verrà utilizzato per aprire e leggere dal file di testo.
  2. char buffer[100];: Dichiarazione di un array di caratteri di dimensione 100, che verrà utilizzato per memorizzare temporaneamente ciascuna riga letta dal file.
  3. file = fopen("testo.txt", "r");: Apre il file “testo.txt” in modalità di sola lettura (“r”) e assegna il puntatore del file a file. Se il file non può essere aperto correttamente (ad esempio, se non esiste), viene stampato un messaggio di errore.
  4. if (file == NULL) { ... }: Controlla se l’apertura del file è stata eseguita con successo. Se file è uguale a NULL, significa che c’è stato un errore nell’apertura del file e il programma termina restituendo 1.
  5. while (fgets(buffer, 100, file) != NULL) { ... }: Legge ogni riga del file di testo utilizzando la funzione fgets. La funzione fgets legge una riga dal file (file) e la memorizza nell’array buffer. Continua a leggere le righe finché non raggiunge la fine del file o si verifica un errore. Se fgets restituisce NULL, significa che non ci sono più righe da leggere e il ciclo termina.
  6. printf("%s", buffer);: Stampa la riga letta dal file utilizzando la funzione printf.
  7. fclose(file);: Chiude il file dopo aver terminato di leggerlo per liberare le risorse utilizzate dal sistema operativo.

Secondo esempio di utilizzo di fgets in C

Consideriamo un semplice esempio in cui apriamo un file in modalità lettura e contiamo quante righe e caratteri contiene.

Iniziamo dichiarando due contatori, uno per le righe (nr) e uno per i caratteri (nc), entrambi inizializzati a zero. Successivamente chiediamo all’utente di inserire il nome del file da analizzare.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define N 60

int main() {
    FILE *fp;
    char nome[FILENAME_MAX], r[N];
    int nr = 0, nc = 0;

    printf("Inserisci il nome del file: ");
    gets(nome);

    if ((fp = fopen(nome, "rt")) == NULL) {
        printf("Errore nell'apertura del file\n");
        exit(1);
    }

    while (fgets(r, N, fp) != NULL) {
        nr++;
        nc += strlen(r); // Includiamo il carattere di nuova riga
    }

    fclose(fp);
    printf("Totale righe: %d\nTotale caratteri: %d\n", nr, nc);

    return 0;
}

In questo esempio, abbiamo utilizzato un ciclo while per leggere continuamente le righe dal file utilizzando fgets. Ogni volta che viene letta una riga, incrementiamo il contatore delle righe (nr) e aggiungiamo il numero di caratteri letti alla variabile nc.

Infine, chiudiamo il file con fclose e stampiamo il totale delle righe e dei caratteri letti.

Ottimizzazioni dell’esempio che utilizza fgets in C

Ci sono alcuni punti che potrebbero essere migliorati o corretti:

  1. Utilizzo di gets: La funzione gets è considerata pericolosa perché non effettua alcun controllo sulla lunghezza dell’input, il che potrebbe causare un overflow del buffer. È consigliabile utilizzare fgets al suo posto, specificando stdin come file di input, in modo da leggere in modo sicuro da standard input.
  2. Controllo dell’overflow del buffer: Quando si leggono le righe con fgets, è importante assicurarsi che la dimensione dell’array r sia sufficientemente grande per contenere la riga più lunga nel file. Se una riga supera la dimensione specificata, fgets non troncherà la riga e potrebbe causare un overflow del buffer. Potresti considerare l’uso di fgets con una dimensione dinamica del buffer per gestire meglio questo problema.
  3. Calcolo dei caratteri: La sottrazione di 1 da strlen(r) potrebbe non essere necessaria se non si vuole escludere il carattere di nuova riga dalla conta dei caratteri. Se si desidera includere il carattere di nuova riga, si può rimuovere questa sottrazione.
  4. Gestione degli errori di chiusura del file: Anche se il codice chiude correttamente il file con fclose, potrebbe essere utile aggiungere la gestione degli errori nel caso in cui la chiusura del file fallisca.
  5. Utilizzo di FILENAME_MAX: L’uso di FILENAME_MAX per dimensionare l’array nome è una pratica comune per garantire che l’array sia sufficientemente grande per contenere il percorso del file più lungo consentito dal sistema operativo. Tuttavia, FILENAME_MAX potrebbe variare tra i sistemi operativi, quindi è importante considerare questa variabilità.

Ecco dunque una versione migliorata ell’esempio che utilizza fgets in C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUFFER_SIZE 1024

int main() {
    FILE *fp;
    char nome[BUFFER_SIZE];
    char riga[BUFFER_SIZE];
    int nr = 0, nc = 0;

    printf("Inserisci il nome del file: ");
    fgets(nome, sizeof(nome), stdin);
    nome[strcspn(nome, "\n")] = '\0'; // Rimuove il carattere di nuova riga se presente

    if ((fp = fopen(nome, "rt")) == NULL) {
        printf("Errore nell'apertura del file\n");
        exit(1);
    }

    while (fgets(riga, sizeof(riga), fp) != NULL) {
        nr++;
        nc += strlen(riga); // Includiamo il carattere di nuova riga
    }

    if (fclose(fp) != 0) {
        printf("Errore nella chiusura del file\n");
        exit(1);
    }

    printf("Totale righe: %d\nTotale caratteri: %d\n", nr, nc);

    return 0;
}

Conclusioni

In questa lezione abbiamo esaminato l’utilizzo della funzione fgets in C per leggere le stringhe da un file. Abbiamo visto che fgets legge una riga alla volta e restituisce un puntatore alla stringa letta. Abbiamo anche discusso della sintassi di fgets e delle considerazioni importanti da tenere a mente quando la si utilizza.

Successivamente, abbiamo esaminato un esempio pratico che illustra come utilizzare fgets per contare il numero di righe e caratteri presenti in un file. Abbiamo implementato un semplice programma che apre un file in lettura, legge le righe utilizzando fgets e tiene traccia del numero totale di righe e caratteri letti.

Infine, abbiamo esaminato il codice proposto, risolvendo eventuali problemi e assicurandoci che il programma funzioni correttamente. Abbiamo anche aggiunto una verifica per assicurarci che il file sia stato letto correttamente fino alla fine.

Più avanti, continueremo ad esplorare altri concetti e funzionalità della funzione fgets del linguaggio C.

Alcuni link utili

Corso linguaggio C

Indice argomenti linguaggio C

Funzione fscanf

Allocazione dinamica della memoria con malloc

Strutture in C

Esercitazione sulle struct in C

Come sommare gli elementi della cornice esterna

Quick sort in C

Insertion Sort in C