Programmazione I a.a. 2004/2005 (Canale
P-Z)
R. Silvestri e I. Salvo
Prova scritta - 8 settembre 2005
Per superare la prova è necessario (ma non
sufficiente) ottenere almeno 7 punti per la soluzione
dell'esercizio
obbligatorio. Gli altri tre esercizi sono a scelta. Il voto è la
somma dei punti ottenuti.
Avvertenze: non usare variabili globali; definire tutte le eventuali
funzioni ausiliarie usate; è consentito usare le funzioni della libreria standard; se una soluzione
non è scritta in modo chiaro ed ordinato non
sarà
presa in considerazione.
typedef struct Odd {
int
num;
long
count;
struct Odd *next;
} Odd, *OList;
Scrivere una funzione, con prototipo OList GetOdd(List *pL),
che rimuove dalla lista *pL
tutti gli elementi che hanno
il campo num con
valore dispari e crea una lista di tipo OList che per ogni
numero
dispari n presente nella lista di input ha un
elemento d tale
che d.num = n
e d.count è
uguale al numero di elementi della lista di input che avevano il campo num con
valore n. Inoltre, la lista creata deve essere ordinata in
senso crescente rispetto al campo num. La funzione ritorna
il
puntatore
alla lista creata, restituisce in *pL il puntatore alla
lista di input modificata e rilascia la memoria non più usata.
Ad esempio, se la lista di input è {13} -> {24} -> {27}
-> {11} -> {18} -> {27}, allora la funzione la
modifica così {24}
-> {18} e crea la lista: {11, 1} -> {13, 1} ->
{27, 2}.
Soluzione Esercizio Obbligatorio
/* Funzione ausiliaria che aggiorna la lista *pL con
un valore
x */
void Update(OList *pL, int x)
{
while (*pL != NULL && (*pL)->num <
x) //Cerca la posizione per x
pL = &((*pL)->next);
if (*pL != NULL && (*pL)->num == x)
//Se x e' gia' presente
(*pL)->count++;
//allora incrementa count.
else {
Odd *d = malloc(sizeof(Odd));
//Altrimenti, alloca un nuovo
d->num = x;
//elemento
e inseriscilo nella
d->count =
1;
//lista.
d->next = *pL;
*pL = d;
}
}
OList GetOdd(List *pL)
{
OList oL = NULL;
while (*pL != NULL) {
//Scorri gli elementi della lista
if
(((*pL)->num) % 2) == 1) { //Se
e' un elemento con numero dispari
Elem *e =
*pL;
//Salva il puntatore
all'elemento
Update(&oL, e->num);
//Aggiorna la nuova lista
*pL =
e->next;
//Sgancia l'elemento dalla
lista
free(e);
//Rilascia la memoria dell'elemento
} else
pL = &((*pL)->next);
}
return oL;
}
Esercizio 1 (max 10 punti)
Scrivere una funzione, con prototipo void
Chg(char *fname), che preso in
input
il nome (contenuto nella stringa fname) di
un file di tipo testo contenente una sequenza di caratteri 'A' e 'B', lo modifica
sostituendo
ogni carattere 'B'
il
cui carattere precedente
e quello successivo sia 'A'
con un carattere 'A'.
Siccome il file può essere molto grande la funzione non deve
copiarlo
in memoria.
Ad esempio se il file contiene la sequenza BAABABBAABAB allora la
funzione
lo modifica così BAAAABBAAAAB.
Soluzione Esercizio 1
/* Funzione ausiliaria che che scrive un carattere 'A'
nella
posizione p del file f
e posiziona il cursore del file pronto per leggere il
carattere
in posizione p + 2 */
void WriteA(FILE
*f, int p)
{
rewind(f);
while (p > 0)
{
//Leggi i primi p - 1 caratteri
fgetc(f);
//per arrivare alla posizione p
p--;
}
fflush(f);
fputc('A',
f);
//Scrivi il carattere 'A'
fflush(f);
fgetc(f);
//Avanza di una
posizione
}
void Chg(char
*fname)
{
int c, c1 = 'X', c2 =
'X',
p = 0;
FILE *f = fopen(fname, "r+");
while ((c = fgetc(f)) != EOF)
{
if
(c1
== 'A' && c2 == 'B' && c == 'A')
WriteA(f, p -
1);
c1 = c2;
//Aggiorna i due caratteri
precedenti
c2 = c;
p++;
//incrementa
la posizione
}
fclose(f);
}
Esercizio 2 (max 9 punti)
Scrivere una funzione, con prototipo void
Frame(int n, char
M[][n]), che presa in input una matrice quadrata nxn
di char, la riempe
con cornici concentriche alternate di caratteri 'X' e 'O'. La cornice
più esterna è sempre fatta con il carattere 'X'.
Ad esempio per n = 4 ed n = 5 la funzione
produce, rispettivamente le seguenti matrici:
XXXX
XOOX
XOOX
XXXX
XXXXX
XOOOX
XOXOX
XOOOX
XXXXX
Soluzione Esercizio 2
void
Frame(int n, char
M[][n])
{
int k =
n;
//Dimensione
della cornice piu' esterna
int nC = (n + 1)/2;
//Numero di cornici
int i, j;
char c = 'X';
//Carattere della cornice
piu' esterna
for (i = 0 ; i < nC
; i++) {
for
(j = i ; j < i + k ; j++) { //Scrivi
l'i-esima cornice
M[i][j] = c;
M[i + k - 1][j] = c;
M[j][i] = c;
M[j][i + k -
1] = c;
}
k -= 2;
//Dimensione
della prossima cornice
c = (c == 'X' ? 'O' :
'X'); //Carattere della
prossima cornice
}
}
Esercizio 3 (max 11 punti)
Si consideri il seguente tipo:
typedef
struct Rec {
char *
info;
//stringa
allocata dinamicamente
int
join;
struct Rec *next;
} Rec, *RList;
Scrivere una funzione, con prototipo RList MJ(RList A, RList B),
che modifica la lista A
in modo tale che
per ogni elemento r
di A se non ci
sono elementi in B
con valore del
campo join uguale
a
r.join allora
l'elemento
r è rimosso,
altrimenti r
è
sostituito da tanti elementi quanti sono gli elementi s in B con s.join = r.join, il
nuovo
elemento t che
corrisponde all'elemento s
in B è tale
che t.join = r.join
e t.info
conterrà la
concatenazione delle stringhe r.info
ed s.info. La
funzione ritorna il puntatore alla lista A così
modificata.
La memoria non più usata deve essere rilasciata.
Ad esempio, se la lista A
è {"blu", 3} ->
{"red", 8} -> {"y", 3} -> {"verde", 5} e la lista B è
{"KM", 8} -> { "M", 3} -> {"L", 7} -> {"G", 8} ->
{"KG", 3} allora la lista A è così modificata:
{"bluM", 3} ->
{"bluKG", 3} -> {"redKM", 8} -> {"redG", 8} -> {"yM", 3} ->
{"yKG", 3}.
Soluzione Esercizio 3
/*
Funzione ausiliaria che cerca il primo elemento della lista L che ha il
campo
join uguale a j. Se lo trova ne ritorna il puntatore,
altrimenti ritorna NULL */
Rec *Find(RList L, int j)
{
while (L != NULL && L->join != j) L = L->next;
return L;
}
RList MJ(RList A, RList B)
{
RList *pA = &A; //pA e' il puntatore alla locazione contenente il
puntatore
//all'elemento corrente.
while (*pA != NULL) { //Scorri
gli elementi della lista A
Rec *r, *cur = *pA, *s = B;
while
((r = Find(s, cur->join)) != NULL) { //Finche' ci sono elementi in B
//con lo stesso valore di join.
Rec *t = malloc(sizeof(Rec));
//Alloca un nuovo elemento
//Alloca il campo info per contenere la
t->info = malloc(strlen(cur->info)
+ strlen(r->info) + 1); //concatenazione.
strcpy(t->info,
cur->info);
//Copia la stringa
cur->info
strcat(t->info,
r->info);
//Concatena la stringa
r->info
t->join =
cur->join;
t->next =
cur->next;
//Aggancia il nuovo elemento alla lista A
*pA = t;
pA =
&(t->next);
s = r->next;
}
*pA =
cur->next;
//Sgancia l'elemento corrente dalla lista A
free(cur->info);
//Rilascia la memoria dell'elemento corrente
free(cur);
}
return A;
}