Introducció al llenguatge de programació...

55
Introducció al llenguatge de programació C Jordi Salvador Pont Curs 2009–2010

Transcript of Introducció al llenguatge de programació...

Page 1: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

Introducció al llenguatge de programació C

Jordi Salvador Pont

Curs 2009–2010

Page 2: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

ii

Page 3: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

Índex

Introducció 1

1 Dades fonamentals en C 31.1 Introducció . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31.2 Els tipus enters . . . . . . . . . . . . . . . . . . . . . . . . . . 3

1.2.1 El tipus int . . . . . . . . . . . . . . . . . . . . . . . . 31.2.2 El tipus booleà . . . . . . . . . . . . . . . . . . . . . . 41.2.3 El tipus char . . . . . . . . . . . . . . . . . . . . . . . 41.2.4 Altres tipus enters . . . . . . . . . . . . . . . . . . . . 41.2.5 Tipus enters sense signe . . . . . . . . . . . . . . . . . 5

1.3 Els tipus reals . . . . . . . . . . . . . . . . . . . . . . . . . . . 51.4 Assignació de variables . . . . . . . . . . . . . . . . . . . . . . 6

1.4.1 Assignació de variables enteres . . . . . . . . . . . . . 61.4.2 Assignació de variables reals . . . . . . . . . . . . . . . 71.4.3 Assignació de variables enteres amb reals . . . . . . . 71.4.4 Assignació múltiple . . . . . . . . . . . . . . . . . . . . 7

1.5 Inicialitzar variables . . . . . . . . . . . . . . . . . . . . . . . 81.6 Més enllà dels tipus simples . . . . . . . . . . . . . . . . . . . 8

2 Control de flux 112.1 Introducció . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112.2 Sentència condicional . . . . . . . . . . . . . . . . . . . . . . . 122.3 Sentència while . . . . . . . . . . . . . . . . . . . . . . . . . 142.4 Sentència do . . . . . . . . . . . . . . . . . . . . . . . . . . . 152.5 Sentència for . . . . . . . . . . . . . . . . . . . . . . . . . . . 152.6 Sentència switch . . . . . . . . . . . . . . . . . . . . . . . . . 162.7 Entrada i sortida . . . . . . . . . . . . . . . . . . . . . . . . . 17

2.7.1 Sortida per pantalla . . . . . . . . . . . . . . . . . . . 172.7.2 Entrada per teclat . . . . . . . . . . . . . . . . . . . . 19

3 Tipus agregats de dades 213.1 Introducció . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213.2 Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

iii

Page 4: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

3.2.1 Introducció als arrays . . . . . . . . . . . . . . . . . . 213.2.2 Inicialització d’arrays . . . . . . . . . . . . . . . . . . 223.2.3 Arrays de caràcters . . . . . . . . . . . . . . . . . . . . 23

3.3 Treballar amb cadenes . . . . . . . . . . . . . . . . . . . . . . 233.4 Structs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

3.4.1 Arrays de structs . . . . . . . . . . . . . . . . . . . . . 263.5 Array d’arrays . . . . . . . . . . . . . . . . . . . . . . . . . . 27

4 Funcions i procediments 294.1 Introducció . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294.2 Procediments . . . . . . . . . . . . . . . . . . . . . . . . . . . 294.3 Funcions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304.4 Àmbit d’una variable . . . . . . . . . . . . . . . . . . . . . . . 314.5 Pas de paràmetres . . . . . . . . . . . . . . . . . . . . . . . . 324.6 La funció main . . . . . . . . . . . . . . . . . . . . . . . . . . 334.7 Prototipus d’una funció . . . . . . . . . . . . . . . . . . . . . 33

5 Arxius 375.1 Introducció . . . . . . . . . . . . . . . . . . . . . . . . . . . . 375.2 Obertura i tancament d’un arxiu . . . . . . . . . . . . . . . . 385.3 Lectura i escriptura en fitxers de text . . . . . . . . . . . . . 39

5.3.1 Final d’arxiu . . . . . . . . . . . . . . . . . . . . . . . 395.4 Lectura i escriptura en fitxers binaris . . . . . . . . . . . . . . 40

5.4.1 Lectura de fitxers binaris . . . . . . . . . . . . . . . . 405.4.2 Escriptura de fitxers binaris . . . . . . . . . . . . . . . 40

6 Memòria dinàmica 436.1 Introducció . . . . . . . . . . . . . . . . . . . . . . . . . . . . 436.2 Adreces i punters . . . . . . . . . . . . . . . . . . . . . . . . . 436.3 Memòria dinàmica . . . . . . . . . . . . . . . . . . . . . . . . 45

6.3.1 Demanar memòria . . . . . . . . . . . . . . . . . . . . 456.3.1.1 Funció malloc . . . . . . . . . . . . . . . . . 456.3.1.2 Funció calloc . . . . . . . . . . . . . . . . . 466.3.1.3 Funció realloc . . . . . . . . . . . . . . . . 46

6.3.2 Alliberar memòria . . . . . . . . . . . . . . . . . . . . 466.3.3 Fuites de memòria . . . . . . . . . . . . . . . . . . . . 476.3.4 Dangling references . . . . . . . . . . . . . . . . . . . . 47

iv

Page 5: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

Índex de figures

1.1 Literals numèrics enters en C . . . . . . . . . . . . . . . . . . 9

2.1 Operadors relacionals en C . . . . . . . . . . . . . . . . . . . 122.2 Caràcters de control per a printf . . . . . . . . . . . . . . . 17

v

Page 6: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

vi

Page 7: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

Introducció

L’objectiu d’aquest volum és servir d’introducció a l’aprenentatge del llen-guatge de programació C. No es tracta, però, d’un manual de programacióo d’uns apunts de l’assignatura de Programació I, o programació II, o Es-tructures de Dades, o de cap altra assignatura. Cal tenir molt en compte, amés a més, que donem per fet que el lector disposa d’unes nocions bàsiquesde programació; altrament li serà bastant difícil seguir les explicacions queaquí farem.

Els elements del llenguatge que aquí presentem se cenyeixen als que s’ex-pliquen a l’assignatura de Programació I. En alguns casos ens hem permèsla llicència d’ampliar una mica el material, sempre i quan no posés en com-promís el caràcter introductori d’aquest volum ni dificultés l’aprenentatgede l’alumne. Hem intentant ser tan didàctics i pedagògics com hem poguten l’explicació dels continguts, però només els alumnes i docents podranavaluar fins a quin punt ho hem aconseguit.

A més d’aquest volum introductori, es pot trobar un volum de nivellavançat, que serveix d’ampliació i de referència al llenguatge C. Aquestsegon volum pot ser útil per a entendre els missatges del compilador i pera fer un ús eficient del llenguatge, però en cap cas és imprescindible per aun primer curs. Seran alumnes d’altres pràctiques els que en podran treuremés profit.

1

Page 8: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

Introducció

2

Page 9: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

Capítol 1

Dades fonamentals en C

1.1 Introducció

Qualsevol programa necessita treballar amb dos components bàsics: dades ioperacions. Sovint pensem en els programes com una sèrie d’instruccions otasques a realitzar, oblidant-nos que aquestes operacions es fan sobre dades.Donar forma adequada a les dades és importantíssim, i sovint afecta molt alrendiment de les aplicacions. En aquest primer capítol estudiarem els tipusde dades més bàsics que ens ofereix el llenguatge C: els tipus aritmètics, querepresenten dades “numèriques” i es poden classificar en dues categories: elstipus enters (o integrals) i els tipus reals (de coma flotant). Veurem que elllenguatge C ofereix una gran varietat de tipus aritmètics.

La unitat fonamental on es guarden dades, en C, és una variable. Unavariable és una posició de memòria a la qual li donem un nom. Aquestavariable té una sèrie de propietats, que s’aniran veient al llarg dels capítolsd’aquest volum.

Abans d’usar una variable, el llenguatge C exigeix que es declari, és adir, que s’indiqui el seu nom i, almenys, el seu tipus.

1.2 Els tipus enters

Els primers tipus que estudiarem són els anomenats tipus enters, i represen-ten quantitats numèriques sense decimals. Opcionalment, poden tenir signeo no tenir-ne. Per defecte, s’admeten nombres positius i negatius.

1.2.1 El tipus int

Aquest tipus és el més bàsic i el més important en C. El tipus int representauna quantitat numèrica, sense decimals, positiva o negativa. La seva midaés, almenys, de 16 bits, però pot ser més gran. A cygnus i a vela, unavariable de tipus int ocupa 32 bits. La seva representació és en complement

3

Page 10: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

1 Dades fonamentals en C

a dos. Per tant, doncs, el rang de valors que pot contenir una variable detipus int és el següent:

[−231, 231 − 1]

Per a declarar una variable de tipus int, primer de tot indiquem el tipusde variable i a continuació el nom; per exemple:

int i;

Aquesta declaració indica que la variable de nom i té tipus int. En Cés obligatori declarar totes les variables abans de fer-les servir.

1.2.2 El tipus booleà

Fins que no va aparèixer l’estàndar C99, en C no hi havia cap tipus “booleà”;per tant, els enters servien com a tals. En el llenguatge C, un valor igual azero es considera el valor “fals”, i qualsevol valor diferent de zero s’interpretacom el valor “cert”.

1.2.3 El tipus char

Tot i que pot semblar estrany, el tipus char (caràcter) és un tipus numèric,ja que les lletres tenen un codi ASCII associat (aquest codi és numèric).Una variable de tipus char ocupa 8 bits. Típicament, les variables de tipuschar s’empren per a guardar-hi caràcters, tot i que hi ha ocasions en quèper a guardar un caràcter necessitarem una variable de tipus int.

El fet que el tipus char sigui un tipus numèric es deu a la taula ASCII,que assigna un valor numèric a cada caràcter. Per exemple, el caràcter ’0’té associat el valor 48, la lletra ’A’ el valor 65 i la lletra ’a’ el valor 97. Lataula ASCII conté 256 caràcters; els 32 primers caràcters no són imprimiblesi els primers 128 són iguals en totes les versions de la taula ASCII.

Cada compilador decideix si, per defecte, una variable de tipus char tésigne o no.

1.2.4 Altres tipus enters

A més dels tipus int i char, en C també disposem dels següents tipus enters:

• short int (o simplement short): és una variable numèrica, la midade la qual ha de ser igual o superior a la d’un char i igual o inferiora la d’un int. Com a mínim, una variable de tipus short int had’ocupar 16 bits. Per defecte, admet nombres positius i negatius. Avela i a cygnus, la mida d’un short int és de 16 bits.

4

Page 11: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

1 Dades fonamentals en C

• long int (o simplement long): és una variable numèrica, la mida dela qual ha de ser igual o superior a la d’un int. Com a mínim, unavariable de tipus long int ha d’ocupar 32 bits. Per defecte, admetnombres positius i negatius. A vela i a cygnus, la mida d’un long intés la mateixa que la d’un int.

• long long int: aquest tipus es va introduir amb l’estàndar C99. Ésuna variable numèrica, la mida de la qual ha de ser igual o superior a lad’un long int. Com a mínim, una variable de tipus long long intha d’ocupar 64 bits. Per defecte, admet nombres positius i negatius.A vela i a cygnus la mida d’una variable long long int és de 64bits.

1.2.5 Tipus enters sense signe

Ja hem dit que, per defecte (a excepció de char), els tipus enters admetentant números positius com negatius. El llenguatge C ens permet indicar queuna variable només contindrà números positius:

unsigned int i;

Aquesta declaració indica que la variable i no admetrà números negatius.Per tant, doncs, el seu rang de valors és:

[0, 232 − 1]

Cal anar amb molt de compte quan es barregen variables amb signe i va-riables sense signe. Recordem que el llenguatge C treballa amb complementa dos: si a una variable sense signe li assignem un valor negatiu, en realitatli estem donant un valor positiu molt gran. Aquest error s’anomena integeroverflow i ha estat font de problemes en algunes aplicacions importants.

1.3 Els tipus realsDins dels tipus aritmètics, a més dels tipus enters, disposem també delstipus reals (o, més exactament, tipus en coma flotant). En C disposem detres tipus reals:

• El tipus float representa un número real de precisió simple. Admetnombres positius i negatius.

• El tipus double representa un número real de precisió doble. Admetnombres positius i negatius.

• El tipus long double representa un número amb més precisió que undouble. Admet nombres positius i negatius.

5

Page 12: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

1 Dades fonamentals en C

Pel que fa a les variables de tipus real, el llenguatge C no especifica capmida mínima en bytes, sinó que especifica el mínim de dígits significatiusque han de tenir. A la pràctica, la mida mínima d’un float solen ser 32bits i la mínima d’un double i long double solen ser 64 bits. A vela i acygnus, una variable de tipus float ocupa 32 bits, una variable de tipusdouble ocupa 64 bits i una variable de tipus long double ocupa 96 bits.

1.4 Assignació de variables

Dues (o més) variables es poden assignar, fent que l’una prengui el valor del’altra. Per exemple:

int a;int b;a = b;

fa que la variable a perdi el seu valor antic i passi a tenir el mateixvalor que b. Evidentment, això no crea cap mena de lligam entre les duesvariables. Per tal que dues variables es puguin assignar, cal que tinguin elmateix tipus, o que almenys tinguin tipus compatibles.

Una variable també pot prendre el valor d’una expressió:

a = 3 * b / 5;

Una expressió és una combinació de valors i operadors. En aquest exem-ple tenim els operadors de multiplicar i dividir, i com a valors tenim literalsnumèrics (3 i 5) i variables (a).

1.4.1 Assignació de variables enteres

Suposem dues variables enteres a i b, i fem la següent assignació:

a = b;

Llavors, la variable a prendrà el valor de la variable b, sempre i quan eltipus de la variable a pugui adoptar, per la seva mida, el valor de la variableb. Per exemple, si a és un int i b és un char, no hi haurà cap problema,perquè un char ocupa 1 byte i un int ocupa, almenys, 2 bytes.

Què passa si el valor que té la variable b no es pot representar en lavariable a? Per exemple, podria ser que la mida de la variable a no fossuficient, o que la variable a no admetés números negatius i justament lavariable b tingués un valor negatiu. En aquest cas, es poden descartar elsbits més alts per tal que el valor hi càpiga, però és bastant probable que elresultat no sigui l’esperat.

6

Page 13: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

1 Dades fonamentals en C

1.4.2 Assignació de variables reals

Dues variables de tipus real es poden assignar segons les següents normes:

1. Si les dues variables tenen el mateix tipus float, o double, o long double,l’assignació es fa sense cap problema.

2. Si la variable a té tipus long double i la variable b té tipus double ofloat; o si la variable a té tipus double i la variable b té tipus float,l’assignació també es fa sense problemes.

3. Si assignem “en sentit contrari” (per exemple, a té tipus float i b tétipus double), llavors s’intenta que a prengui un valor tan aproximatcom sigui possible al valor de b; però si el valor de b està fora del rangde valors possibles de a, llavors a pot prendre qualsevol valor.

1.4.3 Assignació de variables enteres amb reals

El llenguatge C permet fer assignacions com les següents:

int i;float f;i = f;f = i;

Cal distingir dos casos:

1. En el primer cas (la variable de l’esquerra és entera i la de la dretaés real), s’intenta que la variable i tingui un valor tan aproximat comsigui possible al de la variable f (eliminant els decimals). Si això noés possible, la variable i pot prendre qualsevol valor.

2. En el segon cas (la variable de l’esquerra és real i la de la dreta ésentera), s’intenta que la variable f tingui un valor tan aproximat comsigui possible al de la variable i. Si això no és possible, la variable fpot prendre qualsevol valor.

1.4.4 Assignació múltiple

En C es permet fer assignacions com la següent:

a = b = c = d;

Aquesta assignació és equivalent a la següent:

c = d;b = c;a = b;

7

Page 14: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

1 Dades fonamentals en C

1.5 Inicialitzar variablesSi combinem la declaració d’una variable amb una assignació, tenim unainicialització:

int i = 0;

Per a inicialitzar una variable podem fer servir qualsevol literal numèric(com per exemple 0), o bé una expressió que el compilador pugui avaluar entemps de compilació (per exemple, 3 + 4), o bé una altra expressió o fins itot una crida a funció. De totes maneres, hi ha casos en què només podremfer servir expressions constants (aquelles expressions que tenen un valor quees pot calcular quan es compila el programa). Exemples:

int a = 2;int b = 8*8;int c = a/b;int d = foo();

Les variables a i b estan inicialitzades amb expressions constants; lavariable c està inicialitzada amb una expressió no constant i la variable destà inicialitzada amb una crida a funció.

En C, els literals de caràcter (com per exemple ’c’) tenen tipus int. Detotes maneres, podem inicialitzar un caràcter de la següent manera:

char a = ’c’;

