5 PAC4

5.1 strcmp()

En què es basa strcmp() per decidir que, per exemple, la lletra 'O' és més gran que la lletra 'A'?

La resposta la tenim en el codi ASCII (numèric) que té associat cada caràcter. Per aquest motiu és normal que interpreti diferent una 'A' i una 'a', ja que són caràcters diferents; de fet segons els valors ASCII, tenim que 'A' < 'a'.

Per si volem consultar la taula ASCII per internet, la podem generar nosaltres mateixos de la següent forma:

/* Exemple CA0501 */
#include <stdio.h>

int main(int argc, char **argv) {
    int i;
    /* Relació de caràcters ASCII (només és un subconjunt!)
       ordenats de més petit a més gran */
    for (i=33; i<=126; i++) {
        printf("%d : %c\n", i, i);
    }
    return 0;
}

5.2 scanf()

Quan utilitzem scanf() fins ara sempre li hem passat el nom de la variable precedit per &. Això significa que realment li estem passant la posició de la memòria on resideix la variable facilitada.

Així, per exemple, quan fem la següent operació scanf("%d", &numero); estem passant el valor que introduïm per teclat directament a la posició de memòria on tenim desada la variable numero. D’aquí ve utilitzar &numero en comptes de numero. El mateix comportament tenim pels tipus primitius char, float, etc.

Els vectors de caràcters en llenguatge C tenen una característica: el nom de l’array conté l’adreça de memòria on està desada la primera posició de l’array.

Per exemple, quan executem scanf("%s", cadena); el valor de cadena és l’adreça de memòria inicial on està ubicat l’array. Dit d’una altra manera, cadena conté el mateix valor que &cadena[0] (és una altra forma que tenim per referir-nos a la posició inicial en memòria de l’array).

A continuació s’adjunta un exemple amb tots aquests conceptes:

/* Exemple CA0502 */
#include <stdio.h>
#define MAXIM 10

int main(int argc, char **argv) {
    char cadena[MAXIM];
    int numero;

    printf("Reservada la posició de memòria %p per la variable numero\n", &numero);
    printf("Reservada la posició de memòria %p per la variable cadena\n", cadena);
    printf("Reservada la posició de memòria %p per la variable cadena\n", &cadena[0]);

    printf("\nIntrodueix un número enter: ");
    scanf("%d", &numero);
    printf("\nIntrodueix una cadena: ");
    scanf("%s", cadena);

    printf("\nHas assignat els següents valors :\n");
    printf("numero = %d \n", numero);
    printf("cadena = %s \n", cadena);
    return 0;
}

5.3 El finalitzador ‘\0’ i strcmp()

Com es va veure al mòdul Cadenes de caràcters en C de la xWiki, “una cadena de caràcters o string és una seqüència de caràcters finalitzada pel caràcter ‘\0’”. Per tant, hem de tenir en compte que el finalitzador '\0' càpiga a la nostra variable, ja que aquesta és la forma que té C de saber on s’acaba un string en memòria.

Imaginem que tenim tres cadenes, amb el mateix contingut però de mida diferent (podem tenir posicions buides). Què passa si les comparem? I si comparem amb una cadena de mateix contingut però sense finalitzador '\0'?

/* Exemple CA0503 */
#include <stdio.h>
#include <string.h>

int main(int argc, char **argv) {
    char ciutat1[7] = "Girona";
    char ciutat2[8] = "Girona";
    char ciutat3[6] = "Girona"; /* no conté el '\0' final */

    /* si strcmp retorna 0 significa que les dues cadenes són iguals */
    printf ("Les variables ciutat1 i ciutat2 són iguals? %d\n", 
        strcmp(ciutat1, ciutat2));
    printf ("Les variables ciutat1 i ciutat3 són iguals? %d\n", 
        strcmp(ciutat1, ciutat3));
    return 0;
}

La forma que tenim per forçar que una cadena no contingui el finalitzador és limitant la seva mida als caràcters que contindrà, sense tenir en compte reservar-ne un pel '\0'. En aquest cas ho fem amb char ciutat3[6] = "Girona".

