Enrere Mòdul 2
Fonaments de Programació. Llenguatge C/C++---
Pràctica  Exercicis
Pràctica d'ampliació

 
Resum Teòric

Tipus de dades fonamentals: Variables

El llenguatge C/C++, com altres llenguatges, té la possibilitat de treballar amb diferents tipus de dades: caràcters alfanumèrics, nombres enters, reals,…. A més, alguns d'aquests tipus de dades permeten concretar el rang (i/o la precisió) i la possibilitat que els nombres siguin només positius o tinguin signe.

Totes les variables que es fan servir en un programa en C s'han de declarar prèviament. La declaració es fa al començament d'un bloc o bé abans de qualsevol funció. En C++ no és necessari que estigui al començament, però gairebé sempre és aconsellable, per claredat, fer les declaracions al començament.

Per declarar una variable s'escriu el tipus de variable seguit del seu nom. Com tota instrucció C, les declaracions s'acaben amb un punt i coma.

Els tipus fonamentals del C estàndard són: char, int, float i double. Aquests tipus fonamentals es poden ampliar amb l’ús dels modificadors de tipus.

Aquesta taula mostra tots els tipus que es poden fer servir a C:

Enters char signed char unsigned char
  int signed int unsigned int
  short int signed short int unsigned short int
  long int signed long int unsigned long int
Reals float
  double
  long double
 

Els nombres enters (int o char) poden ser positius o negatius (signed), o bé, essencialment, no negatius (unsigned). Els modificadors short i long fan referència al nombre de xifres o rang dels nombres.

Els modificadors signed i int són opcionals i es poden ometre; per exemple, és el mateix short int que short, i signed char que char.

C++ afegeix a aquesta llista, el tipus bool per emmagatzemar només dos valors, true i false. Aquestes tres paraules són noves paraules clau incorporades per C++.

 

Les variables char

Les variables char  contenen un únic caràcter i s'emmagatzemen en un byte o octet (8 bits). Per tant, una variable char pot contenir 28 = 256 valors diferents: de 0 a 255 si s'ha declarat explícitament unsigned, o bé de -128 a 127 en altre cas.

Es pot pensar en el contingut d'una variable char com un enter petit o bé com un caràcter. La correspondència es fa a través del codi ASCII. Aquesta taula es pot crear amb el programa de la pràctica 4 d'aquest mòdul.

Per exemple, el caràcter ‘A’ correspon al codi ASCII: 65.

Es pot observar que el codi ASCII associa nombres consecutius amb les lletres majúscules i minúscules ordenades alfabèticament. Això simplifica notablement les operacions d'ordenació alfabètica (sobre tot en anglès).

Els caràcters amb codi ASCII més petit que 32  són caràcters especials no imprimibles. El 32 correspon a un espai.

Una variable del tipus char es pot considerar com un enter i, per tant, estan permeses les mateixes operacions que entre els enters. A la pràctica 1 veurem un exemple que fa referència a aquest aspecte.

Les variables tipus char es poden escriure com a caràcters o com a nombres petits segons el format de conversió que s'utilitzi en la crida a la funció d'escriptura. A la pràctica 1 es contempla també aquesta dicotomia.

 

Les variables int

Les variables del tipus int poden ocupar 2 o 4 octets. En la plataforma Linkat ocupen 4 octets. Si les definim amb signe (signed) el rang està comprès entre -2.147.483.648 i 2.147.483.647 i si les definim sense signe (unsigned), el rang està comprès entre 0 i 4.294.967.295 (= 232 –1).

Encara que la mida en octets d'una variable del tipus int depèn de la màquina concreta, podem assegurar-nos que ocuparà 2 octets si fem servir el modificador short. Amb el modificador long el rang serà de 4 octets. L'ús dels modificadors que semblen redundants asseguren la portatibitat del codi d'un sistema a un altre.

 

Les variables float i double

Les variables float i double (també anomenades de punt flotant) permeten representar nombres amb una part entera i una part fraccionària. A més, també permeten representar nombres més grans que els enters, encara que sigui perdent precisió.

Aquestes variables es representen internament per mitjà de la mantissa, que és un nombre comprès entre 0.1 i 1.0, i l'exponent, que representa la potència de 10 que multiplica a la mantissa. El nombre quedarà definit com: mantissa per 10 elevat a l'exponent. Per exemple, el nombre pi es representa com 0.314592654 ·101. Tant la mantissa com l’exponent poden ser positius o negatius.

Les variables float ocupen 4 octets (32 bits). Fan servir 24 bits per a la mantissa (1 bit pel signe i 23 pel valor) i 8 bits per a l’exponent (1 bit pel signe i 7 bits pel valor).