Com que els literals de caràcter tenen tipus int, és perfectament legalla següent declaració:

int c = ’F’;

Els literals numèrics poden dur uns sufixos que indiquen, explícitament,quin tipus té aquell literal, com veiem a la figura 1.1.

Pel que fa als literals numèrics de tipus real, el llenguatge C ens permetemprar diferents notacions:

float pi = 3.1415;float bla = 5.6e-5;

Aquestes dues declaracions inicialitzen pi a 3.1415 (el separador decimalés el punt i no la coma) i bla al valor 0.000056: 5.6e-5 significa 5.6 · 10−5.

1.6 Més enllà dels tipus simplesEls tipus que hem vist en aquest capítol són els tipus aritmètics, i conjunta-ment són els tipus simples o elementals que proveeix el C. A partir d’aquí,derivant sobre aquests tipus, es poden anar construint tipus més complexos,que anirem veient a la resta del llibre.

8

Page 15: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

1 Dades fonamentals en C

Tipus Hexadecimal Octal Decimalchar \0x41 \0101 —int 0x41 0101 65unsigned int 0x41u 0101u 65ulong int 0x41L 0101L 65Lunsigned long int 0x41UL 0101UL 65ULlong long int 0x41LL 0101LL 65LLunsigned long longint

0x41ULL 0101ULL 65ULL

Figura 1.1: Literals numèrics enters en C

9

Page 16: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

1 Dades fonamentals en C

10

Page 17: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

Capítol 2

Control de flux

2.1 Introducció

Les estructures de control de flux són l’element que permeten que un pro-grama realitzi unes accions o unes altres en funció de les condicions queestableixi el programador. Algunes estructures de control de flux permetenque l’execució segueixi un o altre camí segons una determinada condició;d’altres estructures repeteixen unes accions mentre es compleixi una certacondició.

Abans de començar a veure les estructures de control de flux, introduïremuns nous operadors, que ens permetran expressar les condicions de què hemparlat; els podem veure a la figura 2.1. Aquests operadors no acceptenqualsevol tipus d’operands. Podem estar segurs que els tipus enters i realssón vàlids per als operadors relacionals.

A més dels operadors de la figura 2.1, també hi ha dos operadors mésque hem de conèixer:

• L’operador && té el significat de “i lògica”. Per exemple:

a < b && b < c

és una expressió que serà certa si a < b i, al mateix temps, b < c.

• L’operador || té el significat de “o lògica”. Per exemple:

a < 0 || a > 9

és una expressió que serà certa si es compleix, almenys, una de les duescondicions: a < 0 o a > 9.

11

Page 18: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

2 Control de flux

Operador Significat== Igualtat. Avalua cert si els dos operands són iguals.!= Diferència. Avalua cert si els dos operands són dife-

rents.< Inferior. Avalua cert si el primer operand és estricta-

ment inferior al segon.<= Inferior o igual. Avalua cert si el primer operand és

igual o inferior al segon.> Superior. Avalua cert si el primer operand és estricta-

ment superior al segon.>= Superior o igual. Avalua cert si el primer operand és

igual o superior al segon.

Els operadors == i != tenen menys prioritat que la resta d’operadors relacionals.

Figura 2.1: Operadors relacionals en C

2.2 Sentència condicional

La sentència condicional permet executar un codi o un altre segons unadeterminada condició. Per això se’n diu “sentència condicional”. En la sevaforma més simple, té l’aspecte que podem veure al següent exemple:

if (a > b) {max = a;

}

El significat d’aquest exemple és el següent:

• Si el valor de la variable a és superior al valor de la variable b, llavorsfem l’assignació i, per tant, la variable max pren el valor de la variablea.

• Si el valor de la variable a no és superior al valor de la variable b, noes fa l’assignació.

Opcionalment, podem especificar què volem que es faci si la condició noés certa; per exemple:

if (a > b) {max = a;

} else {max = b;

}

El significat d’aquest exemple és el següent:

12

Page 19: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

2 Control de flux

• Si el valor de la variable a és superior al valor de la variable b, llavorsfem l’assignació max = a; i, per tant, la variable max pren el valor dela variable a.

• Si el valor de la variable a no és superior al valor de la variable b,llavors fem l’assignació max = b; i, per tant, la variable max pren elvalor de la variable b.

Després d’una branca else podem encadenar un nou if; per exemple:

if (a > b) {max = a;

} else if (a < b) {max = b;

} else {max = 0;

}

El significat d’aquest exemple és el següent:

• Si el valor de la variable a és superior al valor de la variable b, llavorsfem l’assignació max = a; i, per tant, la variable max pren el valor dela variable a.

• Si el valor de la variable a no és superior al valor de la variable b,llavors poden passar dues coses:

– Que el valor de la variable a sigui inferior al de la variable b. Enaquest cas, fem l’assignació max = b; i, per tant, la variable maxpren el valor de la variable b.

– Que el valor de la variable a sigui igual al valor de la variable b.En aquest cas, fem l’assignació max = 0;.

La sentència condicional permet estructures com la següent:

1 if (c == ’-’) {2 opt_plus = 0;3 opt_minus = 1;4 if (d == ’a’) {5 opt_a = 1;6 opt_A = 0;7 } else if (d == ’A’) {8 opt_A = 1;9 opt_A = 0;

10 } else {

13

Page 20: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

2 Control de flux

11 opt_a = opt_A = 0;12 }13 } else if (c == ’+’) {14 opt_plus = 1;15 opt_minus = 0;16 } else {17 opt_plus = opt_minus = 0;18 }

2.3 Sentència while

La sentència while és un tipus de sentència iterativa (també anomenades“bucles”). Les sentències iteratives executen un codi mentre una determi-nada condició avaluï cert. Exemple:

int i = 0, n = 0;while (i < 500) {

n = n + i;i = i + 1;

}

Mentre el valor de la variable i sigui inferior a 500, s’executarà el codique hi ha entre les dues claus ({ i }). Aquest codi s’encarrega de modificarel valor de la variable i, de tal manera que, en algun moment, la condicióavaluarà fals i se sortirà del bucle; en cas contrari, podríem caure en unbucle infinit. Si de forma intencionada volem escriure un bucle infinit, hopodem fer de la següent manera:

while (1) {...

}

Com ja vam veure a l’apartat 1.2.1, un valor diferent de zero s’interpretacom a cert; per tant, la condició sempre s’avalua cert. En alguns tipusd’aplicació pot ser útil tenir un bucle infinit — òbviament, aquests tipusd’aplicacions disposen de mètodes per a interrompre l’execució del bucle.

Hi ha un detall que és important que remarquem. La condició de per-manència (és a dir, la condició que hi ha dins dels parèntesis que segueixena la paraula reservada while) del bucle es comprova abans d’entrar-hi. Ésa dir, que si el nostre codi és, per exemple:

int i = 1000, n = 0;while (i < 500) {

n = n + i;i = i + 1;

}

14

Page 21: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

2 Control de flux

Quan volem entrar al bucle per primer cop, ens trobem que la condicióde permanència és falsa, i per tant no entrarem mai al bucle, i no executaremmai el codi que hi ha entre les dues claus.

2.4 Sentència do

La sentència do és molt similar a la sentència while, però amb una diferènciaimportant: la condició de permanència s’avalua al final del bucle, no alprincipi; per tant, sempre s’executen les sentències del bucle almenys uncop. Exemple:

int i;do {

i = foo();} while (i != 0);

A diferència d’altres llenguatges, per tal que el bucle do segueixi iterantcal que la condició de permanència avaluï cert; és a dir, es tracta d’un bucle“repeteix mentre”, en lloc d’un “repeteix fins”. En general, el bucle do ésaconsellable quan volem que el codi del bucle s’executi, almenys, un cop.

2.5 Sentència for

La sentència for és un bucle que, en C, presenta molta més flexibilitat queels bucles for de molts altres llenguatges de programació. Per exemple:

int i, n = 0;for (i = 0; i < 1000; i++) {

n += i;}

La primera línia declara les variables i i n, totes dues de tipus int. Amés a més, la variable n s’inicialitza a zero. L’expressió i++ fa que aquestavariable aumenti el seu valor en una unitat. La sentència n += i és “equi-valent” a n = n + i.

Cal prestar especial atenció al codi que posem entre parèntesis:

• L’assignació i = 0; és la sentència que s’executa abans d’entrar albucle for, i s’executa un sol cop abans de totes les iteracions del bucleque es faran. És equivalent al seüent codi:

int i = 0, n = 0;for (; i < 1000; i++) {

n += i;}

15

Page 22: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

2 Control de flux

• L’expressió i < 1000 és la condició de permanència del bucle. Escomprova abans d’entrar al bucle.

• La sentència i++ s’executa al final de cada iteració, abans de compro-var la condició de permanència. És equivalent al següent codi:

for (i = 0; i < 1000;) {n += i;i++;

}

2.6 Sentència switch

La sentència switch és una forma de sentència condicional, en el qual s’exe-cuta un codi o un altre segons el valor que pren una expressió. Per exemple:

1 switch (i) {2 case 0:3 j = i + 1;4 break;5

6 case -1:7 j = i + 2;8 break;9

10 default:11 j = i;12 break;13 }

• Si el valor de la variable i val zero, a la variable j li assignem el valorde i sumat una unitat.

• Si el valor de la variable i val −1, a la variable j li assignem el valorde i sumat dues unitats.

• Si el valor de la variable i no val ni zero ni −1, a la variable j liassignem el valor de la variable i.

Cal tenir en compte una sèrie de restriccions:

1. La sentència switch només avalua valors de variables. Les variables detipus enter (recordem que el tipus char també es considera, en C, untipus enter) són vàlides per a ser avaluades amb una sentència switch(les de tipus real no són vàlides).

16

Page 23: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

2 Control de flux

Caràcter Tipus de variable que repc charhd short int (decimal)d int (decimal)ld long int (decimal)lld long long int (decimal)f float, doubleLf long double

En el cas dels tipus enters, si volem que la sortida aparegui en format octal, sub-situïrem només el caràcter d pel caràcter o; si volem que surti en hexadecimal,substituïrem només el caràcter d pel caràcter x.

Figura 2.2: Caràcters de control per a printf

2. Cada branca case avalua un sol valor de la variable. Ha de ser unaexpressió constant, és a dir, que sempre valgui el mateix independent-ment de l’execució del programa.

3. La paraula reservada break indica que s’ha de sortir de la sentènciaswitch. Si no la posem, se seguirà executant el codi que hi hagi acontinuació, encara que pertanyi a d’altres branques case.

4. Dins de cada sentència switch només hi pot haver una branca default,que pot aparèixer en qualsevol moment (no només al final). El codide la branca default s’executa quan el valor de la variable avaluadano pren cap valor dels que s’especifiquen a les branques case.

2.7 Entrada i sortida

Tot el que hem vist fins ara no produeix cap resultat per pantalla, ni in-teractua amb l’usuari de cap manera. En aquest apartat presentarem duesfuncions que ens serveixen per a mostrar dades per pantalla i per a obtenir-nepel teclat.

2.7.1 Sortida per pantalla

La funció que ens permet mostrar informació per pantalla es diu printf.Un exemple molt simple és el següent:

printf("Hello, world!\n");

Aquesta sentència fa que per pantalla obtinguem el missatge Hello, world!.Els dos últims caràcters abans de les cometes fan que se salti a una novalínia. Per exemple:

17

Page 24: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

2 Control de flux

printf("Hola\nAdéu\n");

Aquesta sentència generarà el següent missatge per pantalla:

HolaAdéu

Com podem mostrar per pantalla el valor d’una variable?

printf("El valor de la variable i val %d\n", i);

Si i val 10, el que obtindrem per pantalla serà:

El valor de la variable i val 10

Fixem-nos que per tal de fer sortir el valor de la variable i hem hagutd’escriure %d. Aquests dos caràcters indiquen que aquí hi ha d’anar unavariable de tipus int. Depenent del caràcter (o caràcters) que posem acontinuació del signe % indiquem quin tipus de variable hem de mostrar perpantalla. Pels tipus de variables que hem vist, podem fer la llista de la figura2.2.

Un altre exemple:

short int i = 27;int j = 31;float f = 3.14;

printf("i val %hd, j val %x, f val %f\n", i, j, f);

El resultat que obtindrem per pantalla serà:

i val 27, j val 1f, f val 3.140000

La funció printf permet una quantitat enorme de caràcters de control,que no veurem en aquest apartat. Un últim apunt: pel que fa als caràcters,ja hem vist que són variables numèriques. Per tant, un caràcter es potmostrar de dues maneres:

1. Com a variable numèrica:

char c = ’a’;printf("%d", c);

2. Com a caràcter:

char c = ’b’;printf("%c", c);

18

Page 25: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

2 Control de flux

2.7.2 Entrada per teclat

La funció que ens permet entrar dades per teclat es diu scanf, i té un funci-onament similar al de printf. Cal tenir en compte dos aspectes importants:

1. Si posem espai en blanc, scanf es menjarà l’espai en blanc, indepen-dentment de quina quantitat d’espai en blanc hi hagi.

2. Si posem caràcters que no són de control, scanf esperarà que l’usu-ari teclegi exactament els caràcters que hem escrit. En cas contrari,deixarà d’acceptar entrada per teclat.

3. Si la funció scanf ha de llegir una cadena de caràcters, llegirà caràctersfins que trobi un espai en blanc; en aquest moment, deixarà de llegir.

Exemple:

int i;printf("Valor de i: ");scanf("%d", &i);

Per què posem el caràcter & davant de la variable que llegim? La funcióscanf espera que li passem un punter a la variable que volem llegir; al capítol6 expliquem què son els punters i quin significat té l’operador &.

19

Page 26: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

2 Control de flux

20

Page 27: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

Capítol 3

Tipus agregats de dades

3.1 IntroduccióA més dels tipus de dades que vam veure al capítol 1, el llenguatge C dis-posa d’una sèrie de tipus que anomenarem, seguint la pròpia nomenclaturadel llenguatge, tipus agregats, perquè es componen a partir d’aquells tipusfonamentals que vam veure al capítol 1. Hi ha dues menes de tipus agregats:els arrays i els structs.

3.2 Arrays

3.2.1 Introducció als arrays

Un array és una col·lecció consecutiva d’elements del mateix tipus. És a dir,que sota un mateix nom, agrupem diversos elements que tenen el mateixtipus. Per a un array, el compilador ha de saber exactament quants elementscontindrà; aquesta quantitat d’elements no pot variar en tota l’execució delprograma.

Exemples:

int a[];

Aquesta declaració és un error perquè no indiquem quants enters con-tindrà l’array de nom a. En canvi, el següent exemple sí que és correcte:

int a[32];

Declara que l’array de nom a contindrà 32 enters. El primer d’aquestsenters ocuparà la posició 0 de l’array, i l’últim la posició 31. Els arrayssón variables de “segona categoria” en C: no es poden assignar arrays, i noes pot aplicar els operadors relacionals sobre operands que siguin arrays.Podem fer arrays de qualsevol tipus que existeixi en C, no només dels tipuselementals.

21

Page 28: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

3 Tipus agregats de dades

Accés a un element d’un array Per a accedir a cadascun dels seuselements, emprarem els claudàtors, com poden veure en aquest exemple:

int i, sum = 0, a[32];for (i = 0; i < 32; i++) {

sum = sum + a[i];}printf("La suma val %d\n", sum);

L’expressió i++, en aquest exemple, és equivalent a i=i+1.

3.2.2 Inicialització d’arrays

A l’apartat 1.5 vam veure que les variables de tipus aritmètic es podeninicialitzar al moment de declarar-les. Amb els arrays això també es pot fer:

1. Podem inicialitzar tots els elements de l’array:

int a[4] = {1, 2, 3, 4};

2. Podem optar per inicialitzar només alguns elements de l’array:

float b[3] = {3.14};

En aquest cas, la inicialització és equivalent a:

float b[3] = {3.14, 0.0, 0.0};

Òbviament, no es poden inicialitzar més elements dels que té l’array.

3. Podem inicialitzar un array sense indicar quants elements conté:

int k[] = {1, 2, 4, 8, 16, 32, 64};

Com que estem inicialitzant 7 elements, el compilador dedueix que kés un array de 7 enters.

22

Page 29: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

3 Tipus agregats de dades

3.2.3 Arrays de caràcters

En C no disposem del tipus “string”. Per tal de representar una cadena,podem emprar un array de caràcters. En C, les cadenes de caràcters hand’acabar sempre amb el caràcter ’\0’. El compilador afegeix aquest caràcteren tots els literals de cadena:

char nom[] = "jordi";

L’array nom té 6 caràcters: els 5 que veiem a la inicialització més elcaràcter finalitzador. En canvi:

char nom2[] = {’j’, ’o’, ’r’, ’d’, ’i’};