La sortida generada és la següent:

Les variables ciutat1 i ciutat2 són iguals? 0
Les variables ciutat1 i ciutat3 són iguals? -1

D’aquí la importància del finalitzador de cadenes de caràcters. Per tant, si per exemple tenim una variable x de tipus string i de mida màxima 15, realment al nostre programa la definirem amb longitud 15+1, per tal que hi càpiga el finalitzador '\0' en cas que s’ocupin els 15 caràcters anteriors.

5.4 El finalitzador ‘\0’ i strlen()

A continuació s’exposa un exemple en el qual es mostra la importància del finalitzador '\0' en la funció strlen() de C, que ens retorna la mida d’una cadena de caràcters :

/* Exemple CA0504 */
#include <stdio.h>
#include <string.h>

#define MAX_LLETRES 8+1

int main(int argc, char **argv) {
    char nom[MAX_LLETRES];
    int numLletres;

    printf("Introdueix un nom: ");
    scanf("%s", nom);

    /* Exemple: si en aquest punt hem teclejat el nom
     * Quim, dins de la cadena de caràcters nom[]
     * tindrem les següents dades:
     *
     * nom[0] = 'Q'
     * nom[1] = 'u'
     * nom[2] = 'i'
     * nom[3] = 'm'
     * nom[4] = '\0' (finalitzador de l'string)
     * nom[5] = valor aleatori
     * nom[6] = valor aleatori
     * nom[7] = valor aleatori
     * nom[8] = valor aleatori
     *
     * El finalitzador '\0' s'afegeix automàticament
     * en llegir un string per teclat amb scanf.
     * 
     * La comanda strlen(...) va recorrent l'string posició
     * a posició per saber la seva longitud. Quan finalitza
     * aquest recorregut? hi ha dues opcions possibles:
     *
     * - quan troba el finalitzador '\0'
     * - quan arriba a la darrera posició de l'string
     *
     * Per tant, si com a nom hem entrat Quim, el valor que 
     * retornarà strlen(...) serà 4.
     */

    numLletres = strlen(nom);

    printf("El nom \"%s\" té %d lletres.\n", nom, numLletres);

    /* Què passa si sobreescrivim el finalitzador '\0' amb
     * un caràcter qualsevol? per exemple 'X'
     */
    printf("\nSobreescrivim el finalitzador '\\0'.");
    nom[numLletres] = 'X';

    /* Tornem a calcular la longitud de l'string */
    numLletres = strlen(nom);

    /* Per quin motiu ara ha canviat la longitud de la
     * variable nom, si no l'hem tornat a redefinir?
     */
    printf("\nAra el nom \"%s\" té %d lletres.\n", nom, numLletres);

    return 0;
}

Si s’executa el programa, la sortida obtinguda serà similar a la següent:

Introdueix un nom: Quim
El nom "Quim"4 lletres.

Sobreescrivim el finalitzador '\0'.
Ara el nom "QuimX�!��"9 lletres.

5.5 Exemple: comparacioStrings

La forma com comparem strings en llenguatge algorísmic és diferent a com ho fem en llenguatge C:

  • Llenguatge algorísmic: la comparació entre strings es fa amb =.
  • Llenguatge C: la comparació entre strings es fa amb la funció strcmp(), que realitza una comparació caràcter a caràcter de les dues cadenes i com a resultat:
    • Retorna 0: si les dues cadenes són iguals.
    • Retorna un valor negatiu: si la primera cadena < segona cadena.
    • Retorna un valor positiu: si la primera cadena > segona cadena.

Un exemple on realitza una comparació de dos strings pot ser el següent:

algorithm comparacioStrings

    var
        cadena1: string;
        cadena2: string;
    end var

    cadena1:= "UOC";
    cadena2:= "UAB";

    if (cadena1 = cadena2) then
        writeString(cadena1);
        writeString(" = ");
        writeString(cadena2);
    else
        if (cadena1 > cadena2) then
            writeString(cadena1);
            writeString(" > ");
            writeString(cadena2);
        else
            writeString(cadena1);
            writeString(" < ");
            writeString(cadena2);
        end if
    end if

end algorithm

En llenguatge C, la comparació caràcter a caràcter entre els string "UOC" i "UAB" que realitza la funció strcmp és la següent:

  • Caràcters de la posició 0 dels dos string: UOC vs UAB. Són iguals, per la qual cosa passa a comparar el següent caràcter.
  • Caràcters de la posició 1 dels dos string: UOC vs UAB. Detecta que són diferents, ja que 'O' > 'A' segons els seus valors ASCII, finalitza la comparació i la funció strcmp() retorna un valor positiu.

/* Exemple CA0505 */
#include <stdio.h>
#include <string.h>

#define MAX_LLETRES 3+1

int main(int argc, char **argv) {

    char cadena1[MAX_LLETRES];
    char cadena2[MAX_LLETRES];
    int resultatComparacio;
    
    cadena1[0] = 'U';
    cadena1[1] = 'O';
    cadena1[2] = 'C';
    cadena1[3] = '\0';
    cadena2[0] = 'U';
    cadena2[1] = 'A';
    cadena2[2] = 'B';
    cadena2[3] = '\0';
    
    resultatComparacio = strcmp(cadena1, cadena2);
    
    printf("Comparació dels strings \"%s\" i \"%s\" = %d\n", 
        cadena1, cadena2, resultatComparacio);
    
    if (resultatComparacio == 0) {
        printf("El resultat %d significa ", resultatComparacio);
        printf("que l'string \"%s\" == string \"%s\"\n", 
            cadena1, cadena2);
    } else {
        if (resultatComparacio < 0) {
            printf("El resultat %d significa ", resultatComparacio);
            printf("que l'string \"%s\" < string \"%s\"\n", 
                cadena1, cadena2);
        } else {
            /* En aquest punt, resultatComparacio > 0 */
            printf("El resultat %d significa ", resultatComparacio);
            printf("que l'string \"%s\" > string \"%s\"\n", 
                cadena1, cadena2);
        }
    }
    return 0;
}

El resultat de l’execució del programa en C és:

Comparació dels strings "UOC" i "UAB" = 1
El resultat 1 significa que l'string "UOC" > string "UAB"

5.6 Exemple: nòmines

Imaginem que volem un programa que ens permeti introduir les nòmines de tots els empleats de la nostra empresa. Un empleat el definim com a nom (cadena de caràcters) + nòmina (real). El programa ha de mostrar al final de tot la relació de nòmines de tots els empleats, la mitjana de totes les nòmines de l’empresa, i qui cobra més i menys a l’empresa.

Una possible forma de programar-ho en C seria la següent:

/* Exemple CA0506 */
#include <stdio.h>
#include <string.h>

#define MAX_EMPLEATS 5
#define MAX_NOM 20+1

typedef struct {
    char nom[MAX_NOM];
    float nomina;
} tEmpleat;

int main(int argc, char **argv) {
    tEmpleat empleats[MAX_EMPLEATS];
    int posMaxNomina;
    int posMinNomina;
    float sumaNomines;
    int i;
    
    posMaxNomina = 0;
    posMinNomina = 0;
    sumaNomines = 0.0;

    for (i=0; i<MAX_EMPLEATS; i++) {
        printf("\nNom empleat : ");
        scanf("%s", empleats[i].nom);
        printf("Nòmina empleat : ");
        scanf("%f", &empleats[i].nomina);
     }

     printf("\nLlistat de nòmines d'empleats : \n\n");

     for (i=0; i<MAX_EMPLEATS; i++) {
        sumaNomines = sumaNomines + empleats[i].nomina;
        if (empleats[i].nomina > empleats[posMaxNomina].nomina) {
            posMaxNomina = i;
        }
        if (empleats[i].nomina < empleats[posMinNomina].nomina) {
            posMinNomina = i;
        }
        printf("%s --> %.2f €\n", empleats[i].nom, empleats[i].nomina);
    }

    printf("\nMitjana nònimes : %.2f €", sumaNomines/MAX_EMPLEATS);
    printf("\nNòmina més alta : %.2f € (%s)", 
        empleats[posMaxNomina].nomina, empleats[posMaxNomina].nom);
    printf("\nNòmina més baixa : %.2f € (%s)", 
        empleats[posMinNomina].nomina, empleats[posMinNomina].nom);
    return 0;
}

Com es pot veure, s’utilitza un vector de tEmpleat de forma que, donada una longitud màxima del vector, anirem introduint els tEmpleat un a un a dins. Una vegada fet, tornem a recórrer el vector de tEmpleat i realitzar tots els càlculs que ens demanen, així com mostrar per pantalla les nòmines de tots els empleats.

En aquest exemple la variable i fa d’índex per recórrer el vector, i les variables posMaxNomina i posMinNomina també són índexos: indiquen en quina posició estan els empleats amb la nòmina més alta i més baixa respectivament.

5.7 Exemple: brisca

Exemple amb diferents recorreguts realitzat sobre tuples guardades en un vector, utilitzant el joc de cartes de la brisca. Per tal d’explicar millor el plantejament de cada implementació, s’han afegit comentaris detallats dins del codi.

/* Exemple CA0507 */
#include <stdio.h>
#include <stdbool.h>

/* Punt de partida: sabem jugar perfectament
 * a la brisca (https://ca.wikipedia.org/wiki/Brisca), 
 * però en canvi som un desastre havent de comptar
 * la puntuació de totes les cartes guanyades. Per
 * aquest motiu volem fer un programa que ens ajudi
 * en aquesta tasca (i també per practicar diferents
 * iteracions amb bucles). El programa demanarà per 
 * teclat carta a carta i finalitzarà quan s'introdueixi
 * un tipus de coll diferent dels definits.
 * Haurà de generar les següents sortides:
 * 1. Llistar totes les cartes introduïdes.
 * 2. Mostrar la carta amb una puntuació més alta.
 * 3. Mostrar la puntuació total aconseguida.
 * 4. Comparar parelles de cartes (1a vs 2a, 2a vs 3a,
 *    3a vs 4a,...) i indicar si són del mateix coll.
 */

#define MAX_NUM_CARTES 48
#define NUM_VALORS 13
#define MAX_NUM_COLLS 4

typedef enum {MONEDES, COPES, BASTOS, ESPASES} tColl;
typedef struct {
    tColl coll;
    int numero;
    int valor;
} tCarta;

