4 PR1

4.1 Com tractar elements d’un vector amb un bucle

Imaginem que ens demanen un programa que realitzi dues accions:

  1. Llegir des del canal estàndard d’entrada (teclat) 5 números i introduir-los en un vector d’enters.
  2. Mostrar pel canal estàndard de sortida (pantalla) els 5 números del vector d’enters del punt anterior.

L’algorisme podria ser el següent:

const
    MAX_NUMS: integer = 5;
end const

algorithm vectorDeNumeros
    var
        i: integer;
        numeros: vector[MAX_NUMS] of integer;
    end var

    { Assignar valor a cada posició del vector des de teclat }
    for i := 1 to MAX_NUMS do
        writeString("Introdueix número : ");
        numeros[i] := readInteger();
    end for

    { Mostrar pel canal estàndard de sortida quin valor hi ha 
    a cada posició del vector: es podria haver utilitzat 
    un bucle for, però s'implementa amb un while perquè 
    es vegi que també és possible fer-ho. }
    i := 1;

    while i ≤ MAX_NUMS do
        writeString("La posició ");
        writeInteger(i);
        writeString(" del vector conté el número ");
        writeInteger(numeros[i]);

        { És molt important que amb un bucle while incrementem 
        la variable que utilitzem d'índex abans de finalitzar 
        tot el bloc d'instruccions que executa, ja que 
        en cas contrari el seu valor sempre seria i == 1. }
        i := i+1;
   end while

end algorithm

Com es pot veure, per tal d’insertar/llegir els elements d’un vector aprofitem la iteració d’un bucle per recórrer-los tots, un a un, mitjançant una variable que utilitzem d’índex (en aquests casos, la variable i).

La traducció a C de l’algorisme podria ser així:

/* Exemple CA0401 */
#include <stdio.h>
#define MAX_NUMS 5

int main(int argc, char **argv) {
    int numeros[MAX_NUMS];
    int i;

    /* Assignar valor a cada posició del vector des de teclat */
    for (i = 0; i < MAX_NUMS; i++) {
        printf("Introdueix número : ");
        scanf("%d", &numeros[i]);
    }

    /* Mostrar per pantalla quin valor hi ha a cada posició 
     * del vector: es podria haver utilitzat un bucle for, 
     * però ho implemento amb un while perquè es vegi 
     * que també és possible fer-ho.
     */
    i = 0;

    while (i < MAX_NUMS) {
        printf("\nLa posició %d del vector conté el número %d", i, numeros[i]);
        /* És molt important que amb un bucle while incrementem la variable 
         * que utilitzem d'índex abans de finalitzar tot el bloc d'instruccions 
         * que executa, ja que en cas contrari el seu valor sempre seria i == 0. 
         */
        i = i+1;
    }
    return 0;
}

4.2 Entrada contínua de valors amb un bucle

Imaginem que hem de fer un programa que vagi demanant números indefinidament i que finalitzi únicament en el cas que el número introduït sigui parell.

Una possible forma de fer-ho utilitzant un únic while seria la següent:

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

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

    /* Demanem una primera vegada el número a validar
     * just abans d'entrar al bucle. 
     */
    printf("Tecleja un número parell : ");
    scanf("%d", &numero);

    while ((numero % 2) != 0) {
        /* Entra al bucle en el cas que el
         * residu de la divisió per 2 sigui 
         * diferent de 0 (equival a no ser parell). 
         */
        printf("El número %d no és parell \n", numero);
        /* Tornem a demanar un número, ara ja
         * dins del bucle.
         */
        printf("Tecleja un número parell : ");
        scanf("%d", &numero);
    }
    printf("El número %d és parell \n", numero);
    return 0;
}

Abans d’entrar al bucle demanem el valor de la variable numero. Després s’utilitza la condició de bucle per validar si es tracta d’un número parell o senar:

  • Si el número es parell, no s’entra al bucle.
  • Si el número és senar es compleix la condició del bucle i s’hi entra; dins del bucle es torna a demanar un valor per la variable numero i es torna a actuar igual que abans:
    • Si és senar, no se surt del bucle.
    • En cas contrari, se surt del bucle.

Finalment es mostra per pantalla el missatge “El número X és parell”.

4.3 Com tractar valors en múltiples vectors

Imaginem que volem introduir per teclat una sèrie de dades dels treballadors de la nostra empresa: DNI, dies d’antiguitat i sou brut anual. Aquestes dades les introduïrem en tres vectors diferents: un pels DNI, l’altre per l’antiguitat i l’últim pel sou brut anual. El valor del sou net mensual es calcularà a partir del brut i es desarà també en un vector.

El programa ha de demanar per teclat les dades de 5 empleats, i en finalitzar mostrarà els valors per pantalla de la següent forma:

>> empleat: 39284019x
   antiguitat (dies): 784
   brut anual (€): 36874.78
   net mensual (€): 1659.36

>> empleat: 31214557m
   antiguitat (dies): 128
   brut anual (€): 20015.30
   net mensual (€): 1086.54

El sou net mensual es calcula aplicant la següent retenció, i posteriorment dividint per 14 pagues:

sou brut retenció
sou < 12450.0€ 19.0%
12450.0€ <= sou < 20200.0€ 24.0%
20200.0€ <= sou < 35200.0€ 30.0%
35200.0€ <= sou < 60000.0€ 37.0%
sou > 60000.0€ 45.0%

L’algorisme podria ser el següent:

const
    MAX_ELEMS: integer = 5;
    TRAM1: float = 12450.0;
    RETENCIO1: float = 19.0;
    TRAM2: float = 20200.0;
    RETENCIO2: float = 24.0;
    TRAM3: float = 35200.0;
    RETENCIO3: float = 30.0;
    TRAM4: float = 60000.0;
    RETENCIO4: float = 37.0;
    RETENCIO5: float = 45.0;
    NUM_PAGUES: integer = 14;
end const

algorithm dadesSous

    var
        vDni: vector[MAX_ELEMS] of string;
        vAntiguitat: vector[MAX_ELEMS] of integer;
        vBrutAnual: vector[MAX_ELEMS] of real;
        vNetMensual: vector[MAX_ELEMS] of real;
        i: integer;
    end var

    { La lectura de dades des del canal d'entrada. }
    { S'utilitza un únic índex, 'i', per recórrer tots els vectors. }
    for i := 1 to MAX_ELEMS do
        writeString("dades empleat num. ");
        writeInteger(i);
        writeString(":");
        writeString(">> dni : ");
        vDni[i] := readString();
        writeString(">> antiguitat : ");
        vAntiguitat[i] := readInteger();
        writeString(">> brut anual : ");
        vBrutAnual[i] := readReal();
        
        { Càlcul del sou net mensual }
        if (vBrutAnual[i] < TRAM1) then
            vNetMensual[i] := (vBrutAnual[i] - 
                (vBrutAnual[i]*RETENCIO1/100)) / NUM_PAGUES;
        else
            if (vBrutAnual[i] < TRAM2) then
                vNetMensual[i] := (vBrutAnual[i] - 
                    (vBrutAnual[i]*RETENCIO2/100)) / NUM_PAGUES;
            else
                if (vBrutAnual[i] < TRAM3) then
                    vNetMensual[i] := (vBrutAnual[i] - 
                        (vBrutAnual[i]*RETENCIO3/100)) / NUM_PAGUES;
                else
                    if (vBrutAnual[i] < TRAM4) then
                        vNetMensual[i] := (vBrutAnual[i] - 
                            (vBrutAnual[i]*RETENCIO4/100)) / NUM_PAGUES;
                    else
                        vNetMensual[i] := (vBrutAnual[i] - 
                            (vBrutAnual[i]*RETENCIO5/100)) / NUM_PAGUES;
                    end if
                end if
            end if
        end if
    end for
   
    { Es mostren les dades pel canal de sortida. }
    { S'utilitza un únic índex, 'i', per recórrer tots els vectors. }
    for i := 1 to MAX_ELEMS do
        writeString(">> empleat: ");
        writeString(vDni[i]);
        writeString("   antiguitat (dies): ");
        writeInteger(vAntiguitat[i]);
        writeString("   brut anual (€): ");
        writeInteger(vBrutAnual[i]);
        writeString("   net mensual (€): ");
        writeInteger(vNetMensual[i]);
    end for

end algorithm

Com ho podem implementar en C? Una possible solució seria la següent:

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

#define MAX_ELEMS 5
#define TRAM1 12450.0
#define RETENCIO1 19.0
#define TRAM2 20200.0
#define RETENCIO2 24.0
#define TRAM3 35200.0
#define RETENCIO3 30.0
#define TRAM4 60000.0
#define RETENCIO4 37.0
#define RETENCIO5 45.0
#define NUM_PAGUES 14
#define MAX_DNI 9+1

typedef char tDni[MAX_DNI];

int main(int argc, char **argv) {
    tDni vDni[MAX_ELEMS];
    int vAntiguitat[MAX_ELEMS];
    float vBrutAnual[MAX_ELEMS];
    float vNetMensual[MAX_ELEMS];
    int i;

    /* La lectura de dades des del teclat.
       S'utilitza un únic índex, i, per recórrer tots els vectors. */
    for (i = 0; i < MAX_ELEMS; i++) {
        printf("dades empleat num. %d : \n", i);
        printf(">> dni : ");
        scanf("%s", vDni[i]);
        printf(">> antiguitat : ");
        scanf("%d", &vAntiguitat[i]);
        printf(">> brut anual : ");
        scanf("%f", &vBrutAnual[i]);
        
        /* Càlcul del sou net mensual */
        if (vBrutAnual[i] < TRAM1) {
            vNetMensual[i] = (vBrutAnual[i] - 
                (vBrutAnual[i]*RETENCIO1/100)) / NUM_PAGUES;
        } else {
            if (vBrutAnual[i] < TRAM2) {
                vNetMensual[i] = (vBrutAnual[i] - 
                    (vBrutAnual[i]*RETENCIO2/100)) / NUM_PAGUES;
            } else {
                if (vBrutAnual[i] < TRAM3) {
                    vNetMensual[i] = (vBrutAnual[i] - 
                        (vBrutAnual[i]*RETENCIO3/100)) / NUM_PAGUES;
                } else {
                    if (vBrutAnual[i] < TRAM4) {
                        vNetMensual[i] = (vBrutAnual[i] - 
                            (vBrutAnual[i]*RETENCIO4/100)) / NUM_PAGUES;
                    } else {
                        vNetMensual[i] = (vBrutAnual[i] - 
                            (vBrutAnual[i]*RETENCIO5/100)) / NUM_PAGUES;
                    }
                }
            }
        }
    }
    
    /* Es mostren les dades per pantalla.
       S'utilitza un únic índex, i, per recórrer tots els vectors. */
    for (i = 0; i < MAX_ELEMS; i++) {
        printf("\n>> empleat: %s \n", vDni[i]);
        printf("   antiguitat (dies): %d \n", vAntiguitat[i]);
        printf("   brut anual (€): %.2f \n", vBrutAnual[i]);
        printf("   net mensual (€): %.2f \n", vNetMensual[i]);
    }
    return 0;
}

Dins del bucle utilitzem la variable i com a índex per anar recorrent tots els vectors alhora.

En els dos casos la inserció dels valors en els vectors la fem de la mateixa forma: utilitzem l’índex i per determinar la posició del vector on ubicarem els valors:

/* ... */
scanf("%s", vDni[i]);
/* ... */
scanf("%d", &vAntiguitat[i]);
/* ... */
scanf("%f", &vBrutAnual[i]);

Al final de l’exemple mostrem tots els empleats introduïts mitjançant un segon bucle, mostrant totes les dades introduïdes anteriorment i les calculades.

4.4 Definició chars vs strings

En el llenguatge C, els caràcters es defineixen sempre amb cometa simple ', mentre que pels string s’utilitza la cometa doble ".

Exemple:

/* Exemple CA0404 */
#include <stdio.h>
#include <string.h>
#define MAX_PARAULA 8+1

int main(int argc, char **argv) {
    char salutacio[MAX_PARAULA];
    char exclamacio;
    
    /* Assignació de valor a un string amb cometa doble. */
    strcpy(salutacio, "Hi World");
    /* Assignació de valor a un char amb cometa simple. */
    exclamacio = '!';

    printf("%s %c\n", salutacio, exclamacio);
    return 0;
}

4.5 Variable-sized object may not be initialized

L’error variable-sized object may not be initialized es produeix quan definim la mida d’un vector amb const i a la vegada estem inicialitzant el vector amb valors:

const int NUM_JUGADORS = 5;
/* ... */
int vDorsalsEquip[NUM_JUGADORS] = {1, 3, 23, 12, 99};  /* cas que genera error */

Però en canvi, si realitzem la mateixa operació utilitzant #define, funciona correctament:

#define NUM_JUGADORS 5
/* ... */
int vDorsalsEquip[NUM_JUGADORS] = {1, 3, 23, 12, 99};  /* cas sense error */

El motiu és el comportament de l’array quan rep una constant o bé una variable (en aquest punt és reconamable revisar el punt Constants: define vs const de les FAQ). Comentem els dos casos més detalladament:

Cas sense error

Quan utilitzem #define NUM_JUGADORS 5 per definir una constant significa que en els passos previs a la compilació del programa (fase de precompilació) es realitza una substitució de totes les referències de NUM_JUGADORS pel valor 5. D’aquesta forma, en el moment de compilar el programa, ja s’està treballant amb un valor constant, 5, que pot ser avaluat i, per tant, permet realitzar la inicialització dels 5 valors que li passem:

int vDorsalsEquip[5] = {1, 3, 23, 12, 99};

Cas amb error

Quan utilitzem const int NUM_JUGADORS = 5; no estem definint realment una constant, sinó que es defineix la variable NUM_JUGADORS en memòria i se li assigna el valor 5, amb la particularitat que la variable és read-only. Malgrat tot, aquest tipus no és interpretat pel compilador com a equivalència d’una constant.

Per tant, ens trobem que volem fer la següent operació utilitzant la variable read-only NUM_JUGADORS:

int vDorsalsEquip[NUM_JUGADORS] = {1, 3, 23, 12, 99};

Quan a un vector se li defineix la mida amb una variable, és tractada en el moment d’execució, una vegada el programa s’ha compilat. Per tant, en el moment que el compilador està generant l’executable del nostre programa en C, detecta una situació en la que, d’una banda es vol inicialitzar un array amb 5 valors (1, 3, 23, 12, 99), però d’altra banda s’està concretant la mida del vector amb una variable read-only de la que no se sabrà el valor fins que s’hagi passat la fase de compilació. Aquesta incongruència temporal és la que no pot gestionar el compilador i acaba generant l’error variable-sized object may not be initialized.

Per aquest motiu, falla el cas que acabem de comentar, però en canvi el següent funciona correctament tot i utilitzar-se const:

const int NUM_JUGADORS = 5;
/* ... */
int vDorsalsEquip[NUM_JUGADORS];
/* cas sense error */
vDorsalsEquip[0] = 1;
vDorsalsEquip[1] = 3;
vDorsalsEquip[2] = 23;
vDorsalsEquip[3] = 12;
vDorsalsEquip[4] = 99;

4.6 Exemple: mitjanaPes

Imaginem que volem fer un programa que ens ajudi a calcular el nostre pes promig setmanal. Afegirem per teclat les mesures diàries del nostre pes al programa i, en cas de trobar algun valor incoherent, l’obviarà i el tornarà a demanar.

En llenguatge algorísmic ho podem implementar de la següent forma:

const
    NUM_DIES: integer = 7;
    PES_MIN: real = 50.0;
    PES_MAX: real = 110.0;
end const

algorithm mitjanaPes

    var
        i: integer;    { Comptador que utilitzarà el nostre programa. }
        pes: real;     { Variable auxiliar per la lectura de pesos. }
        pesos: vector[NUM_DIES] of real;   { Pes en Kg: 79.5, ... }
        sumaPesos: real;
    end var

    i := 1;
    sumaPesos := 0;

    { Es llegeix des de teclat els pesos diaris, un a un. }
    while i ≤ NUM_DIES do

        { Llegim un valor des del canal estàndard d'entrada. }
        writeString("Introdueix pes (Kg.) : ");
        pes := readReal();

        { A continuació cal revisar que aquest valor sigui coherent. Prenem 
        com a valors "possibles" aquells que estiguin entre PES_MIN i PES_MAX. 
        Fixeu-vos que la lectura es desa temporalment a la variable 'pes': 
        quan haguem validat que contingui un valor vàlid, l'afegirem dins 
        del vector de pesos. }

        if PES_MIN ≤ pes and pes ≤ PES_MAX then
            { En aquest punt, la variable 'pes' conté un valor correcte, 
            amb el que ja el podem afegir al vector de pesos. }
            pesos[i] := pes;

            { El següent punt és molt important: com que ja hem afegit 
            el pes correcte, incrementarem la variable 'i', la qual ens serveix 
            per accedir a una nova posició del vector a la següent iteració 
            del bucle. }
            i = i + 1;

        else
            { En cas contrari, el pes es incorrecte amb el que mostrem 
            el corresponent missatge d'error. }
            writeString("Pes incorrecte!");

            { Important: aquí no incrementem la variable 'i', ja que el valor 
            no és correcte; volem que en la següent iteració del bucle, 
            es continuï intentant afegir el valor llegit dins de la 
            posició 'i' del vector. }

        end if

        { En aquest punt tenim el pesos que té 7 (=NUM_DIES) pesos vàlids. }

        { Ara utilitzarem un segon bucle per recórrer tots els valors del 
        vector i fer el càlcul demanat: la mitjana de tots ells. Si haguéssim 
        volgut, ho hauríem pogut fer tot en un únic bucle, però s'ha preferit 
        separar-ho perquè quedi més clar què es fa dins de cadascun dels 
        dos bucles. }

        for i := 1 to NUM_DIES do

            { Dins de la variable sumaPesos hi anem sumant cadascun dels pesos
            de les posicions del vector. }
            sumaPesos := sumaPesos + pesos[i];
       
        end for

        { Per calcular la mitjana, únicament ens falta dividir el valor 
        sumaPesos pel número total de pesos introduïts o, el que és el mateix, 
        NUM_DIES. }
        writeString("La mitjana setmanal del pes és : ");
        writeReal(sumaPesos / NUM_DIES);

end algorithm

Una possible implementació en llenguatge C pot ser la següent:

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

#define NUM_DIES 7
#define PES_MIN 50.0
#define PES_MAX 110.0

int main (int argc, char **argv){
    float pesos[NUM_DIES];
    int i;
    float pes;
    float sumaPesos;

    i = 0; /* Important! en llenguatge C els vectors comencen pel 0 */
    sumaPesos = 0;

    /* Primer bucle: introducció i validació de dades */
    while (i<NUM_DIES) {

        printf("Introdueix pes (Kg.) : ");
        scanf("%f", &pes);

        if (PES_MIN <= pes && pes <= PES_MAX) {
            pesos[i] = pes;
            i = i+1;
        } else {
            printf("Pes incorrecte!\n");
        }
    }

    /* Segon bucle: càlcul intermig per la mitjana de pesos */
    for (i=0; i<NUM_DIES; i++) {
        sumaPesos = sumaPesos + pesos[i];
    }

    printf("La mitjana setmanal del pes és : %.2f", sumaPesos/NUM_DIES);
}

4.7 Exemple: topFilms

A continuació s’exposa un exemple en el qual es recorren vectors i calculen resultats en funció d’una sèrie de filtres.

Imaginem que tenim un llistat amb el top 10 de pel·lícules amb més recaptació de la història. De cada pel·lícula sabem el seu ordre en el top 10 (actuarà com a identificador únic de cada pel·lícula), el nom, la recaptació i l’any. Volem que, donats un any i una xifra de recaptació entrats per teclat, es mostrin per pantalla aquelles pel·lícules que siguin del mateix any i acumulin una recaptació superior o igual a la xifra introduida.

Una possible implementació en llenguatge C seria la següent:

/* Exemple CA0406 */
#include <stdio.h>
#define TOP_FILMS 10

int main(int argc, char **argv) {
    /* Declaració de variables */
    /* Vectors */
    int posicions[TOP_FILMS];    /* Conté l'ordre de pel·lícules amb més recaptació. */
    char* titols[TOP_FILMS];     /* Conté els títols de les pel·lícules */
    int anys[TOP_FILMS];         /* Conté els anys de les pel·lícules */ 
    int recaptacions[TOP_FILMS]; /* Conté les recaptacions (en milions US$) */

    int recaptacio;  /* Filtre per cercar pel·lícules amb >= recaptació */
    int any;         /* Filtre per cercar pel·lícules amb == any */
    int posicionsTrobades[TOP_FILMS]; /* Conté l'ordre de les pel·lícules trobades */
    int numFilmsTrobats; /* Comptador de pel·lícules trobades */
    int i;

    /* Inicialització de variables */
    numFilmsTrobats = 0;

    /* Dades de recaptació extretes de https://cutt.ly/iRs0N9v */

    /* Per tal de centrar-nos en els recorreguts dels vectors
     * i cercar les pel·lícules que compleixen una sèrie de
     * requisits, s'introdueixen directament els valors als
     * corresponents vectors, sense passar per la lectura
     * des de teclat.
     */
    posicions[0] = 1;
    posicions[1] = 2;
    posicions[2] = 3;
    posicions[3] = 4;
    posicions[4] = 5;
    posicions[5] = 6;
    posicions[6] = 7;
    posicions[7] = 8;
    posicions[8] = 9;
    posicions[9] = 10;

    titols[0] = "Avengers: Endgame";
    titols[1] = "Avatar";
    titols[2] = "Titanic";
    titols[3] = "Star Wars: El despertar de la força";
    titols[4] = "Avengers: Infinity War";
    titols[5] = "Jurassic World";
    titols[6] = "The Avengers";
    titols[7] = "Furious 7";
    titols[8] = "Avengers: Age of Ultron";
    titols[9] = "Black Panther";

    anys[0] = 2019;
    anys[1] = 2009;
    anys[2] = 1997;
    anys[3] = 2015;
    anys[4] = 2018;
    anys[5] = 2015;
    anys[6] = 2012;
    anys[7] = 2015;
    anys[8] = 2015;
    anys[9] = 2018;

    recaptacions[0] = 2797;
    recaptacions[1] = 2789;
    recaptacions[2] = 2187;
    recaptacions[3] = 2068;
    recaptacions[4] = 2048;
    recaptacions[5] = 1671;
    recaptacions[6] = 1518;
    recaptacions[7] = 1516;
    recaptacions[8] = 1405;
    recaptacions[9] = 1346;

    /* Per teclat es demanen dos filtres per recórrer totes les pel·lícules i
     * trobar les que compleixen les condicions: l'any de creació (ha de ser
     * igual) i la recaptació (ha de ser igual o superior)
     */
    printf("Any: ");
    scanf("%d", &any);
    printf("Recaptació mínima (en milions US$): ");
    scanf("%d", &recaptacio);

    /* En aquest cas hem omplert les 10 posicions màximes dels vectors,
     * amb el que podem utilitzar TOP_FILMS com a límit d'elements a
     * recórrer en els vectors. Si no hagués estat així, caldria utilitzar
     * un comptador addicional que indiqués el número de pel·lícules
     * introduïdes.
     */
    for (i=0; i<TOP_FILMS; i++) {
        /* Es comprova que la pel·lícula tractada compleixi les
         * condicions entrades per teclat
         */
        if (anys[i] == any && recaptacions[i] >= recaptacio) {
            posicionsTrobades[numFilmsTrobats] = posicions[i];
            numFilmsTrobats = numFilmsTrobats + 1;
        }
    }

    /* Sortida de resultats per pantalla */
    if (numFilmsTrobats > 0) {
        printf("Pel·lícules trobades = %d: \n", numFilmsTrobats);
        for (i=0; i<numFilmsTrobats; i++) {
            printf("%d. %s (%d): %d M$\n", posicionsTrobades[i], 
                titols[posicionsTrobades[i]-1], anys[posicionsTrobades[i]-1], 
                recaptacions[posicionsTrobades[i]-1]);
        }
    } else {
        printf("Pel·lícules trobades = %d: cap compleix les condicions.\n", 
            numFilmsTrobats);
    }
    return 0;
}

Un exemple d’execució seria el següent:

Any: 2015
Recaptació mínima (en milions US$): 1500
Pel·lícules trobades = 3:
4. Star Wars: El despertar de la força (2015): 2068 M$
6. Jurassic World (2015): 1671 M$
8. Furious 7 (2015): 1516 M$

4.8 Errors més freqüents

4.8.1 Estructura iterativa: for vs while

Aquest no és un error sintàctic o semàntic, sinó un error de disseny freqüent.

Codi incorrecte:

#include <stdio.h>
#include <stdbool.h>
#define NUM 10

int main(int argc, char **argv) {
    int i;
    char password[NUM] = {'a', '1', 'h', '\0'};
    
    for (i = 0; password[i] != '\0'; i++){
        /* ... */
    }
    return 0;
}

En el codi anterior, sembla que volem recórrer un vector de caràcters element a element, per executar alguna acció. Per fer-ho, decidim utilitzar un bucle i una condició final: les iteracions s’aturaran en el moment en què ens trobem amb el caràcter especial '\0', finalitzador de cadena de caràcters.

El problema és que el bucle for no és l’estructura més indicada per resoldre aquest algorisme, ja que està pensat per repetir un bloc de codi un nombre de vegades predeterminat, basat gairebé sempre en un índex (i) que s’ha d’incrementar/decrementar des d’un valor inicial a un de final. En aquest cas, la condició final no té res a veure amb el valor numèric de l’índex i, per tant, és molt millor utilitzar el bucle while.

Codi correcte:

#include <stdio.h>
#include <stdbool.h>
#define NUM 10

int main(int argc, char **argv) {
    int i;
    char password[NUM] = {'a', '1', 'h', '\0'};
    i = 0;
    while (password[i] != '\0'){
        /* ... */
    i++;
    }
    return 0;
}

És important recordar que en el cas de l’estructura while, l’índex i no s’actualitza automàticament: cal fer-ho manualment abans de tancar el bloc.

4.8.2 Vectors: accés a posicions del vector

Pseudocodi incorrecte:

const
    MAX: integer = 3;
end const

var
    vecNum: vector[MAX] of integer;
end var

vecNum[4] := 3;

En llenguatge algorísmic, un vector de dimensió N té les posicions numerades d’1 a N. En canvi, en llenguatge C les posicions estan numerades de 0 a N-1.

El vector vecNum té tres posicions, però estem accedint a la quarta (inexistent). És un error greu, especialment en C, ja que els accessos a posicions de vector no declarades poden comportar errors d’execució, tot i que en el moment de compilar el codi no es produeixi cap error.

Quan utilitzem vectors, en cas d’errors d’execució inesperats i sense motiu aparent, sempre cal revisar el codi per comprovar que no s’està accedint a posicions incorrectes. És especialment important en el cas dels bucles iteratius, on l’accés als elements del vector es fa mitjançant l’ús d’una variable.

Pseudocodi correcte:

const
    MAX: integer = 3;
end const

var
    vecNum: vector[MAX] of integer;
end var

vecNum[3] := 3;