Le struct
- Soluzione
In questo tutorial non verrà presentata la possibile soluzione nella sua interezza, ma soltanto le parti interessanti, che dovranno essere opportunamente integrate per fornire la soluzione completa e compilabile.
Per ottenere un programma completo e funzionante, si tratta pertanto di scrivere la funzione main
che dichiara le variabili necessarie e che chiama opportunamente le funzioni descritte.
Per cominciare, si assume che vengano effettuate le seguenti dichiarazioni:
#define MAXN (10)
struct punto_t {
double x;
double y;
};
struct rettangolo_t {
struct punto_t A; // alto-sinistra
struct punto_t B; // basso-destra
};
Le funzioni descritte di seguito dovranno essere oppotunamente richiamate nel main
.
Ad esse dovranno essere passati i corretti parametri.
Lettura della matrice
La funzione per la lettura di un punto può essere come segue:
struct punto_t leggi_punto(void)
{
char linea[1024];
struct punto_t p;
fgets(linea, sizeof(linea), stdin);
sscanf(linea, "%lf %lf", &p.x, &p.y);
return p;
}
- utilizza la
fgets
e lasscanf
per leggere una riga di testo ed estrarre i due numeri corrispondenti alle coordinate del punto (vedi S7.2.4 per un esempio di uso dellasscanf
in abbinamento allestruct
) - nella
sscanf
viene usato lo specificatore%lf
per estrarre due numeri in virgola mobile dalla stringa letta con lafgets
- i valori estratti vengono memorizzati nelle variabili
p.x
ep.y
che sono passate allasscanf
per riferimento (si noti l'uso dell'operatore&
, vedi S7.2.4)
Stampa di un punto
La funzione per stampare un singolo punto è la seguente:
void stampa_punto(struct punto_t p)
{
printf("(%.3lf, %.3lf)\n", p.x, p.y);
}
- la
printf
stampa le coordinate del puntop
passatole come parametro, col giusto formato - in particolare, con
%.3lf
vengono stampate 3 cifre dopo la virgola (S2.12)
Distanza dall'origine
La funzione per calcolare la distanza tra due generici punti è la seguente:
double distanza(struct punto_t p1, struct punto_t p2)
{
return sqrt((p1.x-p2.x)*(p1.x-p2.x) + (p1.y-p2.y)*(p1.y-p2.y));
}
I punti p1
e p2
di cui calcolare la distanza sono passati come argomento.
Nel calcolo viene usata la funzione sqrt
della libreria matematica:
- bisogna includere
math.h
per poter usare la funzione - bisogna compilare con
-lm
per evitare errori di compilazione
Punti interni
La funzione che permette di stabilire se un punto è interno o meno ad un rettangolo è la seguente:
int interno(struct punto_t p, struct rettangolo_t r)
{
if (p.x >= r.A.x && p.x <= r.B.x && p.y >= r.B.y && p.y <= r.A.y)
return 1;
else
return 0;
}
- gli argomenti sono il punto
p
e il rettangolor
- si verifica the la
x
dip
sia compresa tra lax
diA
e quella diB
(A
eB
sono i campi dir
)- stessa cosa per la
y
- stessa cosa per la
- tutte e quattro le condizioni devono essere vere contemporaneamente, da cui l'uso dell'operatore
&&
(AND logico, vedi S11.5.1) - attenzione all'uso di
<=
e>=
, in quanto un punto è considerato interno anche se giace sul perimetro del rettangolo
Area del rettangolo
La funzione per il calcolo dell'area del rettangolo è la seguente:
double area_rettangolo(struct rettangolo_t r)
{
double b, h;
b = r.B.x - r.A.x;
h = r.A.y - r.B.y;
return b*h;
}
- viene calcolata la lunghezza della base
b
come differenza tra le coordinatex
dei punti estremi - la stessa cosa avviene con la differenza tra le coordinate
y
per l'altezzah
- lo stesso risultato si sarebbe ottenuto anche senza l'uso delle variabili temporanee
b
eh
Coppia dei punti più lontani
La funzione per il calcolo degli indici dei punti più distanti può essere come la seguente:
void indici_max_dist(struct punto_t vett[], int len, int *max_i, int *max_j)
{
double max, dist;
int i, j;
*max_i = 0;
*max_j = 0;
max = distanza(vett[0], vett[1]);
for (i = 0; i < len - 1; i++) {
for (j = i + 1; j < len; j++) {
dist = distanza(vett[i], vett[j]);
if (dist > max) {
max = dist;
*max_i = i;
*max_j = j;
}
}
}
}
- gli argomenti sono il vettore
vett
, la sua lunghezzalen
, e gli indici dei punti più distantimax_i
emax_j
- questi ultimi sono passati per riferimento, in modo che la funzione possa modificarne il valore (S6.6)
- la variabile
max
tiene traccia della massima distanza registrata max
viene inizializzata ponendola uguale alla distanza tra i primi due punti nel vettore- i due cicli
for
annidati calcolano la distanza tra ciascun puntoi
e ogni puntoj
che lo segue nel vettore - se la distanza è maggiore di
max
il nuovo massimo viene memorizzato, così come gli indici dei punti corrispondenti - da notare i limiti dei contatori nei cicli
for
:- il contatore
i
parte da0
e arriva alen-1
(escluso) - il contatore
j
parte dai+1
fino ad arrivare alen
(escluso)
- il contatore
NOTA: l'uso della variabile temporanea dist
è degno di nota; quel pezzo di codice si sarebbe potuto anche scrivere così:
if (distanza(vett[i], vett[j]) > max) {
max = distanza(vett[i], vett[j]);
*max_i = i;
*max_j = j;
}
Così facendo, però, nel caso in cui la condizione dell'if
risultasse vera, la funzione distanza
verrebbe chiamata due volte per svolgere lo stesso calcolo, cosa che allungherebbe il tempo di esecuzione del programma.
Usando la variabile dist
, il calcolo viene fatto una volta sola e il risultato viene usato due volte (quando serve).
DOMANDA: che succederebbe se entrambi i contatori i
e j
partissero da 0
e arrivassero a len
(escluso)?