int main(int argc, char **argv) {
    tCarta cartaAux;
    tCarta cartaDeMajorValor;
    tCarta cartes[MAX_NUM_CARTES];
    int valors[NUM_VALORS];
    char* noms[MAX_NUM_COLLS];
    bool isFinalitzat;
    int puntuacio;
    bool isMateixColl;
    int i, j;
    
    /* S'inicialitza el vector valors amb les
     * puntuacions de totes les cartes. El nom
     * de la carta fa d'índex del vector, i el
     * valor desat en aquella posició és la seva
     * puntuació. Exemple: 
     * - una carta amb un 1 retornarà 11 punts,
     *   corresponents al valor de la posició 1.
     * - una carta amb un 5 retornarà 0 punts,
     *   corresponents al valor de la posició 5.
     */
    valors[0] = 0;
    valors[1] = 11;
    valors[2] = 0;
    valors[3] = 10;
    valors[4] = 0;
    valors[5] = 0;
    valors[6] = 0;
    valors[7] = 0;
    valors[8] = 0;
    valors[9] = 0;
    valors[10] = 2;
    valors[11] = 3;
    valors[12] = 4;

    /* El següent vector ens ajudarà a mostrar
     * per pantalla de forma automàtica la descripció 
     * associada a cadascun dels valors definits a 
     * l'enumeratiu tColl
     */
    noms[0] = "Monedes";
    noms[1] = "Copes"; 
    noms[2] = "Bastos";
    noms[3] = "Espases";

    /* La variable booleana s'utilitzarà per
     * finalitzar el primer bucle d'introducció
     * de cartes des de teclat
     */
    isFinalitzat = false;
    
    i = 0;
    j = 0;
    puntuacio = 0;
    
    printf("Tipus carta: 0=MONEDES, 1=COPES, 2=BASTOS, 3=ESPASES.\n");

    while (!isFinalitzat) {
        printf("\nIntrodueix tipus carta: ");
        scanf("%u", &cartaAux.coll);
        
        /* Si el coll introduit no correspon a cap dels
         * quatre definits, significa que no es vol 
         * entrar cap més carta des de teclat
         */
        if (cartaAux.coll != MONEDES && cartaAux.coll != COPES
            && cartaAux.coll != BASTOS && cartaAux.coll != ESPASES) {
            isFinalitzat = true;

        } else {
            printf("Introdueix número carta: ");
            scanf("%d", &cartaAux.numero);
            
            /* Es valida que el número de la carta
             * introduïda sigui vàlid: valor comprès
             * entre 1 i 12
             */
            if (cartaAux.numero < 1 || cartaAux.numero > 12) {
                printf("Error: número de la carta incorrecte!\n");
                
            } else {
                /* Es calcula el valor de la carta i 
                 * s'assigna al camp valor de la tupla
                 * cartaAux (de tipus tCarta)
                 */
                cartaAux.valor = valors[cartaAux.numero];
                cartes[i] = cartaAux;
                
                /* La variable 'i' contindrà el número
                 * de cartes vàlides introduïdes per
                 * teclat.
                 */
                i = i + 1;
            }
        }
    }
    
    /* Sortida 1:
     * Recorrem el vector de cartes per mostrar
     * per pantalla tots els elements (cartes)
     * que conté.
     */
    printf("\nRelació de cartes introduïdes: \n");
    for (j = 0; j < i; j++) {
        printf("\t%d de %s (%d punts) \n", cartes[j].numero, 
            noms[cartes[j].coll], cartes[j].valor);
    }
    
    /* Sortida 2:
     * Recorrem el vector de cartes i busquem
     * la que té una major puntuació. En cas 
     * d'empat, mostrem l'última introduïda.
     */

    /* Inicialitzem el valor de cartaDeMajorValor
     * a valor = 0
     */
    cartaDeMajorValor.valor = 0;
    printf("\nCarta de major puntuació: \n");
    for (j = 0; j < i; j++) {
        /* En cada iteració del bucle ens assegurem
         * que cartaDeMajorValor sigui la carta
         * amb un valor més gran. Comparem la carta
         * que estem tractant actualment amb la carta
         * que fins ara hem trobat de major valor.
         */
        if (cartes[j].valor >= cartaDeMajorValor.valor) {
            cartaDeMajorValor.coll = cartes[j].coll;
            cartaDeMajorValor.numero = cartes[j].numero;
            cartaDeMajorValor.valor = cartes[j].valor;
        }
    }
    printf("\t%d de %s (%d punts) \n", cartaDeMajorValor.numero, 
        noms[cartaDeMajorValor.coll], cartaDeMajorValor.valor);

    /* Sortida 3:
     * Recorrem el vector de cartes i anem sumant
     * tots els valors, per tal d'obtenir la 
     * puntuació total.
     */
    printf("\nPuntuació total: \n");
    for (j = 0; j < i; j++) {
        puntuacio = puntuacio + cartes[j].valor;
    }
    printf("\t%d punts \n", puntuacio);
    
    /* Sortida 4:
     * Recorrem el vector de cartes i anem comparant
     * parelles de carta: la que estem tractant amb
     * la que ve a continuació. Mostrem per pantalla
     * si són del mateix coll o no.
     */
    printf("\nComparació de cartes: \n");
    
    /* Important: en aquest recorregut del vector
     * de cartes anem comparant la carta de la 
     * posició actual j amb la carta que està
     * a la següent posició j+1. Això significa
     * que el límit de les iteracions del 
     * bucle passa a ser i-1 (un element abans
     * del final), ja que quan tractem aquest
     * element el compararem amb el següent,
     * que és l'últim del vector. Si en comptes
     * de tenir i-1 tinguéssim només i, en 
     * la darrera iteració donaria error, ja 
     * que s'estaria accedint a una posició
     * incorrecta del vector de cartes (i+1).
     */
    for (j = 0; j < i-1; j++) {
        
        /* Per comparar la carta de la posició actual
         * amb la que hi ha a la següent posició,
         * utilitzem els índex j i j+1 respectivament.
         */
        isMateixColl = (cartes[j].coll == cartes[j+1].coll);
        printf("\t%d de %s vs %d de %s: ", cartes[j].numero, 
            noms[cartes[j].coll], cartes[j+1].numero, 
            noms[cartes[j+1].coll]);
        if (isMateixColl) {
            printf("són del mateix coll!\n");
        } else {
            printf("són de colls diferents!\n");
        }
    }
    return 0;
}

Un exemple d’execució pot ser el següent:

Tipus carta: 0=MONEDES, 1=COPES, 2=BASTOS, 3=ESPASES.

Introdueix tipus carta: 0
Introdueix número carta: 1

Introdueix tipus carta: 0
Introdueix número carta: 10

Introdueix tipus carta: 0
Introdueix número carta: 5

Introdueix tipus carta: 2
Introdueix número carta: 10

Introdueix tipus carta: 2
Introdueix número carta: 1

Introdueix tipus carta: 3
Introdueix número carta: 4

Introdueix tipus carta: 9

Relació de cartes introduïdes: 
    1 de Monedes (11 punts) 
    10 de Monedes (2 punts) 
    5 de Monedes (0 punts) 
    10 de Bastos (2 punts) 
    1 de Bastos (11 punts) 
    4 de Espases (0 punts) 

Carta de major puntuació: 
    1 de Bastos (11 punts) 

Puntuació total: 
    26 punts 

Comparació de cartes: 
    1 de Monedes vs 10 de Monedes: són del mateix coll!
    10 de Monedes vs 5 de Monedes: són del mateix coll!
    5 de Monedes vs 10 de Bastos: són de colls diferents!
    10 de Bastos vs 1 de Bastos: són del mateix coll!
    1 de Bastos vs 4 de Espases: són de colls diferents!

5.8 Exemple: revisioITV

A continuació es planteja un exemple en el qual es modifica el comportament que tenen per defecte els enumeratius en C.

En aquest cas, tenim un centre autoritzat per realitzar revisions de la ITV a diferents tipus de vehicles. Volem que el nostre programa llegeixi des de teclat el valor dels tres camps que defineixen la tupla tRevisioITV: la matrícula del vehicle, el tipus i el resultat de la revisió. Al final de tot, ens ha de mostrar per pantalla el detall de totes les revisions realitzades.

Una possible codificació del programa és la següent:

/* Exemple CA0508 */
#include <stdio.h>
#include <string.h>

#define MAX_MATRICULA 10+1
#define MAX_REVISIONS 3
#define MAX_RESULTAT 3
const int MAX_CATEGORIA = 10;

/* Per defecte el valor que s'assigna
 * al primer element d'un enumeratiu és 0,
 * i es va incrementant en +1 per cada
 * element successiu. Aquest comportament,
 * però, el podem modificar.
 *
 * Opció 1: li podem assignar directament
 * un valor enter a cada element de la
 * següent forma:
 */
typedef enum {FAVORABLE = 1, DESFAVORABLE = 2, NEGATIVA = 0} tResultat;

