Altra conferma - funzioni e struct

ELWOOD1
Ciao a tutti, scusate se abuso della vostra disponibilità, avrei un altro esercizio da postarvi e la mia interpretazione.

Vorrei capire se e dove sbaglio, vi ringrazio.

/*
Il programma deve consentire di immagazzinare i dati relativi ad un appartamento:
•	stanza, caratterizzata da un identificativo numerico, da un nome, una superficie un numero di finestre, 
•	piano, caratterizzato da un numero, da un numero di stanze e da un insieme di stanze. 
•	casa, caratterizzata da un numero di piani e da un insieme di piani, da un indirizzo (via, num civico, CAP, città).
Si assuma che il programma possa immagazzinare al massimo 20 case, ciascuna composta da un massimo di 5 piani ognuno composta da un massimo di 10 stanze. 
a)	Definire opportuni tipi e strutture dati per rappresentare le informazioni di cui sopra. 
b)	Si assuma che le strutture dati di cui sopra siano state popolate dall’utente con dati opportuni. Implementare le seguenti funzioni: 
o	conta_finestre_piano che, dati in input una variabile di tipo piano, ritorna il totale delle finestre presenti.	
o	conta_finestre_casa che, dati in input una variabile di tipo casa, ritorna il totale delle finestre presenti. Questa seconda funzione deve utilizzare la precedente.	
o	cerca_casa che, dato un insieme di case ed un numero di finestre, ritorna 1 se esiste almeno 1 casa con questo esatto numero di finestre, 0 altrimenti. Questa terza funzione deve utilizzare la precedente. 
*/


#include <stdio.h>
#include <stdlib.h>
#define N_CAR 20
#define N_MAX_STANZE 10
#define N_MAX_PIANI 5
#define N_MAX_CASE 20

typedef char stringa[N_CAR];

typedef struct{
        int num;
        stringa nome;
        float superficie;
        int n_finestre;
        }tstanza;

typedef struct{
        int n_piano;
        tstanza stanze[N_MAX_STANZE];
        }tpiano;

typedef struct{
        stringa via;
        int n_civico;
        int cap;
        stringa citta;
        tpiano piani[N_MAX_PIANI];        
        }tcasa;

typedef struct{
        tcasa casa[N_MAX_CASE];
        }elenco_case;

//Funzione contafinestre piano.

int conta_finestre_piano(tpiano p){
    int i,tot=0;
    for(i=0;i<N_MAX_STANZE;i++){
                                             tot+=p.stanze[i].n_finestre;                  
                                             }
    return tot;
    }

//Funzione conta finestre casa

int conta_finestre_casa(tcasa c){
    int i,j,tot=0;
    for(i=0;i<N_MAX_PIANI;i++){
                                          tot+=conta_finestre_piano(c.piani[i]);
                                          }    
    return tot;
    }

// Funzione cerca_casa

int cerca_casa(elenco_case a,int nf){
    int i,j,somma=0,ris,tot=0,r;

    for(j=0;j<N_MAX_CASE;j++){
                              somma=0;
                              somma+=conta_finestre_casa(a.casa[j]);
                              if(somma==nf){ris=1;}
                              else{ris=0;}
                              tot+=ris;
                              }
    if(ris!=0){r=1;}
    else{r=0;}
    
    return r;
    }

int main(int argc, char *argv[]){
    
  system("PAUSE");	
  return 0;
}



Risposte
claudio862
Le prime due funzioni sono (quasi) giuste, mentre la terza no. Il controllo finale non devi farlo sulla variabile "ris" che dipende solo dall'ultima casa considerata, ma su "tot" (che dovrebbe rappresentare il numero di case con il numero giusto di finestre). Comunque una via più semplice è di restituire 1 non appena trovi una casa con il giusto numero di finestre:

int cerca_casa(elenco_case case, int finestre){
    for(int i = 0; i < N_MAX_CASE; i++) {
        int finestre_casa_corrente = conta_finestre_casa(case.casa[i]);
        if (finestre_casa_corrente == finestre) {
            return 1;
        }
    }
    
    // Se sono arrivato fin qui non c'erano case con "finestre" finestre.
    return 0;
}