L’array nom2 no té el caràcter finalitzador i només ocupa 5 caràcters. Caltenir en compte que els arrays de caràcters segueixen sent arrays, sotmesosa les mateixes restriccions que la resta d’arrays.

3.3 Treballar amb cadenesPer a treballar i fer operacions amb cadenes de caràcters, en C és necessariemprar una sèrie de funcions, que detallem a continuació:

Copiar cadenes La funció strcpy copia cadenes. Si tenim, per exemple,dues cadenes anomenades origen i desti, llavors podem copiar-les de lasegüent manera:

strcpy(desti, origen);

Aquest codi fa que la cadena desti tingui el mateix contingut que lacadena origen. Cal tenir en compte que la funció strcpy no comprova sidesti té espai suficient per a encabir-hi el contingut de origen.

Hi ha una altra funció, que es diu strncpy, que permet indicar el màximde caràcters que es copiaran.

Comparar cadenes La funció strcmp permet comparar si dues cadenessón idèntiques (diferenciant entre majúscules i minúscules). Si les dues ca-denes són idèntiques, retorna zero. Si són diferents, retorna un valor diferentde zero. Per exemple:

char str1[] = "hola";char str2[] = "adéu";if (strcmp(str1, str2) == 0) {

printf("Són iguals\n");} else {

printf("Són diferents\n");}

23

Page 30: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

3 Tipus agregats de dades

Hi ha una funció, anomenada strncmp, que permet especificar una quan-titat màxima de caràcters a comparar.

Concatenar cadenes La funció strcat serveix per a concatenar cadenes.Ho explicarem amb un exemple:

char str1[] = "hola ";char str2[] = "Jordi";char str3[200];strcat(str3, str1);strcat(str3, str2);printf("%s\n", str3);

per pantalla obtindrem:

hola Jordi

La funció strcat no comprova que la cadena de destí tingui espai sufi-cient.

Mida d’una cadena La funció strlen calcula la quantitat de caràctersd’una cadena, i ens retorna aquesta quantitat. Cal tenir en compte que nos’inclou el caràcter ’\0’ del final.

3.4 StructsUn struct és un tipus resultant de l’agregació d’altres tipus ja existents.En d’altres llenguatges de programació se’n diuen “registres”. Exemple:

struct alumne {char nom[32];int dia_naixement;int mes_naixement;int any_naixement;

};

Aquest exemple defineix un nou tipus struct alumne, que està compostper 4 membres (també anomenats camps): un array de 32 caràcters i tresenters. Un cop tenim definit el nou tipus, podem crear tantes variablesd’aquest tipus com vulguem:

struct alumne jordi, albert, josep, marc;

També podem inicialitzar un struct:

24

Page 31: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

3 Tipus agregats de dades

struct alumne jordi = {"Jordi", 8, 7, 1982};

El camp d’un struct pot tenir qualsevol tipus que ja existeixi. Una altramanera de definir un struct és la següent:

struct {char nom[32];int dia_naixement;int mes_naixement;int any_naixement;

} alumne;

Aquest exemple declara alumne com una variable struct que té 4 camps:un array de 32 caràcters i tres enters. Fixem-nos amb la diferència entreaquesta declaració i la de l’exemple anterior. Resumint:

1. L’identificador que posem després de la paraula clau struct serveixper a donar nom a un tipus.

2. L’identificador que posem després de la clau } serveix per a donar noma una variable.

El següent exemple és correcte:

struct foo {int foo;

} foo;

Aquest exemple defineix un nou tipus struct foo, que conté un campde tipus enter que es diu foo, i al mateix temps declara una variable de nomfoo el tipus de la qual és struct foo.

Cap dels operadors relacionals es pot aplicar sobre structs. Sí que estàpermesa l’assignació de structs, sempre i quan els tipus siguin exactamentels mateixos. Per exemple:

struct primer {int i;

};

struct segon {int i;

};

struct primer p;struct segon s;p = s;

25

Page 32: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

3 Tipus agregats de dades

La declaració dels structs i de les variables és correcta, però l’assignacióno, perquè p té tipus struct primer i s té tipus struct segon. No és téen compte el fet que struct primer com struct segon tenen exactamentel mateix número de camps i el mateix tipus.

Accés als membres d’un struct Per a accedir als membres d’un structemprarem l’operador punt:

struct alumne {char nom[32];int dia_naixement;int mes_naixement;int any_naixement;

};

struct alumne jordi;jordi.dia_naixement = 8;jordi.mes_naixement = 7;jordi.any_naixement = 1982;

3.4.1 Arrays de structs

Al parlar dels arrays (apartat 3.2) hem dit que podem fer arrays a partirde qualsevol tipus que estigui definit; això vol dir que podem fer arraysd’estructures. Partint de la definició de struct alumne que hem vist enels últims exemples, i suposant que tenim 25 alumnes en una classe, podemdeclarar el següent array:

struct alumne classe[25];

on classe és un array de 25 elements, cadascun dels quals té el tipusstruct alumne. Per a accedir a un element de l’array, emprem l’operadorclaudàtors:

classe[0]

i el tipus és struct alumne. Finalment, si volem accedir a un dels campsde l’estructura, emprem l’operador punt:

classe[0].any_naixement = 1986;

26

Page 33: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

3 Tipus agregats de dades

3.5 Array d’arraysAl parlar dels arrays, a l’apartat 3.2, hem dit que un array pot tenir qualsevoltipus com a element. Per tant, doncs, és lògic pensar que podem trobar-nosarrays d’arrays. El llenguatge C permet arrays d’arrays, ja sigui de dues,tres o més dimensions. La forma de declarar-los és la següent:

int a[2][3];

Aquesta declaració indica que a és un array de dos elements, cadascundels quals és, al seu torn, un array de 3 enters. Llavors, doncs, a[0] ésel primer array de tres enters, i a[1] és el segon array de 3 enters. Per aaccedir al primer enter del segon array de tres enters escriurem el següent:

a[1][0];

27

Page 34: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

3 Tipus agregats de dades

28

Page 35: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

Capítol 4

Funcions i procediments

4.1 IntroduccióUn dels aspectes més importants d’un programa en C és la seva estructuracióen funcions i procediments, que són fragments de codi agrupats sota unmateix nom. Tant les funcions com els procediments realitzen funcionalitatsconcretes de l’aplicació que programem, i poden rebre dades a través deparàmetres. La diferència entre funcions i procediments és que les funcionsretornen un valor, mentre que els procediments no en retornen cap.

En aquest capítol presentarem els aspectes fonamentals del llenguatge Csobre funcions i procediments, i aprofitarem per presentar una nova propietatde les variables.

Tot programa en C ha de tenir una funció amb el nom de main. Quanexecutem un programa, es comença executant la funció main.

4.2 ProcedimentsUn procediment és un grup de codi que realitza una acció. Aquest grup decodi rep un nom, el nom del procediment, i se li pot passar dades amb unsmecanismes que veurem més endavant. Per exemple:

void PintaMenu(void) {printf("Menú d’opcions:\n");printf("1. Afegir contacte\n");printf("2. Consultar contacte\n");printf("3. Eliminar contacte\n");printf("Q. Sortir\n");

}

Fixem-nos en la primera línia:

1. La paraula reservada void, escrita abans del nom del procediment,indica que PintaMenu és un procediment.

29

Page 36: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

4 Funcions i procediments

2. A continuació de void hem escrit el nom del procediment.

3. A continuació, entre parèntesis, hem escrit void, que vol dir que aquestprocediment no rep dades. No era necessari escriure void, però posar-ho reflecteix un bon estil de programació. A l’apartat 4.5 veurem compodem enviar dades a un procediment.

4. A continuació obrim una clau i escrivim el codi del procediment, queés el codi que s’executarà cada cop que cridem el procediment.

Finalment, a l’última línia, tanquem la clau que hem obert a la primeralínia. Per a cridar aquest procediment escriurem el següent:

PintaMenu();

4.3 FuncionsEn C, una funció és exactament que un procediment, però amb la següentdiferència: un procediment no retorna cap dada a qui l’ha cridat, mentreque una funció sí que retorna una dada. De fet, en C no es fa diferènciesentre funció i procediment. Un exemple de funció pot ser el següent:

1 int a = 2;2 int b = 3;3

4 int maxim(void) {5 int resultat;6 if (a > b) {7 resultat = a;8 } else {9 resultat = b;

10 }11 return resultat;12 }

Fixem-nos en els següents detalls:

