INFORMATICA Esercizi Esempio: polinomi • Realizzare un programma strutturato in linguaggio C che richieda da tastiera il grado di due polinomi P1 e P2. • Successivamente il programma dovrà richiedere i coefficienti dei due polinomi. • Infine dovrà eseguire la somma e il prodotto dei due polinomi e visualizzare il risultato. • Esempio: Grado polinomio P1: Grado polinomio P2: 3 2 © Piero Demichelis 2 Esempio: polinomi Polinomio P1 Coefficiente Coefficiente Coefficiente Coefficiente x^0: x^1: x^2: x^3: 2 -3 1 2 Polinomio P2 Coefficiente x^0: Coefficiente x^1: Coefficiente x^2: -1 2 2 P1: +2x^0 -3x^1 +1x^2 +2x^3 P1: -1x^0 +2x^1 +2x^2 Somma: +1x^0 -1x^1 +3x^2 +2x^3 Prodotto: -2x^0 +7x^1 -3x^2 -6x^3 © Piero Demichelis +6x^4 +4x^5 3 Esempio: polinomi #include <stdio.h> #include <stdlib.h> #define NMAX 50 main() { int n, m, i, j; float p1[NMAX], p2[NMAX]; double somma[NMAX], prodotto[2*NMAX]; /* Inizializza i due polinomi ponendo tutti i coefficienti a zero for (i=0; i<NMAX; i++) { p1[i] = 0; p2[i] = 0; } © Piero Demichelis */ 4 Esempio: polinomi /* Legge il grado dei due polinomi */ printf ("\nGrado di P1: "); scanf ("%d", &n); printf ("\nGrado di P2: "); scanf ("%d", &m); /* Test se il grado è positivo */ if (m<1 || n<1) { printf (“\nIl grado deve essere >= 1!"); exit(2); } © Piero Demichelis 5 Esempio: polinomi /* Legge i coefficienti dei polinomi */ printf ("\nCoefficienti di P1: "); for (i=0; i<=n; i++) { printf ("\nCoefficiente x^%d: ", i); scanf ("%f", &p1[i]); } printf ("\nCoefficienti di P2: "); for (i=0; i<=m; i++) { printf ("\nCoefficiente x^%d: ",i); scanf ("%f", &p2[i]); } © Piero Demichelis 6 Esempio: polinomi /* Calcola la somma for (i=0; i<=max(m,n); i++) somma[i] = p1[i] + p2[i]; /* /* /* /* */ Calcola il prodotto: inizializza m+n coefficienti a 0. L'indice del */ vettore prodotto corrisponde al grado di quell'elemento. */ Usa gli elementi del vettore per accumulare i risultati delle */ moltiplicazioni parziali */ for(i=0; i<=n+m; prodotto[i++]=0); for(i=0; i<=n; i++) for(j=0; j<=m; j++) prodotto[i+j] = prodotto[i+j] + (p1[i] * p2[j]); © Piero Demichelis 7 Esempio: polinomi /* Visualizzazione dei risultati */ printf ("\n\nPolinomio P1: "); for (i=0; i<=n; i++) printf ("+%fx^%d", p1[i], i); printf ("\nPolinomio P2: "); for (i=0; i<=m; i++) printf ("+%fx^%d", p2[i], i); printf ("\nSomma: "); for(i=0; i<=max(m,n); i++) printf ("+%6.2lfx^%d", somma[i], i); printf ("\nProdotto: "); for(i=0; i<=n+m; i++) printf ("+%6.2lfx^%d", prodotto[i], i); } © Piero Demichelis 8 Elaborazione di una matrice • Scrivere un programma in linguaggio C che: - legga dal file «matrice.dat» una matrice M di numeri interi preceduta dal numero di righe e dal numero di colonne (dimensione massima della matrice: 20x20) - legga da tastiera un numero intero num; - cerchi fra gli elementi della matrice il numero num, ed ogni volta che lo trova (anche più di una) scriva sul file «out.dat» tutte le sottomatrici che si ottengono da M cancellando la riga e la colonna in cui si trova num. • I formati dei due file sono specificati nell’esempio. Si osservi che a seconda della posizione in cui si trova num, le sottomatrici possono essere una, due o quattro. © Piero Demichelis 9 Elaborazione di una matrice Esempio - File «matrice.dat»: 6 7 12 -3 7 34 -3 33 -2 71 0 12 41 15 1 -5 -4 2 21 -3 15 23 16 11 -1 34 24 -7 63 95 7 16 0 11 5 -9 43 0 41 10 -6 27 10 12 Inserisci il numero: 16 © Piero Demichelis 10 Elaborazione di una matrice File «out.dat»: Coordinate trovate: 2 3 Sottomatrici: 12 7 -3 34 1 -5 24 -7 0 11 41 10 -2 0 41 71 12 15 2 21 -3 95 7 16 -9 43 0 27 10 12 12 7 2 -3 -2 0 41 © Piero Demichelis -3 34 33 71 12 15 1 -5 -4 2 21 -3 3 15 23 16 11 -1 34 24 -7 63 95 7 16 0 11 5 -9 43 0 41 10 -6 27 10 12 11 Elaborazione di una matrice Coordinate trovate: 4 5 Sottomatrici: 12 7 -3 -2 0 -3 34 33 71 12 0 11 5 -9 43 41 10 -6 27 10 1 -5 -4 2 21 15 23 16 11 -1 12 7 -3 -2 0 5 41 © Piero Demichelis -3 34 33 71 12 15 1 -5 -4 2 21 -3 15 23 16 11 -1 34 4 24 -7 63 95 7 16 0 11 5 -9 43 0 41 10 -6 27 10 12 12 Elaborazione di una matrice #include <stdio.h> #include <stdlib.h> void sotto_matr (int r_in, int r_fin, int c_in, int c_fin); FILE *f1, *f2; int M[20][20]; main() { int, num, rig, col, i, j, k, w; /* apre il file contenente la matrice */ if ((f1 = fopen (“matrice.dat”, "r")) == NULL) { printf (“\nErrore nell'apertura del file matrice.dat"); return 1; } © Piero Demichelis 13 Elaborazione di una matrice /* richiede il numero da ricercare */ printf (“\nInserisci un numero intero: "); scanf ("%d", &num); /* crea il file di output */ if ((f2 = fopen (“out.dat”, “w")) == NULL) { printf (“\nErrore nella creazione del file out.dat"); return 2; } /* legge numero di righe e colonne della matrice */ fscanf (f1, "%d %d", &rig, &col); © Piero Demichelis 14 Elaborazione di una matrice /* legge il file e lo salva nella matrice M */ for (i = 0; i < rig; i++) for (j = 0; j < col; j++) fscanf (f1, "%d", &M[i][j]); fclose(f1); /* /* /* /* /* cerca nella matrice se esiste num controllando ogni elemento */ della matrice tramite due for annidati; quando lo trova esegue la */ funzione sotto_matr per tutte le sottomatrici effettive. Ovvero */ controlla che numero di righe o colonne della sottomatrice sia */ maggiore di zero */ © Piero Demichelis 15 Elaborazione di una matrice for (i = 0; i < rig; i++) { for (j = 0; j < col; j++) { if (M[i][j] == num) { /* trovato num: output delle coordinate */ fprintf (f2, "\nCoordinate trovate: %d %d\n\nSottomatrici:\n\n", i, j); /* output delle matrici (se esistono) */ if ((i > 0) && (j > 0)) sotto_matr (0, i, 0, j); if ((i > 0) && (j < col – 1)) sotto_matr (0, i, j+1, col); if ((i < rig - 1) && (j > 0)) sotto_matr (i+1, rig, 0, j); if ((i < rig -1) && (j < col – 1)) sotto_matr (i+1, rig, j+1, col); } } } fclose(f2); } © Piero Demichelis 16 Elaborazione di una matrice void sotto_matr (int r_in, int r_fin, int c_in, int c_fin); { int riga, colonna; /* scrive la matrice sul file di output */ for (riga = r_in; riga < r_fin; riga++) { for (colonna = c_in; colonna < c_fin; colonna++) fprintf (f2, "%d ", M[riga][colonna]); fprintf (f2, "\n"); } fprintf (f2,"\n"); return; } © Piero Demichelis 17 Mappa Sia data una mappa rettangolare contenente lettere dell’alfabeto. Tale mappa è memorizzata in un file di testo (il cui nome deve essere richiesto preventivamente da tastiera) in ragione di una riga per ogni linea del file. Si supponga che non vi siano errori di formato e che le linee abbiano tutte la stessa lunghezza. Le dimensioni della mappa non sono note in fase di compilazione, ma non possono eccedere le 20 righe per 80 colonne e devono essere dedotte dal file. © Piero Demichelis 18 Mappa A scopo di esempio, si riporta di seguito il formato di una mappa 8x8: qqAAAczz wwwcccsb edddCDde dddbccQw sssdcdww QAAzczzE RrRqqHHi abcdEFGH © Piero Demichelis 19 Mappa Si realizzi un programma strutturato in linguaggio C in grado di determinare quale è la sequenza di caratteri uguali disposti sulla stessa riga o sulla stessa colonna avente lunghezza massima. Le lettere maiuscole dovranno essere considerate equivalenti alle minuscole (ad esempio, ‘b’ e ‘B’, ai fini del programma, devono essere considerate la stessa lettera). Nel caso della mappa precedente, l’output del programma dovrà essere esattamente il seguente: La sequenza più lunga si trova in colonna 5, da riga 2 a riga 6. La disposizione è verticale La lunghezza 5 Il carattere c. © Piero Demichelis 20 Mappa • Base dati: - la mappa verrà memorizzata in una matrice di caratteri di nome matr (vettore di stringhe). - Il numero di righe e il numero di colonne (entrambi ricavati dalla lettura del file) saranno nr e nc. - Per poter stampare i parametri richiesti occorre costruire una sequenza di variabili: lmax = lunghezza della stringa più lunga carattere = carattere della sequenza riga = riga di inizio sequenza colonna = colonna di inizio sequenza direz = direzione della sequenza ('o‘ oppure ‘v’) © Piero Demichelis 21 Mappa #include <stdio.h> #include <string.h> #include <conio.h> #define N_RIGHE 21 #define N_COL 81 main() { int i, j, nr, nc, cont, riga, colonna, lmax; char matr[N_RIGHE][N_COL]; FILE *leggi; char nomefile[50], carattere, cfr, direz; clrscr(); © Piero Demichelis 22 Mappa printf (“\nNome file: "); scanf ("%s", nomefile); /* apre il file */ if ((leggi = fopen (nomefile, "r")) == NULL) { printf ("\n Errore apertura %s\n", nomefile); exit (0); } /* inizializza tutta la matrice col carattere di fine stringa */ for (i = 0; i < N_RIGHE; i++) for (j = 0; j < N_COL; j++) matr[i][j] = '\0'; © Piero Demichelis 23 Mappa /* Ciclo di lettura della mappa; legge fino a EOF */ nr = 0; while (!feof (leggi)) { fscanf (leggi, "%s", &matr[nr]); nr++; /* in nr numero di righe lette */ } fclose (leggi); /* setta in nc = numero colonne matrice */ nc = strlen (matr[0]); /* in lmax registra la lunghezza della sequenza più lunga */ lmax = 0; © Piero Demichelis 24 Mappa /* Ricerca per righe: in cfr carattere campione da confrontare, in cont numero di ripetizioni consecutive di quel carattere */ for (i = 0; i < nr; i++) { cfr = tolower (matr[i][0]); /* primo carattere campione = al primo */ cont = 1; /* carattere della riga! inoltre inizializza il contatore a 1 */ /* scandisce le colonne della riga i */ for (j = 1; j <= nc; j++) { if (tolower(matr[i][j]) == cfr) /* è = al carattere campione? */ cont++; /* si, incrementa il contatore */ else /* no, è diverso per cui è terminata una sequenza la cui lunghezza è in cont: verifica se è la più lunga finora. Contemporaneamente col carattere attuale è iniziata una nuova sequenza. © Piero Demichelis 25 Mappa { if (cont > lmax) /* è la sequenza più lunga? */ { lmax = cont; /* si, la sostituisce alla precedente */ carattere = cfr; riga = i+1; /* riga di inizio sequenza */ colonna = j – cont + 1; /* colonna di inizio sequenza */ direz = 'o'; /* direzione (orizzontale) */ } cfr = tolower (matr[i][j]); /* nuovo carattere campione */ cont = 1; } /* else….. */ } /* for (j=1; …… */ } /* for (i=0;…… */ © Piero Demichelis 26 Mappa /* Ricerca per colonne: blocco di istruzioni identico al caso della ricerca per righe scambiando solamente i ruoli delle variabili nc e nr */ for (j = 0; j <= nc; j++) { cfr = tolower (matr[0][j]); cont = 1; for (i = 1; i <= nr; i++) { if (tolower (matr[i][j]) == cfr) cont++; else © Piero Demichelis 27 Mappa { if (cont > lmax) { lmax = cont; carattere = cfr; riga = i - cont + 1; colonna = j + 1; direz = 'v'; } cfr = tolower(matr[i][j]); cont = 1; } /* else…… */ } /* for (i=1;……. */ } /* for (j=0;….. */ © Piero Demichelis 28 Mappa /* Visualizza i risultati */ printf ("\nSequenza più lunga "); if (direz == 'v') { printf ("in colonna %d, da riga %d a riga %d", colonna, riga, riga + lmax -1); printf ("\nLa disposizione è verticale"); } else { printf ("in riga %d, da colonna %d a colonna %d", riga, colonna, colonna + lmax -1); printf ("\nLa disposizione è orrizzontale"); } printf ("\nLa lunghezza è %d\nIl carattere %c\n", lmax, carattere); } © Piero Demichelis 29 Esempio: prenotazione aerei • All'interno di un file di testo è elencato un insieme di voli aerei. Per ognuno di essi, su ciascuna riga del file, sono riportate (separate da un singolo spazio) la città di partenza, quella di arrivo e la sigla (2 caratteri) della compagnia aerea che gestisce il volo. E' garantito che il nome della città non contenga spazi (es. New York verrà scritto New_York). • Si scriva un programma in linguaggio C che, ricevuto come primo argomento sulla riga di comando il nome del file e come secondo argomento il nome di una città, produca il seguente risultato sull'unità di output standard: - l’elenco dei voli in partenza dalla città - l'elenco dei voli in arrivo nella città - l'elenco delle compagnie aeree con voli in partenza o in arrivo alla città selezionata. • Il numero massimo di voli in partenza da una città (o in arrivo) non supera le 100 unità. © Piero Demichelis 30 Esempio: prenotazione aerei • Ad esempio, se il file VOLI.TXT contenesse i seguenti dati: Roma Milano AZ Milano Roma AZ Torino Parigi AF Parigi Torino AF Milano Londra BA Londra Milano BA Milano New York AZ Milano New York UA New York Milano AZ New York Milano UA e il programma - denominato FLY - venisse attivato nel seguente modo: FLY VOLI.TXT Milano © Piero Demichelis 31 Esempio: prenotazione aerei allora dovrebbe generarsi il seguente output: Voli in partenza da Milano: Milano Roma AZ Milano Londra BA Milano New_York AZ Milano New_York UA Voli in arrivo a Milano: Roma Milano AZ Londra Milano BA New_York Milano AZ New_York Milano UA Compagnie aeree: AZ BA UA © Piero Demichelis 32 Esempio: prenotazione aerei #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXVOLI 100 typedef enum{FALSO,VERO} boolean; int main(int argc, char *argv[ ]) { char tab_arrivi[MAXVOLI][80], compagnie[MAXVOLI][3]; int num_arrivi,num_comp,i; char partenza[80], arrivo[80], compagnia[3], citta[20]; boolean trovato, presente; FILE *in; © Piero Demichelis 33 Esempio: prenotazione aerei /* /* Controlli sulla correttezza del numero di parametri introdotto */ dalla linea di comando */ if (argc != 3) { printf ("\nErrore: imposta come parametri nome file e città\n"); exit (1); } /* apre il file dei voli */ if ((in=fopen(argv[1],"r"))==NULL) { printf ("\nErrore in apertura file\n"); exit (2); } © Piero Demichelis 34 Esempio: prenotazione aerei strcpy (citta, argv[2]); num_arrivi = 0; num_comp = 0; /* argv[2] in citta */ printf ("\nVoli in partenza da %s:\n\n", citta); while (!feof(in)) { fscanf (in, "%s %s %s", partenza, arrivo, compagnia) trovato = FALSO; /* controlla la partenza */ if (strcmp (partenza, citta)==0) { printf ("%s %s %s\n", partenza, arrivo, compagnia); trovato = VERO; } © Piero Demichelis 35 Esempio: prenotazione aerei /* controlla l'arrivo */ if (strcmp (arrivo,citta)==0) { sprintf (tab_arrivi[num_arrivi], "%s %s %s", partenza, arrivo, compagnia); num_arrivi++; trovato = VERO; } /* controlla se la compagnia è già presente nella lista */ if (trovato) { presente = FALSO; for (i=0; i<num_comp; i++) if (strcmp(compagnia, compagnie[i]) == 0) presente = VERO; © Piero Demichelis 36 Esempio: prenotazione aerei if (!presente) { strcpy(compagnie[num_comp], compagnia); num_comp++; } } } /* fine while */ /* Elenca i voli in arrivo e le compagnie accumulati nei vettori di */ /* stringhe tab_arrivi e compagnie in precedenza */ printf ("\n\nVoli in arrivo a %s:\n\n", citta); for (i=0; i<num_arrivi; i++) printf ("%s\n", tab_arrivi[i]); } printf ("\n\nCompagnie che operano a %s:\n\n", citta); for (i=0; i<num_comp; i++) printf ("%s\n", compagnie[i]); © Piero Demichelis 37 Compressione di immagini • Scrivere un programma in linguaggio C per la compressione di immagini che: - legga dal file «matrice.dat» una matrice di numeri reali di dimensione 30x30; - legga da tastiera due numeri interi N e M che rappresentano le dimensioni di una sottomatrice; • suddivida la matrice in sottomatrici NxM a partire dall’elemento in alto a sinistra, e costruisca una nuova matrice 30x30 di numeri reali, in cui ogni elemento delle sottomatrici è dato dalla media degli elementi della sottomatrice stessa (vedere esempio); • visualizzi su video la matrice finale. • Importante: vicino al bordo destro e inferiore è possibile che le sottomatrici da considerare abbiamo dimensioni inferiori a NxM (vedere esempio). © Piero Demichelis 38 Compressione di immagini • Esempio: Con N= 2, M=4: File «matrice.dat» (per semplicità sia 6x6): 1 0 1 2 3 4 2 3 2 3 0 5 0 2 1 2 4 3 1 2 2 2 1 0 1 5 4 3 2 1 2 1 2 0 7 0 media = 1.75 Matrice finale : 1.75 1.75 1.75 1.75 1.75 1.75 1.5 1.5 1.5 1.5 1.5 1.5 2.25 2.25 2.25 2.25 2.25 2.25 1.75 1.75 1.5 1.5 2.25 2.25 3.0 3.0 2.0 2.0 2.5 2.5 3.0 3.0 2.0 2.0 2.5 2.5 © Piero Demichelis 39 Compressione di immagini #include <stdio.h> #include <stdlib.h> #define DIM 30 main() { float mat[DIM][DIM], som, med; int N, M, i, j, k, rig, col; FILE *f1; printf ("\nInserisci il numero di righe N: "); scanf ("%d",&N); printf ("\nInserisci il numero di colonne M: "); scanf ("%d",&M); © Piero Demichelis 40 Compressione di immagini /* apre il file matrice.dat */ if ((f1 = fopen ("matrice.dat","r")) == NULL); { printf (“\nErrore apertura di matrice.dat\n”); return (1); } /* legge il file matrice.dat ritenuto corretto, pertanto non ci sono */ /* controlli sui valori letti */ for (i = 0; i < DIM; i++) for (j = 0; j < DIM; j++) fscanf (f1, "%f", &mat[i][j]); fclose(f1); © Piero Demichelis 41 Compressione di immagini /* individua riga e colonna iniziale di tutte le possibili sottomatrici */ for (rig = 0; rig < DIM; rig += N) { for (col = 0; col < DIM; col += M) { /* per ognuna calcola il valor medio */ k = 0; som = 0; for (i = rig; i < (N + rig) && i < DIM; i++) { for (j = col; j < (M + col) && j < DIM; j++) { k++; som += mat[i][j]; } /* fine “for (j = col; j < (M + col) &&....” */ } /* fine “for (i = rig; i < (N + rig) &&....” */ © Piero Demichelis 42 Compressione di immagini /* costruisce la nuova sottomatrice sostituendo ai valori precedenti */ /* il valor medio appena calcolato */ med = som / k; for (i = rig; i < (N + rig) && i < DIM; i++) for (j = col; j < (M + col) && j < DIM; j++) mat[i][j] = med; } /* fine “for (col = 0; col < DIM; col += M)” } /* fine “for (rig = 0; rig < DIM; rig += N)” */ /* visualizza la nuova matrice */ for (i = 0; i < DIM; i++) { for (j = 0; j < DIM; j++) printf ("%.2f ", mat[i][j]); printf ("\n"); } } © Piero Demichelis */ 43 Gestione di un bar • Si desidera realizzare un programma in linguaggio C che consenta di gestire i conti dei clienti di un bar. Il programma permette di inserire da tastiera il codice numerico di ognuna delle consumazioni di un cliente. • Il codice 0 indica che l’inserimento è finito e che il programma deve stampare il conto; il conto stampato dal programma contiene la descrizione e il costo di ognuna delle consumazioni, nonché l’importo totale dovuto dal cliente. • Si noti che il codice 0 non implica la fine del programma, il quale deve invece ritornare all’inizio dell’inserimento di un nuovo conto. Il programma termina quando viene introdotto il codice –1. © Piero Demichelis 44 Gestione di un bar • La corrispondenza tra il codice di una consumazione e un articolo si trova in un primo file il cui nome viene specificato come primo parametro sulla linea di comando. Nel file i codici (e i relativi articoli) sono elencati in ordine a partire dal codice 1 (vedi esempio). • La corrispondenza tra un articolo ed il suo prezzo si trova in un secondo file il cui nome viene specificato come secondo parametro sulla linea di comando. • Si facciano inoltre le seguenti assunzioni: - Ciascun conto consiste al massimo di 10 consumazioni - Sono previsti al massimo 100 articoli diversi. © Piero Demichelis 45 Gestione di un bar • Esempio: • 1 2 3 4 5 Supponendo che il file CODICI.DAT contenga i seguenti dati: Birra_Media Birra_Piccola Panino Coca_Cola Acqua_Minerale e che il file PREZZI.DAT contenga i seguenti dati: Panino 3.50 Coca_Cola 2.00 Birra_Media 4.00 Birra_Piccola 2.50 Acqua_Minerale 1.00 © Piero Demichelis 46 Gestione di un bar • Invocando il programma di nome CONTO con il seguente comando: CONTO CODICI.DAT PREZZI.DAT • Inserendo i seguenti dati, Consumazione? Consumazione? Consumazione? Consumazione? 1 5 1 0 il programma produrrà il seguente output: Birra_Media 4.00 Panino 3.50 Birra_Media 4.00 Totale 11.50 Euro. Consumazione? © Piero Demichelis 47 Gestione di un bar #include <stdio.h> typedef enum {FALSO, VERO} boolean; typedef struct { char articolo[30]; float costo; } prodotti; void stampa_output (prodotti v[], int n, float tot) int main (int argc, char *argv[]) { prodotti consumazione[10], articoli[101]; float totale_cons = 0.0, costo; int i, artic = 0, codice, cod, N_articoli = 0; char prodotto[30]; boolean trovato; FILE *fp1, *fp2; © Piero Demichelis 48 Gestione di un bar if(argc != 3) { printf ("errore parametri\n"); return 1; } /* controllo argomenti */ if ((fp1 = fopen (argv[1],"r")) == NULL) { fprintf (stderr,"Errore nell'apertura del file %s\n", argv[1]); return 2; } if ((fp2 = fopen (argv[2],"r")) == NULL) { fprintf (stderr,"Errore nell'apertura del file %s\n", argv[2]); return 3; } © Piero Demichelis 49 Gestione di un bar /* riempimento del vettore di strutture articoli */ while (fscanf (fp1,"%d%s", &cod, prodotto) != EOF) { strcpy (articoli[cod].articolo, prodotto); N_articoli++; } fclose (fp1); /* Legge il costo dei prodotti e li salva nel campo di pertinenza */ while (fscanf (fp2,"%s%f", prodotto, &costo) != EOF) { /* cerco nel vettore di strutture */ i = 1; trovato = FALSO; while (!trovato && (i <= N_articoli)) { if (strcmp (prodotto, articoli[i].articolo) == 0) { articoli[i].costo = costo; trovato = VERO; } i++; } } fclose(fp2); © Piero Demichelis 50 Gestione di un bar /* inizio parte interattiva printf (“\nConsumazione? "); scanf ("%d", &codice); */ while (codice != -1) { if (codice == 0) { stampa_output (consumazione, artic, totale_cons); artic = 0; /* inizializzazioni per prossimo conto */ totale_cons = 0.0; } else { consumazione[artic] = articoli[codice]); artic++; totale_cons += articoli[codice].costo; } © Piero Demichelis 51 Gestione di un bar printf ("\nConsumazione? "); /* leggi un altro codice */ scanf ("%d", &codice); } /* fine del ciclo while (c!= -1)...... */ } /* fine del main*/ void stampa_output (prodotti v[], int n, float tot) { int i; for (i=0; i<n; i++) printf ("%s %f\n", v[i].articolo, v[i].costo); printf ("Totale %f\n", tot); } © Piero Demichelis 52 Esempio: supermercato • Gli acquisti effettuati in un piccolo supermercato sono registrati e memorizzati in un file di caratteri costituito da un numero di righe indefinito. Ciascuna riga ha il seguente formato: prodotto categoria valore • in cui: prodotto indica il nome del prodotto acquistato, categoria indica una suddivisione in categorie dei prodotti (e.g., alimentari, vestiario, etc.), valore indica la cifra spesa (e.g., in lire o euro) per l'acquisto dello stesso. • Il prodotto e la categoria sono individuati da stringhe di caratteri (non contenenti spazi) e di lunghezza massima uguale a 50 e 3 caratteri rispettivamente; valore è un numero intero. © Piero Demichelis 53 Esempio: supermercato • Si richiede la scrittura di un programma in linguaggio C che produca un secondo file contenente delle statistiche sugli acquisti, suddivise per categoria (i.e., ciascuna categoria deve comparire nel file una sola volta). Ciascuna riga del file deve avere il seguente formato: categoria numero valore-totale valore-medio • in cui: numero indica il numero totale di acquisti per la relativa categoria, valore-totale la somma totale dei valori per quella categoria, e valore-medio la cifra media spesa per quella categoria in ciascun acquisto. Tutti i valori numerici devono essere riportati quali interi. • I nomi dei due file devono essere letti da tastiera, il file di ingresso si può supporre di formato corretto, il numero massimo di categorie è uguale a 100, l'ordine di memorizzazione nel file di uscita delle varie categorie può essere qualsiasi. © Piero Demichelis 54 Esempio: supermercato Esempio. • Supponendo che il file di ingresso abbia il seguente formato pastaXYZ ali 8000 pannolini123 mis 30000 paneAAA ali 2500 jeansBBB ves 85000 scarpeCCC ves 45000 olioXYWZ ali 12500 • occorre produrre il seguente file ali 3 23000 7667 ves 2 130000 65000 mis 1 30000 30000 © Piero Demichelis 55 Esempio: supermercato #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX 100 typedef enum {FALSO,VERO} boolean; main() { char nomefile[80]; struct cate { char nome[4]; long num; long val; } categorie[MAX]; © Piero Demichelis 56 Esempio: supermercato FILE *in,*out; long ncat = 0, val, i; boolean trovato; char cat[4], prod[51]; /* Richiede nome file */ printf ("\nNome file aquisti: "); scanf ("%s", nomefile); /* Apre il file */ if ((in = fopen(nomefile, "r")) == NULL) { printf ("\nErrore open\n"); exit (1); } © Piero Demichelis 57 Esempio: supermercato /* Legge il file riga per riga e cerca se la categoria è già presente */ while (!feof (in)) { fscanf (in, "%s %s %ld", prod, cat, &val) trovato = FALSO; i = 0; while (!trovato && (i < ncat)) if (strcmp(categorie[i].nome, cat) == 0) { /* categoria già vista prima: aggiorna i campi */ categorie[i].num++; categorie[i].val += val; trovato = VERO; } © Piero Demichelis 58 Esempio: supermercato /* categoria nuova, aggiunge un nuovo elemento al vettore di */ /* strutture per l’output finale */ if (!trovato) { strcpy (categorie[ncat].nome, cat); categorie[ncat].num = 1; categorie[ncat].val = val; ncat++; } } fclose(in); /* Chiede il nome file di output e lo crea */ printf ("\nNome file output: "); scanf ("%s", nomefile); © Piero Demichelis 59 Esempio: supermercato if ((out = fopen(nomefile,"w")) == NULL) { printf ("\nErrore open\n"); exit (3); } /* Scrive sul file di output i dati richiesti */ for (i=0; i<ncat; i++) fprintf (out,"%s %ld %ld %ld\n", categorie[i].nome, categorie[i].num, categorie[i].val, categorie[i].val/categorie[i].num); fclose(out); } © Piero Demichelis 60 Crittografia Si desidera realizzare un programma in linguaggio C a cui vengono forniti come parametri sulla riga di comando due nomi di file e un numero intero N maggiore di zero. Il primo file contiene un testo in formato ASCII, e consiste di un numero indefinito di righe ciascuna formata al massimo da 80 caratteri. Il programma deve crittografare il contenuto del primo file e scriverlo nel secondo file, anch'esso in formato ASCII. Il metodo crittografico considerato funziona nel seguente modo: ogni lettera maiuscola e minuscola dell'alfabeto deve essere sostituita con la lettera dell'alfabeto stesso che si ottiene spostandosi di N posizioni in ordine alfabetico crescente, partendo dalla lettera che si vuole crittografare. Ad esempio se N=5 e il carattere da crittografare è il carattere “m”, il carattere crittografato sarà “r” (5 posizioni nell’ordine alfabetico dopo la “m”). © Piero Demichelis 61 Crittografia Lo spostamento deve essere effettuato in modo “circolare”: Se nello spostamento, dalla lettera considerata, si supera la fine dell'alfabeto, si deve ripartire a contare dall’inizio. Ad esempio, se N=1, e il carattere da crittografare è "z" il carattere da scrivere nel secondo file sarà il carattere "a". A sostituzione avvenuta, la riga crittografata deve essere scritta invertita nel secondo file (cioè l'ultimo carattere diventa il primo, il penultimo diventa il secondo e così via). Tutti gli altri caratteri (punteggiatura, spaziatura) rimangono inalterati. NOTE: - Si consiglia di processare un carattere per volta usando le opportune funzioni di interrogazione dell’insieme dei caratteri ASCII. © Piero Demichelis 62 Crittografia Esempio di esecuzione: Supponendo di avere N=1 e che il contenuto del file di input sia: Questo compito e’ facilissimo! Vero? Nel file di output dovrà esserci scritto: !pnjttjmdbg ‘f pujpnpd putfvR ?psfW © Piero Demichelis 63 Crittografia #include <stdio.h> #include <string.h> #include <ctype.h> #define DIM 80 /* prototipo */ void inverti (char s[]); /* main */ int main (int argc, char *argv[]) { FILE *fin, *fout; int i, N, val; char lineain[DIM], lineaout[DIM]; © Piero Demichelis 64 Crittografia if (argc != 4) { printf ("Errore di formato dei parametri!\n"); exit (0); } if ((fin = fopen (argv[1], "r")) == NULL) { printf ("Errore nell'apertura del file %s\n", argv[1]); exit (0); } if ((fout = fopen (argv[2], "w")) == NULL) { printf ("Errore nell'apertura del file %s\n", argv[2]); exit (0); } © Piero Demichelis 65 Crittografia N = atoi (argv[3]); /* legge una linea alla volta e poi inverte la stringa crittografata */ while (fgets (lineain, DIM, fin) != NULL) { /* ora processa carattere per carattere */ for (i=0; i<strlen (lineain); i++) { /* processa solo i caratteri alfabetici */ if (isalpha (lineain[i])) { /* devo sommare N al codice ASCII */ if (islower(lineain[i])) val = lineain[i]-'a'; else val = lineain[i]-'A'; val = ((val + N) % 26); /* somma 'circolare‘: ci sono 26 caratteri */ /* ritrasformo 'val' in un carattere ASCII */ if (islower(lineain[i])) lineaout[i] = val + 'a'; else lineaout[i] = val + 'A'; /* NOTA: non e' l'unico modo per sommare N ! */ } © Piero Demichelis 66 Crittografia /* else non è un carattere alfabetico, quindi lo scrive invariato lineaout[i] = lineain[i]; /* chiusura di for (i=0; i<strlen (lineain);….. */ /* finito il processamento della linea 'lineain‘, ora la inverto e la /* scrivo sul file 'fout'. Prima pero' devo aggiungere il NULL se no /* non e' una stringa! lineaout[i] = '\0'; inverti (lineaout); puts (lineaout); /* visualizza anche sul monitor (non richiesto) fputs (lineaout, fout); fprintf (fout, “\n”); } /* chiusura di while (fgets(lineain, DIM, fin)…… */ */ */ } } */ */ */ fclose (fin); fclose (fout); © Piero Demichelis 67 Crittografia void inverti (char s[]) { int i, len = strlen(s); char tmp; for (i=0; i < len/2; i++) { /* scambio i valori i e N-i-1 tmp = s[i]; s[i] = s[len-i-1]; s[len-i-1] = tmp; } /* nota: s viene passata per indirizzo (e' un vettore) e pertanto /* viene ritornata al main modificata } © Piero Demichelis */ */ */ 68 Import / Export • Sono dati tre file di testo contenenti le informazioni sulle operazioni di una ditta di import/export, che ha relazioni commerciali con società appartenenti a vari stati. • Un primo file (il cui nome è STATI.DAT) contiene l’elenco degli stati (al massimo 100) con cui esistono relazioni commerciali, nel seguente formato: <codice_stato> <nome_stato> dove <codice_stato> è un codice numerico progressivo (un numero intero: 0 per il primo stato, 1 per il secondo, …), mentre <nome_stato> è il nome dello stato, privo di spazi. Esempio: 0 Stati_Uniti 1 Corea 2 Giappone 3 Francia 4 Germania © Piero Demichelis 69 Import / Export • Un secondo file (il cui nome DITTE.DAT) contiene l’elenco delle ditte (al massimo 1000) , con cui esistono relazioni commerciali, nel seguente formato: <codice_stato> <nome_societa> dove <codice_stato> è il codice dello stato cui appartiene la società, <nome_societa> è il nome della società. Esempio: 1 Kia 4 BMW 4 Mercedes 3 Peugeot 3 Citroen 2 2 0 0 0 © Piero Demichelis Honda Mitsubishi Chrysler General_Motors Chevrolet 70 Import / Export • Un terzo file (il cui nome è TRANSAZIONI.DAT) contiene le informazioni su un certo numero di transazioni commerciali, ognuna delle quali viene rappresentata, su una riga del file, secondo il formato: <nome_societa> <importo> <data> dove <nome_società> è il nome della società, <importo> è un intero, che rappresenta l’importo della transazione (valore negativo per importazione, positivo per esportazione), <data> è la data della transazione (formato gg/mm/aaaa). Esempio: Mitsubishi 101 21/01/2004 Chrysler -30 01/02/2004 General_Motors -2000 10/02/2004 Chevrolet 50 04/03/2004 Kia 500 12/03/2004 BMW -1200 15/04/2004 Mercedes -400 23/04/2004 BMW -1000 22/06/2004 Mercedes 300 23/06/2004 Peugeot 403 02/07/2004 General_Motors 1124 05/07/2004 Chevrolet 350 10/08/2004 Citroen -325 11/08/2004 Honda -670 30/08/2004 Peugeot -768 21/09/2004 Kia -800 23/09/2004 © Piero Demichelis 71 Import / Export • Si scriva un programma in linguaggio C che legga ed elabori i dati secondo le richieste seguenti. • Calcoli il numero totale delle transazioni e i bilanci complessivi delle transazioni di importazione e esportazione (somma degli importi relativi, rispettivamente, a importazioni ed esportazioni), che vanno stampati su video. • Calcoli per ogni stato, il bilancio complessivo commerciale di import/export (cioé la sommatoria, per ogni stato, degli importi relativi a tutte le società appartenenti allo stato). Per ogni stato vanno stampati su video il nome e il bilancio totale. © Piero Demichelis 72 Import / Export • Sulla base di questi dati, l’output del programma sarà il seguente: Numero transazioni: 16 Totale importazioni: -7193 Totale esportazioni: 2828 STATO: STATO: STATO: STATO: STATO: Stati_Uniti BILANCIO: -506 (ottenuto come: -30-2000+50+1124+350) Corea BILANCIO: -300 (ottenuto come: 500-800) Giappone BILANCIO: -569 (ottenuto come: 101-670) Francia BILANCIO: -690 (ottenuto come: 403-325-768) Germania BILANCIO: -2300 (ottenuto come: -1200-400-1000+300) © Piero Demichelis 73 Import / Export Per semplicità non devono essere eseguiti controlli di errore sul formato dei file, sugli argomenti al main, sull'apertura corretta dei file. La soluzione proposta prevede due tipi struct (t_stato e t_societa) per le informazioni relative, rispettivamente, a stati e società. I primi due file vengono infatti letti caricando i dati un due vettori di struct (tabella_stati e tabella_societa). Il codice di uno stato non viene inserito nella struttura t_stato in quanto coincide con l'indice dello stato stesso nel vettore (0 per il primo stato, 1 per il secondo, ...). Per i dati nel terzo file non sono previste tabelle, in quanto non è necessario disporre di tutte le informazioni (su tutte le transazioni) contemporaneamente: il file viene letto riga per riga aggiornando le statistiche sulle transazioni (globali e per stato) mediante i dati appena letti: le date vengono lette ma ignorate, in quanto non necessarie alla soluzione del problema. © Piero Demichelis 74 Import / Export #include <stdio.h> /* tipi struct per stato e societa' */ typedef struct { char nome[30]; int bilancio; } t_stato; typedef struct { char nome[30]; int codice_stato; } t_societa; /* prototipo di funzione */ int cercaCodiceStato (t_societa tabella_societa[], int n, char nome[]); © Piero Demichelis 75 Import / Export int main (void) { FILE *fp; int i, nst, nsoc; int codice_stato, importo; int nt, si, se; /* num. trans., importazioni, esportazioni */ char nome[30]; t_stato tabella_stati[100]; t_societa tabella_societa[1000]; /* lettura file stati.dat: tabella stati */ fp = fopen ("stati.dat","r"); © Piero Demichelis 76 Import / Export nst=0; while (fscanf(fp,"%d%s", &codice_stato, nome)!=EOF) { nst++; strcpy (tabella_stati[codice_stato].nome,nome); tabella_stati[codice_stato].bilancio = 0; } fclose(fp); /* lettura file ditte.dat: tabella societa' */ fp = fopen ("ditte.dat", "r"); nsoc = 0; while (fscanf(fp,"%d%s", &codice_stato, nome) != EOF) { strcpy (tabella_societa[nsoc].nome, nome); tabella_societa[nsoc].codice_stato = codice_stato; nsoc++; } fclose(fp); © Piero Demichelis 77 Import / Export /* Lettura transazioni.dat ed elaborazione dei dati. Per ogni riga del file transazioni.dat, letti nome della societa e importo, si aggiornano gli importi totali e di import/export. Si calcola quindi il codice dello stato (mediante la funzione cercaCodiceStato, quindi si aggiorna la statistica di bilancio totale relativa allo stato. */ fp = fopen ("transazioni.dat", "r"); nt = si = se = 0; while (fscanf (fp,"%s%d%*s", nome, &importo) != EOF) { nt++; if (importo > 0) se += importo; else si += importo; i = cercaCodiceStato (tabella_societa, nsoc, nome); tabella_stati[i].bilancio += importo; } fclose(fp); © Piero Demichelis 78 Import / Export /* stampa statistiche globali */ printf ("Numero transazioni: %d\n", nt); printf ("Totale importazioni: %d\n", si); printf ("Totale esportazioni: %d\n\n", se); /* stampa statistiche per stato */ for (i=0; i<nst; i++) printf ("STATO: %-30s BILANCIO: %8d\n", tabella_stati[i].nome, tabella_stati[i].bilancio); } © Piero Demichelis 79 Import / Export /* funzione che cerca il codice dello stato cui appartiene una societa', dato il nome di quest'ultima. La ricerca viene fatta nella tabella delle societa'. */ int cercaCodiceStato ( t_societa tabella_societa[], int n, char nome[]) { int i; for (i=0; i<n; i++) { if (strcmp (tabella_societa[i].nome, nome) == 0) index = tabella_societa[i].codice_stato; } return (index); } © Piero Demichelis 80