Il programma utilizza le pipe per gestire diversi processi concorrenti. Quando il programma deve scrivere sulla pipe2 per poi condividerla col processo concorrente stampa, smette di funzionare correttamente perché quando leggo la pipe2 su stampa non legge niente. La ragione esatta di questa interruzione non è chiara, e sono necessari ulteriori debug per identificare la causa di questo problema.
Attraverso alcuni debug con varie print inserite qua e là, ho potuto circoscrivere che il problema risiede nella funzione stampa o alla fine della funzione creaTabella quando scrive sulla pipe2[1] in modalità scrittura.
#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, int indice, 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[], int MAX);
long int primaParola(FILE* file, matrice* matrix);
int main() { // 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));
long int posizione = primaParola(file, &matrix);
if (posizione == -1) {
exit(EXIT_FAILURE); // esco con errore
}
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(); // creo il secondo processo
if (pid_Processo2 == -1) { // se la fork fallisce
perror("Fork errore"); // stampo un errore
return 1; // ritorno 1
} else if (pid_Processo2 == 0) { // se sono nel processo figlio
close(pipe2[0]); // chiudo la lettura della pipe2
wchar_t primaParolaArray[31]; // Assicurati che la dimensione sia sufficiente
wcscpy(primaParolaArray, matrix.lista[0][0].Stringa);
MAX = creaTabella(file, 0, &matrix, dizionario, pipe1, pipe2, primaParolaArray); // chiamo la funzione creaTabella che ritorna numero massimo di bytes delle righe della matrice
exit(0); // esce dal processo
} else { // se sono nel processo padre
close(pipe1[0]); // chiudo la lettura della pipe1
close(pipe2[1]); // chiudo la scrittura della pipe2
waitpid(pid_Processo2, NULL, 0); // attendo la terminazione del processo 2
}
pid_Processo3 = fork(); // creo il terzo processo
if (pid_Processo3 == -1) { // se la fork fallisce
perror("Fork errore"); // stampo un errore
return 1; // ritorno 1
} else if (pid_Processo3 == 0) { // se sono nel processo figlio
close(pipe2[1]); // chiudo la scrittura della pipe2
stampa(foglio, pipe2, MAX); // chiamo la funzione stampa
close(pipe2[0]); // chiudo la lettura della pipe2
exit(0); // esce dal processo
}
waitpid(pid_Processo3, NULL, 0); // attendo la terminazione del processo 3
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 46 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
}
// Funzione per trovare la prima parola nel file
long int primaParola(FILE* file, matrice* matrix) {
char 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);
fseek(file, -1, SEEK_CUR);
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'!' || successivo == L'?' || successivo == L'.') { // se seguito da spazio o da a capo termina la Stringa
matrix->lista[0][0].Stringa[indice] = L'\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';
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
matrix->lista[0][0].Stringa[indice] = carattere;
matrix->lista[0][0].Stringa[indice + 1] = L'\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 && 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) { // se n è maggiore della dimensione x della matrice
m->x = 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, int indice, 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->x = 1; // inizializzo la dimensione x a 1
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) { // se il controllo è 0
matrix->y++; // incremento la dimensione y
matrix->lista = realloc(matrix->lista, matrix->y * sizeof(oggetto*)); // rialloco la memoria per la matrice
matrix->lista[matrix->y - 1] = (oggetto*)calloc(1, 2 * sizeof(oggetto)); // alloco memoria per una nuova riga
}
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
int dimRiga = 31; // dimensione minima di ogni riga
int dimMAX = 31; // dimensione massima che può assumere una riga della matrice
// Scrive le righe della matrice nella pipe2
for (int i = 0; i < matrix->y - 1; i++) { // scrivo le righe della matrice nella pipe2
wchar_t* riga = calloc(1, dimRiga * sizeof(wchar_t)); // Buffer per memorizzare la rappresentazione in stringa della riga allocato dinamicamente
int occorrenze = 0; // contatore occorrenze
swprintf(riga, dimRiga, L"%ls", matrix->lista[i][0].Stringa);
for (int j = 1; j < matrix->x + 1; j++) { // itero sulle colonne
if (occorrenze == matrix->lista[i][0].occorrenza) { // se le occorrenze sono uguali
break; // esce dal ciclo
}
occorrenze = occorrenze + matrix->lista[i][j].occorrenza; // incremento le occorrenze
int incremento = wcslen(matrix->lista[i][j].Stringa) + 6; // calcolo l'incremento di bytes che ogni volta bisogna aggiungere
dimRiga += incremento; // sommo alla dimensione di quella riga
if (dimRiga > dimMAX) { // verifico se quella corrisponde alla dimensione massima della riga più lunga della matrice
dimMAX = dimRiga; // se si associo quel valore
}
riga = realloc(riga, dimRiga * sizeof(wchar_t)); // estendo sempre il buffer riga reallocandolo
swprintf(riga + wcslen(riga), dimRiga - wcslen(riga), L",%ls,%.4f", matrix->lista[i][j].Stringa, matrix->lista[i][j].frequenza); // aggiungo la stringa e la frequenza
}
if ((i + 1) != matrix->y - 1) { // se non è l'ultima riga
swprintf(riga + wcslen(riga), dimRiga - wcslen(riga), L"%ls", L"\n"); // aggiungo una nuova linea
}
wprintf(L"%ls", riga);
write(pipe2[1], riga, sizeof(riga)); // scrivo la rappresentazione in stringa della riga sulla pipe2
}
close(pipe2[1]); // chiudo la pipe2
return dimMAX; // ritorno dimMAX
}
void stampa(FILE* foglio, int pipe2[], int MAX) { // dichiaro la funzione stampa
close(pipe2[1]); // chiudo la scrittura della pipe2
wchar_t riga[MAX]; // dichiaro un buffer per la riga con dimensione di bytes pari alla dimensione massima della riga più lunga della matrice
while (read(pipe2[0], riga, sizeof(riga)) > 0) { // leggo dalla pipe2
fwprintf(foglio, L"%ls", riga); // scrivo la riga nel file
}
}
// 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"àèéìòóùÀÈÉÌÒÓÙ";
fseek(file, posizione, SEEK_SET);
while ((carattere = fgetwc(file)) != WEOF) {
wchar_t successivo = fgetwc(file);
fseek(file, -1, SEEK_CUR);
if ((carattere == L' ' || carattere == L'\n') && successivo == WEOF) {
// Gestisci il caso in cui l'ultimo carattere è uno spazio o una nuova riga
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[0] = carattere;
stringa1[1] = L'\0';
write(pipe1[1], stringa1, sizeof(stringa1));
if (successivo == WEOF) {
break;
}
} else if (iswalnum(carattere) || (wcschr(caratteriAccentati, carattere) != NULL) || carattere == L'\'') {
stringa1[indice++] = carattere;
if (successivo == L' ' || successivo == L'\n' || successivo == WEOF ||
successivo == L'!' || successivo == L'?' || successivo == L'.' || carattere == L'\'') {
stringa1[indice] = L'\0';
write(pipe1[1], stringa1, sizeof(stringa1));
indice = 0;
}
} else if (carattere == L' ' || carattere == L'\n') {
if (indice > 0) {
stringa1[indice] = L'\0';
write(pipe1[1], stringa1, sizeof(stringa1));
indice = 0;
}
} else if (!(iswalnum(carattere) || (wcschr(caratteriAccentati, carattere) != NULL) ||
carattere == L'\'' || carattere == L'!' ||
carattere == L'?' || carattere == L'.') &&
(successivo == L' ' || successivo == L'\n')) {
if (indice > 0) {
stringa1[indice] = L'\0';
write(pipe1[1], stringa1, sizeof(stringa1));
indice = 0;
}
continue;
}
if (successivo == WEOF) {
break;
}
}
close(pipe1[1]);
}