Esercizio 21
Scrivere una funzione, con prototipo char
*DelChar(const char *string, char del) che ritorna una stringa,
allocata dinamicamente, ottenuta eliminando dalla stringa string tutte le eventuali
occorrenze del carattere del.
La stringa
ritornata non deve usare più memoria di quella strettamente necessaria.
Ad esempio DelChar("programma",
'a') ritorna la stringa "progrmm".
Soluzione Esercizio 21
char *DelChar(const char
*string, char del)
{
char *newStr;
long i, j, ndc;
for (ndc = 0, i = 0 ; string[i]
!= '\0' ; i++) //Calcola il numero
di caratteri
if (string[i]
== del) ndc++;
//da eliminare.
//Alloca lo spazio di memoria strettamente necessario
per la nuova stringa
newStr = malloc((strlen(string) - ndc + 1)*sizeof(char));
for (j = 0, i = 0 ; string[i]
!= '\0' ; i++) //Copia i caratteri diversi da del
if (string[i]
!= del) newStr[j++] = string[i]; //nella nuova
stringa.
newStr[j] = '\0';
return newStr;
}
Esercizio 22
Si consideri il seguente tipo:
typedef
struct MultiElem {
short
num;
long
count;
struct MultiElem *next;
} MultiElem, *MultiSet;
Scrivere una funzione, con prototipo void
Compact(MultiSet M), che elimina dalla lista M tutti gli elementi
h per cui
esiste un elemento k
che precede h e che
ha lo stesso valore del campo num (k.num = h.num), inoltre per
ogni elemento k non
eliminato il campo count
di k deve contenere
la somma dei valori dei campi count degli elementi della
lista originale che avevano lo
stesso valore del campo num
di k. L'ordine degli
elementi non deve essere cambiato e la memoria degli elementi eliminati deve
essere
rilasciata. Ad esempio se la lista di input è
{233, 2} -> {457, 1} -> {233, 1} -> {132, 5} -> {132, 3} ->
{233, 8}
allora la funzione modifica la lista così {233, 11} -> {457, 1} -> {132,
8}.
Soluzione Esercizio 22
/* Funzione
ausiliaria che elimina da M tutti gli elementi (oltre il primo) che hanno
nel campo num lo stesso valore del campo num del primo elemento
di M e ritorna la
somma dei valori del campo count degli elementi eliminati.
Se la lista e' vuota o
non vengono eliminati elementi ritorna 0.
*/
long DelNext(MultiSet M)
{
long sumCount = 0;
if (M != NULL) {
int
num = M->num;
while
(M->next != NULL) { //Scorri la lista a partire dal secondo elemento
MultiElem *nextE = M->next;
if (nextE->num
== num) {
//Se l'elemento ha lo stesso valore del
MultiElem
*nextnextE
= nextE->next; //campo num, eliminalo.
sumCount += nextE->count;
free(nextE);
M->next = nextnextE;
}
M = M->next;
}
}
return sumCount;
}
void Compact(MultiSet M)
{
while (M != NULL) {
M->count += DelNext(M);
M = M->next;
}
}
Esercizio 23
Scrivere una funzione, con prototipo long
CatFiles(char *conF, char
*catF), che appende il contenuto del
file il cui nome è nella stringa catF al file il cui nome è
nella stringa conF e
ritorna il numero di caratteri del primo file dopo
l'aggiunta. Entrambi i files si assumono di tipo testo.
Ad esempio, se il contenuto del file conF è Gli?esami? e il contenuto del file catF è non?finiscono?mai
allora la funzione rende il contenuto del file conF uguale a Gli?esami?non?finiscono?mai
e ritorna 27.
Soluzione Esercizio 23
long CatFiles(char *conF,
char *catF)
{
FILE *fcon = fopen(conF, "r+"); //Apri il file conF in lettura e scrittura
FILE *fcat = fopen(catF, "r"); //Apri il file catF in lettura
long nc = 0;
int c;
while (fgetc(fcon)
!= EOF) nc++; //Calcola il numero di caratteri di conF
while ((c = fgetc(fcat)) != EOF)
{ //Aggiungi il contenuto di catF a conF
fputc(c,
fcon);
nc++;
}
fclose(fcon);
fclose(fcat);
return nc;
}
Esercizio 24
Scrivere una funzione che presa in input una lista di stringhe crea
una stringa uguale alla concatenazione delle stringhe
della lista. Il tipo degli elementi della lista è il seguente:
typedef struct
StrElem {
char *
str;
struct StrElem *next;
} StrElem;
Il prototipo della funzione è
char *ConcatList(const StrElem *). Ovviamente la stringa ritornata
deve essere
allocata dinamicamente. Ad esempio se la lista è
"List" -> "a di es" -> "" -> "e" ->
"mpio" allora la
funzione deve restituire la stringa
"Lista di esempio".
Soluzione Esercizio 24
char *ConcatList(const StrElem *L)
{
char *stringa;
const StrElem *p = L;
long lung = 0;
/* Calcola la lunghezza della stringa che */
while (p != NULL) {
/* e' uguale alla somma delle lunghezze
*/
lung += strlen(p->str); /* delle stringhe della lista.
*/
p = p->next;
}
stringa = malloc((lung + 1)*sizeof(char)); /* Alloca
la stringa e */
stringa[0] = '\0';
/* inizializzala a vuota. */
p = L;
while (p != NULL) {
/* Concatena le stringhe della lista */
strcat(stringa, p->str);
/* copiandole nella stringa.
*/
p = p->next;
}
return stringa;
}
Esercizio 25
Data una sequenza di numeri diciamo che un numero
x della sequenza
è un
massimo se sia il numero che precede
x che quello
che
lo segue sono strettamente minori di
x (né il primo né
l'ultimo numero della sequenza può essere un massimo). Scrivere una
funzione
che presa in input una lista di numeri restituisce un vettore contenente
i massimi della lista (nell'ordine in cui appaiono nella lista).
Il tipo degli elementi della lista è il seguente:
typedef
struct ENum {
float
n;
struct ENum *next;
} ENum;
Il prototipo della funzione è
float
*Massimi(const ENum *L, long *dim). In
dim restituisce la dimensione
del vettore
ritornato (che deve essere allocato dinamicamente). Il vettore non deve
essere sovradimensionato. Ad esempio se la lista è
12 -> 3 -> 7 -> 4 -> 3 -> 2 -> 5 -> 1 -> 8 ->
8 allora la funzione ritorna il vettore
[7, 5] e in
dim restituisce
2.
Soluzione Esercizio 25
/*
Funzione ausiliaria che ritorna il puntatore al primo massimo della lista
L. *
* Se non ci sono massimi ritorna NULL.
*/
ENum *PrimoMax(const ENum *L)
{
if (L == NULL || L->next == NULL)
return NULL;
else {
float prec =
L->n;
L = L->next;
while (L->next
!= NULL && (L->n <= prec || L->n
<= L->next->n)) {
prec = L->n;
L = L->next;
}
return (L->next
!= NULL ? L : NULL);
}
}
float *Massimi(const
ENum *L, long *dim)
{
float *vetMax = NULL;
long nMax = 0;
const ENum *e = L;
while ((e = PrimoMax(e))
!= NULL)
nMax++; /* Conta i massimi */
if (nMax > 0) {
long i = 0;
vetMax = malloc(nMax*sizeof(float));
/* Alloca il vettore dei massimi */
while ((L =
PrimoMax(L)) != NULL) vetMax[i++] = L->n;
}
*dim = nMax;
return vetMax;
}
Esercizio 26
Si consideri il seguente tipo:
typedef
struct Elem {
int
val;
struct Elem * next;
} Elem, *List;
Scrivere una funzione, con prototipo
List Twist(List A, List B),
che fonde le due liste di input in una lista
L che se
A è
a1 -> a2
-> a3 -> ecc. e
B è
b1 -> b2
-> b3 -> ecc. allora
L è
a1 -> b1 -> a2 -> b2
-> a3 -> b3 -> ecc. La funzione ritorna
il puntatore alla lista
L.
La lista
L non deve usare
memoria in più rispetto a quella usata da
A e
B. Se
A è vuota la funzione
ritornerà
B e
se
B è vuota ritornerà
A. Se le due liste hanno
lunghezze differenti, gli elementi rimanenti della lista più lunga
vengono accodati.
Ad esempio se
A è
la lista
100 -> 101 ->
102 e
B
è la lista
1
-> 2 -> 3 -> 4 -> 5 allora
L sarà la lista
100 -> 1 -> 101 ->
2 -> 102 -> 3 -> 4 -> 5.
Soluzione Esercizio 26
List Twist(List
A, List B)
{
if (A == NULL) return B;
List L = A;
while (A != NULL && B != NULL)
{
//Finche' le due liste non sono vuote
List nextA = A->next, nextB =
B->next; //Salva
i prossimi elementi
A->next = B;
//Accoda un elemento di B
if (nextA
!= NULL)
//Se A non e' terminata allora
B->next = nextA;
//accoda un elemento di A.
A = nextA;
B = nextB;
}
return L;
}
Esercizio 27
Scrivere una funzione, con prototipo int **MTri(long n), che crea e restituisce una matrice
triangolare di interi (int)
i cui
elementi hanno valori 1,2,3,...,
n(n+1)/2. Naturalmente, la matrice deve essere allocata dinamicamente
e non bisogna usare
più memoria di quella strettamente necessaria. Ad esempio se n = 5 la funzione deve creare
la matrice:
1 2 3 4
5
6 7 8 9
10 11 12
13 14
15.
Soluzione Esercizio 27
int **MTri(long n)
{
int **M = malloc(n*sizeof(int *)); //Alloca
il vettore delle righe
long r, c, nc = n, k = 1;
for (r = 0 ; r < n ; r++) {
//Per ogni riga della
matrice...
M[r] = malloc(nc*sizeof(int));
//Alloca la riga r-esima
for
(c = 0 ; c < nc ; c++) { //Assegna i valori agli elementi della
M[r][c] = k;
//riga r-esima.
k++;
}
nc--;
}
return M;
}
Esercizio 28
Scrivere una funzione, con prototipo
void
Paste(char *fName, unsigned
n, const char *str, char
*fOut), che crea
un file di tipo testo, il cui nome è nella stringa
fOut, il cui contenuto è
dato da i primi
n caratteri
del file il cui nome è nella stringa
fName seguiti
dai caratteri della stringa
str ed infine seguiti dai
caratteri del file
fName
oltre l'
n-esimo. Se
n = 0 il contenuto del file
fOut è dato dai
caratteri di
str seguiti
da tutti i caratteri del file
fName. Se
n è maggiore od uguale
alla lunghezza del file
fName
allora
fOut conterrà
i
caratteri del file
fName
seguiti dai caratteri della stringa
str. Ad esempio se il file
fName contiene:
L'esame del 2004.
ed
n = 12, la stringa
str è
"7 giugno ",
allora il file
fOut conterrà:
L'esame del 7 giugno 2004.
Soluzione Esercizio 28
void Paste(char *fName,
unsigned n, const char
*str, char *fOut)
{
FILE *f = fopen(fName, "r");
//Apri il file fName in lettura
FILE *fO = fopen(fOut, "w+");
//Crea ed apri il file fOut
int c;
while (n > 0 &&
(c = fgetc(f)) != EOF)
{ //Leggi i primi n caratteri del
file
fputc(c,
fO);
//fName
e scrivili nel file fOut.
n--
}
fprintf(fO, "%s", str);
//Scrivi la stringa str nel file fOut
while ((c = fgetc(f)) != EOF)
//Scrivi
i rimanenti caratteri del file
fputc(c,
fO);
//fName
nel file fOut.
fclose(f);
fclose(fO);
}
Esercizio 29
Scrivere una funzione che presi in input due vettori di interi
A e
B
e le loro dimensioni, elimina dal vettore
A
compattandolo tutti i valori che non sono presenti anche in
B e ritorna il numero di valori rimasti
in
A. Il
prototipo della funzione è
long Com(int A[], long dimA,
int B[], long dimB).
Ad esempio
se
A = [2, 7, 2, 4, 9, 9, 5]
(
dimA = 7) e
B = [5, 5, 4, 6, 2] (
dimB = 5) allora la
funzione modifica il vettore
A
in modo tale che nelle prime
4 posizioni
di
A vi sia
[2, 2, 4, 5] e ritorna
4.
Soluzione Esercizio 29
long Com(int A[], long dimA, int B[], long dimB)
{
long k = 0, i;
/* La variabile k manterra' l'indice della prima */
/* posizione disponibile del vettore A.
*/
for (i = 0 ; i < dimA ; i++) {
long j = 0;
while (j < dimB && A[i] !=
B[j]) j++; /* Controlla se A[i] appare in B
*/
if (A[i] == B[j]) {
/* Se e' cosi' sposta A[i] nella */
A[k] = A[i];
/* prima posizione disponibile, */
k++;
/* compattando cosi' il vettore. */
}
}
return k;
}
Esercizio 30
Scrivere una funzione che presi in input una lista
L, un vettore di interi
V e la sua dimensione
dim, elimina dalla lista tutti gli elementi
che si
trovano in una posizione
k tale
che
k < dim e
V[k] = 0 e ritorna la lista così
modificata. Per posizione di un elemento si intende il
numero di elementi che lo precedono, cioè, il primo elemento
ha posizione 0, il secondo ha posizione 1 e così via. Il tipo degli
elementi
della lista è
typedef
struct Elem {
long
v;
struct Elem *p;
} Elem, *List;
La memoria degli elementi eliminati deve essere rilasciata. Il prototipo
della funzione è
List Elimina(List
L, int V[], int
dim).
Ad esempio se la lista è
15
-> 23 -> 5 -> 8 -> 76 ->13 e il vettore
[0, 1, 0, 0, 1] (
dim = 5) allora la funzione
modifica la lista così
23 ->
76 -> 13.
Soluzione Esercizio 30
List Elimina(List L, int V[], int dim)
{
List *cur = &L;
/* Puntatore alla locazione che contiene l'indirizzo
*/
/* dell'elemento corrente.
*/
int k = 0;
while (*cur != NULL &&
k < dim) {
Elem *e = *cur;
if (V[k] == 0) { /* Se V[k] e' 0 elimina dalla lista l'elemento */
*cur = e->next; /* in posizione k.
*/
free(e);
} cur = &(e->next);
k++;
}
return L;
}
Esercizio 31
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 stringhe del file che compaiono
almeno due volte, 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 **FileStrRip(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 che si ripetono almeno due volte).
Si sottolinea che sia il vettore che le stringhe (i cui puntatori
sono contenuti nel vettore) devono essere allocati dinamicamente. Ad esempio
se il file contiene
rosso
verde viola bruno rosso marrone giallo viola blu viola
la funzione deve restituire un vettore di stringhe di dimensione 2 contenente
le stringhe
"rosso",
"viola".
Soluzione Esercizio 31
/* Funzione ausiliaria che ritorna la stringa k-esima del
file f se questa non *
* compare in posizioni precedenti alla k-esima e compare in
qualche posizione *
* successiva alla k-esima, altrimenti ritorna NULL.
*/
const char StrRip(FILE
*f, int k)
{
static char str[101];
char s[101];
int j = 0;
rewind(f);
/* Riporta il file all'inizio
*/
while (j < k && fscanf(f, "%100s", str) == 1) /* Scorri le stringhe del file
fino alla */
j++;
/*
k-esima.
*/
if (j != k) return NULL; /* Se il file ha meno di k stringhe, ritorna NULL */
/* A questo punto in str c'e' la k-esima stringa */
rewind(f);
/* Riporta il file all'inizio */
j
= 0;
while (fscanf(f, "%100s", s) == 1) {
j++;
if (strcmp(s, str) == 0) {
if
(j < k) /* La stringa compare anche in
una */
return NULL; /* posizione
precedente alla k-esima. */
else if
(j > k) /* La stringa compare
anche in una */
return str; /* posizione successiva alla k-esima. */
}
}
return NULL;
}
char **FileStrRip(const char *fStr, long *dim)
{
char **vetStr,
*str;
FILE *f = fopen(fStr, "r");
/* Apri il file (di tipo testo) in sola lettura
*/
int i, j, nRipStr
= 0, nStr = 0;
char s[101];
while (fscanf(f, "%100s", s) == 1) /* Leggi il file per calcolare il numero di */
nStr++;
/* stringhe in esso contenute.
*/
for (j = 1 ; j <= nStr ;
j++) { /* Calcola
il numero di stringhe ripetute */
if (StrRip(f, j) != NULL)
nRipStr++;
}
vetStr = malloc(nRipStr*sizeof(char *)); /* Alloca il vettore di stringhe */
i = 0;
for (j = 1 ; j <= nStr ; j++) {
/* Per ogni stringa del file ...
*/
char *str;
/* se e' una stringa ripetuta allora
*/
if ((str = StrRip(f, j)) != NULL) { /* alloca un
blocco per la stringa. */
vetStr[i] = malloc((strlen(str) + 1)*sizeof(char));
strcpy(vetStr[i], str);
i++;
}
}
fclose(f);
*dim = nRipStr;
return vetStr;
}
Esercizio 32
Scrivere una funzione, con prototipo
void
SMove(char *str, int
k), che modifica la stringa
str spostando i
primi
k caratteri
in coda alla stringa. Ovviamente se
k è maggiore od uguale
alla lunghezza di
str
o
k ≤ 0 allora
SMove
non fa nulla. Ad esempio se
str è
"abcdefg" e
k = 3 allora
SMove modifica
str così
"defgabc".
Soluzione Esercizio 32
void SMove(char *str,
int k)
{
int len = strlen(str);
if (k < len &&
k > 0) {
char
head[k]; //Vettore
per salvare i primi k caratteri
int
i, j;
for
(i = 0 ; i < k ; i++)
//Salva i primi k caratteri
head[i] = str[i];
for
(j = 0 ; i < len ; i++, j++) //Sposta i caratteri successivi
str[j] = str[i];
for
(i = 0 ; j < len ; i++, j++) //Copia i k caratteri in coda
str[j] = head[i];
}
}
Esercizio 33
Si consideri il seguente tipo:
typedef
struct Elem {
long
count;
char *
str; //Stringa
allocata dinamicamente
struct Elem *next;
} Elem, *List;
Scrivere una funzione, con prototipo List Clean(List L, const char *test),
che presa in input una lista L, ordinata
in senso non decrescente rispetto al campo count, la modifica eliminando
tutti gli elementi che hanno la stringa del campo str
uguale alla stringa test
(ve ne possono essere più d'uno) e inserisce un nuovo elemento con
campo count pari al numero
di
elementi eliminati e il campo str contenente una stringa
uguale alla stringa test,
mantenendo l'ordinamento della lista. La funzione
ritorna il puntatore al primo elemento della lista così modificata.
La memoria degli elementi eliminati deve essere interamente rilasciata.
Ad esempio se la lista L
è {0, "blu"}->{1, "rosso"}->{3,
"viola"}->{3, "verde"}->{4, "rosso"}
e la stringa test
è "rosso" allora
Clean modifica la lista
così
{0, "blu"}->{2, "rosso"}->{3, "viola"}->{3, "verde"}.
Soluzione Esercizio 33
List Clean(List L, const char *test)
{
List *pCurr = &L; //Puntatore alla locazione che contiene il puntatore
//all'elemento corrente.
long n = 0;
while (*pCurr != NULL) { //Scorri
la lista per eliminare eventuali elementi
if
(strcmp((*pCurr)->str, test) == 0) {
//E' un elemento da eliminare
Elem *e = *pCurr;
//Salva il puntatore all'elemento
da eliminare
*pCurr = (*pCurr)->next;
//Elimina l'elemento dalla lista
free(e->str);
//Rilascia la memoria della
stringa
free(e);
//Rilascia la memoria dell'elemento
n++;
//Incrementa il conteggio degli elementi eliminati
} else
pCurr = &((*pCurr)->next);
}
Elem *new = malloc(sizeof(Elem)); //Alloca memoria per il nuovo elemento
new->count = n;
new->str = malloc(sizeof(char)*(strlen(test)
+ 1)); //Alloca memoria per stringa
strcpy(new->str, test);
*pCurr = &L;
//Scorri la lista per trovare
while (*pCurr != NULL && (*pCurr)->count <= n)
//dove va inserito il nuovo
pCurr = &((*pCurr)->next);
//elemento.
new->next = *pCurr;
//Inserisci
il nuovo elemento nella lista
*pCurr = new;
return L;
}
Esercizio 34
Scrivere una funzione, con prototipo
char Matrix(char
*fName, int row, int
col, char newC), che scrive il
carattere
newC nell'elemento
posto nella riga
row
e colonna
col della matrice
memorizzata nel file di tipo testo il cui nome è nella
stringa
fName e ritorna
il carattere precedente di tale elemento. La matrice è una matrice
di caratteri ed è memorizzata per righe, i primi
due interi del file rappresentano rispettivamente il numero di righe e
il numero di colonne della matrice. Tali interi sono separati da un
carattere spazio e il primo carattere dopo il secondo intero è il
primo carattere della matrice. La matrice può essere molto grande
per cui la
funzione non deve copiare la matrice in memoria. Ad esempio se il file
fName contiene:
4 3ABCFFFMNLVVV
(si tratta quindi di una matrice con 4 righe e 3 colonne) e se
row = 3,
col = 1 e
newC = 'A' allora
Matrix modifica il file così:
4 3ABCFFFANLVVV
e ritorna il carattere '
M'.
Soluzione Esercizio 34
/* Funzione ausiliaria che posiziona il cursore del file
f pronto per leggere/scrivere
l'elemento in riga row e colonna col.
*/
void Elem(FILE
*f, int row, int
col)
{
int nr, nc, i;
char c;
rewind(f);
fscanf(f, "%d", &nr);
//Leggi il numero di righe
fscanf(f, " %d", &nc);
//Leggi il numero di colonne
for ( ; row > 1 ; row--)
//Scorri le prime row - 1
righe
for
(i = 1 ; i <= nc ; i++)
fscanf(f, "%c", &c);
for (i = 1 ; i < col
; i++) //Scorri la
riga row fino alla colonna col - 1
fscanf(f,
"%c", &c);
}
char Matrix(char *fName, int row,
int col, char
newC)
{
FILE *f = fopen(fName, "r+"); //Apri il file di tipo testo in lettura e scrittura
char c;
Elem(f, row, col);
//Posizionati sull'elemento di riga row e colonna col
fscanf(f, "%c", &c);
//Leggi il carattere dell'elemento
Elem(f, row, col);
//Posizionati sull'elemento di riga row e colonna col
fprintf(f, "%c", newC); //Scrivi il nuovo carattere dell'elemento
fclose(f);
return c;
}
Esercizio 35
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 35
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;
char str[101];
while (fscanf(f, "%100s", str) ==
1) { /* Leggi il
file per calcolare il numero di */
nStr++;
/* stringhe in esso contenute.
*/
vetStr = malloc(nStr*sizeof(char *));
/* Alloca il vettore di stringhe */
rewind(f);
/* Riporta il file all'inizio */
i = 0;
while (fscanf(f, "%100s", str) ==
1) { /* Leggi di
nuovo le stringhe del file */
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 36
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 36
/* 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 37
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 37
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;
}
Esercizio 38
Scrivere una funzione, con prototipo
char
*PadString(const char *str, unsigned start, unsigned
end, char pad),
che ritorna una stringa, allocata dinamicamente, formata da
start caratteri
pad seguiti dai caratteri della
stringa
str ed infine
seguiti da
end caratteri
pad. Ad esempio
PadString("giorno", 3, 2, '*')
ritorna la stringa
"***giorno**".
Soluzione Esercizio 38
char
*PadString(const char *str, unsigned start, unsigned
end, char pad)
{
int k;
// Alloca la nuova stringa
char *newStr = malloc((strlen(str) +
start + end + 1)*sizeof(char));
for (k = 0 ; k < start ;
k++) newStr[k] = pad; // Scrivi i caratteri pad iniziali
for ( ; *str != '\0' ;
str++, k++) newStr[k] = *str; // Copia i caratteri
di str
for ( ; end > 0 ; end--,
k++) newStr[k] = pad; // Scrivi i caratteri pad finali
newStr[k] = '\0';
return newStr;
}
Esercizio 39
Scrivere una funzione, con prototipo void
PrintNumOcc(const char *str1, const char *str2), che per ogni
carattere distinto in str1
stampa il numero di occorrenze di quel carattere in str2. Ad esempio,
PrintNumOcc("pennino", "penna")
deve stampare:
p 1
e 1
n 2
i 0
o 0
Soluzione Esercizio 39
/* Funzione ausiliaria che ritorna
il numero di occorrenze del carattere c
nei primi n caratteri di s.
*/
long CountOcc(const
char *s, long n, char c)
{
long k, nOcc = 0;
for (k = 0 ; k < n ;
k++) if (s[k] == c) nOcc++;
return nOcc;
}
void PrintNumOcc(const char
*str1, const char *str2)
{
long k, len2 = strlen(str2);
for (k = 0 ; str1[k] !=
'\0' ; k++) { // Per ogni carattere
c di str1...
char
c = str1[k];
if (CountOcc(str1,
k, c) == 0) // Se e'
la prima occorrenza di c in str1,
printf("%c %ld\n", c, CountOcc(str2, len2, c));
// stampa il numero di volte
}
// che c occorre in str2.
}
Esercizio 40
Scrivere una funzione, con prototipo
void
InvFile(char *nameF, char
*newF), che legge il file di tipo testo il cui nome
è nella stringa
nameF,
contenente una sequenza di numeri interi separati da spazi, e crea un nuovo
file di testo, con nome dato
dalla stringa
newF,
e vi scrive la sequenza inversa. Ad esempio, se il file
nameF contiene la sequenza
3 7 -2 15 allora il
nuovo
file creato dalla funzione deve contenere
15 -2 7 3.
Soluzione Esercizio 40
void
InvFile(char *nameF, char
*newF)
{
FILE *f = fopen(nameF, "r");
//Apri il file
in lettura
int n, lenF = 0;
while (fscanf(f, "%d", &n) == 1) lenF++;
//Conta gli interi nel file
int k = 0, v[lenF];
//Vettore a dimensione variabile atto a contenere
gli interi del file
rewind(f);
//Riporta il cursore
del file all'inizio
while (fscanf(f,
"%d", &(v[k])) == 1) k++; //Copia gli interi
del file nel vettore v
fclose(f);
FILE *nF = fopen(newF, "w");
//Crea ed apri il nuovo
file
for (k = lenF - 1 ; k >= 0 ; k--)
//Scrivi nel nuovo file
gli interi in
fprintf(nF,
"%d ", v[k]);
//ordine inverso.
fclose(nF);
}
Esercizio 41
Scrivere una funzione che prese in input due stringhe
fCompact e
fMatrix legge la matrice
di interi memorizzata
in formato
compatto nel file
fCompact e crea un nuovo file
di nome
fMatrix in cui
scrive la stessa matrice in
formato
standard. Nel formato
compatto la matrice è
memorizzata in modo tale che i primi due interi sono il numero di
righe e il numero di colonne della matrice e poi per ogni riga vi è
un intero che indica quanti elementi della riga sono diversi
da zero e poi per ognuno di questi elementi il numero di colonna e il valore.
Nel formato
standard la matrice è memorizzata
in modo tale che i primi due interi sono il numero di righe e il numero
di colonne della matrice e poi seguono gli elementi
della matrice disposti per righe (separati da spazi). Entrambi i file sono
di tipo testo. Il prototipo della funzione è
void Conv(char *fCompact,
char *fMatrix).
Ad esempio se il contenuto del file
fCompact è
3 4 2 1 12 3 -2 0 1 4
25 allora la matrice ha 3 righe
e 4 colonne. La prima riga ha due elementi diversi da zero: quello
nella colonna
1 di valore
12 e quello nella
colonna
3 di valore
-2. La seconda riga
non ha elementi diversi da zero e la terza riga ne ha uno solo: quello nella
colonna
4 di valore
25. La funzione deve creare
un file contenente
3 4 12 0
-2 0 0 0 0 0 0 0 0 25.
Soluzione Esercizio 41
void
Conv(char *fCompact, char
*fMatrix)
{
FILE *fC, *fM;
int r, nr, nc;
fC = fopen(fCompact, "r");
/* Apri il file in formato compatto
in lettura */
fscanf(fC, "%d %d", &nr,
&nc); /* Leggi il numero di righe
e di colonne */
fM = fopen(fMatrix, "w");
/* Crea ed apri il nuovo file */
fprintf(fM, "%d %d", nc, nr); /* Scrivi il numero di righe e di colonne */
for (r = 1 ; r <= nr
; r++) { /* Per ogni riga . . . */
int n, c, ec,
ev;
fscanf(fC, "%d",
&n); /*
Leggi il numero di elementi diversi da zero */
ec = 0;
/* Colonna del prossimo elemento diverso da */
/*
zero (inizializzata a zero). */
for (c = 1 ; c
<= nc ; c++) { /* Per ogni colonna .
. . */
if
(c > ec && n > 0) {
/* Leggi, se c'e', il prossimo elemento */
fscanf(fC, "%d %d", &ec, &ev); /* diverso da zero.
*/
n--;
}
fprintf(fM,
" %d", (c == ec ? ev : 0)); /* Scrivi il valore
dell'elemento in */
}
/* in posizione (r,
c). */
}
fclose(fC);
fclose(fM);
}
Esercizio 42
Scrivere una funzione che presa in input una lista di interi,
modifica la lista in modo tale che i primi n/2 (parte intera inferiore)
elementi, dove n è il numero di elementi della lista, vengono posti
in fondo alla lista e restituisce la lista così modificata.
Il tipo degli elementi della lista è così definito:
typedef
struct Rec {
int
info;
struct Rec *next;
} Rec;
Il prototipo della funzione è Rec *Sposta(Rec *L). Ad esempio se la lista
è
1 -> 2 -> 3 -> 4 ->
5 -> 6 -> 7
allora la funzione deve restituire la lista 4 -> 5 -> 6 -> 7 ->
1 -> 2 -> 3.
Soluzione Esercizio 42
Rec *Sposta(Rec *L)
{
if (L != NULL && L->next != NULL) {
int n = 1;
/* Calcola in n la lunghezza della lista e */
Rec *p = L;
/* in p
il puntatore all'ultimo elemento. */
while (p->next
!= NULL) {
p = p->next;
n++;
}
p->next = L;
/* Accoda i primi
elementi */
p = L;
/* Calcola in p il puntatore allo */
for (n = n/2 ;
n > 1 ; n--) p = p->next;
/* ultimo elemento
dei primi n/2. */
L = p->next;
/* Sposta i restanti elementi in testa
alla lista */
p->next = NULL;
/*
Chiudi la lista */
}
return L;
}
Esercizio 43
Scrivere una funzione che preso in input un intero
n crea e restituisce una matrice
nxn di interi (
long) i cui elementi hanno
i valori
1,2,3,. . .,n2.
Naturalmente, la matrice deve essere allocata dinamicamente. Il prototipo
della funzione è
long
**Matrice(short n). Ad esempio, se
n = 4, la funzione deve creare
la matrice:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16.
Soluzione Esercizio 43
long **Matrice(short n)
{
long **M, r, c, k;
M = malloc(n*sizeof(long *));
/* Alloca il vettore delle righe */
k = 1;
for (r = 0 ; r < n ; r++)
{ /* Per ogni riga... */
M[r] = malloc(n*sizeof(long));
/* Alloca l'r-esima riga */
for (c = 0 ; c
< n ; c++) { /* Assegna i valori
agli elementi */
M[r][c] = k;
/* della r-esima riga.
*/
k++;
}
}
return M;
}
Esercizio 44
Scrivere una funzione, con prototipo
long
*IndMax(const int V[], long n, long *nMax),
che preso in input un
vettore
V di dimensione
n, ritorna un vettore
di
long
allocato dinamicamente contenente gli indici degli elementi di
V che hanno
valore uguale al massimo intero presente in
V e in
*nMax restituisce il numero
di tali elementi. Il vettore ritornato non deve usare più
memoria di quella strettamente necessaria. Se
V = [-1, 2, 7, -5, 7] allora
la funzione ritorna il vettore
[2, 4] e in
*nMax restituisce
2.
Soluzione Esercizio 44
long *IndMax(const int
V[], long n, long
*nMax)
{
long *ind = NULL;
//Inizializza i valori di ind e *nMax cosicche'
*nMax = 0;
//se n <= 0 ritorna NULL e in
*nMax restituisce 0.
if (n > 0) {
long
i, k;
int max
= V[0];
for (i = 1 ; i < n ; i++)
//Calcola
il valore massimo di V
if (V[i] > max) max = V[i];
for
(i = 0 ; i < n ; i++)
//Calcola il numero di elementi di V
if (V[i] == max) (*nMax)++;
//con valore massimo.
ind = malloc((*nMax)*sizeof(long));
//Alloca il nuovo vettore
for
(k = 0, i = 0 ; i < n ; i++) //Scrivi nel nuovo vettore gli indici
if (V[i] == max) ind[k++] = i; //degli elementi con valore massimo.
}
return ind;
}
Esercizio 45
Si consideri il seguente tipo:
typedef struct Estr {
char *
s; //puntatore ad una stringa allocata dinamicamente
struct Estr *next;
}Estr, *Lstr;
Scrivere una funzione, con prototipo Lstr MoveStr(Lstr L, const char *str), che sposta ogni elemento
della lista L che ha
la stringa del campo s
uguale alla stringa str
in coda alla lista e ritorna il puntatore alla lista così modificata.
L'ordine degli altri elementi non
deve essere cambiato. Se str
= "last" e L = "last" -> "first" -> "just"
-> "first" -> "last" -> "mah"
allora la funzione modifica la lista così "first" -> "just" -> "first"
-> "mah" -> "last" -> "last".
Soluzione Esercizio 45
Lstr
MoveStr(Lstr L, const char *str)
{
Lstr *cur = &L; //Indirizzo della locazione che contiene il puntatore
//all'elemento corrente.
Lstr mL = NULL;
//Lista degli elementi che devono essere spostati
in coda
while (*cur != NULL) {
if
(strcmp((*cur)->s, str) == 0) {
Estr *aux
= *cur; //Salva il puntatore
all'elemento che deve essere spostato
*cur = (*cur)->next;
//Togli l'elemento dalla lista L
aux->next
= mL; //Aggiungi
l'elemento in testa alla lista degli elementi
mL = aux;
//che dovranno
essere posti in coda.
} else
cur = &((*cur)->next);
}
*cur = mL;
//Aggiungi gli elementi tolti in coda alla
lista L
return L;
}
Esercizio 46
Scrivere una funzione, con prototipo
long
Inv(char *fName, char
*invF), che prende in input il nome
fName di un file
di tipo testo contenente una sequenza di parole separate da spazi, crea
un nuovo file di tipo testo il cui nome è nella stringa
invF, vi scrive
le stesse parole del primo file ma in ordine inverso e ritorna la lunghezza
della parola più lunga. Le parole sono sequenze di caratteri diversi
dal carattere spazio. Si assume che tra una parola e quella successiva
c'è un solo carattere spazio. Non è dato alcun limite sulla
lunghezza
delle parole. Ad esempio se il contenuto del file
fName è
rosso Verde1234 08754franconi_56
allora la funzione scrive nel nuovo file
08754franconi_56 Verde1234
rosso
e ritorna 16.
Soluzione Esercizio 46
/* Funzione ausiliaria che legge la k-esima parola dal file
f e la copia nella stringa
str. La funzione assume che il blocco di memoria puntato
da str sia abbastanza
grande da contenere una qualsiasi parola del file.
*/
void ReadKthWord(FILE
*f, long k, char
*str)
{
rewind(f);
for ( ; k > 0 ; k--)
fscanf(f, "%s", str);
}
long Inv(char
*fName, char *invF)
{
FILE *f = fopen(fName, "r");
//Apri il file in lettura
long l = 0, maxWord =
0, nWords = 0;
int c;
while ((c = fgetc(f)) != EOF) {
//Leggi i caratteri
del file e se e' letto
if
(c == ' ') {
//uno spazio
allora una parola e' terminata
if (l > maxWord) maxWord = l;
//e quindi aggiorna la massima lunghezza e
il
nWords++;
//numero di parole finora
lette e
l = 0;
//riporta
a 0 il contatore di caratteri.
} else
l++;
}
if (l > 0) {
//Per l'ultima parola del file aggiorna la
if (l
> maxWord) maxWord = l;
//massima lunghezza
e il numero di parole.
nWords++;
}
//Dichiara un vettore abbastanza
grande da
char str[maxWord + 1];
//contenere una qualsiasi
parola del file.
FILE
*iF = fopen(invF, "w+");
//Crea ed apri il nuovo file
for ( ; nWords > 0 ; nWords--) {
//Leggi le parole del file
in ordine inverso
ReadKthWord(f, nWords, str);
fprintf(iF,
"%s", str);
//Aggiungi la parola letta al nuovo file
if
(nWords > 1) fprintf(iF, " ");
//Se non e' l'ultima parola scrivi uno spazio
}
fclose(f);
fclose(iF);
return maxWord;
}
Esercizio 47
Scrivere una funzione che preso in input una stringa e un intero positivo
k crea una lista i cui elementi
contengono i segmenti
consecutivi di lunghezza k
della stringa. Il tipo degli elementi della lista è così
definito:
typedef struct ElemS {
char *
seg; /* campo che contiene un segmento
(come stringa C) */
struct ElemS *next;
} ElemS, *ListaS;
Il prototipo della funzione è ListaS
Segment(const char *str, unsigned k). Chiaramente sia gli elementi
della lista che i campi seg di
tali elementi devono essere allocati dinamicamente. Ad esempio se la stringa
di input è
"Stringa di esempio" e k = 4 allora la funzione
deve restituire la lista:
"Stri" -> "nga
" -> "di e" -> "semp" -> "io".
Soluzione Esercizio 47
ListaS Segment(const char *str, unsigned
k)
{
/* La variabile ultimo mantiene l'indirizzo
*/
ListaS L = NULL, *ultimo = &L; /* della locazione che conterra' il puntatore */
int i = 0;
/* all'ultimo elemento che sara' aggiunto.
*/
while (str[i] != '\0') {
ElemS *nuovo = malloc(sizeof(ElemS)); /* Alloca un nuovo elemento */
int j, lung = 0;
/* Calcola la lunghezza */
while (str[i + lung] != '\0' &&
lung < k) lung++; /* del segmento.
*/
nuovo->seg = malloc((lung + 1)*sizeof(char));
/* Alloca il campo seg e */
for (j = 0 ; j < lung ; j++)
/* copiaci il segmento. */
nuovo->seg[j] = str[i + j];
nuovo->seg[lung] = '\0';
nuovo->next = NULL;
/* Accoda il nuovo elemento e
*/
*ultimo = nuovo;
/* aggiorna la variabile ultimo. */
ultimo = &(nuovo->next);
i += lung;
}
return L;
}
Esercizio 48
Scrivere una funzione che prese in input due stringhe
fMatrice e
fTrasp, crea un file di nome
fTrasp e vi scrive
la trasposta della matrice di interi memorizzata nel file di nome
fMatrice. La matrice è memorizzata
in modo tale che
i primi due interi sono il numero di righe e il numero di colonne della
matrice e poi seguono gli elementi della matrice
disposti per righe (separati da spazi). Entrambi i file sono di tipo
testo. Il prototipo della funzione è
void Trasp(char *fMatrice, char
*fTrasp).
Si ricorda che la trasposta di una matrice è la matrice che si
ottiene scambiando le righe con le colonne della matrice originale.
Ad esempio se il contenuto del file
fMatrice
è
2 3 13 8 -4 34 17 104
allora la matrice ha 2 righe, 3 colonne, la prima riga è
13 8 -4 e la seconda riga è
34 17 104. La funzione deve
creare un file contenente
3 2
13 34 8 17 -4 104.
Soluzione Esercizio 48
/* Funzione ausiliaria che ritorna l'intero che si trova
nella riga r e colonna c *
* della matrice memorizzata nel file f.
*/
int LeggiElem(FILE *f,
int r, int c)
{
int nc, n, e;
rewind(f);
/* Riporta il file all'inizio */
fscanf(f, "%d",
&n); /* Leggi il numero
di righe (che non sara' usato) */
fscanf(f, "%d", &nc); /* Leggi il numero di colonne */
n = r*nc + c;
/* Numero di elementi che precedono
quello da leggere */
while (n > 0) {
/* Scorri
gli elementi che precedono l'elemento */
fscanf(f,
"%d", &e);
n--;
}
fscanf(f, "%d",
&e); /* Leggi
l'elemento */
return e;
}
void Trasp(char *fMatrice, char
*fTrasp)
{
FILE *fM, *fT;
int r, c, nr, nc;
fM = fopen(fMatrice, "r"); /* Apri il file matrice */
fscanf(fM, "%d %d", &nr, &nc); /* Leggi
il numero di righe e di colonne */
fT = fopen(fTrasp,
"w"); /* Crea
ed apri il file fTrasp */
fprintf(fT, "%d
%d", nc, nr); /* Scrivi il numero di righe e di colonne */
for (r = 0 ; r < nc ; r++)
/* Scrivi la matrice trasposta nel file fTrasp */
for (c = 0 ; c < nr ; c++)
fprintf(fT, " %d", LeggiElem(fM, c, r));
fclose(fM);
fclose(fT);
}
Esercizio 49
Si consideri il tipo
Simbol così
definito:
typedef
struct Simbol{
char
s;
struct Simbol *next;
} Simbol, *SimbolSeq;
Scrivere una funzione che presa in input una lista i cui elementi sono
di tipo
Simbol elimina dalla lista,
se esiste, la prima sotto lista che
inizia con il simbolo
'(' termina
con il simbolo
')' e non contiene
altri simboli
'(',
')' e ritorna la lista così
modificata. La memoria
degli elementi eliminati deve essere rilasciata. Il prototipo della funzione
è
SimbolSeq Riduci(SimbolSeq).
Ad esempio se la lista
di input è
x
-> ( -> y -> + -> ( -> z ->
x -> ) -> w -> ) allora la funzione modifica la lista così
x
-> ( -> y -> + -> w ->
).
Soluzione Esercizio 49
SimbolSeq Riduci(SimbolSeq ss)
{
if (ss != NULL &&
ss->next != NULL) {
SimbolSeq psL = &ss; /* Puntatore alla locazione che conterra' l'indirizzo *
* del primo elemento della sotto lista da eliminare. */
while (*psL != NULL
&& (*psL)->s != '(') /*
Cerca il primo elemento che */
psL = &((*psL)->next);
/* contiene '('.
*/
if (*psL != NULL)
{
/* Se esiste allora */
SimbolSeq last = *psL;
/* cerca la sotto lista */
while (last->next != NULL && last->next->s != ')') {
/* da eliminare.
*/
if (last->next->s == '(')
/* Se trovi '(' allora modifica */
psL = &(last->next);
/* l'inizio della sotto lista. */
last = last->next;
}
if (last->next != NULL) {
/* Se la sotto lista esiste */
while (1) {
/* eliminala.
*/
char s = last->s;
last = *psL;
*psL = last->next;
free(last);
if (s == ')') break;
}
}
}
}
return ss;
}