Le struct
Realizzare un programma che acquisisca da tastiera un numero intero senza segno n
.
Se l'utente inserisce un numero maggiore di 10
si assuma n = 10
.
Successivamente il programma deve acquisire una lista di coordinate di n
punti nel piano; le coordinate di ogni punto, che sono dei numeri in virgola mobile, devono essere inserite sulla stessa riga per es.:
1.23 4.5678
Suggerimenti generali
Conviene dichiarare una struttura dati, denominata per esempio struct punto_t
, che contenga i due campi x
e y
di tipo double
(in S7.2 c'è un esempio di dichiarazione con campi di tipo int
).
È possibile utilizzare anche la typedef
spiegata in S7.3, ma in questo tutorial non verrà utilizzata.
Dichiara nel main
un vettore di MAXN
strutture di tipo struct punto_t
, per es.
struct punto_t vett[MAXN];
MAXN
sia una macro dichiarata con #define
e posta uguale al massimo numero di punti da memorizzare (10
).
Dopodiché va letto il valore di di n
.
Per la lettura dei singoli punti può essere creata una funzione come la seguente:
struct punto_t leggi_punto(void);
La funzione utilizzerà la fgets
per leggere dal file una riga di testo alla volta, e per ciascuna riga letta verrà chiamata la sscanf
per estrarre dalla riga i due numeri corrispondenti alle coordinate del punto (vedi S7.2.4 per un esempio di uso della sscanf
in abbinamento alle struct
).
Dichiarerà una variabile di tipo struct punto_t
i cui campi saranno assegnati con la sscanf
; tale variabile verrà restituita con la return
.
1) Stampa dei punti
Stampare a video (uno per riga) i punti acquisiti, utilizzando il seguente formato:
[PUNTI]
(1.000, 2.000)
(3.000, 4.000)
(5.000, 6.000)
Suggerimenti
Visto che nel corso del programma servirà stampare varie volte i punti, conviene definire una funzione come
void stampa_punto(struct punto_t p);
La funzione stamperà le coordinate di un singolo punto p
passato come parametro usando il formato richiesto, ovvero:
- due numeri
double
, tra parentesi tonde e separati da virgola- lo spazio dopo la virgola è importante, non dimenticarlo!
- ciascun numero deve avere
3
cifre dopo la virgola - ricorda che per stampare un singolo numero con il formato richiesto si può usare lo specificatore
%.3lf
.
La funzione stampa_punto
verrà chiamata in un ciclo for
all'interno del main
per stampare tutti i punti memorizzati nel vettore vett
dichiarato precedentemente.
2) Distanza dall'origine
Calcolare la distanza dall'origine (il punto (0, 0)
) di ogni punto acquisito.
Stampare le distanze in ordine corrispondente a quello dei rispettivi punti.
Utilizzare il seguente formato:
[DISTANZE]
2.236
5.000
7.810
Suggerimenti
Crea innanzitutto una funzione chiamata distanza
, come la seguente:
double distanza(struct punto_t p1, struct punto_t p2);
La funzinoe calcola la distanza tra due punti generici p1
e p2
(una funzione simile è mostrata in S7.2).
La distanza d
tra i punti p_1 = (x_1,y_1)
e p_2 = (x_2, y_2)
è data dalla formula (attenzione che non è codice C):
d = sqrt((x_2-x_1)^2 + (y_2-y_1)^2)
dove sqrt
è la funzione che calcola la radice quadrata, mentre ^
indica un elevamento a potenza.
Per poter usare la funzione per il calcolo della radice quadrata in C, bisogna:
- includere
math.h
(con la direttiva#include
) - compilare il programma aggiungendo l'opzione
-lm
(elle minuscola + emme minuscola) alla linea di comando (su alcuni sistemi non è necessario), ovvero, supponendo che il programma si chiamistruct.c
, l'istruzione per la compilazione è:
cc -Wall struct.c -lm
Per risolvere il problema, la funzione distanza
verrà chiamata per ciasun elemento del vettore vett
con un ciclo for
nel main
.
L'istruzione che calcola la distanza d
da stampare sarà simile alla seguente:
d = distanza(origine, vett[i]);
dove origine
è una struttura che contiene le coordinate dell'origine e può essere dichiarata come segue:
struct punto_t origine = {0, 0};
3) Punti interni
Si richieda in input i dati di un rettangolo avente i lati paralleli agli assi cartesiani.
Dire quali sono i punti contenuti nel rettangolo.
Il rettangolo parallelo agli assi sia definito da una coppia di punti A
e B
.
Per acquisire il rettangolo si acquisiscano quindi i 2 punti A
e B
come ad esempio:
0.0 5.0
5.0 -1.0
Il programma dovrà cercare quali punti, tra quelli acquisiti in precedenza, siano interni al rettangolo. Si considerino contenuti anche i punti che si trovino sul bordo del rettangolo. Si stampino i punti interni usando il formato:
[INTERNI]
(1.000, 2.000)
(3.000, 4.000)
Suggerimenti
- si leggano i due punti
A
eB
utilizzando la funzioneleggi_punto
già implementata - può essere utile creare una
struct rettangolo_t
i cui due campi siano di tipostruct punto_t
(un esempio simile è riportato nella Sezione di approfondimento 7, nel capitolo delle strutture) - si può allora definire una funzione come
int interno(struct punto_t p, struct rettangolo_t r);
che, dato un punto p
e un rettangolo r
restituisce 1
se il punto è interno al rettangolo, e 0
altrimenti.
Questa funzione può essere chiamata in un ciclo for
nel main
passando di volta in volta tutti i punti nel vettore di punti, e stampando il punto con la funzione stampa_punto
se le coordinate sono interne.
4) Area del rettangolo
Calcolare l'area del rettangolo acquisito al punto precedente. Stampare il valore dell'area col seguente formato:
[AREA]
30.000
Suggerimenti
Creare una funzione tipo:
double area_rettangolo(struct rettangolo_t r);
la quale, dato un rettangolo r
, ne restituisce l'area.
NOTA: la lunghezza di base e altezza del rettangolo, essendo i suoi lati paralleli agli assi, si può calcolare ripettivamente come la differenza delle coordinate x
e y
dei punti estremi (in valore assoluto).
5) Coppia dei punti più lontani
Trovi la coppia di punti acquisiti più lontani tra loro. Si stampino i due punti con il seguente formato:
[COPPIA]
(5.000, 6.000)
(1.000, 2.000)
Suggerimenti
- bisogna confrontare ciascun punto nel vettore con tutti gli altri
- per questo sono sufficienti due cicli
for
annidati: quello più esterno coni
che va da0
an-1
, mentre quello più interno conj
che va dai+1
an
- una variabile
max
memorizzerà il valore massimo corrente
- per questo sono sufficienti due cicli
- la distanza tra due punti può essere calcolata con la funzione
distanza
implementata per risolvere il punto precedente corrispondente - quando la distanza tra i due punti correnti supera
max
, gli indici dei punti nel vettore che danno luogo alla distanza corrente sono memorizzati in due variabilimax_i
emax_j
Questo procedimento può essere implementato in una funzione come la seguente:
void indici_max_dist(struct punto_t vett[], int len, int *max_i, int *max_j);
Essa restituisce gli indici max_i
e max_j
nel vettore vett
di lunghezza len
che corrispondono ai punti che si trovano alla maggior distanza tra loro.
Verifica automatica
Si utilizzi il tool pvcheck
di verifica automatica per testare il corretto funzionamento del programma (maggiori informazioni circa l'uso di pvcheck
sono disponibili qui).
Il file contenente i test è struct.test.
Il comando da eseguire per il test è il seguente:
./pvcheck -f struct.test ./a.out
Nella prossima pagina potrai esaminare un esempio di soluzione dell'esercizio.