Les variables double ocupen 8 octets o 64 bits (53 bits per a la mantissa i 11 per a l'exponent).

Les variables reals no poden tenir l'identificador unsigned.

 

Les variables bool

L’estàndard C++ emes per les organitzacions ANSI/ISO proporciona el tipus de dades del tipus bool,i els seus valors només poden ser false o true. Aquestes variables son una bona alternativa a utilitzar  0 ( zero ) per indicar fals i diferent de 0 ( zero ) per indicar veritat.

#include <iostream>

#include <iomanip>

using namespace std;

 

int main()

{

            bool bVar = true; // correcte

            bool bVar2 = 10; // no dona error  però no és una bona pràctica de programació.

            int x=5;

           

            cout <<" la variables bVar val "<<bVar;

             if (x)

                        cout<<"\nveritat";

            else

                        cout<<"\nfals";

           

            return 0;

}

 Qualsevol valor diferent de zero és interpretat com veritat ( cert ). Aquest és el cas de la variable x de l’anterior programa.

 

A la taula següent es mostra la llista dels tipus, els octets que ocupen i el rang de dades numèriques que poden contenir:

 

TIPUS

bytes

rang

char

1

-128 a 127

unsigned char

1

0 a 255

short int

2

-32768 a 32767

unsigned short int

2

0 a 65535

int

4

-2.147.483.648 a 2.147.483.647

unsigned int

4

0 a 4.294.967.295

long int

4

-2.147.483.648 a 2.147.483.647

unsigned long int

4

0 a 4.294.967.295

float

4

3.4 E-38 a 3.4 E+38 (i els negatius)

double

8

1.7 E-308 a 1.7 E+308 (i els negatius)

bool 1 true (1) o false (0)

C inclou un operador en temps de compilació anomenat sizeof() que torna la mida de la variable o tipus que té com argument. Aquest operador és altra eina que té C per fer programes portables d'una màquina a una altra.

 

Duració i visibilitat de les variables

El tipus de variable es refereix a la natura de la informació que conté i de la quantitat de memòria necessària per al seu emmagatzematge. Una altra propietat que tenen les variables és la visibilitat o duració. A C existeixen quatre modes fonamentals: auto, extern, static i register

auto (automàtic)

És l'opció per defecte per a les variables que es declaren a dintre d'un bloc {…}, inclòs el bloc que conté el codi de les funcions. A C, al contrari que a C++, és obligatori que les declaracions de variables estiguin al començament. La paraula auto és optativa i gairebé mai es posa. Les variables auto són variables locals, és a dir, només existeixen dintre del blocs on estan definides i els blocs interiors a aquest. En aquests blocs interiors es poden ocultar si hi ha una altra variable amb el mateix nom. Les variables auto no són inicialitzades per defecte, és a dir, quan es creen tenen valors aleatoris.

extern

Són variables globals, que es defineixen fora de qualsevol bloc o funció, inclús de la funció main(). Aquestes variables existeixen al llarg de tota l'execució del programa i són visibles per totes les funcions que estan entre la definició i el final de l'arxiu. Per tal que altres funcions puguin veure una variable extern, s'ha de declarar la variable en aquestes funcions com extern. L'ús de variables extern és considerada una pràctica perillosa i poc recomanable; s'ha d'evitar sempre que es pugui. Les variables extern són automàticament inicialitzades a 0.

Si en un programa una variable global (extern) té el mateix nom que una variable local (auto), aquesta oculta la primera. No obstant això, es pot fer servir la variable global amb l'operador de resolució d'àmbit (::). Aquest operador és propi de C++ i no es pot fer servir amb programes que s'hagin de compilar en compiladors ANSI C.

static

Les variables que es defineixen static a dintre d'un bloc conserven el seu valor entre diferents execucions d'aquest bloc. Les variables static són inicialitzades a 0 automàticament.

Les variables definides com static extern són visibles només per a les funcions i blocs compresos des de la seva definició fins al final de l'arxiu. No són visibles des d'altres funcions encara que es declarin en aquestes funcions com extern. Aquesta és una forma de restringir la visibilitat de les variables.

register

Aquest mode és una recomanació per al compilador, amb l'objectiu que -si és possible- algunes variables siguin emmagatzemades directament en els registres de la CPU, aconseguint d'aquesta forma un augment de la velocitat.

 

Constants

Les constants són un tipus d'informació numèrica o alfanumèrica que no poden canviar més que amb una nova compilació del programa. Les constants poden ser: constants numèriques o alfanumèriques.

 

Constants numèriques

Les constants numèriques poden ser enteres o de punt flotant.

Les constant enteres poden estar en base 10 (decimal), base 8 (octal) o base 16 (hexagesimal). Les constants octals comencen amb 0 (zero) i les hexagesimals amb x0. Encara que un programador no expert no faci servir les bases octal i hexagesimal, és important conèixer la seva existència per tal de no escriure per error constants enteres que comencin amb 0.

El tipus de la constant es pot determinar automàticament segons la seva magnitud, o explícitament amb els caràcters de tipus just a continuació del nombre. Exemple:

12312 constant tipus int
54154551145 constant no vàlida
54154551145. constant tipus double
1.25f constant tipus float
1.25l constant tipus long double

Les constants de punt flotant per defecte són double. Per indicar que una constant és float s'ha d'afegir una f o F i per indicar que és del tipus long double una l o L. Les constants de punt flotant es poden representar amb notació científica, és a dir, una part entera, un punt, una part fraccionària, la lletra e o E i un exponent enter.

 

Constants de caràcter

Una constant de caràcter és un caràcter qualsevol tancat entre cometes simples (ex: ' t' ). De fet, el valor d'una constant de caràcter és el valor numèric segons el codi ASCII.

 

Cadenes de caràcters

Una cadena de caràcters és una seqüència de caràcters delimitada per dobles cometes (" "). Per emmagatzemar una cadena de caràcters fa falta un vector char o conjunt de variables del tipus char amb el mateix nom. L'estudi dels vectors es farà en un mòdul posterior.

 

const

Es pot fer servir el qualificador const davant de la declaració d'una variable. Això servirà per tal d'assegurar-nos que el contingut d'aquesta variable no serà modificat al llarg de l'execució del programa.

 

Operadors, expressions i sentències

Un operador és un caràcter o grup de caràcters que actua sobre una o més variables, constants o expressions per realitzar una determinada operació.

Una expressió és un conjunt de variables i constants relacionades a través d'operadors. Les expressions poden contenir parèntesis (...) per tal d'agrupar part de elles i per alterar la jerarquia de les operacions.

 

Operadors aritmètics

Els operadors aritmètics de C són:

- Canvia el signe  (és un operador unari, és a dir, actua només sobre un operant)
+ Suma 
-  Resta
*  Producte
/  Divisió
% Mòdul (resta de la divisió entera)

 

Operadors d'assignació

Una expressió dóna un resultat. Aquest resultat pot assignar-se a una variable mitjançant un operador d'assignació. L'operador d'assignació més utilitzat és (=), que no s'ha de confondre amb una igualtat matemàtica. La seva forma general és:

nom_variable = expressió;

A l'expressió de la dreta pot aparèixer la mateixa variable a la qual es vol assignar l'expressió. Una sentència tal com:

a = a+1;

és totalment correcte en C, encara que matemàticament sembli incorrecta.

A més de l'operador d'assignació (=) existeixen quatre operadors d'assignació més: (+=, –=, *= i /=)

a += b significa a = a + b
a –= b significa a = a – b
a *= b significa a = a * b
a /= b significa a = a / b

 

Operadors incrementals

Els operadors incrementals (++) i (--) són operadors unaris (un sol operant)  que incrementen o disminueixen en una unitat el valor de la variable que afecten. Aquests operadors poden anar davant la variable o darrera la variable. A continuació es mostra la diferència entre aquests dos usos dels operadors incrementals:

a = 2;
b = a++;              /* a = 3 i b = 2 */
b = ++a;              /* a = 3 i b = 3 */

A la segona assignació, primer s'assigna a b el valor d'a i a continuació s'incrementa la variable a. A la tercera assignació, primer s'incrementa la variable a i a continuació s'assigna a la variable b.

 

Operadors relacionals

Els operadors relacionals permeten analitzar si es compleixen o no algunes condicions. Si una condició es compleix es diu que és certa (true), en cas contrari es diu que és falsa (false). En C, false es representa amb un 0 i true amb qualsevol nombre diferent de 0. Per conveni, C assigna un 1 si una expressió lògica és certa. Els operadors relacionals de C són:

== Igual que (no confondre amb l'operador d'assignació =)
<  Menor que
>  Major que
<= Menor o igual que
>= Major o igual que
!= Diferent que:

 

Operadors lògics

Els operadors lògics permeten combinar els resultats de les operadors relacionals. Hi ha tres operadors lògics:

!  ,  &&  , ||

L'operador ! és unari i torna 1 (veritat) si l'operant és 0 (fals) o torna 0 (fals) si l'operant és diferent de 0 (veritat).

L'operant binari && correspon a la conjunció i.  Torna 1 (veritat) en el cas que els dos operants siguin diferents de 0 (veritat), en altre cas torna 0 (fals).

L'operant binari || correspon a la disjunció o. Torna 0 (fals) en el cas que els dos operants siguin 0 (fals), en altre cas torna 1 (veritat).

 

Altres operadors

operador unari: + no fa res, però serveix com a complement de l'operador unari -.

operador sizeof(): torna la mida del tipus, variable o expressió introduït com argument.

operador , (coma): serveix per avaluar expressions múltiples. El seu ús més freqüent és en expressions de la sentència for.

 

Expressions

Una expressió és una combinació de variables, constants i operadors. Quan el compilador troba una expressió, l'avalua i torna el seu resultat. Encara que es poden diferenciar dos tipus d'expressions: aritmètiques i lògiques, de fet com que en C/C++ els operadors lògics actuen sobre números, aquests dos tipus d'expressions es solen barrejar. En C és habitual una expressió com:

(a-b*2.0)||(c!=a)

 

Jerarquia de les operacions

És sabut que el valor d'una expressió depèn de l'ordre en què es facin les operacions. Per aquest motiu s'ha de determinar unes regles de jerarquia de les operacions. Aquest ordre sempre es pot modificar amb parèntesis. Aquestes regles es presenten a la taula treta directament de les ajudes de VC++. S'ha de tenir en compte que hi ha operadors no tractats en aquest curs com els operadors sobre bits.

Operador

Associabilitat

[ ] ( ) . –> postfix ++ and postfix --

d'esquerra a dreta

prefix ++ and prefix--
sizeof & * + – ~ !

de dreta a esquerra

typecasts

de dreta a esquerra

* / %

d'esquerra a dreta

+ –

d'esquerra a dreta

<< >>

d'esquerra a dreta

< > <= >=

d'esquerra a dreta

== !=

d'esquerra a dreta

&

d'esquerra a dreta

^

d'esquerra a dreta

|

d'esquerra a dreta

&&

d'esquerra a dreta

||

d'esquerra a dreta

? :

de dreta a esquerra

= *= /= %=
+= –= <<= >>=
&= ^= |=

de dreta a esquerra

,

d'esquerra a dreta

 

Conversions de tipus implícites i explícites (casting)

Si barregen variables o constants de tipus diferents per fer operacions, es produeix una conversió implícita i automàtica de la dada de menor rang abans de realitzar-se l'operació. Es diu que la variable o constant de menor rang promociona al rang de l'altra. La jerarquia dels rangs és la següent:

long double > double > float > unsigned long > long > unsigned int > int > char

Una altra classe de promoció implícita es dóna quan el resultat d'una expressió és assignat a una variable. Aquest resultat es converteix al tipus de la variable. Aquesta última circumstància és advertida pel compilador.

En C és també possible realitzar conversions explícites de tipus (casting). Per fer aquesta conversió es pot triar la forma tradicional de C que consisteix en posar davant de la variable o constant que es vulgui convertir el tipus nou entre parèntesis. Per exemple, en l'expressió:

k = (int) 1.7 + (int) 2.5

k prendrà el valor 3, ja que al convertir 1.7 i 2.5 a enters, s'han convertit en 1 i 2.

C++ incorpora una altra forma de fer aquestes conversions i consisteix en fer servir el tipus de variable com una funció l'argument de la qual és l'expressió que es vulgui convertir, per exemple:

k = int(1.7) + int (2.5)

és equivalent a l'anterior.

 

Sentències

Una sentència en C és una unitat executable com pot ser una assignació o una crida a una funció. Una sentència  pot ser simple o composta. Les sentències simples acaben amb el caràcter ; (punt i coma). Les sentències compostes són un conjunt de sentències simples agrupades dintre de claus {}. Una sentència composta també es coneix amb el nom de bloc.

 

Directives del preprocessador: #include i #define

El preprocessador del llenguatge C/C++ actua prèviament al compilador. Entre d'altres directives que pot realitzar el preprocessador, les més usuals són #define i #include. Totes les directives estan precedides pel caràcter #.

La directiva #include va seguida d'un nom d'arxiu. El preprocessador substitueix aquesta línia pel contingut de l'arxiu. Si l'arxiu s'escriu entre dobles cometes: 

#include "nom_arxiu"

el preprocessador busca l'arxiu en el directori actual i després en el directori estàndard de llibreries. Si l'arxiu s'escriu entre els símbols <>:

#include <nom_arxiu>

el preprocessador busca l'arxiu directament en el directori estàndard de llibreries. El directori estàndard està contingut en una variable d'entorn.

Aquesta directiva es fa servir normalment per incloure arxius amb les declaracions de les funcions de llibreria. Aquests arxius solen tenir l'extensió .h

La directiva #define permet definir macros o constants. Una sentència com:

#define NOM text

busca en el codi NOM i el substitueix per text. És important adonar-se que aquesta substitució es fa abans de fer la compilació. 

 

Funcions

Les aplicacions informàtiques que s'utilitzen avui dia solen tenir desenes de milers de línies de codi font. A mida que un programa augmenta de mida és indispensable la modularització que és el procés de dividir un programa en parts més petites que fan coses més concretes. A aquestes parts se li diuen subprogrames, subrutines, procediments, funcions,… depenent del llenguatge emprat. En C es fa servir el terme funció. En C++ també es fa servir aquest terme, encara que C++ permet una altra forma de programar que abstrau el concepte de funció amb el concepte d'objecte. En aquest resum veurem les característiques de les funcions pròpies de C.

La divisió d'un programa en unitats més petites o funcions presenta molts avantatges:

  • Cada funció té un nombre de línies més reduït i és més fàcil manipular-la,

  • Una mateixa funció pot ser cridada moltes vegades per parts diferents del programa estalviant memòria, temps de desenvolupament i presentant més claredat.

  • Independència de dades i ocultament de la informació que disminueix la possibilitat d'error al modificar una funció.

A la tècnica de programació que consisteix en dividir el programa en unitats separades de codi i dades se li diu programació estructurada.

Un programa C és una col·lecció d'una o més funcions.

Una funció de C és una porció de codi o programa que realitza una determinada tasca.

Una funció està associada amb un identificador o nom, i una llista d'arguments, que s'utilitza per referir-se a ella des de la resta del programa.

En totes les funcions de C cal distingir entre definició, declaració i crida.

crida

Les funcions de C es criden escrivint el seu nom seguit dels arguments en una sentència del programa principal o d'altra funció. Els arguments són dades que s'envien a la funció. Es posen dintre d'un parèntesi i es separen per comes. Per exemple, podem considerar la funció anomenada hipotenusa que calcula el valor de la hipotenusa d'un triangle rectangle a partir de la mesura dels seus catets a i b. Una forma de cridar a aquesta funció en C seria:

hipotenusa(a ,b)

En aquest exemple, hipotenusa és el nom de la funció, i a i b són els arguments o dades necessaris per al càlcul desitjat. El resultat de les instruccions que realitza una funció és el valor de retorn i aquest substituirà el nom de la funció en el mateix lloc on s'ha fet la crida.

definició

Per poder fer una crida a una funció és necessari que en altre lloc, en el mateix arxiu o en un altre, estigui la definició de la funció. La definició és el conjunt de sentències o instruccions necessàries per tal que la funció pugui realitzar la seva tasca quan sigui cridada. A més del codi, la definició de la funció inclou la definició del tipus de valor de retorn i de cada un dels seus arguments.

A continuació, de forma incompleta i a mode d'exemple, hi ha el possible codi de la funció hipotenusa()

double hipotenusa(double catet1, double catet2){

double resultat;

...

resultat = ... ;

return resultat;

}

 

La primera línia de la definició conté el tipus de valor de retorn (double en aquest cas). A continuació ve el nom de la funció seguit -entre parèntesis- dels arguments i els seus tipus respectius. En aquest cas hi ha dos arguments (catet1 i catet2), ambdós del tipus double. Després s'obren les claus que contenen el codi de la funció. Dintre d'aquest codi hi ha una o més sentències return que tornen el valor de retorn. En aquest cas, torna el valor de la variable resultat a la funció que ha cridat a la funció.

Les claus "{}" són el mètode utilitzat per C per agrupar diferents sentències per tal que es comportin com una sentència única. Tot el cos d'una funció ha d'estar sempre comprès entre claus.

declaració

Una funció ha de ser declarada abans de ser cridada. La declaració de la funció és una sentència que permet al compilador comprovar el nombre i tipus d'arguments, així com el del seu valor de retorn. La declaració d'una funció també es coneix com el prototipus de la funció. La declaració d'una funció era optativa en C i és obligatòria en C++

La funció main() és una funció que existeix en tot programa C, des del més petit al més gran. Conté el codi pel qual comença l'execució del programa. Aquest programa principal és també una funció. 

 

--- ---