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 la sscanf 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 della sscanf in abbinamento alle struct)
  • nella sscanf viene usato lo specificatore %lf per estrarre due numeri in virgola mobile dalla stringa letta con la fgets
  • i valori estratti vengono memorizzati nelle variabili p.x e p.y che sono passate alla sscanf 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 punto p 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 rettangolo r
  • si verifica the la x di p sia compresa tra la x di A e quella di B (A e B sono i campi di r)
    • stessa cosa per la y
  • 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 coordinate x dei punti estremi
  • la stessa cosa avviene con la differenza tra le coordinate y per l'altezza h
  • lo stesso risultato si sarebbe ottenuto anche senza l'uso delle variabili temporanee b e h

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 lunghezza len, e gli indici dei punti più distanti max_i e max_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 punto i e ogni punto j 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 da 0 e arriva a len-1 (escluso)
    • il contatore j parte da i+1 fino ad arrivare a len (escluso)

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)?

Scopri la risposta »