Questo programma analizza un file di testo di input e genera una rappresentazione statistica delle sequenze di parole, simile a una catena di Markov del primo ordine. Il risultato è una tabella CSV dove ogni riga rappresenta una parola iniziale seguita dalle parole che la seguono con le rispettive frequenze.
- Legge il testo di input, tokenizzando in parole e simboli di punteggiatura.
- Costruisce una struttura dati matriciale dove:
- La prima colonna contiene le parole iniziali (chiavi).
- Le colonne successive contengono le parole che seguono con le loro frequenze.
- Utilizza un dizionario (trie) per l'efficiente ricerca e inserimento delle parole.
- Elabora i dati attraverso processi separati usando pipe per la comunicazione.
- Genera un file CSV di output con le statistiche calcolate.
Il programma funziona correttamente con input di piccole dimensioni, ma si blocca o entra in un loop indeterminato con input molto grandi (centinaia di migliaia o milioni di righe). Il debugging è difficoltoso poiché in questo stato il programma non produce output. Si sospetta che il problema sia legato alla gestione della memoria o alla logica di elaborazione per input di grandi dimensioni.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <wchar.h>
#include <wctype.h>
#include <locale.h>
// Definizione della struttura per un oggetto contenente una stringa, la sua frequenza, e le coordinate nella matrice
typedef struct {
wchar_t Stringa[31];
float frequenza;
int occorrenza;
int x;
int y;
} oggetto;
// Definizione della struttura per una matrice contenente una lista di oggetti e le sue dimensioni
typedef struct {
oggetto** lista;
int* x;
int y;
} matrice;
// Definizione della struttura per l'alfabeto contenente un sottoalfabeto e una parola
struct Alfabeto {
struct Alfabeto* sottoalfabeto[46];
oggetto *parola;
};
// Definizione del tipo Dizionario come un puntatore a struct Alfabeto
typedef struct Alfabeto Dizionario;
// Dichiarazione della funzione ricorsivaDeallocazione
Dizionario* deallocazione(Dizionario* diz);
int creaTabella(FILE* file, matrice* matrix, Dizionario* diz, int pipe1[], int pipe2[], wchar_t primaParola[]);
int indiceAscii(wchar_t carattere);
bool confrontaStringhe(wchar_t* stringa1, wchar_t* stringa2);
bool ricercaOperativa(wchar_t stringa[], int indice, Dizionario* diz, int i, int p, matrice* m);
void leggiParolaFileInput(FILE* file, int pipe1[],long int posizione);
void stampa(FILE* foglio, int pipe2[]);
long int primaParola(FILE* file, matrice* matrix);
int main(void) { //dichiaro la funzione main
setlocale(LC_ALL, "it_IT.UTF-8"); // Imposta una locale che supporta Unicode
FILE* file = fopen("prova.txt", "r");
FILE* foglio = fopen("controprova.csv", "w");
if (file == NULL || foglio == NULL) { //se uno dei file non si apre
exit(EXIT_FAILURE); //esco con errore
}
Dizionario* dizionario = (Dizionario*)calloc(1, sizeof(Dizionario)); //alloco il dizionario
dizionario->parola = (oggetto*)calloc(1,sizeof(oggetto)); //alloco una parola nel dizionario
matrice matrix; //dichiaro una matrice
matrix.lista = (oggetto**)calloc(1, sizeof(oggetto*));
matrix.lista[0] = (oggetto*)calloc(2, sizeof(oggetto));
matrix.x = (int*)calloc(1, sizeof(int));
matrix.x[0] = 1;
long int posizione = primaParola(file, &matrix);
if(posizione == -1){
exit(EXIT_FAILURE); //esco con errore
}
//wprintf(L"%ls ", matrix.lista[0][0].Stringa);
int pipe1[2], pipe2[2]; //dichiaro due pipe
if (pipe(pipe1) == -1 || pipe(pipe2) == -1) { //se la creazione delle pipe fallisce
exit(EXIT_FAILURE); //esco con errore
}
int MAX; //massimo numero di bytes da allocare in una riga nella matrice
pid_t pid_Processo1, pid_Processo2, pid_Processo3; //dichiaro i pid dei processi
pid_Processo1 = fork(); //creo il primo processo
if (pid_Processo1 == -1) { //se la fork fallisce
perror("Fork errore"); //stampo un errore
return 1; //ritorno 1
} else if (pid_Processo1 == 0) { //se sono nel processo figlio
close(pipe1[0]); //chiudo la lettura della pipe1
leggiParolaFileInput(file, pipe1,posizione); //chiamo la funzione leggiParolaFileInput
exit(0); //esce dal processo
} else { //se sono nel processo padre
close(pipe1[1]); //chiudo la scrittura della pipe1
waitpid(pid_Processo1, NULL, 0); //attendo la terminazione del processo 1
}
pid_Processo2 = fork();
if (pid_Processo2 == -1) {
perror("Fork errore");
return 1;
} else if (pid_Processo2 == 0) {
close(pipe2[0]); // Chiudi la lettura della pipe2
wchar_t primaParolaArray[31];
wcscpy(primaParolaArray, matrix.lista[0][0].Stringa);
creaTabella(file, &matrix, dizionario, pipe1, pipe2, primaParolaArray);
exit(0);
}
// Attendi che il processo 2 finisca prima di iniziare il processo 3
waitpid(pid_Processo2, NULL, 0);
pid_Processo3 = fork();
if (pid_Processo3 == -1) {
perror("Fork errore");
return 1;
} else if (pid_Processo3 == 0) {
close(pipe2[1]); // Chiudi la scrittura della pipe2
stampa(foglio, pipe2);
exit(0);
}
// Chiudi tutte le estremità delle pipe nel processo principale
close(pipe1[0]);
close(pipe1[1]);
close(pipe2[0]);
close(pipe2[1]);
waitpid(pid_Processo3, NULL, 0);
wait(NULL); //attendo la terminazione di tutti i processi figli
wait(NULL); //attendo la terminazione di tutti i processi figli
wait(NULL); //attendo la terminazione di tutti i processi figli
fclose(foglio); //chiudo il file di output
fclose(file); //chiudo il file di input
for (int i = 0; i < 46; i++) { //libero la memoria del dizionario
dizionario->sottoalfabeto[i] = deallocazione(dizionario->sottoalfabeto[i]); //chiamo la funzione deallocazione
}
free(dizionario->parola); //libero la memoria della parola
free(dizionario); //libero la memoria del dizionario
return 0; //ritorno 0
}
Dizionario* deallocazione(Dizionario* diz) { //dichiaro la funzione deallocazione
if (diz == NULL) { //se il dizionario è NULL
return NULL; //ritorno NULL
}
for (int i = 0; i < 46; i++) { //scorro i 30 elementi del sottoalfabeto
diz->sottoalfabeto[i] = deallocazione(diz->sottoalfabeto[i]); //chiamo la funzione deallocazione ricorsivamente
}
free(diz->parola); //libero la memoria della parola
free(diz); //libero la memoria del dizionario
return NULL;
}
// Funzione per ottenere l'indice ASCII di un carattere
int indiceAscii(wchar_t carattere) {
// Converti il carattere in minuscolo
wchar_t c = towlower(carattere);
if (iswalpha(c)) {
//Gestione delle lettere non accentate
return c - L'a';
} else {
//Gestione dei caratteri accentati
switch (c) {
case L'à': return 26;
case L'è': return 27;
case L'é': return 28;
case L'ì': return 29;
case L'ò': return 30;
case L'ù': return 31;
case L'!': return 32;
case L'?': return 33;
case L'.': return 34;
case L'\'': return 35;
}
}
//Gestione dei numeri
if (c >= L'0' && c <= L'9') {
return 36 + (c - L'0');
}
//Carattere non riconosciuto
return -1;
}
//funzione per confrontare due stringhe
bool confrontaStringhe(wchar_t* Stringa1, wchar_t* Stringa2) { //dichiaro la funzione confrontaStringhe
if (*Stringa1 == L'\0' && *Stringa2 == L'\0') { //se entrambe le stringhe sono terminate
return true; //ritorno true
}
if (*Stringa1 == *Stringa2 || (towlower((wchar_t)*Stringa1) == towlower((wchar_t)*Stringa2))) { //controlla se i caratteri sono uguali o se sono uguali in minuscolo
return confrontaStringhe(Stringa1 + 1, Stringa2 + 1); //richiamo la funzione sul prossimo carattere
}
return false; //se i caratteri non sono uguali, ritorno false
}
long int primaParola(FILE* file, matrice* matrix){
wchar_t carattere;
const wchar_t* caratteriAccentati = L"àèéìòóùÀÈÉÌÒÓÙ";
int indice = 0; //inizializzo l'indice a 0
long int pos = 0; // Inizializza pos a 0
while((carattere = fgetwc(file)) != WEOF){
wchar_t successivo = fgetwc(file);
ungetwc(successivo,file);
if (carattere==L'\n'|| carattere==L' '){ //se i primi caratteri sono \n o spazio saltali
continue;
}else if(iswalnum(carattere) || (wcschr(caratteriAccentati, carattere) != NULL)){ //se trovi o quando troverai dei caratteri alfanumerici allora aggiungi alla matrice in prima posizione
matrix->lista[0][0].Stringa[indice]= carattere;
indice++;
if (successivo==L' '||(successivo == L'\n' || successivo == L'\r')|| successivo==L'!' || successivo ==L'?' || successivo == L'.'){ //se seguito da spazio o da a capo termina la Stringa
matrix->lista[0][0].Stringa[indice]= L'\0';
indice = 0;
return ftell(file);
}else if (successivo == L'\''){ //se seguito da apostrofo appendi l'apostrofo e termina la Stringa e la primaparola
matrix->lista[0][0].Stringa[indice]= L'\'';
matrix->lista[0][0].Stringa[indice+1]= L'\0';
indice = 0;
return ftell(file);
}
continue;
}else if (carattere == L'!' || carattere == L'?' || carattere == L'.'){ // se incontri dei caratteri speciali aggiungili alla matrice come dei caratteri a se
indice = 0;
matrix->lista[0][0].Stringa[indice++] = carattere;
if(successivo == '\''){
matrix->lista[0][0].Stringa[indice++] = '\'';
fgetwc(file);
}
matrix->lista[0][0].Stringa[indice] = L'\0';
indice = 0;
return ftell(file);
}
}
// Se arriviamo qui, significa che abbiamo raggiunto la fine del file senza trovare una parola valida
return -1; // Ritorniamo -1 per indicare che non è stata trovata una parola valida
}
// Funzione per la ricerca operativa di una stringa nella matrice
bool ricercaOperativa(wchar_t stringa[], int indice, Dizionario* diz, int i, int p, matrice* m) { //dichiaro la funzione ricercaOperativa
Dizionario* dizAttuale = diz; //inizializzo dizAttuale con diz
int ASCII; //dichiaro la variabile ASCII
if (stringa[indice] == '\0') { //se il carattere corrente è il terminatore di stringa
if (confrontaStringhe(dizAttuale->parola->Stringa, m->lista[i][0].Stringa)) { //se la stringa della parola del dizionario è uguale alla stringa della matrice
int n = 1; //inizializzo n a 1
int y = dizAttuale->parola->y; //assegno la coordinata y della parola del dizionario a y
int x = dizAttuale->parola->x; //assegno la coordinata x della parola del dizionario a x
int trovato = 0; //inizializzo trovato a 0
m->lista[y][0].occorrenza++; //incremento l'occorrenza della parola nella matrice
while (n <= m->x[y] && m->lista[y][n].x == n) { //finché n è minore o uguale alla dimensione x della matrice e l'elemento della matrice è uguale a n
if (confrontaStringhe(m->lista[y][n].Stringa, m->lista[i][p].Stringa)) { //se la stringa corrente è uguale alla stringa della matrice
m->lista[y][n].occorrenza++; //incremento l'occorrenza
m->lista[y][n].frequenza = (float)m->lista[y][n].occorrenza / (float)m->lista[y][0].occorrenza; //calcolo la frequenza
trovato = 1; //imposto trovato a 1
}
m->lista[y][n].frequenza = (float)m->lista[y][n].occorrenza / (float)m->lista[y][0].occorrenza; //calcolo la frequenza
n++; //incremento n
}
if (!trovato) { //se non ho trovato la stringa
if (n > m->x[y]) { //se n è maggiore della dimensione x della matrice
m->x[y] = n; //assegno n a x
}
m->lista[y] = realloc(m->lista[y], (n + 1) * sizeof(oggetto)); //rialloco la memoria per la riga della matrice
wcscpy(m->lista[y][n].Stringa, m->lista[i][p].Stringa); //copio la stringa nella matrice
m->lista[y][n].occorrenza = 1; //inizializzo l'occorrenza a 1
m->lista[y][n].frequenza = (float)m->lista[y][n].occorrenza / (float)m->lista[y][0].occorrenza; //calcolo la frequenza
m->lista[y][n].x = n; //assegno n alla coordinata x
}
return true; //ritorno true
}
wcscpy(dizAttuale->parola->Stringa, stringa); //copio la stringa nella parola del dizionario
dizAttuale->parola->x = p; //assegno p alla coordinata x della parola
dizAttuale->parola->y = i; //assegno i alla coordinata y della parola
m->lista[i][1].x = 1; //assegno 1 alla coordinata x della matrice
m->lista[i][0].x = 0; //assegno 0 alla coordinata x della matrice
m->lista[i][1].occorrenza = 1; //inizializzo l'occorrenza a 1
m->lista[i][0].occorrenza = 1; //inizializzo l'occorrenza a 1
m->lista[i][1].frequenza = (float)m->lista[i][1].occorrenza / (float)m->lista[i][0].occorrenza; //calcolo la frequenza
return false; //ritorno false
}
ASCII = indiceAscii(stringa[indice]); //calcolo l'indice ASCII del carattere corrente
if (dizAttuale->sottoalfabeto[ASCII] == NULL) { //se il sottoalfabeto corrente è NULL
dizAttuale->sottoalfabeto[ASCII] = (Dizionario*)calloc(1, sizeof(Dizionario)); //alloco memoria per il sottoalfabeto
if (dizAttuale->sottoalfabeto[ASCII] == NULL) { //se la memoria non è stata allocata
exit(1); //esco con errore
}
dizAttuale->sottoalfabeto[ASCII]->parola = (oggetto*)calloc(1,sizeof(oggetto)); //alloco memoria per la parola del sottoalfabeto
if (dizAttuale->sottoalfabeto[ASCII]->parola == NULL) { //se la memoria non è stata allocata
exit(1); //esco con errore
}
}
dizAttuale = dizAttuale->sottoalfabeto[ASCII]; //assegno il sottoalfabeto corrente a dizAttuale
return ricercaOperativa(stringa, indice + 1, dizAttuale, i, p, m); //richiamo la funzione ricorsivamente
}
// Funzione per gestire la fine di una stringa
int creaTabella(FILE* file, matrice* matrix, Dizionario* diz, int pipe1[], int pipe2[], wchar_t primaParola[]) { //dichiaro la funzione creaTabella
wchar_t stringa1[31]; //dichiaro una stringa di 31 caratteri
matrix->y = 1; //inizializzo la dimensione y a 1
matrix->lista = NULL; //inizializzo la lista a NULL
matrix->lista = (oggetto**)calloc(1,matrix->y * sizeof(oggetto*)); //alloco memoria per la matrice
matrix->lista[matrix->y - 1] = (oggetto*)calloc(1,2 * sizeof(oggetto)); //alloco memoria per una riga della matrice
wcscpy(matrix->lista[0][0].Stringa, primaParola); //copio la prima parola nella matrice
// Legge tutte le parole dalla pipe1 prima di scrivere sulla pipe2
while (read(pipe1[0], &stringa1, sizeof(stringa1)) > 0) { //legge tutte le parole dalla pipe1
if (stringa1[0] == '\0') { //se la stringa è vuota
break; //esce dal ciclo
}
// Aggiunge le parole come valore alla struttura dati Matrice
wcscpy(matrix->lista[matrix->y - 1][1].Stringa, stringa1); //copio la stringa nella matrice
matrix->lista[matrix->y - 1][1].x = 1; //assegno 1 alla coordinata x
matrix->lista[matrix->y - 1][0].x = 0; //assegno 0 alla coordinata x
int controllo = ricercaOperativa(matrix->lista[matrix->y - 1][0].Stringa, 0, diz, matrix->y - 1, 1, matrix); //chiamo la funzione ricercaOperativa
if (controllo == 0) {
matrix->y++;
matrix->lista = realloc(matrix->lista, matrix->y * sizeof(oggetto*));
matrix->lista[matrix->y - 1] = (oggetto*)calloc(2, sizeof(oggetto));
matrix->x = realloc(matrix->x, matrix->y * sizeof(int));
matrix->x[matrix->y - 1] = 1;
}
wcscpy(matrix->lista[matrix->y - 1][0].Stringa, stringa1); //copio la stringa nella matrice
stringa1[0] = '\0'; //resetto la stringa
}
// Gestisci la fine
wcscpy(matrix->lista[matrix->y - 1][1].Stringa, matrix->lista[0][0].Stringa); //copio la prima parola nell'ultima riga
int controllo = ricercaOperativa(matrix->lista[matrix->y - 1][0].Stringa, 0, diz, matrix->y - 1, 1, matrix); //chiamo la funzione ricercaOperativa
if (controllo == 0) { //se il controllo è 0
matrix->y++; //incremento la dimensione y
}
close(pipe1[0]); //chiudo la pipe1
// Scrivi il numero di righe della matrice
write(pipe2[1], &(matrix->y), sizeof(int));
for (int i = 0; i < matrix->y-1; i++) {
// Calcola la lunghezza della riga
size_t len = wcslen(matrix->lista[i][0].Stringa);
for (int j = 1; j <= matrix->x[i]; j++) {
len += wcslen(matrix->lista[i][j].Stringa) + 7; // +7 per ",%.4f,"
}
len++; // Per il carattere di nuova linea
// Alloca memoria per la riga
wchar_t* riga = calloc(len + 1, sizeof(wchar_t));
// Costruisci la riga
swprintf(riga, len + 1, L"%ls", matrix->lista[i][0].Stringa);
for (int j = 1; j <= matrix->x[i]; j++) {
wchar_t temp[50];
swprintf(temp, 50, L",%ls,%.4f", matrix->lista[i][j].Stringa, matrix->lista[i][j].frequenza);
len += 50;
riga = realloc(riga,len*sizeof(wchar_t));
wcscat(riga, temp);
}
wcscat(riga, L"\n");
// Scrivi la lunghezza della riga e poi la riga stessa
write(pipe2[1], &len, sizeof(size_t));
write(pipe2[1], riga, len * sizeof(wchar_t));
free(riga);
}
// Scrivi un segnale di fine (lunghezza 0)
size_t end_signal = 0;
write(pipe2[1], &end_signal, sizeof(size_t));
close(pipe2[1]);
return 0;
}
void stampa(FILE* foglio, int pipe2[]) {
close(pipe2[1]); // Chiudi la scrittura della pipe2
int num_righe;
ssize_t bytes_read = read(pipe2[0], &num_righe, sizeof(int));
if (bytes_read != sizeof(int)) {
if (bytes_read == 0) {
fprintf(stderr, "Pipe chiusa inaspettatamente durante la lettura del numero di righe\n");
} else {
perror("Errore nella lettura del numero di righe");
}
exit(EXIT_FAILURE);
}
fprintf(stderr, "Numero di righe lette: %d\n", num_righe);
for (int i = 0; i < num_righe; i++) {
size_t len;
bytes_read = read(pipe2[0], &len, sizeof(size_t));
if (bytes_read != sizeof(size_t)) {
if (bytes_read == 0) {
fprintf(stderr, "Pipe chiusa inaspettatamente durante la lettura della lunghezza della riga %d\n", i);
} else {
perror("Errore nella lettura della lunghezza della riga");
}
exit(EXIT_FAILURE);
}
fprintf(stderr, "Lunghezza della riga %d: %zu\n", i, len);
if (len == 0) {
fprintf(stderr, "Ricevuto segnale di fine dati\n");
break;
}
wchar_t* riga = calloc(len + 1, sizeof(wchar_t));
if (riga == NULL) {
perror("Errore nell'allocazione della memoria per la riga");
exit(EXIT_FAILURE);
}
bytes_read = read(pipe2[0], riga, len * sizeof(wchar_t));
if (bytes_read != len * sizeof(wchar_t)) {
if (bytes_read == 0) {
fprintf(stderr, "Pipe chiusa inaspettatamente durante la lettura della riga %d\n", i);
} else {
perror("Errore nella lettura della riga");
}
free(riga);
exit(EXIT_FAILURE);
}
riga[len] = L'\0';
fprintf(stderr, "Riga %d letta: %ls\n", i, riga);
fwprintf(foglio, L"%ls", riga);
free(riga);
}
close(pipe2[0]);
fprintf(stderr, "Stampa completata\n");
}
// Funzione per la lettura del file di input
void leggiParolaFileInput(FILE* file, int pipe1[], long int posizione) {
wchar_t stringa1[31];
int indice = 0;
wchar_t carattere;
const wchar_t* caratteriAccentati = L"àèéìòóùÀÈÉÌÒÓÙ";
for(int i = 0; i==posizione; i++){
fgetwc(file);
}
while ((carattere = fgetwc(file)) != WEOF) {
wchar_t successivo = fgetwc(file);
ungetwc(successivo,file);
if ((carattere == L' ' || (carattere == L'\n' || carattere == L'\r')) && successivo == WEOF) {
// Handle the case where the last character is a space or newline
if (indice > 0) {
stringa1[indice] = L'\0';
write(pipe1[1], stringa1, sizeof(stringa1));
}
break;
}
if (carattere == L'!' || carattere == L'?' || carattere == L'.') {
if (indice > 0) {
stringa1[indice] = L'\0';
write(pipe1[1], stringa1, sizeof(stringa1));
indice = 0;
}
stringa1[indice] = carattere;
if (successivo == L'\'') {
indice++;
stringa1[indice] = L'\'';
fgetwc(file);
}
indice ++;
if (successivo == WEOF) {
stringa1[indice] = L'\0';
write(pipe1[1], stringa1, sizeof(stringa1));
break;
}
} else if (indice>0 && carattere=='\''){
stringa1[indice] = L'\'';
indice++;
stringa1[indice] = L'\0';
write(pipe1[1], stringa1, sizeof(stringa1));
indice = 0;
stringa1[indice] = L'\0';
} else if (iswalnum(carattere) || (wcschr(caratteriAccentati, carattere) != NULL)) {
if (indice > 0 && (stringa1[indice -1] == '!' || stringa1[indice -1] == '?' || stringa1[indice -1] == '.' || stringa1[indice -1] == '\'')) {
stringa1[indice] = L'\0';
write(pipe1[1], stringa1, sizeof(stringa1));
indice = 0;
stringa1[indice] = L'\0';
}
stringa1[indice++] = carattere;
if(successivo == '\''){
stringa1[indice++] = L'\'';
stringa1[indice] = L'\0';
write(pipe1[1], stringa1, sizeof(stringa1));
fgetwc(file);
indice = 0;
}
if (successivo == L' ' || (successivo == L'\n' || successivo == L'\r') || successivo == WEOF ||
successivo == L'!' || successivo == L'?' || successivo == L'.' ) {
stringa1[indice] = L'\0';
write(pipe1[1], stringa1, sizeof(stringa1));
indice = 0;
}
}
else if (carattere == L' ' || (carattere == L'\n' || carattere == L'\r')) {
if (indice > 0) {
stringa1[indice] = L'\0';
write(pipe1[1], stringa1, sizeof(stringa1));
indice = 0;
stringa1[indice] = L'\0';
}
} else if (!(iswalnum(carattere) || (wcschr(caratteriAccentati, carattere) != NULL) ||
carattere == L'\'' || carattere == L'!' ||
carattere == L'?' || carattere == L'.') &&
(successivo == L' ' || (successivo == L'\n' || successivo == L'\r'))) {
continue;
}
if (successivo == WEOF) {
stringa1[indice] = L'\0';
write(pipe1[1], stringa1, sizeof(stringa1));
break;
}
}
close(pipe1[1]);
}
Esempio di input/output atteso: Input:
Cosa dicono le previsioni del tempo? Previsioni del tempo di oggi: tempo incerto! Previsioni di domani?
Output CSV:
Cosa,dicono,1.0000
dicono,le,1.0000
le,previsioni,1.0000
previsioni,del,0.6667,di,0.3333
del,tempo,1.0000
tempo,?,0.3333,di,0.3333,incerto,0.3333
?,Previsioni,0.5000,Cosa,0.5000
di,oggi,0.5000,domani,0.5000
oggi,tempo,1.0000
incerto,!,1.0000
!,Previsioni,1.0000
domani,?,1.0000
Questo esempio mostra come il programma dovrebbe elaborare le sequenze di parole e calcolare le frequenze delle parole successive. Il problema attuale impedisce di ottenere risultati simili per testi molto più lunghi.
Ho cercato di creare una versione minimizzata del codice per facilitare il debug, ma dato il comportamento imprevedibile con input di grandi dimensioni, questo tentativo non ha prodotto risultati significativi. Il programma continua a entrare in uno stato di loop o di blocco senza fornire output utili per il debugging.
Basandomi sull'analisi del codice e sul comportamento osservato, ho un forte sospetto che il problema si verifichi nella comunicazione tra le funzioni creaTabella() e stampa(), in particolare quando si scrivono dati sulla PIPE2. È possibile che ci sia un problema di sincronizzazione o di gestione della memoria in questa fase critica del programma.