Programmazione I a.a. 2002/2003 (Canale P-Z)
R. Silvestri e A. Sterbini
Scritto del 15 gennaio 2003 con Soluzioni
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.
Esercizio 1 (max 12 punti)
Si consideri il tipo Record così definito:
typedef struct {
char
descr[40];
long
inv;
struct {
long prot;
short ind;
}
sub;
} Record;
Scrivere
una funzione che prese in input due stringhe fArch ed fAgg aggiunge al file di nome fArch tutti i record del file di nome
fAgg che non sono già presenti nel
file fArch e ritorna il numero di record
aggiunti. Si assume che entrambi i file siano di tipo binario
e che
contengano record di tipo Record. Il
prototipo della funzione è long AggArchivio(char *fArch,
char *fAgg).
La funzione deve garantire
che se il file fArch non conteneva
inizialmente duplicati anche dopo l'esecuzione della funzione AggArchivio
il file arch non deve contenere duplicati. Due record
si considerano uguali solo se campo per campo hanno lo stesso valore. Si tenga
presente che il campo descr contiene
sempre una stringa.
Soluzione Esercizio 1
/* Funzione ausiliaria che ritorna un intero diverso da 0 se i due
*
*
record r1 ed r2 sono uguali e 0
altrimenti.
*/
short RecUguali(const Record
*r1, const Record *r2)
{
if
(strcmp(r1->descr, r2->descr) != 0) return 0;
else if
(r1->inv != r2->inv) return 0;
else if
(r1->sub.prot != r2->sub.prot) return 0;
else
if (r1->sub.ind != r2->sub.ind) return
0;
else return 1;
}
/* Funzione ausiliaria
che ritorna un intero diverso da 0 se il record *
* r e' presente nel file f
e 0
altrimenti.
*/
short TrovaRec(FILE *f, Record *r)
{
short
trovato = 0;
fseek(f, 0, SEEK_SET); /* Imposta la posizione del file all'inizio */
while (!feof(f) &&
!trovato) { /* Finche' non e' stata raggiunta la fine
del file */
Record
r;
/* e il record di input non e' stato
trovato. */
fread(&r, sizeof(r), 1,
f); /* Leggi il prossimo record e
confrontalo */
trovato =
RecUguali(p, &r); /* con il record di
input.
*/
}
return trovato;
}
/* Funzione ausiliaria
che aggiunge il record r al file f */
void AggRec(FILE *f, const Record *r)
{
fseek(f, 0, SEEK_END);
/* Imposta la posizione del file alla fine */
fwrite(r, sizeof(Record), 1,
f); /* Scrivi il record
*/
}
long
AggArchivio(char *fArch, char *fAgg)
{
long
nRecAgg = 0;
FILE *arch = fopen(fArch,
"r+b"); /* Apri il file archivio
*/
FILE *agg = fopen(fAgg,
"rb"); /* Apri il file
di aggiornamento */
while
(!feof(agg)) {
Record
rec;
/* Leggi il prossimo record del file di aggiornamento
*/
fread(&rec, sizeof(rec), 1,
agg);
if
(!TrovaRec(arch, &rec)) { /* Se il record non e'
presente nel file archivio, */
AggRec(arch, &rec); /* aggiungilo al file
archivio.
*/
nRecAgg++;
}
}
fclose(arch);
fclose(agg);
return
nRecAgg;
}
Esercizio 2 (max 10 punti)
Scrivere una funzione che preso in input il nome di un file,
contenente una sequenza di stringhe, alloca dinamicamente un vettore di
stringhe
che contiene le stesse stringhe del file
e nello stesso ordine, e restituisce il vettore e la sua dimensione. Il file è
di tipo testo e la lunghezza
massima delle
stringhe è 100. Però la lunghezza media è 7 per cui il vettore allocato non deve
sprecare memoria. Il prototipo della funzione
è char **FileStr2VetStr(const char *fStr, long *dim). La funzione quindi ritorna il puntatore al vettore di
stringhe
e in dim restituisce la
dimensione del vettore (cioè il numero delle stringhe). Si sottolinea che
sia il vettore che le stringhe (i cui puntatori
sono contenuti nel vettore)
devono essere allocati dinamicamente.
Soluzione Esercizio 2
char **FileStr2VetStr(const char *fStr, long *dim)
{
char **vetStr;
FILE *f = fopen(fStr, "r");
/* Apri il file (di tipo testo) in sola lettura
*/
long i, nStr =
0;
while (!feof(f))
{ /* Leggi il file per calcolare il numero di */
char
str[101];
/* stringhe in esso
contenute.
*/
fscanf(f, "%100s", str);
nStr++;
}
vetStr = malloc(nStr*sizeof(char *));
/* Alloca il vettore di stringhe */
rewind(f);
/* Riporta il file all'inizio */
i =
0;
while (!feof(f))
{
/* Leggi di nuovo le stringhe del file
*/
char str[101];
fscanf(f, "%100s", str);
vetStr[i] =
malloc((strlen(str) + 1)*sizeof(char)); /*
Alloca la i-esima stringa */
strcpy(vetStr[i], str);
i++;
}
fclose(f);
*dim = nStr;
return vetStr;
}
Esercizio 3 (max 11 punti)
Scrivere una funzione che
presa in input una lista di interi e un intero positivo k, restituisce un vettore allocato
dinamicamente che
contiene i k
interi più piccoli della lista. Il tipo degli elementi della lista è così
definito:
typedef
struct Elem {
int
val;
struct Elem *next;
} Elem;
Il prototipo della funzione è
int *Piccoli(const Elem *L, unsigned
k). Si assume che gli interi della lista sono
tutti distinti e che
sono in numero maggiore di k. Si
richiede che il vettore sia ordinato in senso crescente. Ad esempio se la lista
è 6 -> 2 -> 7 -> 9 -> 5 -> 3
-> 10 e k =
3 allora la funzione deve restituire il vettore [2, 3, 5].
Soluzione Esercizio 3
/* Funzione ausiliaria che ritorna il piu' piccolo intero
strettamente maggiore di x *
* contenuto nella lista L
(se non esiste ritorna
x).
*/
int MinMagg(int x, const Elem *L)
{
int mm
= x;
while (L != NULL) {
int v = L->val;
if (v > x && (mm == x || v < mm)) mm =
v;
L =
L->next;
}
return mm;
}
int
*Piccoli(const Elem *L, unsigned k)
{
int
*vet = malloc(k*sizeof(int)); /* Alloca il vettore */
const
Elem *p = L;
int i, min =
L->val;
/* Scorri la lista per trovare il minimo */
while (p != NULL) {
if (p->val < min) min = p->val;
p = p->next;
}
vet[0] =
min;
for (i = 1 ; i < k ;
i++)
/* Trova il prossimo intero piu' piccolo */
vet[i] = MinMagg(vet[i - 1], L); /* tramite la
funzione MinMagg.
*/
return vet;
}
Esercizio 4 (max 9 punti)
Scrivere una funzione che
presa in input una lista e un intero positivo k modifica la lista spostando il k-esimo elemento in coda alla lista
e
ritorna il puntatore alla lista modificata. Se la lista ha meno di k elementi la funzione non fa nulla. Il tipo
degli elementi della lista è
typedef struct Elem {
int
info;
struct Elem *next;
} Elem, *List;
Il prototipo della funzione
è List Sposta(List L, unsigned k). Ad esempio se la lista è 7 -> 4 -> 2 -> 8 -> 9 e
k = 3 allora la funzione modifica la
lista così 7 -> 4 -> 8 -> 9 ->
2.
Soluzione Esercizio 4
List Sposta(List
L, unsigned k)
{
List *p =
&L;
/* Vai al k-esimo elemento mantenendo in
*/
while (*p != NULL && k
> 1) { /* p l'indirizzo della locazione
che */
p =
&((*p)->next); /* contiene il puntatore a tale elemento. */
k--;
}
if (*p != NULL)
{
/* Se il k-esimo elemento esiste */
Elem *e =
*p;
/* toglilo dalla
lista, */
*p = e->next;
while (*p != NULL) p =
&((*p)->next); /* arriva alla fine della
lista */
*p =
e;
/* e aggancia
l'elemento. */
e->next
= NULL;
}
return
L;
}