// adreces de memòria

Apuntadors en C

El que els paràmetres per valor no podien fer: una funció que de debò modifica les variables de qui la crida. I, amb això, vectors com a paràmetre i el primer algorisme d'ordenació.

Adreces de memòria i apuntadors

Cada variable viu en algun lloc concret de la memòria del programa: la seva adreça. Un apuntador és una variable que, en lloc de guardar un número o un caràcter, guarda una adreça.

Els dos símbols nous

SímbolSignificat
&x"l'adreça de x" — on viu x a la memòria
*p"el valor al qual apunta p" — el contingut d'aquella adreça

Exemple

int x = 42;
int *p;      // p és un apuntador a int

p = &x;      // p ara guarda l'adreça de x

printf("%d\n", x);    // 42
printf("%d\n", *p);   // 42 — el mateix, a través de p

int *p; declara p com "un apuntador a un int": p no guardarà mai directament un 42, sinó l'adreça d'algun int que el val 42. *p (desreferenciar) et porta fins a aquell valor.

Per fi: una funció que intercanvia de debò

Recordes incrementa(int n) del capítol de funcions? Rebia una còpia i mai tocava la variable original. Amb apuntadors, una funció pot rebre l'adreça d'una variable i modificar-la de debò.

Exemple

void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

int main() {
    int x = 5;
    int y = 8;

    swap(&x, &y);
    printf("x=%d y=%d\n", x, y);

    return 0;
}

La sortida és x=8 y=5: s'han intercanviat de debò. swap no rep els valors 5 i 8, sinó les adreces de x i y; *a = *b no canvia el paràmetre a, canvia el que hi ha a l'adreça on apunta a — és a dir, x mateixa.

Fixa't en el patró: igual que scanf("%d", &edat) necessitava & perquè havia d'escriure un valor a la variable del cridant, qualsevol funció que vulgui modificar una variable de qui la crida necessita la seva adreça.

Vectors com a paràmetre

A diferència d'un int, un vector mai es copia quan el passes a una funció: la funció rep accés directe a les mateixes cel·les de l'original.

Exemple

int suma_vector(int v[], int mida) {
    int i, suma = 0;

    for (i = 0; i < mida; i++) {
        suma = suma + v[i];
    }

    return suma;
}

int v[] com a paràmetre no crea una còpia del vector: per sota, el que realment es passa és l'adreça de la primera cel·la (per això sol caldre passar també mida: el vector, un cop dins la funció, ja no "sap" quants elements té). Com que no hi ha còpia, si la funció escriu a v[i], modifica el vector original — això és exactament el que farà l'ordenació.

Ordenació: el mètode de la bombolla

Amb vectors com a paràmetre, ja podem escriure una funció que ordeni un vector de debò, modificant-lo des de dins.

La idea

Es recorre el vector comparant parelles d'elements consecutius; si estan desordenats, s'intercanvien. Repetint prou voltes, els elements més grans van "pujant" cap al final, com bombolles.

Exemple

void bombolla(int v[], int mida) {
    int i, j, temp;

    for (i = 0; i < mida - 1; i++) {
        for (j = 0; j < mida - 1 - i; j++) {
            if (v[j] > v[j + 1]) {
                temp = v[j];
                v[j] = v[j + 1];
                v[j + 1] = temp;
            }
        }
    }
}

El bucle de fora (i) compta les passades; el de dins (j) recorre el vector comparant v[j] amb v[j+1]. Cada passada deixa un element més "col·locat" al final, per això el bucle de dins es va escurçant (mida - 1 - i). L'intercanvi és exactament el swap de més amunt, fet a mà sobre dues cel·les.

Mira el programa executar-se pas a pas

Fixa't en com el vector del panell "Vector" va canviant quan la funció hi escriu — la prova que no treballa amb cap còpia.

Apuntadors

Vectors i funcions

Codi

Variables

NomValor

Vector

Terminal

Pas 1 / 1

Problemes per resoldre

Sense solució ni comprovació automàtica: escriu el programa, compila'l (gcc programa.c -o programa) i prova'l amb els exemples. Les pistes són plegades perquè les obris només si les necessites.

1. Intercanviar dos decimals

Escriu una funció swap_double(double *a, double *b) que intercanviï els valors de dues variables double. Demana dos nombres decimals, mostra'ls, intercanvia'ls i torna'ls a mostrar.

Primer: 2.5
Segon: 7.1
Abans: 2.50 7.10
Després: 7.10 2.50
Pistes

És exactament el swap de la teoria, canviant int per double a tot arreu (paràmetres, temp...).

Crida-la com swap_double(&a, &b); — no t'oblidis del &.

2. El màxim d'un vector

Escriu una funció maxim(int v[], int mida) que retorni el valor més gran del vector. Prova-la amb un vector d'uns quants enters escrits directament al codi (no cal demanar-los a l'usuari).

El màxim és: 9
Pistes

Comença suposant que el màxim és v[0], i recorre la resta del vector comparant cada element amb el candidat actual.

Aquí no cal modificar el vector: n'hi ha prou de llegir-lo, així que la funció el pot rebre i prou, sense necessitat de return cap altra cosa que el màxim trobat.

3. Ordenació per selecció

Escriu una funció seleccio(int v[], int mida) que ordeni el vector amb un algorisme diferent de la bombolla: a cada passada, busca l'element més petit de la part encara no ordenada i l'intercanvia amb el primer d'aquesta part.

Abans:   5 2 4 1
Després: 1 2 4 5
Pistes

Bucle de fora i de 0 a mida-2: a cada volta, busca l'índex del mínim entre v[i] i v[mida-1] (un bucle de dins, com a l'exercici 2, però guardant l'índex, no el valor).

Un cop trobat l'índex del mínim, intercanvia'l amb v[i] — igual que a la bombolla, fes-ho amb una variable temp.

4. Invertir un vector

Escriu una funció invertir(int v[], int mida) que giri l'ordre dels elements del vector (el primer passa a ser l'últim, i així), modificant-lo directament — sense crear-ne cap altre.

Abans:   1 2 4 5
Després: 5 4 2 1
Pistes

Intercanvia l'element 0 amb el darrer, l'1 amb el penúltim, i així, parant-te a la meitat (si segueixes després de creuar-te, desfaries la feina).

Amb dos índexs esquerra (comença a 0) i dreta (comença a mida-1) que s'acosten: intercanvia v[esquerra] amb v[dreta] i avança'ls fins que esquerra >= dreta.

Exercicis d'autoavaluació

Aquests es generen amb valors nous a l'atzar i tenen solució comprovable.

—

Quina serà la sortida per terminal d'aquest programa?