1. A les línies 1 i 2 estem declarant dues variables, i les inicialitzem a unvalor concret. Fins aquí, cap novetat.

2. A la línia 4 ja no posem void abans del nom de la funció, sinó int,perquè volem que la funció retorni un enter. Si volem que la funcióretorni un número real, posarem float o double. Del tipus que posemabans del nom de la funció se’n diu tipus de retorn. Un procedimentno és res més que una funció que retorna void — és a dir, que noretorna res.

30

Page 37: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

4 Funcions i procediments

3. A la línia 5 hem declarat una variable. A l’apartat 4.4 veurem quinadiferència hi ha entre aquesta variable i les que hem declarat a les línies1 i 2.

4. A la línia 11 hi ha una sentència anomenada return, acompanyadad’una variable. Aquesta sentència s’utilitza per a indicar d’on ha desortir el valor que retorna la funció. Com que la nostra funció retornaun enter, hem posat una variable entera. Un procediment també pottenir una sentència return, però no pot anar acompanyada de capvalor ni de cap variable. No és obligatori guardar ni fer servir el valorde retorn d’una funció1.La sentència return finalitza l’execució de la funció o procediment aon es troba.

Exemple de crida:

int a, b;int r;r = maxim();

4.4 Àmbit d’una variableTornem a l’exemple anterior. Hem vist que a les línies 1 i 2 declaràvem duesvariables a i b, i a la línia 5 declaràvem una variable resultat. Les variablesa i b estaven declarades fora de la funció, mentre que la variable resultatestava declarada dins de la funció.

• Una variable que està declarada fora de qualsevol funció és una variableglobal. Una variable global es pot utilitzar des del moment en què esdeclara i fins al final de l’arxiu. És a dir, que el seu àmbit començaamb la seva declaració i s’acaba al final de l’arxiu.

• Una variable que està declarada a dins d’una funció és una variablelocal. El seu àmbit comença des del moment en què es declara i s’acabaal final de la funció2.Si no s’especifica el contrari, cada cop que entrem en una funció es creauna nova còpia de les variables locals, sense inicialitzar-les. Al sortirde la funció, les variables locals deixen d’existir i, per tant, perden elseu valor.Important: quan es declara una variable local, pren un valor desco-negut (a menys que la inicialitzem).

1Per exemple, la funció printf retorna int, però rares vegades s’utilitza aquest valorde retorn.

2Això no és estrictament cert, però en tots els exemples d’aquesta primera part, sí queho serà.

31

Page 38: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

4 Funcions i procediments

Si una variable local es diu igual que una variable global, llavors a dinsde la funció la variagle global queda oculta.

4.5 Pas de paràmetres

La funció que calcula el màxim de dos nombres l’haguéssim pogut escriurede la següent manera:

int maxim(int a, int b) {int resultat;if (a > b) {

resultat = a;} else {

resultat = b;}return resultat;

}

La diferència rau en el que posem dins dels parèntesis, a la primera línia.Les funcions (i els procediments també) poden rebre dades en el momentde cridar-los. En el nostre exemple, la funció maxim rep dos paràmetres,a i b, el tipus dels quals és int. Dins de la funció, els paràmetres actuencom si fossin variables locals. En el moment de cridar una funció, hem desubministrar les dades que li hem de passar — és a dir, els arguments:

int r = maxim(4, 8);

Què cal tenir en compte, pel que fa al pas de paràmetres?

1. Si una funció rep un número n de paràmetres, al cridar-la se li han depassar n arguments.

2. Per a cada paràmetre, l’argument ha de tenir un tipus igual o compa-tible amb el que demana la funció. Per exemple, si demana un enterno podem passar un struct. Els tipus enters són compatibles entreells, els tipus reals són compatibles entre ells. Pel que fa als arrays,han de ser compatibles els tipus de l’element dels arrays. I pel que faals structs, han de tenir el mateix nom (struct a no és compatibleamb struct b, sigui quina sigui l’estructura interna de struct a istruct b).

3. Excepte en el cas dels arrays, quan passem una variable com a argu-ment, el que es fa és passar una còpia de la variable. Fixem-nos en elsegüent exemple:

32

Page 39: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

4 Funcions i procediments

void swap(int a, int b) {int t;t = a;a = b;b = t;

}

Si cridem aquesta funció de la següent manera:

int a = 2, b = 3;swap(a, b);printf("%d %d\n", a, b);

el resultat per pantalla serà 2 3 i no 3 2, que és el que voldríem. Perquè? Perquè quan hem passat les variables a i b al procediment swap,aquest se n’ha fet una còpia, i ha treballat amb les còpies. Les variablesa i b originals no han canviat de valor. A l’apartat 6.2 veurem compodem aconseguir que sí canviïn de valor.

4.6 La funció main

A la introducció hem dit que tot programa en C necessita tenir una funciómain, que és la que s’executa a l’inici del programa. Aquesta funció ha deretornar sempre int, i pel que fa als seus paràmetres:

• Podem definir la funció de manera que no rebi cap paràmetre:

int main(void) {

• Podem definir la funció per tal que rebi dos paràmetres: un de tipusint, i un altre de tipus array de punters a caràcter:

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

Al capítol 6 expliquem què són els punters.

4.7 Prototipus d’una funció

Suposem el següent exemple:

33

Page 40: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

4 Funcions i procediments

int main(void) {int a, b;printf("Digues un número: ");scanf("%d", &a);printf("Digues un altre número: ");scanf("%d", &b);printf("El màxim entre %d i %d és %d\n",

a, b, maxim(a,b));return 0;

}

int maxim(int a, int b) {int resultat;if (a > b) {

resultat = a;} else {

resultat = b;}return resultat;

}

A la funció principal (main) cridem la funció maxim, però quan el com-pilador veu la crida, no té cap mena d’informació sobre la funció maxim.Segons l’última definició del llenguatge C, aquesta situació és un error, tot ique la majoria de compiladors la toleren. Però el compilador segueix sensetenir informació suficient, i no pot fer les verificacions que hauria de fer.

La primera solució a aquest problema consisteix en definir la funció maximabans de la seva crida:

int maxim(int a, int b) {int resultat;if (a > b) {

resultat = a;} else {

resultat = b;}return resultat;

}

int main(void) {int a, b;printf("Digues un número: ");scanf("%d", &a);printf("Digues un altre número: ");

34

Page 41: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

4 Funcions i procediments

scanf("%d", &b);printf("El màxim entre %d i %d és %d\n",

a, b, maxim(a,b));return 0;

}

Aquesta solució falla quan tenim dues (o més funcions) que es cridenentre elles, és a dir, quan una funció foo pot cridar una altra funció bar, iaquesta funció bar, al seu torn, pot cridar la funció foo. Aquí hem d’optarper una altra alternativa: declarar la funció amb un prototipus. Exemple:

int maxim(int, int);

int main(void) {int a, b;printf("Digues un número: ");scanf("%d", &a);printf("Digues un altre número: ");scanf("%d", &b);printf("El màxim entre %d i %d és %d\n",

a, b, maxim(a,b));return 0;

}

int maxim(int a, int b) {int resultat;if (a > b) {

resultat = a;} else {

resultat = b;}return resultat;

}

La primera línia indica que hi haurà una funció que es dirà maxim, queretornarà un enter i que rebrà dos paràmetres de tipus int. No cal posar elnom dels paràmetres, però si volem els podem posar. D’aquesta declaracióse’n sol dir “prototipus” de la funció.

És important que, quan s’usi una funció, hi hagi un prototipus, ja siguiamb la declaració que acabem de veure o perquè hem implementat la funció.No només perquè el compilador pugui fer les comprovacions necessàries, sinóperquè hi ha una sèrie d’aspectes que canvien, però aquí no ho explicarem.

35

Page 42: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

4 Funcions i procediments

36

Page 43: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

Capítol 5

Arxius

5.1 Introducció

La llibreria estàndar de C proveeix d’una sèrie d’eines per a treballar ambfitxers. Aquestes eines inclouen tipus de dades i funcions. Però abans depassar a veure tots aquests aspectes, primer cal donar alguns conceptesfonamentals sobre arxius.

Els arxius es poden classificar en “arxius de text” i en “arxius binaris”:

• Els arxius de text contenen caràcters que es poden mostrar per pantallai que es poden imprimir, com ara lletres, números, signes de puntu-ació, etc. Cada línia finalitza amb un o dos caràcters que marquen,justament, el final d’una línia. En UNIX es fa servir un sol caràcter definal de línia; en MS-DOS i Windows es fan servir dos caràcters. Quanobrim un fitxer de text amb un editor com ara ViM podem veure’n elcontingut sense problemes.Els arxius de codi font són arxius de text. Els arxius de Word no sónarxius de text.

• Els arxius binaris contenen qualsevol tipus de caràcters, sense que tin-guin cap significat en especial. Si obrim un arxiu binari amb un editorcom ara ViM veurem molts caràcters “estranys”, sense cap significataparent. Exemples d’arxius binaris són: els executables, les imatges,els arxius de música, els PDFs, els documents de Word, . . .

Per a treballar amb arxius — tant si són binaris com si són de text —inclourem el fitxer stdio.h:

#include <stdio.h>

i el tipus de dades que farem servir és FILE *. Un petit avís: les cap-çaleres de les funcions que veurem en aquest capítol no són exactament les

37

Page 44: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

5 Arxius

reals. Alguns aspectes s’han simplificat per tal de fer-les més comprensibles.Si busqueu a les pàgines manual, a internet, o als llibres de la bibliografia,podreu trobar les versions completes.

5.2 Obertura i tancament d’un arxiuPer a treballar amb un arxiu, abans l’hem d’obrir. D’aquesta manera indi-quem al sistema operatiu que la nostra aplicació farà lectures i/o escripturesa l’arxiu. Per a obrir un arxiu disposem de la següent funció:

FILE * fopen(char *path, char *mode);

El primer argument, path, és el nom de l’arxiu que es vol obrir. El segonargument, mode, pot prendre un dels valors següents:

• "r": l’arxiu s’obre per a lectura. Es comença a llegir pel principi del’arxiu. L’arxiu que es vol obrir ha d’existir.

• "r+": l’arxiu s’obre per a lectura i escriptura. Es comença a llegir oa escriure pel principi de l’arxiu. L’arxiu que es vol obrir ha d’existir.No s’esborra el contingut de l’arxiu si ja existeix.

• "w": l’arxiu s’obre per a escriptura. Si l’arxiu no existeix, es crea. Sija existeix, s’esborra tot el seu contingut. Es comença a escriure pelprincipi de l’arxiu.

• "w+": l’arxiu s’obre per a lectura i escriptura. Si l’arxiu no existeix,es crea. Si ja existeix, s’esborra tot el seu contingut. Es comença allegir o a escriure pel principi de l’arxiu.

• "a": l’arxiu s’obre per a escriptura. Si l’arxiu no existeix, es crea. Escomença a escriure pel final de l’arxiu.

• "a+": l’arxiu s’obre per a lectura i escriptura. Si l’arxiu no existeix,es crea. Les lectures es faran pel final de l’arxiu, i totes les escripturessempre es faran al final de l’arxiu.

Per als fitxers binaris, afegim la lletra "b" al final. Per exemple, per aobrir un fitxer binari per a lectura, l’argument mode serà "rb". Cal tenir encompte que, en UNIX, a l’obrir un arxiu no cal fer cap mena de distinciósobre si és un arxiu de text o un arxiu binari.

La funció fopen retorna NULL si no ha pogut obrir l’arxiu. Cada cop ques’obre un arxiu cal comprovar si realment s’ha obert bé.

Per a tancar un arxiu disposem de la funció fclose, que rep com aúnic argument l’arxiu (un FILE *) que volem tancar. Òbviament, només espoden tancar aquells arxius que s’han obert correctament. Per exemple:

38

Page 45: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

5 Arxius

FILE * f;f = fopen("arxiu.txt", "r");// treballem amb l’arxiufclose(f);

5.3 Lectura i escriptura en fitxers de textPer a llegir i escriure en fitxers de text emprarem unes funcions molt similarsa les que vam veure per a llegir de teclat i escriure de pantalla:

• La funció fprintf és exactament igual que la funció printf, peròpren un argument extra, al principi de tot, que és un arxiu prèviamentobert amb fopen.

• La funció fscanf és exactament igual que la funció scanf, però prenun argument extra, al principi de tot, que és un arxiu prèviament obertamb fopen.

Evidentment, els arxius s’han d’haver obert de tal manera que permetinl’operació: per exemple, si volem escriure amb fprintf hem d’haver obertl’arxiu per a poder-hi escriure.

5.3.1 Final d’arxiu

Convé tenir alguna manera de saber si hem arribat al final d’un arxiu. Lafunció feof ens ho indica, tant per a arxius binaris com per a arxius de text.La funció feof rep una variable de tipus FILE *, que representa un arxiuobert, i retorna cert (un valor diferent de zero) en cas que l’última lecturade l’arxiu hagi sobrepassat el seu final.

Dit d’una altra manera: feof no retorna cert quan hem arribat al finalde l’arxiu, sinó quan l’hem sobrepassat.

Suposem el següent codi:

FILE *f = fopen("arxiu", "r");char str[MAX];do {

fscanf(f, "%s", str);printf(f, "%s", str);

} while (!feof(f));

Aquesta funció llegeix un arxiu i el mostra per pantalla (no és, ni de lluny,la millor manera de fer-ho, però com a exemple ens servirà). El problema queté aquest exemple és que l’última lectura apareixerà dos cops per pantalla:quan s’hagi fet l’última lectura, feof encara no retornarà cert (perquè nos’ha traspassat el final de l’arxiu), per tant el bucle do-while farà una nova

39

Page 46: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

5 Arxius

iteració. L’intent de lectura fracassarà perquè s’haurà traspassat el final del’arxiu, printf mostrarà el contingut de l’última lectura vàlida i, ara sí,feof retornarà cert.

Per tant, la manera correcta de fer-ho és:

FILE *f = fopen("arxiu", "r");char str[MAX];fscanf(f, "%s", str);while (!feof(f)) {

printf("%s", str);fscanf(f, "%s", str);

}

5.4 Lectura i escriptura en fitxers binarisPer a llegir i escriure en fitxers binaris disposem de les següents funcions:

5.4.1 Lectura de fitxers binaris

Per a llegir disposem de la funció fread:

int fread(void *ptr, int size, int nmemb, FILE *stream);

El significat de cada paràmetre és el següent:

• El paràmetre ptr és un punter a la variable on voldrem que es posinles dades llegides. Encara no s’han explicat els punters, per tant: sila variable no és un array i en la seva declaració no hi apareix capasterisc, posarem l’operador & al davant.

• El paràmetre size indica la mida, en bytes, de cadascun dels objectesque volem llegir. L’operador sizeof retorna la mida en bytes d’untipus o d’una variable.

• El paràmetre nmemb indica la quantitat d’objectes que volem llegir.Cadascun d’aquests objectes ocupa size bytes.

• El paràmetre stream és l’arxiu que hem obert per a fer-hi lectures.

5.4.2 Escriptura de fitxers binaris

Per a escriure disposem de la funció fwrite:

int fwrite(void *ptr, int size, int nmemb, FILE *stream);

El significat de cada paràmetre és el següent:

40

Page 47: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

5 Arxius

• El paràmetre ptr és un punter a la variable on hi ha les dades ques’han d’escriure al fitxer. Encara no s’han explicat els punters, pertant: si la variable no és un array i en la seva declaració no hi apareixcap asterisc, posarem l’operador & al davant.

• El paràmetre size indica la mida, en bytes, de cadascun dels objectesque volem escriure.

• El paràmetre nmemb indica la quantitat d’objectes que volem escriure.Cadascun d’aquests objectes ocupa size bytes.

• El paràmetre stream és l’arxiu que hem obert per a fer-hi escriptures.

41

Page 48: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

5 Arxius

42

Page 49: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

Capítol 6

Memòria dinàmica

6.1 Introducció

La memòria dinàmica és un dels mecanismes més importants de la progra-mació en C, i el seu concepte fonamental — els punters — són un aspectecentral en la programació en C. Per altra banda, la majoria de problemesrelacionats amb les aplicacions escrites en C tenen a veure amb una gestióincorrecta de la memòria dinàmica.

La memòria que el sistema operatiu assigna a un programa en execucióes divideix en quatre grans àrees:

1. Instruccions: conté les instruccions que formen part del programa.

2. Dades estàtiques: conté les variables globals del programa.

3. Pila d’execució: serveix per a la crida de funcions i conté, entre d’altrescoses, les variables locals.

4. Memòria dinàmica: conté la memòria que un programa demana mentres’està executant.

En aquest capítol començarem estudiant el concepte d’adreça i de pun-ter, per passar a continuació a estudiar les eines per a demanar i alliberarmemòria dinàmica.

6.2 Adreces i punters

L’adreça d’una variable indica la seva ubicació a memòria. Amb l’operador& podem conèixer l’adreça d’una variable, tant si és global com local.

Un punter és una variable que conté l’adreça d’un o més objectes d’undeterminat tipus. La declaració d’un punter inclou el tipus dels objectes alsquals apunta. Per exemple:

43

Page 50: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

6 Memòria dinàmica

int *p;

declara la variable p com un punter a int. Això vol dir que el contingutde la variable p és una adreça a un o més objectes de tipus int. Si volemdeclarar un punter de tipus genèric, ho farem de la següent manera:

void *v;

Els punters genèrics tenen una sèrie de restriccions que anirem veient. Laprimera utilitat que veurem dels punters és el pas per referència. A l’apartat4.5 vam veure com podíem passar paràmetres a una funció, i vam veure unexemple de funció swap que no funcionava:

void swap(int a, int b) {int t;t = a;a = b;b = t;

}

La versió correcta d’aquesta funció és la següent:

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

}

Fixem-nos que ara la funció no rep dos enters, sinó dos punters a enter,de manera que el que la funció rep és, en realitat, les adreces de les variables.D’aquesta manera en pot modificar el contingut i fer que els canvis siguinvisibles a tot arreu.

Fixem-nos també que per a accedir al contingut de les variables que s’hanpassat es fa servir l’operador *. Aquest operador significa que el que ensinteressa no és l’adreça que conté el punter, sinó l’objecte de memòria queviu en tal adreça. No et pot aplicar l’operador * a un punter genèric.

Ara hem de cridar la funció de la següent manera:

int a = 2, b = 3;swap(&a, &b);printf("%d %d\n", a, b);

I efectivament veurem que per pantalla obtenim la següent sortida:

3 2

44

Page 51: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

6 Memòria dinàmica

6.3 Memòria dinàmica

Fins ara hem vist el concepte fonamental per a treballar amb memòria dinà-mica: el punter. Però l’única utilitat que fins ara hem vist dels punters és ladel pas de paràmetres per referència. Ens queda per veure la seva utilitat enmemòria dinàmica. Per a treballar amb les funcions que veurem tot seguitcal incloure stdlib.h:

#include <stdlib.h>

6.3.1 Demanar memòria

6.3.1.1 Funció malloc

La funció malloc demana nova memòria per al programa:

void * malloc(int numbytes);

L’únic paràmetre que rep la funció malloc és el número de bytes que hade demanar.

• Si malloc aconsegueix obtenir la memòria, retorna un punter queapunta a la nova zona de memòria. Tenim garantit que aquesta zonade memòria contindrà almenys la quantitat de bytes que hem demanat.

• Si malloc no aconsegueix obtenir la memòria, retorna un punter NULL,el valor del qual és zero. Si s’aplica l’operador * sobre un punter queval NULL el programa fallarà amb un missatge semblant a:

Segmentation fault (core dumped)

• Si l’argument que passem a malloc val zero, pot ser que malloc retorniun punter NULL.

El següent exemple demana memòria per a deu enters:

int *a;a = malloc(sizeof(int)*10);

L’operador sizeof ja el coneixem de l’apartat 5.4.1. A partir d’aquestmoment, la variable a conté l’adreça d’una zona de memòria on hi ha deuenters. Aquesta variable a la podem fer servir com si fos un array de 10enters:

a[3] = 256;

45

Page 52: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

6 Memòria dinàmica

Nota En molts llibres i exemples a Internet, es posa un “cast” abans dela crida a la funció malloc, per exemple:

int *a = (int *) malloc(sizeof(int)*10);

Aquesta conversió no és necessària: malloc retorna un punter genèric,i un punter genèric es converteix automàticament a qualsevol altre tipus depunter, sense necessitat de cap conversió implícita.1

6.3.1.2 Funció calloc

La funció malloc no inicialitza la memòria que obté. Si a més a més ensinteressa que aquesta memòria estigui inicialitzada a zero, podem fer servirla funció calloc:

int *a;a = calloc(10, sizeof(int));

Fixem-nos, a més a més, que la funció calloc rep dos paràmetres enlloc d’un: el primer és la quantitat d’objectes pels quals volem demanarmemòria; el segon és la mida d’un d’aquests objectes.

6.3.1.3 Funció realloc

La funció realloc serveix per a intentar aumentar o disminuir la mida dela zona de memòria referenciada per un punter.

Aquesta funció rep dos paràmetres:

• Un punter a la zona de memòria que volem ampliar o reduir.

• La nova mida que volem que tingui la zona de memòria.

A més de rebre aquests dos paràmetres, realloc retorna un punter, queapunta a la zona de memòria amb la nova mida. Pot ser igual o diferental valor del punter que passem com a paràmetre. Si realloc retorna NULL,vol dir que no ha pogut aumentar o disminuir la zona de memòria; de totesmaneres, realloc no allibera cap punter en cas d’error.

6.3.2 Alliberar memòria

És important que alliberem la memòria que ja no fem servir. A tal fi,disposem de la funció free:

void free(void *);1Vegeu l’estàndar de C (ISO/IEC 9899:1999,TC3), apartat 6.3.2.3, paràgraf 1.

46

Page 53: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

6 Memòria dinàmica

A la funció free no cal especificar-li la mida de la zona de memòria ala qual apunta l’argument que li passem. Si el punter que passem apuntaa una variable, podem tenir problemes i el programa pot finalitzar la sevaexecució amb un missatge d’error.

Intentar desreferenciar un punter que ha estat alliberat també pot serproblemàtic:

int *a = malloc(sizeof(int)*10);// fem cosesfree(a);a[3] = 256; // pot provocar un error

6.3.3 Fuites de memòria

Suposem el següent exemple:

int i, *p;for (i = 0; i < 10; i++) {

p = malloc(sizeof(int)*10);}

A la primera iteració es demana memòria per a deu enters. El punter papunta a aquesta zona de memòria. A la segona iteració es torna a demanarmemòria per a deu enters, i el punter p apunta a aquesta nova zona dememòria. Però què passa amb la primera zona de memòria? No ha estatalliberada, per tant segueix sent del programa. Però com que p apunta a lasegona zona de memòria, no hi ha cap punter que apunti a la primera, i pertant resulta innacessible. D’això se’n diu “fuita de memòria” (memory leaken anglès).

Hauria estat millor haver declarat p com un array de deu punters:

int i, *p[10];for (i = 0; i < 10; i++) {

p[i] = malloc(sizeof(int)*10);}

6.3.4 Dangling references

Molt pitjor que les fuites de memòria són les dangling references: puntersque apunten a una zona de memòria que ja ha estat alliberada. El pitjorde tot plegat és que intentar usar un punter d’aquestes característiques nosempre causa un error. Convé que el programador tingui molta cura en usarla memòria dinàmica.

47

Page 54: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

6 Memòria dinàmica

48

Page 55: Introducció al llenguatge de programació Cusers.salleurl.edu/~xavier.canaleta/so/assig/LlibreC.pdfmida mínima en bytes, sinó que especifica el mínim de dígits significatius

Bibliografia

[KR78] The C Programming Language, Brian B. Kernighan, DennisM. Ritchie, 1978 (primera edició), Prentice Hall. ISBN: 0-13-110163-3

[KR88] The C Programming Language, Brian B. Kernighan, DennisM. Ritchie, 1988 (segona edició), Prentice Hall. ISBN: 0-13-110362-8

[PvdL94] Expert C Programming, Peter van der Linden, 1994, PrenticeHall. ISBN: 0-13-177429-8

[Sum96] C Programming FAQs, Steve Summit, 1996, Addison-Wesley,ISBN: 0-201-84519-9

[HS02] C: A Reference Manual, Samuel P. Harbison, Guy L. Steele,2002 (cinquena edició), Prentice Hall, ISBN: 0-13-089592X.

[Prata04] C Primer Plus, Stephen Prata, 2004 (cinquena edició), Sams,ISBN: 0-672-32696-5.

[ALSU07] Compilers: Principles, Techniques and Tools, Alfred S.Aho, Monica S. Lam, Ravi Sethi, Jeffrey D. Ullman, 2007 (segona edi-ció), Addison-Wesley. ISBN: 0-321-48681-1

[SunC12] Sun Studio 12: C User’s Guide, Sun Microsystems, 2007.Disponible lliurement a la web de Sun Microsystems.

[N1256] ISO/IEC 9899:TC3, ISO comitè WG14/N1256, 2007. Disponiblelliurement a internet.

49