Fondamenti di Informatica Prima prova intermedia - 11 Novembre 2009 Si risolvano i seguenti esercizi. Il compitino prevede un punteggio massimo di 15/14-esimi, cui andranno sommati i punti ottenuti nel secondo compitino (almeno 14 punti) e quelli del laboratorio (5 punti). Il tempo a disposizione è 2 h. e 30 minuti. Esercizio 1 (2 punti) Si fornisca la rappresentazione in complemento a 2 del numero decimale 10824 usando il minimo numero di bit necessario. Esercizio 2 (4 punti) Si dichiari in C il tipo SchedaLibro utilizzabile ad esempio in un archivio di biblioteca. Il tipo richiesto deve contenere le seguenti informazioni: Titolo del libro: una stringa di 50 caratteri (un opportuno terminatore indicherà la fine della parte significative delle stringa) Autore o autori del libro: un altra stringa pure di 50 caratteri Data dell ultimo prestito (rappresentata mediante tre interi, giorno, mese, anno). Si assuma ora che un programma C contenga una variabile Libro del tipo suddetto e che essa sia memorizzata a partire dalla cella 1000; una variabile P di tipo puntatore a SchedaLibro, memorizzata nella cella 2000 Si scriva una sequenza di istruzioni nel linguaggio di von Neumann che traduca la seguente istruzione C: Libro.Data.anno = P -> Data.anno Si facciano le seguenti assunzioni: ogni carattere e ogni intero occupi esattamente una cella di memoria; siano disponibili per uso temporaneo le celle comprese tra la 900 e la 999; Le istruzioni del linguaggio di von Neumann utilizzabili siano le seguenti: LOAD xxx STORE xxx ADD xxx SUB xxx MUL xxx DIV xxx BR zzz (Salta all istruzione numero zzz) BEQ zzz (Salta all istruzione numero zzz se il contenuto dell accumulatore è 0) WRITE READ
L aggiunta del simbolo = subito dopo il codice operativo di un istruzione indica la modalità di indirizzamento immediata. Nel caso esso sia applicato all istruzione WRITE determina la stampa dell operando xxx che potrebbe anche essere una stringa di caratteri. L aggiunta del simbolo @ subito dopo il codice operativo di un istruzione indica la modalità di indirizzamento indiretta. Esercizio 3 (2 punti) Si considerino le seguenti dichiarazioni: int x, y, i; int *P; int seq1[20]; Si consideri poi il seguente frammento di programma C: for (i = 0 ; i < 20; i ++) seq1[i] = i; P = seq1; P = P +10; x = *P; P = P + 10; y = *P Si dica, spiegandone brevemente le ragioni se il frammento precedente contiene errori a compile time o a run time; nel caso il frammento sia corretto si dica quale valore avranno le variabili x e y al termine della sua esecuzione. Esercizio 4 (7 punti) Si costruisca un programma per calcolare il resto di un pagamento in euro. Il programma legge in primo luogo dallo standard Input il contenuto della cassa, ossia un numero intero non negativo di pezzi di banconote e monete. Per semplicità si assuma che questi pezzi non comprendano i centesimi ma siano solo valori in euro interi. Successivamente il programma legge un importo da pagare e un pagamento consistente in un certo numero di pezzi (ad esempio, 2 banconote da 20); anche in questo caso, per semplicità si può assumere che si tratti di importi espressi in un numero intero di euro; il programma, dopo aver verificato che l importo versato sia non inferiore al pagamento richiesto, tenta di calcolare il resto nel modo seguente: partendo dai pezzi di taglio maggiore ne alloca il massimo numero tale che il prezzo da pagare sommato all ammontare di questi pezzi non superi la cifra versata; se in questo modo si raggiunge il pareggio, l operazione termina con successo, altrimenti si procede con pezzi di taglio via via più piccolo. Se in questa maniera non si riesce a trovare un resto esatto, il programma produce un messaggio che informa della propria incapacità di calcolare un resto esatto (NB: ciò non significa che non esista il resto esatto nella disponibilità della cassa, perché?). Se invece un resto esatto viene individuato esso viene comunicato e la cassa viene aggiornata aggiungendo i pezzi consegnati dal cliente e sottraendo quelli dati in resto; l operazione viene ripetuta per un nuovo pagamento finché non viene fornito un segnale opportuno di fine operazioni. NB Poiché lo svliuppo completo di questo programma potrebbe richiedere una notevole quantità di operazioni di I/O (soprattutto se si intende stampare a video opportuni messaggi con la richiesta dei dati da fornire) è permesso non sviluppare in maniera completa tutta la messaggistica necessaria facendo uso, ad esempio, di opportuno pseudocodice; è anche ammesso evitare la codifica completa di frammenti di programma molto simili ad altri già sviluppati, sostituendola con opportuno pseudocodice che faccia riferimento al codice già sviluppato in precedenza.
(Tracce di) Soluzioni Esercizio 1 La rappresentazione binaria del valore assoluto 10824 è 10101001001000 che richiede quindi 14 bit. Un ulteriore bit è necessario per il segno, quindi m = 15. La rappresentazione del numero dato in complemento a due è perciò 101010110111000 Esercizio 2 Il campo anno del campo data di una variabile di tipo SchedaLibro si trova nella cella # 102 a partire dall indirizzo della prima cella della variabile; quindi per la variabile Libro si trova nella cella 2102. Per accedere a P -> Data.anno occorre sommare 102 al valore di P. Qundi l istruzione C richiesta può essere tradotta nel modo seguente: LOAD 2000 ADD= 102 STORE 900 LOAD@ 900 STORE 1102 Esercizio 3 Il frammento di codice è corretto in quanto il puntatore viene gestito in modo coerente con il suo tipo. Inoltre, essendo l array seq1 nient altro che un puntatore a interi, l assegnamento P = seq1; è lecito e produce l effetto che P punti a seq1[0]; l assegnamento P = P + 10 porta poi P a puntare a seq1[10]; quindi x assume il valore 10 in conseguenza dell assegnamento x = *P; successivamente però P viene fatto puntare a una cella che non appartiene più a seq1; y assume quindi un valore imprecisabile, almeno sulla base del codice in esame.
Esercizio 4 (traccia in pseudo-c) #include <stdio.h> void main () typedef enum Cento, Cinquanta, Venti, Dieci, Cinque, Due, Uno Taglio; typedef enum False, True Boolean int Cassa [Taglio]; /*definisce quanti pezzi ci sono in cassa per ogni taglio*/ int Importo, RestoDaCalcolare; int Resto [Taglio]; /*definisce di quanti pezzi per ogni taglio deve essere costituito il resto*/ int Versamento [Taglio]; /*definisce di quanti pezzi per ogni taglio consiste il pagamento per il quale deve essere calcolato il resto*/ boolean Prosegui;. [l array Resto viene inizializzato a tutti 0]; i = 0; for (i = 0, i <= Uno, i++) do printf ( [messaggio di richiesta del numero di pezzi di taglio i-esimo, specificando che i = 0 significa pezzi da 100, i = 1, pezzi da 50, ecc.; NB: costruendo un opportuna tabella di corrispondenze è possibile stampare un messaggio che specifichi direttamente il taglio richiesto senza indicarne la corrispondenza numerica all utente ]); scanf ("%d", &Cassa[i]); printf ([messaggio di richiesta se si intende eseguire un operazione]); scanf ("%d", &Prosegui); while (Prosegui) do [acquisizione dell importo da versare nella variabile Importo; acquisizione, mediante ciclo analogo al precedente, del versamento e memorizzazione nell apposita variabile; verifica che il totale versato sia non inferiore all importo; inizializzazione della variabile RestoDaCalcolare come differenza tra l ammontare versato e l importo richiesto]; /* calcolo del resto*/ while (RestoDaCalcolare > 0) do if (RestoDaCalcolare/100 <= Cassa[Cento]) Cassa[Cento] = Cassa[Cento] - RestoDaCalcolare/100; Resto[Cento] = RestoDaCalcolare/100; RestoDaCalcolare = RestoDaCalcolare % 100 else Resto[Cento] = Cassa[Cento]; Cassa[Cento] = 0; RestoDaCalcolare = RestoDaCalcolare % 100 ; if (RestoDaCalcolare == 0) break;
[sequenze di istruzioni analoghe alle precedenti per i tagli successivi; anche in questo caso la ripetizione delle sequenze potrebbe essere evitata utilizzando un ciclo e un apposita tabella per i vari tagli: e.g., tabella[0] = 100; tabella[1] = 50, ecc.]; if (RestoDaCalcolare == 0) printf [messaggio che indica il resto espresso in numero di pezzi per ogni taglio]; [azzeramento dell array Resto in vista del prossimo calcolo]; for (i = 0; i <= Uno; i++) do Cassa[i] = Cassa[i] + Versamento[i]; Versamento[i] = 0; else printf [messaggio che specifica che non è stato possibile individuare un resto adeguato nella disponibilità di cassa]; [azzeramento dell array Resto e ripsritino del valore originario di Cassa]; printf ([messaggio di richiesta se si intende eseguire un operazione]); scanf ("%d", &Prosegui);