Linuxtrent: Re: Ancora C

  • From: Matteo Ianeselli <m.ianeselli@xxxxxxxxxxx>
  • To: linuxtrent@xxxxxxxxxxxxx
  • Date: Sun, 4 Nov 2001 23:08:48 +0100

Daniele Nicolodi writes:


 >      printf("-------------------------------------\n");
 >      printf("   Alunno: %s %s\n", e->cognome, e->nome);
 >      printf("Matricola: %s\n", e->matricola);
 >      printf("    Corso: %s\n", e->corso);
 >      printf("     Voto: %d\n", e->voto);


Volendo, il C ANSI permette una cosa del tipo

printf("-------------------------------------\n"
       "   Alunno: %s %s\n"
       "Matricola: %s\n"
       "    Corso: %s\n"
       "     Voto: %d\n",
       e->cognome, e->nome,
       e->matricola,
       e->corso,
       e->voto);

(notare l'assenza di virgole tra le costanti stringa - che vengono
pertanto concatenate dal compilatore in fase di compilazione in
un'unica costante stringa).

Hai il vantaggio di una printf() sola contro 5. Hai lo svantaggio che
e` piu` prono ad errori se son piu` di una manciata di parametri.

+++

In esame_fill() vale giustamente la considerazione di Flavio. In
aggiunta, io userei strdup() che c'e` apposta e fa la stessa cosa.

Inoltre darei un'occhiata al fatto che i parametri passati siano
validi... strlen(NULL) dovrebbe andare in core dump secco, idem
strdup(NULL).


Considerato poi che la struct si tiene delle copie delle stringhe che
passi come parametro, sarebbe il caso di dichiararle const per far
capire al programmatore che le stringhe passate non vengono modificate
(e, 3 volte su 4, che la proprieta` delle stesse rimane del chiamante).
Inoltre cosi` non si lamenta se passi come parametri delle costanti
stringa.

Del tipo

void 
esame_fill(struct esame * e,
           const char *   nome,
           cont char *    cognome,
           const char *   matricola,
           const char *   corso ,
           int            voto)
{
    if(e->nome)       free(e->nome);
    if(e->cognome)    free(e->cognome);
    if(e->matricola)  free(e->matricola);
    if(e->corso)      free(e->corso);

    e->nome       = nome      ? strdup(nome)      : NULL;
    e->cognome    = cognome   ? strdup(cognome)   : NULL;
    e->matricola  = matricola ? strdup(matricola) : NULL;
    e->corso      = corso     ? strdup(corso)     : NULL;
    e->voto       = voto;
}


(se non ci metto i ``!= NULL'' e` per mia abitudine storica... cmq e`
perfettamente equivalente, anche sulle piattaforme dove NULL non e`
all'indirizzo 0: ci pensa il compilatore).

+++

In prospettiva, cmq, quando la struttura diventa grande con tanti
membri, conviene fare tante funzioni `getter' e `setter' quanti sono
gli attributi, invece che un metodone per impostare tutti gli
attributi, del tipo

int
esame_setNome(struct esame * e, const char * nome)
{
    char * newNome = NULL;
    int result = 0;

    if(nome) 
    {
        newNome = strdup(nome);

        if(newNome) 
        {
            if(e->nome) free(e->nome);

            e->nome = newNome;
        }
        else
        {
            result = -1;
        }
    }
    else
    {
        result = -1;
    } 

    return result;
}

const char *
esame_getNome(struct esame * e)
{
    return e->nome;
}

(setNome e` una sbrodolata di if() giusto per controllare i parametri
in ingresso, si sa mai...)

Avendo funzioni di questo genere diventa poi semplice realizzare
funzioni che creano una nuova struct esame come copia di una
esistente, o che assegnano ad una struct esame i valori a partire da
un'altra struct esame. Inoltre, posto che usi solo queste per accedere
ai valori della struct, se un domani la rappresentazione interna
cambia puoi sempre rivedere queste funzioni e basta invece che andare
a cambiar tutti i riferimenti nel codice. 
-- 
Per iscriversi  (o disiscriversi), basta spedire un  messaggio con SOGGETTO
"subscribe" (o "unsubscribe") a mailto:linuxtrent-request@xxxxxxxxxxxxxxxxx


Other related posts: