3  Estructures de control

Objectius

  • Recordar que tot algorisme es pot construir amb tres tipus d’estructures.
  • Dominar les estructures de selecció (prendre decisions).
  • Dominar les estructures de repetició (bucles).
  • Conèixer les estructures de salt i quan (no) usar-les.
  • Introduir el control d’excepcions i les assercions.

3.1 Els tres pilars de tot algorisme

El teorema del programa estructurat ens diu que qualsevol algorisme, per complex que sigui, es pot escriure combinant només tres estructures:

  1. Seqüència: fer les coses una darrere l’altra.
  2. Selecció: triar entre camins segons una condició.
  3. Repetició: repetir accions mentre calgui.

A nivell visual, ho podem representar així:

%%{init: {"flowchart": {"nodeSpacing": 120}}}%%

%%| fig-align: center
%%{init: {"flowchart": {"nodeSpacing": 120}}}%%

%%| fig-align: center
flowchart TB
    %% Orden invers: workaround del bug de Mermaid #7741 (els subgrafs
    %% germans sense arestes es mostren a l'inrevés de la definició).
    subgraph Repetició
        direction TB
        Q{Condició?} -->|Cert| AC[Acció]
        AC --> Q
        Q -->|Fals| FI[Continua]
    end
    subgraph Selecció
        direction TB
        C{Condició?} -->|Cert| A[Acció A]
        C -->|Fals| B[Acció B]
    end
    classDef noBox fill:none,stroke:none;
    class Selecció,Repetició noBox;

Amb aquestes estructures i les variables, es pot programar qualsevol cosa.

3.2 Estructures de selecció

La selecció simple: SI

Executa unes instruccions només si una condició és certa.

    SI edat >= 18 LLAVORS
        ESCRIURE "Ets major d'edat"
    FI_SI

flowchart TB
    A[Inici] --> C{edat >= 18?}
    C -->|Cert| B["ESCRIURE major d'edat"]
    C -->|Fals| D[Continua]
    B --> D

La selecció doble: SI ... SI_NO

Un camí si es compleix, un altre si no.

    SI nota >= 5 LLAVORS
        ESCRIURE "Aprovat"
    SI_NO
        ESCRIURE "Suspès"
    FI_SI

flowchart TB
    A[Inici] --> C{nota >= 5?}
    C -->|Cert| B["ESCRIURE Aprovat"]
    C -->|Fals| E["ESCRIURE Suspès"]
    B --> D[Continua]
    E --> D

Seleccions encadenades: SI_NO_SI

Per triar entre més de dues opcions.

SI nota >= 9 LLAVORS
    ESCRIURE "Excel·lent"
SI_NO_SI nota >= 7 LLAVORS
    ESCRIURE "Notable"
SI_NO_SI nota >= 5 LLAVORS
    ESCRIURE "Aprovat"
SI_NO
    ESCRIURE "Suspès"
FI_SI

flowchart TB
    A[Inici] --> C1{nota >= 9?}
    C1 -->|Cert| B["ESCRIURE Excel·lent"]
    C1 -->|Fals| C2{nota >= 7?}
    C2 -->|Cert| D["ESCRIURE Notable"]
    C2 -->|Fals| C3{nota >= 5?}
    C3 -->|Cert| E["ESCRIURE Aprovat"]
    C3 -->|Fals| G["ESCRIURE Suspès"]
    B --> FI[Continua]
    D --> FI[Continua]
    E --> FI[Continua]
    G --> FI[Continua]

L’ordre de les condicions importa Les condicions es comproven de dalt a baix i s’atura a la primera certa. Si posessis nota >= 5 abans que nota >= 9, un 10 entraria per “Aprovat” i mai arribaria a “Excel·lent”. Ordena sempre de la condició més restrictiva a la més general.

La selecció múltiple: SEGONS

Quan comparem una variable amb valors concrets, és més net que un SI encadenat.

SEGONS diaSetmana FER
    CAS 1: ESCRIURE "Dilluns"
    CAS 2: ESCRIURE "Dimarts"
    ...
    CAS 6, 7: ESCRIURE "Cap de setmana"
    PER_DEFECTE: ESCRIURE "Dia no vàlid"
FI_SEGONS

flowchart TB
    A[Inici] --> C{diaSetmana}
    C -->|1| B["ESCRIURE Dilluns"]
    C -->|2| D["ESCRIURE Dimarts"]
    C -->|...| H["..."]
    C -->|6, 7| E["ESCRIURE Cap de setmana"]
    C -->|PER_DEFECTE| F["ESCRIURE Dia no vàlid"]
    B --> FI[Continua]
    D --> FI[Continua]
    H --> FI[Continua]
    E --> FI[Continua]
    F --> FI[Continua]

En Java això serà el switch. Serveix per a valors discrets (números, caràcters, cadenes), no per a rangs (nota >= 5), on cal el SI.

3.3 Estructures de repetició (bucles)

Un bucle repeteix un bloc d’instruccions. Cada volta s’anomena iteració.

Hi ha tres formes bàsiques; totes són equivalents en potència, però cada una encaixa millor segons el cas.

MENTRE: repetir mentre es compleixi (0 o més cops)

Comprova la condició abans de cada iteració. Si de bon principi és falsa, no s’executa mai.

    i ← 1
    MENTRE i <= 5 FER
        ESCRIURE i
        i ← i + 1
    FI_MENTRE

flowchart TB
    A["i ← 1"] --> C{i <= 5?}
    C -->|Cert| B["ESCRIURE i"]
    B --> D["i <- i + 1"]
    D --> C
    C -->|Fals| E[Fi]

El malson del bucle infinit Si dins del MENTRE oblides modificar la variable de la condició (aquí, i <- i + 1), la condició mai es fa falsa i el programa no s’atura mai. És l’error més comú amb bucles. Regla d’or: en escriure un MENTRE, comprova immediatament què fa que acabi.

FES ... MENTRE: repetir almenys un cop

Comprova la condició al final, així que el cos s’executa com a mínim una vegada. Ideal per validar entrades (demanar fins que sigui correcte).

    FES
        ESCRIURE "Introdueix un número positiu:"
        LLEGIR n
    MENTRE n <= 0

PER A: quan saps quantes voltes

Quan coneixes el nombre d’iteracions per endavant. Gestiona el comptador sol.

    PER A i DES DE 1 FINS A 10 FER
        ESCRIURE i
    FI_PER

Bucles aniuats

Un bucle dins d’un altre. Per exemple, per dibuixar una graella o recórrer una taula:

    PER A fila DES DE 1 FINS A 3 FER
        PER A columna DES DE 1 FINS A 4 FER
            ESCRIURE "*"          
        FI_PER
        SALT_DE_LÍNIA
    FI_PER

Resultat:

    ****
    ****
    ****
NotaQuin bucle triar?
  • PER A: sé exactament quantes voltes (recórrer 1..N, els elements d’una llista).
  • MENTRE: repeteixo mentre una condició es compleixi, sense saber quants cops (llegir fins que arribi un 0, per exemple).
  • FES...MENTRE: com el MENTRE, però necessito almenys una execució (menús, validar dades).

3.4 Estructures de salt

Modifiquen el flux normal dels bucles:

  • TRENCAR (break): surt immediatament del bucle.
  • CONTINUAR (continue): salta a la següent iteració, sense acabar l’actual.

Exemple de TRENCAR: esperem l’entrada de 10 valors numèrics. Si s’entra un 0 ha d’acabar l’execució del bucle.

    C ← 0
    PER A i DES DE 1 FINS A 10 FER
        LLEGIR num
        SI num = 0 LLAVORS
            TRENCAR           // 0 = final de les dades
        FI_SI
        C ← C + 1
    FI_PER
    ESCRIURE "Números llegits:", C

flowchart TB
    A[Inici: C ← 0] --> LOOP{i <= 10?}
    LOOP -->|Fals| FI["ESCRIURE C"]
    LOOP -->|Cert| R["LLEGIR num"]
    R --> Z{num = 0?}
    Z -->|TRENCAR el bucle| FI
    Z -->|Fals| INC[C ← C + 1]
    INC --> LOOP


Exemple de CONTINUAR: esperem l’entrada de 5 notes. Els valors fora que no estiguin entre 1 i 10 no són vàlids: els ignorem i passem a la següent iteració del bucle.

    C ← 0
    PER A i DES DE 1 FINS A 5 FER
        LLEGIR num
        SI num < 1 O num > 10 LLAVORS
            CONTINUAR         // fora de rang, l'ignorem
        FI_SI
        C ← C + 1
    FI_PER
    ESCRIURE "Números vàlids:", C

flowchart TB
    A[Inici: C ← 0] --> LOOP{i <= 5?}
    LOOP -->|Fals| FI["ESCRIURE C"]
    LOOP -->|Cert| R["LLEGIR num"]
    R --> V{num < 1 o num > 10?}
    V -->|CONTINUAR: propera iteració| LOOP
    V -->|Fals| INC[C ← C + 1]
    INC --> LOOP

NotaRecomanacions sobre els salts
  • TRENCAR i CONTINUAR són útils, però abusar-ne fa el codi difícil de seguir.
  • Existeix també el GOTO (saltar a qualsevol línia), però està prohibit de facto: genera “codi espagueti” impossible de mantenir. No el farem servir mai.

3.5 Control d’excepcions

Fins ara hem suposat que tot va bé. Però… i si l’usuari escriu “hola” quan demanem un número? I si intentem dividir per zero? Aquestes situacions anòmales s’anomenen excepcions.

Una excepció és un esdeveniment que interromp el flux normal perquè ha passat alguna cosa inesperada. En lloc de deixar que el programa “peti”, podem capturar-la i reaccionar-hi amb una estructura INTENTA ... CAPTURA:

    INTENTA
        resultat ← a / b
    CAPTURA divisióPerZero
        ESCRIURE "Error: no es pot dividir per zero"
    FI_INTENTA

flowchart TB
    A[INTENTA: codi que pot fallar] --> C{Hi ha error?}
    C -->|No| OK[Continua normal]
    C -->|Sí| H[CAPTURA: gestiona l'error]
    H --> OK

NotaProgramació robusta

Un programa professional no confia en què les dades siguin correctes. Preveu què pot anar malament i ho gestiona amb elegància.

3.6 Documentació

Un programa ben documentat s’entén sense haver de desxifrar-lo.

La documentació inclou:

  • Comentaris al codi (el perquè).
  • Noms clars de variables i funcions (documentació implícita).
  • Documentació externa: manuals, README,…