Ultimo aggiornamento: 2024-03-22
Scrivere un programma che legga un file di testo il cui nome viene specificato sulla riga di comando, e determini il numero di parole e il numero di parole distinte in esso contenute; non si deve fare distinzione fra lettere maiuscole e minuscole, per cui “prova”, “Prova”, “PROVA”, ecc. sono la stessa parola.
Per “parola” si intende una sequenza contigua di caratteri per i quali la funzione
restituisce true (cioè un valore diverso da zero). Ad esempio, la stringa “i diritti inviolabili dell’uomo” è composta da cinque parole: “i”, “diritti”, “inviolabili”, “dell” e “uomo”.
Quindi, nel testo
La Repubblica riconosce e garantisce i diritti inviolabili dell’uomo, sia come singolo, sia nelle formazioni sociali ove si svolge la sua personalita’, e richiede l’adempimento dei doveri inderogabili di solidarieta’ politica, economica e sociale.
sono presenti le 36 parole seguenti:
la
repubblica
riconosce
e
garantisce
i
diritti
inviolabili
dell
uomo
sia
come
singolo
sia
nelle
formazioni
sociali
ove
si
svolge
la
sua
personalita
e
richiede
l
adempimento
dei
doveri
inderogabili
di
solidarieta
politica
economica
e
sociale
di cui 32 sono distinte.
Conviene leggere le parole un carattere alla volta usando la funzione
dichiarata in <stdio.h>
; la funzione restituisce il codice ASCII del prossimo carattere presente nel file stream
, oppure EOF
in caso di fine file; EOF
è una costante definita in <stdio.h>
.
Per convertire un carattere in minuscolo si può usare la funzione
dichiarata in <ctype.h>
. La funzione accetta come parametro il codice ASCII c di un simbolo, e restituisce il codice ASCII del corrispondente carattere minuscolo se c è una lettera dell’alfabeto, oppure restituisce c se si tratta di un altro simbolo.
Si può assumere che tutte le parole abbiano lunghezza strettamente minore a WORDLEN
.
Per risolvere il problema si possono salvare le parole come chiavi di una hash table, che è stata oggetto di un altro esercizio. Si consiglia di procedere come segue:
Si crea una tabella hash di dimensioni adeguate, ad esempio 10000. Dato che stiamo usando una tabella hash in cui le collisioni vengono gestite mediante liste di trabocco, è possibile inserire un numero qualsiasi di coppie; la dimensione incide solo sulle prestazioni delle operazioni.
Si legge dal file la parola successiva usando una funzione read_word()
(da completare), convertendo tutti i caratteri in minuscolo.
Si usa la funzione ht_insert()
per inserisce nella tabella hash la coppia (w, 0), dove w è la parola letta al punto precedente. La chiave associata a w è posta arbitrariamente a zero, dato che non ci interessa per la soluzione del problema.
Quando si arriva alla fine del file, si stampa il numero di coppie (chiave, valore) presenti nella tabella hash usando la funzione ht_count()
.
Per compilare:
gcc -std=c90 -Wall -Wpedantic hashtable.c conta-parole.c -o conta-parole
Per eseguire in ambiente Linux/MacOSX:
./conta-parole nome_file_input
Per eseguire in ambiente Windows:
.\conta-parole nome_file_input
Si presti attenzione che il linguaggio C non specifica se il tipo char
dabba essere signed o unsigned. In altre parole, la dichiarazione char c;
lascia libertà ai compilatori di decidere se c
rappresenta un valore con segno o senza segno. Nel caso si desideri uno dei due occorre specificarlo esplicitamente (es., unsigned char c
definisce c
come unsigned).
In alcuni sistemi (tra cui il mio) viene usato il tipo signed
; questo significa che il seguente frammento di codice:
non è corretto in presenza di lettere accentate, perché queste hanno un codice ASCII superiore a 127. Ad esempio, se alla variabile c
fosse assegnato il carattere 'è'
(codice ASCII 195), il valore memorizzato in c
sarebbe -61, dato che 195 non può essere rappresentato con 8 bit in complemento a due. Di conseguenza la funzione isalpha(c)
riceverebbe un valore negativo producendo un risultato indefinito.
La soluzione consiste nel dichiarare c
di tipo int
:
Si noti che non sarebbe corretto definire c
di tipo unsigned char
, perché in caso di fine file, la funzione fetc()
restituisce EOF
che normalmente ha valore -1.