/*
 * Opció 2: podem assignar valors a uns
 * pocs elements, i la resta d'elements
 * sense valor prenen com a valor el darrer
 * conegut incrementat en +1; en el
 * següent cas, FURGONETA = 5 i CAMIO = 6, ja
 * que l'anterior valor conegut és COTXE = 4:
 */
typedef enum {MOTO = 2, COTXE = 4, FURGONETA, CAMIO} tCategoria;

typedef char tMatricula[MAX_MATRICULA];

typedef struct {
    tMatricula matricula;
    tCategoria categoria;
    tResultat resultat;
} tRevisioITV;

int main(int argc, char **argv) {

    tRevisioITV revisioITV;
    tRevisioITV revisionsITV[MAX_REVISIONS];
    int i;

    /* Utilitzarem els següents dos vectors
     * per mostrar per pantalla el literal
     * corresponent al valor de l'enumeratiu.
     */
    char* resultats[MAX_RESULTAT];
    char* categories[MAX_CATEGORIA];
    
    resultats[0] = "negativa";
    resultats[1] = "favorable";
    resultats[2] = "desfavorable";
    
    categories[2] = "moto";
    categories[4] = "cotxe";
    categories[5] = "furgoneta";
    categories[6] = "camió";

    /* Lectura de dades des de teclat */
    for (i=0; i<MAX_REVISIONS; i++) {
        printf("Matrícula: ");
        scanf("%s", revisioITV.matricula);
        printf("Categoria (2=moto, 4=cotxe, 5=furgoneta, 6=camió): ");
        scanf("%u", &revisioITV.categoria);
        printf("Resultat (1=favorable, 2=desfavorable, 0=negativa): ");
        scanf("%u", &revisioITV.resultat);
        
        /* Important: en llenguatge C no farem una assignació directa
         * entre estructures complexes (tuples). En el seu lloc 
         * realitzarem assignacions camp a camp.
         */
        strcpy(revisionsITV[i].matricula, revisioITV.matricula);
        revisionsITV[i].categoria = revisioITV.categoria;
        revisionsITV[i].resultat = revisioITV.resultat;
        printf("\n");
    }

    /* Es mostren els resultats per pantalla */
    printf("Llistat de revisions realitzades: \n");
    for (i=0; i<MAX_REVISIONS; i++) {
        printf("\tVehicle: %s, categoria: %s, ITV: %s \n",
            revisionsITV[i].matricula,
            categories[revisionsITV[i].categoria],
            resultats[revisionsITV[i].resultat]);
    }
    return 0;
}

Un exemple d’execució pot ser el següent:

Matrícula: 7654-GFD
Categoria (2=moto, 4=cotxe, 5=furgoneta, 6=camió): 2
Resultat (1=favorable, 2=desfavorable, 0=negativa): 1

Matrícula: B-2189-FM
Categoria (2=moto, 4=cotxe, 5=furgoneta, 6=camió): 4
Resultat (1=favorable, 2=desfavorable, 0=negativa): 2

Matrícula: 566423
Categoria (2=moto, 4=cotxe, 5=furgoneta, 6=camió): 6
Resultat (1=favorable, 2=desfavorable, 0=negativa): 0

Llistat de revisions realitzades:
    Vehicle: 7654-GFD, categoria: moto, ITV: favorable
    Vehicle: B-2189-FM, categoria: cotxe, ITV: desfavorable
    Vehicle: 566423, categoria: camió, ITV: negativa

5.9 Exemple: conductors

Imaginem que tenim una empresa d’assegurances i volem penalitzar aquells conductors assegurats que hagin comès moltes infraccions de trànsit, independentment dels punts associats a cadascuna d’elles. Per trobar-los ens caldrà revisar tots els conductors, per tant estem davant d’un recorregut.

Una possible implementació en llenguatge C seria:

/* Exemple CA0509 */
#include <stdio.h>
#include <string.h>

#define MAX_CONDUCTORS 4
#define MAX_NOM 15+1

typedef struct{
    char nom[MAX_NOM];
    int numInfraccions;
} tConductor;


int main(int argc, char **argv) {

    tConductor conductors[MAX_CONDUCTORS];
    int minimInfraccions;
    int conductorsTrobats;
    int i;

    minimInfraccions = 0;
    conductorsTrobats = 0;

    for (i=0; i<MAX_CONDUCTORS; i++) {
        printf("Nom: ");
        scanf("%s", conductors[i].nom);
        printf("Número d'infraccions: ");
        scanf("%d", & conductors[i].numInfraccions);
    }

    printf("\nLímit mínim d'infraccions: ");
    scanf("%d", &minimInfraccions);


    /* Recorregut: a partir d'un valor mínim d'infraccions,
     * recorrem tot el vector de tConductor i comptabilitzem
     * aquells que com a mínim en tenen el mateix nombre. */
    for (i=0; i<MAX_CONDUCTORS; i++) {
        if (conductors[i].numInfraccions >= minimInfraccions) {
            conductorsTrobats++;
        }
    }
    printf("\n>> S'han trobat %d conductors amb un mínim de %d infraccions. \n", 
        conductorsTrobats, minimInfraccions);
    return 0;
}

Un exemple d’execució pot ser el següent:

Nom: Jan
Número d'infraccions: 2
Nom: Belén
Número d'infraccions: 3
Nom: Luis
Número d'infraccions: 5
Nom: Maria
Número d'infraccions: 5

Límit mínim d'infraccions: 3

>> S'han trobat 3 conductors amb un mínim de 3 infraccions.

5.10 Errors més freqüents

5.10.1 Definició de tipus: definició de tuples mal ubicada

Codi incorrecte:

#include <stdio.h>
#include <stdbool.h>

int main(int argc, char **argv) {
    typedef struct{
        int id;
        char brand[MAX_LEN];
        float price;
    } tHotel;

    tHotel myHotel;
    /* ... */
    return 0;
}

Els tipus de dades s’han de declarar al principi del bloc de codi, i fora de qualsevol funció (sigui el main o una altra), ja que els tipus són globals a tot el programa, i les variables associades als tipus es declaren posteriorment en cada una de les funcions on es necessiten.

Les tuples (struct) no en són una excepció i, per tant, no és correcte obrir un bloc de definició de tuples dins un bloc central de codi (i encara menys obrir diversos blocs de definició de tuples a mesura que els necessitem).

Codi correcte:

#include <stdio.h>
#include <stdbool.h>

typedef struct{
    int id;
    char brand[MAX_LEN];
    float price;
} tHotel;

int main(int argc, char **argv) {
    tHotel myHotel;
    /* ... */
    return 0;
}

5.10.2 Definició de tipus: definició mal ubicada

Codi incorrecte:

#include <stdio.h>
#include <stdbool.h>

int main(int argc, char **argv) {
    typedef enum {BUDGET, INN, RESORT} tTypeHotel;
    typedef enum {STANDARD, SUITE} tTypeRoom;

    tTypeHotel myHotelType;
    tTypeRoom myRoomType;
    
    myHotelType = BUDGET;
    myRoomType = STANDARD;
    /* ... */
    return 0;
}

Els tipus de dades s’han de declarar al principi del bloc de codi, i fora de qualsevol funció (sigui el main o una altra), ja que els tipus són globals a tot el programa, i les variables associades als tipus es declaren posteriorment en cada una de les funcions on es necessiten. No és correcte obrir un bloc de definició de tipus dins un bloc central de codi (i encara menys obrir diversos blocs de definició de tipus a mesura que els necessitem).

Codi correcte:

#include <stdio.h>
#include <stdbool.h>

typedef enum {BUDGET, INN, RESORT} tTypeHotel;
typedef enum {STANDARD, SUITE} tTypeRoom;

int main(int argc, char **argv) {
 
    tTypeHotel myHotelType;
    tTypeRoom myRoomType;
    
    myHotelType = BUDGET;
    myRoomType = STANDARD;
    /* ... */
    return 0;
}