Rimane comunque un problema con tutte le funzioni (compresa quella che ho scritto io). Non è detto che un piano abbia N_MAX_STANZE stanze, potrebbe averne di meno; ugualmente una casa potrebbe avere meno di N_MAX_PIANI piani. Quelli sono i limiti massimi. Quindi devi memorizzare nele strutture anche il numero effettivo di stanze / piani / case, ed iterare solo su quelli.

Nota a margine:
Usa un'indentazione più leggibile. Non allineare il contenuto di un "for" alla parentesi graffa, usa degli spazi tra gli operatori (magari come faccio io, ma ci sono anche altri stili).

Nota a margine 2:
Fai notare al tuo professore che il verbo inglese "return" in italiano si traduce "restituire" e non "ritornare" (che è pure intransitivo e dire "la funzione ritorna il totale" è un orrore ortografico). A meno che non sia permaloso, allora lascia perdere (ma non fare anche tu questo errore).

ELWOOD1
"claudio86":
Le prime due funzioni sono (quasi) giuste


centra sempre la dimensione effettiva?
Il fatto è che quella si potrà sapere solo in fase di compilazione.

"claudio86":

Il controllo finale non devi farlo sulla variabile "ris" che dipende solo dall'ultima casa considerata, ma su "tot"


Giusto! che idiota!! ](*,)
grazie per il suggerimento di semplificazione.


Un consiglio, quando si deve maneggiare con dati di tipo struct, che contengono altri dati struct e via dicendo è facile confondersi o non capire bene in che maniera inizializzare i dati.
In questi casi cosa sarebbe utile fare?
Magari uno schema scritto con le varie tipologie?


"claudio86":

Fai notare al tuo professore che il verbo inglese "return" in italiano si traduce "restituire" e non "ritornare" (che è pure intransitivo e dire "la funzione ritorna il totale" è un orrore ortografico). A meno che non sia permaloso, allora lascia perdere (ma non fare anche tu questo errore).


Sei un mito! :prayer:

claudio862
"ELWOOD":
centra sempre la dimensione effettiva?
Il fatto è che quella si potrà sapere solo in fase di compilazione.

No al contrario, si può sapere solo a tempo di esecuzione (runtime), perché dipende da quante case / stanze / piani inserisce l'utente. Ma nella consegna dice di assumere che le strutture dati siano popolate correttamente. Ti serve semplicemente una variabile aggiuntiva nelle strutture:

struct casa {
    piano[MAX_PIANI] piani;
    int numero_piani;
};

...

struct casa c1;
for (int i = 0; i < numero_piani; ++i) {
    // fai qualcosa con c1.piani[i];
}


Un consiglio, quando si deve maneggiare con dati di tipo struct, che contengono altri dati struct e via dicendo è facile confondersi o non capire bene in che maniera inizializzare i dati.
In questi casi cosa sarebbe utile fare?
Magari uno schema scritto con le varie tipologie?

Potrebbe essere utile anche un diagramma di classi UML (le struct C sono praticamente classi senza operazioni).
Anche la tecnica usata nell'esercizio è importante: scrivi funzioni separate che lavorano sulle strutture più "interne". Casa contiene piani, piano contiene stanze, stanza contiene finestra. Vuoi sapere quante finestre contiene una casa. Un'alternativa è il codice che hai scritto tu, dove la funzione per contare le finestre di una casa usa la funzione per contare le finestre di un singolo piano. Un'altra alternativa è di scrivere codice del tipo:

struct casa c1;
int totale_finestre = 0;
for (int p = 0; p < c1.numero_piani; ++p) {
    for (int s = 0; s < c1.piani[p].numero_stanze; ++s) {
        totale_finestre += c1.piani[p].stanze[s].numero_finestre;
    }
}

Per accedere esplicitamente a "c1.piani

.stanze.numero_finestre" devi conoscere tutte le strutture in dettaglio; inoltre se modifichi ad esempio la struttura "stanza" devi poi aggiornare tutte le funzioni che lavorano su casa.

In sostanza quando lavori sulle strutture più esterne non ti interessa sapere come sono fatte quelle più esterne, è meglio accederci tramite operazioni offerte dalle strutture più esterne (nella programmazione ad oggetti è più semplice, ma si può fare anche in C tramite funzioni separate come hai fatto tu).

Sei un mito!

Beh, a dire il vero facevo anch'io questo errore, finché non me l'hanno fatto notare.

ELWOOD1
Perfetto, mi sei stato di grande aiuto!

Grazie mille davvero.

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.