26
1 Prezentarea noŃiunii de limbaj de programare Am văzut în secŃiunea precedenta cum pot fi reprezentaŃi algoritmii prin utilizarea pseudo codului sau a schemelor logice, insa prelucrarea automata a datelor presupune scrierea algoritmului intr-o forma ce poate fi înŃeleasă de calculatorul electronic. Algoritmii vor fi scrişi intr-un “limbaj de programare”, care va conŃine operaŃii asemănătoare celor despre care am amintit, numite acum instrucŃiuni. Limbajul de programare conŃine: ALFABETUL: o mulŃime de simboluri pentru scrierea cuvintelor din limbaj VOCABULARUL (LEXICUL): mulŃime de cuvinte acceptate ca făcând parte din limbaj Se numeşte UNITATE LEXICALA cea mai mica "îmbinare" de caractere din vocabular, care are un înŃeles. Exista un set de reguli privind combinarea unităŃilor lexicale în cuvinte şi a cuvintelor în "fraze" (reguli de SINTAXA), respectarea regulilor ducând la obŃinerea unor construcŃii corecte. SEMANTICA unui limbaj se refera la înŃelesul structurilor obŃinute prin combinarea cuvintelor acceptate de limbaj. În vocabular avem: cuvinte cheie = cuvinte sau prescurtări ale unor cuvinte din limba engleza, ce reprezintă comenzi (instrucŃiuni) identificatori = nume folosite pentru variabile, tipuri de date şi funcŃii definite de utilizator. Un identificator este format dintr-un şir de caractere care începe cu o litera şi poate conŃine litere, cifre şi caracterul "_" (underscore). Identificatorul nu poate conŃine spatii sau apostrof, virgula, ghilimele ... Identificatorii nu pot coincide cu cuvintele cheie. Prin PROGRAM se înŃelege o succesiune de comenzi(instrucŃiuni) de prelucrare a datelor, scrise intr-un limbaj de programare. Programul este memorat intr-o entitate numita fişier sursa (este un fişier text). Prelucrările dintr-un program C++ sunt grupate în FUNCłII. Rezolvarea unei probleme se face prin utilizarea unor funcŃii definite în limbaj şi / sau a unor funcŃii scrise de programator, atunci când funcŃiile deja existente nu sunt suficiente. FuncŃiile pe care limbajul le pune la dispoziŃia utilizatorului sunt grupate, după tipul de prelucrare oferit, în mai multe fişiere numite "biblioteci" (fişiere HEADER). Pentru a putea utiliza o funcŃie trebuie să se specifice la începutul programului numele bibliotecii care conŃine funcŃia respectiva. Orice program C++ trebuie să conŃină o funcŃie numita "main" (un fel de “program principal”), instrucŃiunile conŃinute de aceasta fiind cele prelucrate atunci când programul este lansat în execuŃie. Pentru a se putea obŃine rezultatele prelucrării datelor cu ajutorul programelor, trebuiesc parcurse următoarele faze: scrierea programului (editarea textului sursa); compilarea programului (= verificarea corectitudinii sintactice şi semantice a textului sursa şi prelucrarea sa fişier obiect) editarea legaturilor (fişierul / fişierele obiect obŃinute în urma compilării sunt transformate intr-un fişier executabil, adică într-un fişier care poate fi lansat în execuŃie prin simpla scriere a numelui sau la prompterul sistemului de operare; Numim mediu de programare un program care permite asistarea programatorului în toate fazele de elaborare a unui program, scris intr-un limbaj de programare (editare, depanare, compilare, execuŃie). Mediul de programare Borland C++ poate fi lansat în execuŃie prin tastarea comenzii bc la prompterul MSDOS. În paragraful următor vor fi prezentate elementele de baza ale limbajului C. Prezentarea generala a limbajului C++ Alfabetul Alfabetul limbajului este format din acele simboluri utilizate la reprezentarea entităŃilor unui program, adică a unitarilor lexicale. Reamintim ca, prin unităŃi lexicale înŃelegem cele mai mici entităŃi cu valoare semantica (adică au o semnificaŃie), prin combinarea cărora rezulta construcŃiile sintactice ("propoziŃii şi fraze"). Alfabetul limbajului C se compune din următoarele categorii de simboluri: Literele mari şi mici ale alfabetului englez şi caracterul de subliniere "_" (underscore) Cifrele arabe: 0-9 Semne de punctuaŃie: ; , ‘ " Alte caractere: +, -, *, / (, ), {, }, [, ], \, ~, ^, <, >, =, ?, !, #, &, Literele şi cifrele, precum şi caracterul underscore, de multe ori asimilat în mulŃimea literelor, sunt utilizate pentru construirea identificatorilor şi cuvintelor cheie, după reguli ce vor fi descrise în paragrafele corespunzătoare. În limbajul C se face diferenŃa dintre literele mici şi majusculele corespunzătoare, deci identificatorul "a" va fi diferit de identificatorul "A", iar “turbo” va fi diferit de “TURBO” sau “TuRbO” sau orice altă combinaŃie majusculă minusculă.

Prezentarea noŃiunii de limbaj de programarescoala6vaslui.freehostia.com/files/Limbaj_C++.pdf · unui program, scris intr-un limbaj de programare (editare, depanare, compilare, execuŃie)

  • Upload
    others

  • View
    17

  • Download
    0

Embed Size (px)

Citation preview

1

Prezentarea noŃiunii de limbaj de programare Am văzut în secŃiunea precedenta cum pot fi reprezentaŃi algoritmii prin utilizarea pseudo codului sau a

schemelor logice, insa prelucrarea automata a datelor presupune scrierea algoritmului intr-o forma ce poate fi înŃeleasă de calculatorul electronic. Algoritmii vor fi scrişi intr-un “limbaj de programare”, care va conŃine operaŃii asemănătoare celor despre care am amintit, numite acum instrucŃiuni.

Limbajul de programare conŃine: ALFABETUL: o mulŃime de simboluri pentru scrierea cuvintelor din limbaj VOCABULARUL (LEXICUL): mulŃime de cuvinte acceptate ca făcând parte din limbaj Se numeşte UNITATE LEXICALA cea mai mica "îmbinare" de caractere din vocabular, care are un înŃeles.

Exista un set de reguli privind combinarea unităŃilor lexicale în cuvinte şi a cuvintelor în "fraze" (reguli de SINTAXA), respectarea regulilor ducând la obŃinerea unor construcŃii corecte. SEMANTICA unui limbaj se refera la înŃelesul structurilor obŃinute prin combinarea cuvintelor acceptate de limbaj.

În vocabular avem: cuvinte cheie = cuvinte sau prescurtări ale unor cuvinte din limba engleza, ce reprezintă comenzi (instrucŃiuni) identificatori = nume folosite pentru variabile, tipuri de date şi funcŃii definite de utilizator. Un identificator

este format dintr-un şir de caractere care începe cu o litera şi poate conŃine litere, cifre şi caracterul "_" (underscore). Identificatorul nu poate conŃine spatii sau apostrof, virgula, ghilimele ... Identificatorii nu pot coincide cu cuvintele cheie.

Prin PROGRAM se înŃelege o succesiune de comenzi(instrucŃiuni) de prelucrare a datelor, scrise intr-un limbaj de programare. Programul este memorat intr-o entitate numita fişier sursa (este un fişier text).

Prelucrările dintr-un program C++ sunt grupate în FUNCłII. Rezolvarea unei probleme se face prin utilizarea unor funcŃii definite în limbaj şi / sau a unor funcŃii scrise de programator, atunci când funcŃiile deja existente nu sunt suficiente. FuncŃiile pe care limbajul le pune la dispoziŃia utilizatorului sunt grupate, după tipul de prelucrare oferit, în mai multe fişiere numite "biblioteci" (fişiere HEADER). Pentru a putea utiliza o funcŃie trebuie să se specifice la începutul programului numele bibliotecii care conŃine funcŃia respectiva.

Orice program C++ trebuie să conŃină o funcŃie numita "main" (un fel de “program principal”), instrucŃiunile conŃinute de aceasta fiind cele prelucrate atunci când programul este lansat în execuŃie.

Pentru a se putea obŃine rezultatele prelucrării datelor cu ajutorul programelor, trebuiesc parcurse următoarele faze: • scrierea programului (editarea textului sursa); • compilarea programului (= verificarea corectitudinii sintactice şi semantice a textului sursa şi prelucrarea sa �fişier obiect) • editarea legaturilor (fişierul / fişierele obiect obŃinute în urma compilării sunt transformate intr-un fişier executabil, adică într-un fişier care poate fi lansat în execuŃie prin simpla scriere a numelui sau la prompterul sistemului de operare;

Numim mediu de programare un program care permite asistarea programatorului în toate fazele de elaborare a unui program, scris intr-un limbaj de programare (editare, depanare, compilare, execuŃie). Mediul de programare Borland C++ poate fi lansat în execuŃie prin tastarea comenzii bc la prompterul MSDOS.

În paragraful următor vor fi prezentate elementele de baza ale limbajului C.

Prezentarea generala a limbajului C++

Alfabetul Alfabetul limbajului este format din acele simboluri utilizate la reprezentarea entităŃilor unui program, adică a

unitarilor lexicale. Reamintim ca, prin unităŃi lexicale înŃelegem cele mai mici entităŃi cu valoare semantica (adică au o semnificaŃie), prin combinarea cărora rezulta construcŃiile sintactice ("propoziŃii şi fraze").

Alfabetul limbajului C se compune din următoarele categorii de simboluri: • Literele mari şi mici ale alfabetului englez şi caracterul de subliniere "_" (underscore) • Cifrele arabe: 0-9 • Semne de punctuaŃie: ; , ‘ " • Alte caractere:

+, -, *, / (, ), {, }, [, ], \, ~, ^, <, >, =, ?, !, #, &,

Literele şi cifrele, precum şi caracterul underscore, de multe ori asimilat în mulŃimea literelor, sunt utilizate pentru construirea identificatorilor şi cuvintelor cheie, după reguli ce vor fi descrise în paragrafele corespunzătoare. În limbajul C se face diferenŃa dintre literele mici şi majusculele corespunzătoare, deci identificatorul "a" va fi diferit de identificatorul "A", iar “turbo” va fi diferit de “TURBO” sau “TuRbO” sau orice altă combinaŃie majusculă minusculă.

2

Identificatori Identificatorul reprezintă nume pe care le atribuim variabilelor, constantelor, funcŃiilor, tipurilor de date definite

de utilizator. Un identificator este o secvenŃa de litere, cifre şi caracterul underscore, primul caracter trebuind să fie litera sau underscore. FolosiŃi cu multa precauŃie identificatori care încep cu underscore, pentru a nu intra în conflict cu numele rutinelor sistem, a căror ortografiere nu se cunoaşte (numele rutinelor sistem încep întotdeauna cu "_").

Regulile de formare a identificatorilor sunt aceleaşi cu regulile din Pascal. Un identificator poate avea, teoretic, o lungime arbitrara, dar numai primele 31 de caractere sunt luate în considerare de compilator.

Identificatorii următori: nume, Nume, NuME, NUMe sunt diferiŃi, deoarece literele mici sunt considerate diferite de literele mari corespunzătoare.

Cuvinte rezervate (keywords) Numele rezervate instrucŃiunilor, tipurilor predefinite şi sintaxei de definire a funcŃiilor şi tipurilor de date se

numesc cuvinte cheie. Lista cuvintelor cheie ale limbajului C este: auto break case char const continue default do double else enum extern float for goto if int long register

return short signed sizeof static struct switch typedef union unsigned void volatile while Identificatorii definiŃi de utilizator nu trebuie să coincidă cu cuvintele rezervate. În limbajul C++ se mai adaugă

câteva cuvinte cheie, care vor fi descrise la momentul oportun (în capitolul rezervat programării orientate obiect).

Comentarii Comentariile sunt acele şiruri de caractere utilizate la explicarea programelor sursa, delimitate prin caractere

speciale care determina ignorarea lor de către compilator. Un comentariu are următoarea forma: /* şir de caractere */

sau // şir de caractere

unde prin şir de caractere se înŃelege o secvenŃa de caractere din setul caracterelor reprezentabile, mai puŃin combinaŃia */. Nu se admit comentariile imbricate. Comentariul poate fi scris pe mai multe linii dacă este scris în prima forma. A doua forma este specifica Borland C şi permite scrierea unor comentarii ce nu depăşesc o linie.

Tipuri de date DefiniŃia noŃiunii de tip de dată cuprinde, pe lângă mulŃimea de valori a tipului, şi alte aspecte:

• dimensiunea memoriei alocate • mulŃimea operaŃiilor ce acŃionează asupra elementelor tipului • timpul de viata asociat datei, dat de clasa de memorie

Tipurile de date sunt: • tipuri de baza: tipuri predefinite în limbaj;

caracter (char) întreg (int) real (float, double)

• tipuri derivate: tipuri definite de utilizator; enumerare referinŃa structurate: tablou structura uniune

Spre deosebire de Pascal, în C nu este definit tipul logic, considerându-se ca o expresie este adevărata dacă are o valoare ne nulă (adică diferită de 0) şi falsă în caz contrar. Tipul char diferă de tipul caracter din Pascal, în C caracterele fiind de fapt numere întregi, care desemnează o echivalenŃă cu codul ASCII. Se defineşte şi tipul void, care desemnează fie "orice tip", fie indica lipsa oricărui parametru intr-o funcŃie.

Tipuri de date predefinite Tipurile de baza definite în limbajul C sunt: întreg, real şi caracter. Exista insa mai multe tipuri întregi şi reale,

în funcŃie de numărul de biŃi pe care se pot memora valorile şi dacă valorile sunt cu sau fără semn. În plus, unele dintre aceste tipuri diferă de la o implementare la alta a limbajului (în funcŃie de calculatorul pe care se lucrează). În tabelul următor sunt prezentate tipurile fundamentale, memoria necesara stocării valorilor de acel tip şi limita valorilor ce pot fi memorate intr-o variabila de acel tip.

3

Tipul Dimensiune memorie Limita valorilor

char 1 byte -128…127 int depinde de implementare

(uzual 2 bytes) -32768…32767

short int 2 bytes -32768…32767 unsigned char

1 byte 0..255

unsigned int depinde de implementare - long int 4 bytes -2147483648

…2147483647 unsigned long int

4 bytes 0…4294967295

float 4 bytes - double 8 bytes - long double 10 bytes -

Primul tip este tipul caracter. O variabila de acest tip va avea ca valoare codul ASCII asociat caracterului respectiv. De exemplu, dacă unei variabile i se atribuie caracterul ’a’, variabila va conŃine valoarea 97 (numărul de ordine al caracterului ‘a’ în codul ASCII).

Tipul întreg cel mai des utilizat în programe este int, dar numărul de bytes pe care se memorează valorile de acest tip diferă de la o implementare la alta a limbajului C (în funcŃie de tipul calculatorului). Astfel, tipul int este echivalent cu short int sau long int, în funcŃie de implementare.

Celelalte tipuri întregi sunt obŃinute prin folosirea prefixului signed sau unsigned, indicând dacă valorile respective sunt cu semn (conŃin şi valori negative), respectiv fără semn ( valori naturale).

Ultimele trei tipuri din tabel sunt tipuri reale, diferenŃa dintre ele constând în cantitatea de memorie utilizata, intervalul de valori şi precizia memorării valorilor (numărul de zecimale reŃinute). Valorile reale se reprezintă conform notaŃiei din standardul IEEE (folosind semnul, mantisa şi exponentul). De exemplu, pentru tipul float se utilizează reprezentarea în simpla precizie, folosind un bit de semn, 7 biŃi pentru exponent şi 24 de biŃi pentru mantisa. Aceasta reprezentare are un exponent în limita a 10-37 şi 1038 cu până la 7 zecimale precizie. Valoarea maxima a unui float este de 1.701411 E38.

Din tabel se observa ca nu exista un tip logic, aşa cum este el definit în alte limbaje de programare. În limbajul Pascal, tipul logic e definit ca mulŃimea cu valorile {false, true} împreuna cu operatorii logici cunoscuŃi (şi, sau , negaŃia logica). În limbajul C nu s-a definit acest tip dar se foloseşte următoarea convenŃie: o expresie este considerata adevărata dacă valoarea obŃinuta la evaluarea ei este ne nulă şi falsă în caz contrar. Variabilele care se vor folosi ca variabile logice vor fi declarate de tip întreg.

O alta caracteristica aparte o constituie introducerea tipului void, pentru a desemna “nimic” sau “orice tip”, în funcŃie de contextul în care este utilizat. În exemplele de până acum tipul void a fost folosit pentru a indica faptul ca funcŃia main nu întoarce nici o valoare.

Pentru a putea utiliza o variabila intr-un program C, este obligatorie declararea acesteia, astfel: [clasa_de_memorie] TIP_DE_DATE lista_variabile;

unde: • clasa_de_memorie specifica locul unde se va aloca memorie pentru variabila şi durata sa de viata, noŃiuni la

care vom reveni mai târziu). Specificarea clasei de memorie este opŃionala; • TIP_DE_DATE este orice tip predefinit sau derivat; • lista_variabile conŃine lista variabilelor de acel tip, despărŃite prin virgula;

Exemple: int a,b,c; char ch; float x,y; long int z; int g=7;

ObservaŃie: La declararea variabilei întregi g s-a realizat şi iniŃializarea acesteia ( adică stabilirea unei valori iniŃiale).

Variabilele care sunt declarate în interiorul corpului unei funcŃii se numesc variabile locale, iar cele declarate în afara oricărei funcŃii din program se numesc variabile globale. Variabilele globale vor putea fi utilizate în toate funcŃiile ce compun programul, iar variabilele locale doar în cadrul funcŃiei în care au fost definite.

Citirea şi afişarea datelor. Primele programe în C++ Pentru introducerea datelor prin intermediul tastaturii avem nevoie de funcŃia CIN, iar pentru afişarea valorilor

sau mesajelor de funcŃia COUT. Exemplul 1: Cel mai simplu program este programul care nu realizează nici o prelucrare:

void main( )

4

{ }

Exemplul 2: Să se afişeze pe ecran un mesaj. #include <iostream.h> void main() { cout<< "Salut!"; }

ObservaŃii: 1. Linia #include <iostream.h> declară că se va utiliza biblioteca de funcŃii cu numele "iostream.h", din care face parte funcŃia de afişare cout. 2. FuncŃia main() este funcŃia principală a unui program C, prelucrările conŃinute de aceasta fiind primele efectuate la executarea unui program. 3. Prelucrările ce apar intr-o funcŃie trebuiesc scrise intre { şi } 4. După scrierea unei comenzi (funcŃie / instrucŃiune) se pune ; Exemplul 3: Reluăm exemplul precedent:

#include <iostream.h> void main() { cout<< "Acesta este primul program în C "; cout<<"\n scris în prima ora de laborator "; }

ObservaŃii: • Caracterul "\n" are ca efect afişarea a ceea ce urmează pe linia următoare a ecranului. • Mesajul trebuie precedat de <<

Exemplul 4: Să se scrie un program pentru însumarea a doua numere. #include <iostream.h> void main() { int a; //variabila care va memora primul număr int b; //variabila care va memora al doilea număr int s; //variabila care va memora suma celor doua numere cout <<"IntroduceŃi primul număr:"; cin >> a; cout <<"IntroduceŃi al doilea număr:"; cin >>b; s=a+b; cout<<"Suma "<<a<<"+"<<b<<"="<<c<<"\n"; }

ObservaŃii: • Se folosesc trei variabile pentru a memora numerele şi suma acestora. Prin "int a" se declara folosirea unei variabile de tip întreg, având numele "a". • "cin >> a" determina citirea unei valori de la tastatura, valoare ce va fi memorata în zona de memorie a variabilei "a". Cel care introduce date trebuie să tasteze o valoare întreagă, altfel semnalându-se eroare. • Dacă se afişează un mesaj, conŃinutul acestuia trebuie pus intre ghilimele. Dacă se doreşte afişarea valorii unei variabile atunci se scrie, după <<, numele acesteia. • Executând programul de mai sus veŃi observa modul de afişare al rezultatului. • În textul programului au fost introduse mici comentarii, precedate de //, pentru a facilita înŃelegerea textului sursa. Exemplul 5: ScrieŃi un program care să afişeze următorul meniu:

Băuturi Bere ………..12500 Vin …………34764 Suc……………5000 Cafea Nes….10000 Expreso………6000 #include <iostream.h> void main( ) { cout <<”Bauturi:”;

5

cout <<”\t Bere………………12500”; cout <<”\t Vin………………..34764”; cout <<”\t Suc…………………5000”; cout <<”Cafea:”; cout <<”\t Nes……………….10000”; cout <<”\t Expreso……………6000”; }

ObservaŃii: S-a folosit caracterul \t pentru a se “începe” un nou paragraf. Caracterele “\t” şi “\n” fac parte dintre caracterele numite caractere escape, deoarece sunt caractere ne afişabile pe ecran decât prin utilizarea unor simboluri (secvenŃe de evitare).

FuncŃia fscanf

Este utilizata pentru citirea datelor dintr-un fişier sau de la tastatura (dispozitivul standard de intrare) şi are următoarea sintaxa:

fscanf(tipul_valorii_citite, variabila); Modul de funcŃionare este următorul: se citeşte de la tastatura, în variabila dată, o valoare de tipul specificat. Tipul valorii citite se specifica prin

%caracter, unde caracter poate fi:

c - dacă se citeşte un caracter d sau i - int x - întreg în baza 16 - întreg în baza 8 u - întreg fără semn hd, hi, hx, ho, hu, hx - short int ld, li, l0, lu, lx - long int s - şir de caractere f , e, g, E, G- float le, lg, lf- double Le, Lg, Lf - long double

Înaintea variabilei care stochează valoarea citita se va scrie întotdeauna & (operatorul adresa), ca în exemplul următor:

fscanf ("%f", &a); Se citeşte o valoare de tip float, valoarea fiind stocata în variabila a. ObservaŃie: Nu se va folosi operatorul & pentru citire atunci când variabila este un pointer (care este el însuşi o

adresa, dar asta mai târziu...) Dacă dorim să citim mai multe valori cu aceeaşi funcŃie fscanf, vom specifica pentru fiecare variabila tipul

valorii: int a; char ch; float f; fscanf("%i%c%f",&a, &ch, &:f);

ObservaŃii: • Şirul de caractere care defineşte tipul valorii citite se numeşte descriptor de format. • Numărul descriptorilor de format trebuie să fie acelaşi cu numărul variabilelor din lista • Ordinea de scriere a descriptorilor este importanta • Nu introduceŃi alte caractere intre descriptori decât cele permise

FuncŃia fprintf FuncŃia fprintf este utilizata pentru scrierea datelor la dispozitivul standard de ieşire. Sintaxa este:

fprintf ( tipul_valorii_scrise, variabila) ; SemnificaŃia parametrilor este aceeaşi ca şi pentru fscanf. FuncŃia are ca efect scrierea pe ecran a unei valori de

tipul specificat, valoare stocata în variabila. Nu se mai foloseşte operatorul &. Exemplu: CalculaŃi suma a doua numere. int a, b, suma; printf("Primul număr ="); scanf("%i",&a); printf("Al doilea număr = "); scanf("%i",&b); suma = a+b; printf("Suma dintre %i şi %i este %i", a, b, suma);

6

Operatori Operatorii constituie unul din conceptele cele mai importante şi mai interesante care stau la baza unui limbaj de

programare. Limbajul C este vestit pentru marea varietate de operatori pe care-i pune la dispoziŃia programatorului rezultând şi o diversitate de expresii ce se pot forma pe baza acestora. După cum se ştie, o expresie este formata din variabile, constante, funcŃii şi operatori. În acest paragraf voi aminti câteva din categoriile de operatori ai limbajului C:

Operatorii aritmetici: + adunare, - scădere, * produs, / împărŃire, % - restul împărŃirii întregi ++, -- incrementare şi decrementare

Operatori relaŃionali:

< , > == egal <= mai mic sau egal >= mai mare sau egal != diferit

Operatori logici: && - şi logic || - sau logic ! - negaŃie logica

Operatorii logici şi relaŃionali sunt implicaŃi în formarea expresiilor cu valoare logica. Spre exemplu: a<2, 7/5+2<s-1, (X>-3) &&(x<3), !(a==b)

sunt expresii cu valoare logica.

Operatori de atribuire. În secŃiunea precedenta am amintit, vorbind despre reprezentarea algoritmilor prin scheme logice, de operaŃia

de atribuire. În limbajul C se considera ca atribuirea este un operator. Atribuirea are următoarea sintaxa: variabila = expresie;

Modul de funcŃionare este următorul: 1. se evaluează expresia; 2. valoarea obŃinuta este stocata în zona de memorie a variabilei, realizându-se eventuale conversii de tip. 3. valoarea rezultata în urma atribuirii este valoarea atribuita variabilei. ObservaŃie: Atribuirea fiind un operator, se considera ca operanzii sunt variabila din partea stânga, respectiv expresia din partea dreapta. Orice expresie trebuie să aibă, în urma evaluării sale, o valoare (un rezultat). Valoarea expresiei de atribuire este valoarea obŃinuta prin evaluarea expresiei din partea dreapta a atribuirii.

Dacă valoarea obŃinuta prin evaluarea expresiei din dreapta atribuirii este de alt tip decât tipul variabilei din stânga atunci se încearcă conversia tipului valorii la tipul variabilei. Nu întotdeauna conversia este posibila, caz în care se va afişa un mesaj de eroare în urma compilării. Exemplul 1 : Fie următoarea secvenŃa de program:

void main(void) { int a; float c; a=3./2.+9./4.; cout<<”a=”<<a<<”\n”; c=3./2.+9./4.; cout<<”c=”<<c<<”\n” /* aceeaşi expresie are valori diferite, în funcŃie de tipul variabilei din stânga atribuirii */ }

ObservaŃie: Executând programul de mai sus se vor obŃine valori diferite pentru variabilele a şi c, deşi expresia care apare în dreapta ambelor atribuiri este aceeaşi. Pentru a se obŃine valoarea 3, iar pentru c se obŃine 3,75. ExplicaŃia sta în modul în care se realizează conversiile de tip în cadrul atribuirilor. Valoarea expresiei 3./2.+9./4. este 3,75 dar variabilei a i se va atribui partea întreaga a acestei valori, adică 3. Variabila c este de tip float (număr real), deci nu va mai fi nevoie de conversia rezultatului evaluării expresiei la tipul variabilei. Exemplul 2:

void main(void)

7

{ float a; a=5/2; cout<<a;

}

ObservaŃie: Executând acest program se va afişa valoarea 2 şi nu valoarea 2,5 aşa cum ar fi fost de aşteptat. ExplicaŃia este următoarea: operatorul / realizează, atunci când operanzii sunt întregi, împărŃirea întreaga, deci vom obŃine catul împărŃirii întregi dintre 5 şi 2. Exista doua modalităŃi de rezolvare a problemei: fie înlocuim expresia cu 5./2. (5.=5.0) fie utilizam operatorul de conversie explicita ( ). Acest nou operator ( numit cast), se utilizează astfel

( tip_de_date) expresie;

SemnificaŃia este următoarea: Se cere convertirea valorii rezultate din evaluarea expresiei la o valoare de tipul specificat intre paranteze. În exemplul de mai sus vom înlocui atribuirea cu:

a=(float) 5/2;

(rezultatul expresiei va fi de tip float, deci variabilei a i se va atribui valoarea 2.5). ExerciŃiu: Fie următorul program, care calculează media aritmetica a trei numere a,b,c , primele doua introduse de la tastatura.:

void main(void) { int a,b,c; float s; cin>>a; cin>>b; c=a/2+b/3; s=(a+b+c)/3; cout<<”Media aritmetica este=”<<s; }

ExecutaŃi acest program şi identificaŃi greşelile. CorectaŃi greşelile găsite.

operatori de atribuire compusa:

+=, -=, *=, /=, %=

Operatorii de atribuire compusa au fost introduşi pentru a fi utilizaŃi în locul atribuirilor de tipul: v=v+expresie; v=v-expresie; v=v*expresie; e.t.c

unde: • v-variabila • expresie-orice expresie corecta în limbajul C

În locul acestor expresii se vor folosi: v+=expresie; v-=expresie; e.t.c

Folosirea operatorilor de atribuire compusă sporeşte lizibilitatea programului şi viteza de execuŃie. Dacă atribuirea este de forma:

v=v+1; sau

v=v-1; se pot utiliza operatorii de incrementare şi decrementare ++ şi --. Expresiile de mai sus se vor putea scrie:

v++; respectiv

v--; Exemplul 3: Se da următorul program:

void main(void) { int a,b,i=3; a=++i; //preincrementare a lui i

cout<<a;

8

b=a--; //postdecrementare cout<<”a=”<<a<<”\n”; cout<<”b=”<<b<<”\n”; a+=++b; //atribuire compusa cout<<”a=”<<a<<”\n”; cout<<”b=”<<b<<”\n”; }

ObservaŃie: Când apar expresii de tipul : ++variabila

sau --variabila;

spunem ca se realizează o preincrementare, respectiv predecrementare. În cazul preincrementării, variabila va primi ca valoare 1+valoarea iniŃială. Dacă preincrementarea apare intr-o expresie se realizează întâi aceasta operaŃie şi abia apoi celelalte operaŃii care mai apar în expresie (preincrementarea are prioritate mai mare). În atribuirea a = ++I se realizează întâi preincrementarea, în urma căreia i va avea valoarea 4, şi abia apoi se realizează atribuirea (a va avea valoarea 4).

În expresia b = a — se realizează o postdecrementare, adică se modifica valoarea variabilei a doar după ce s-au efectuat celelalte operaŃii din expresie. În cazul nostru, b va primi valoarea lui a (4, în momentul acela) şi abia apoi se va micşora valoarea lui a cu o unitate.

ExerciŃiu: ExecutaŃi programul de mai sus şi urmăriŃi rezultatele care se obŃin. Mai exista operatori de atribuire compusa, folosindu-se operatorii logici ce acŃionează la nivel de bit, dar despre

aceştia vom vorbi intr-o secŃiune viitoare. Tot atunci vom discuta şi despre atribuirea multipla.

InstrucŃiunea alternativa (IF) Până acum am folosit ca exemple programe simple, care conŃineau doar funcŃiile de intrare / ieşire şi operatorul

de atribuire. Atunci când elaboram programe ceva mai complexe este necesar ca, intr-un anumit punct al programului, să decidem continuarea acestuia în funcŃie de o condiŃie. În primul laborator am dat ca exemplu de algoritm rezolvarea ecuaŃiei de gradul 1 (pseudocod şi schema logica). Intr-o schema logica ni se permitea utilizarea unui bloc de decizie de următorul tip: cu semnificaŃia: dacă este adevărata condiŃia se executa prelucrarea B, altfel se executa prelucrarea A.

În limbajul C este utilizata instrucŃiunea IF, cu următoarea sintaxă: if (expresie) instrucŃiune1; [else instrucŃiune2;}

unde: • expresie - orice expresie valida în limbajul C • instrucŃiune1, instrucŃiune2 - orice instrucŃiune corecta din limbajul C ; Mod de funcŃionare: • se evaluează expresia • dacă expresia este ne nulă (convenŃia pentru adevărat) se executa instrucŃiune1 • dacă expresia este nula (falsă) se executa instrucŃiune2 • se trece la următoarea instrucŃiune a programului ObservaŃie: alternativa else instrucŃiune2 poate să lipsească. Exemplul 4: Să se scrie un program pentru calcularea maximului a doua numere.

#include <iostream.h> void main(void) { int a,b; int max; cout<<”a=”; cin>>a; cout<<”\nb=”;

C

A B

NU

DA

C

B

D

A

N

9

cin>>b; if (a<=b)

max=b; else

max=a; cout<<”Maximul celor doua numere este=”<<max<<”\n”; }

Exemplul 5: ScrieŃi un program care calculează maximul a 3 numere. #include <iostream.h> void main (void) { int a,b,c; int max; cout<<”a=”; cin>>a; cout<<”\nb=”; cin>>b; cout<<”\nc=”; cin>>c; if (a<=b)

if (c<=b) max=b;

else max=c;

else if (c<=a)

max=a; else

max=c; cout<<”\nMaximul este=”<<max;

}

ObservaŃie: După cum se vede din exemplu, instrucŃiune1 şi instrucŃiune2 pot fi de asemenea instrucŃiuni if. Spunem ca sunt instrucŃiuni if imbricate. A se observa şi modul cum a fost scris programul, astfel încât să se vadă clar cărei instrucŃiuni if ii aparŃine fiecare else. Exemplul 6: Se dau trei numere întregi a,b,c. Să se testeze dacă numerele date pot fi lungimile laturilor unui triunghi.

#include <iostream.h> void main (void) { int a,b,c; cout<<”a=”; cin>>a; cout<<”\nb=”; cin>>b; cout<<”\nc=”; cin>>c; if (a<b+c)

if (b<a+c) if c<a+b)

cout<<” Numerele pot fi lungimile laturilor unui triunghi !”; else

cout<<”Numerele nu pot fi lungimile laturilor unui triunghi !”; else cout<<”Numerele nu pot fi lungimile laturilor unui triunghi !”;

else cout<<”Numerele nu pot fi lungimile laturilor unui triunghi !”; }

ObservaŃie: Nu am mai verificat dacă a, b , c sunt pozitive. Exemplul 7. Reluăm exemplul precedent cu intenŃia de a folosi mai puŃine instrucŃiuni if.

#include <iostream.h> void main (void) {

10

int a,b,c; cout<<”a=”; cin>>a; cout<<”\nb=”; cin>>b; cout<<”\nc=”; cin>>c; if ((a<b+c) && (b<a+c) && (c<a+b))

cout<<”Numerele pot fi lungimile laturilor unui triunghi !”; else cout<<”Numerele nu pot fi lungimile laturilor unui triunghi !”; }

ObservaŃie: Am folosit o singura instrucŃiune if, cele trei condiŃii anterioare fiind conectate prin operatorul ŞI logic. După cum se ştie, dacă avem propoziŃiile p,q,r, atunci propoziŃia p&&q&&r va fi adevărata dacă toate propoziŃiile componente sunt adevărate şi falsă dacă una dintre propoziŃiile componente este falsă.

Este indicata aceasta scriere pentru ca sporeşte lizibilitatea programului. Exemplul 8: Rezolvarea ecuaŃiei de gradul I. #include <iostream.h> void main(void) { int a,b; float x; cout<<”\na=”; cin>>a; cout<<”\nb=”; cin>>b; if (a!=0) {

x=(float) -b/a; cout<<”\nx=”<<x;

} else

if (b==0) cout<<”\n x aparŃine lui R “; else cout <<”\n EcuaŃia nu are soluŃii”;

}

ObservaŃie: În cazul în care a este ne nul avem de realizat doua operaŃii: atribuirea valorii -b/a variabilei x şi afişarea valorii rădăcinii. Atunci când se realizează mai multe operaŃii acestea trebuiesc incluse intre { şi }.

InstrucŃiuni iterative Toate problemele prezentate până acum au putut fi rezolvate folosind numai funcŃii de citire / scriere, atribuiri

şi instrucŃiunea de decizie (IF). Cele mai multe dintre probleme vor necesita structuri de date mai complexe precum şi folosirea unor noi instrucŃiuni, care să permită repetarea de un număr oarecare de ori a unor parŃi din algoritm.

Să luam ca exemplu algoritmul de calcul al sumei a 2 numere introduse de la tastatura. El consta în citirea valorilor pentru cele doua numere şi afişarea sumei acestora. Nu era nevoie decât de doua variabile, cate una pentru fiecare număr. Acest exemplu este doar unul didactic, în practica ne întâlnindu-se prea des cazuri în care să fie nevoie de a suma doua numere. Generalizarea problemei pentru n numere va modifica substanŃial algoritmul nostru. Nu vom putea folosi cate o variabila pentru fiecare număr introdus deoarece nu cunoaştem exact cate numere avem (n este introdus de utilizatorul programului, altfel algoritmul nu ar mai fi general). Chiar dacă s-ar şti ca avem, să zicem, 2500 de numere ar fi cam dificil să utilizam 2500 de variabile distincte.

Problema noastră se poate rezolva simplu dacă utilizam o instrucŃiune iterativa (ciclica), care să ne permită repetarea de n ori a următoarei secvenŃe de operaŃii: 1. citim o valoare folosind variabila “a”; 2. adunam valoarea citita la rezultatul parŃial, memorat în variabila “s”;

InstrucŃiunile ce descriu aceste prelucrări ciclice sunt compuse din doua părŃi: • corpul ciclului, format din prelucrările ce se doresc a fi realizate de mai multe ori; • condiŃia, pe baza căreia se stabileşte dacă se vor mai executa prelucrările din ciclu (este obligatorie executarea prelucrărilor din corpul instrucŃiunii de un număr finit de ori);

Corpul ciclului sau condiŃia trebuie să conŃină acele operaŃii care, după efectuarea de un număr de ori a corpului instrucŃiunii, să determine schimbarea valorii de adevăr a condiŃiei, permiŃând încheierea executării instrucŃiunii

11

ciclice şi trecerea la următoarele instrucŃiuni ale algoritmului. În cazul în care este neglijat acest aspect, programul se va executa la infinit.

CondiŃia trebuie să fie o expresie cu valoare logica. Reamintesc faptul ca în limbajul C++ nu exista un tip de date logic, dar se utilizează convenŃia ca orice valoare ne nula să fie considerata ca adevăr iar valoarea zero ca valoarea fals. În consecinŃă, orice expresie cu valoare de tip întreg va putea fi utilizata drept condiŃie intr-o instrucŃiune iterativa.

În finalul paragrafului o chestiune de terminologie: o execuŃie a corpului instrucŃiunii poarta numele se iteraŃie. InstrucŃiunile iterative pot fi clasificate, în funcŃie de momentul evaluării condiŃiei, astfel:

• cicluri cu test iniŃial (While şi For)- evaluarea condiŃiei se face înaintea fiecărei iteraŃii; • cicluri cu test final (Do .. While)- evaluarea condiŃiei se face la sfârşitul fiecărei iteraŃii;

InstrucŃiunea While InstrucŃiunea While (“atât timp cat”) este o instrucŃiune iterativa cu test iniŃial şi are următoarea sintaxa: while ( <condiŃie>) instrucŃiune;

unde: <condiŃie> - orice expresie cu valoare întreaga; instrucŃiune - orice instrucŃiune valida a limbajului; Mod de funcŃionare:

• dacă expresia este adevărată se executa prelucrările din ciclu; • altfel, se trece la următoarea instrucŃiune de după while;

Cu alte cuvinte, prelucrările din ciclu se executa atât timp cat condiŃia este adevărata. Dacă expresia este falsă de la început corpul ciclului nu se va executa deloc.

Problema propusa în paragraful precedent se poate rezolva astfel: Exemplul 1 Suma a n numere introduse de utilizator

#include <iostream.h> void main() { float a; int i,n; float suma=0; i=1; cout<<"\nNumărul de elemente="; cin>>n; while(i<=n) {

cout<<"Elementul "<<i<<"este: "; cin>>a; suma=suma+a; //se mai poate scrie suma+=a i++;

} cout<<"Suma este= "<<suma; }

Exemplul 2: Suma primelor n numere naturale. #include <iostream.h> void main() { int n; int i; int suma=0; cout<<"n="; cin>>n; i=1; while(i<=n) {

suma=suma+i; i++;

} cout<<"Suma este: "<<suma; }

12

ObservaŃie: Se poate utiliza o scriere mai compacta, care elimina şi necesitatea utilizării variabilei i: while (n--) suma+=n;

Modul de execuŃie este următorul: • valoarea condiŃiei este valoarea variabilei n, valoare care scade cu o unitate după fiecare iteraŃie (postdecrementare) • condiŃia devine falsă atunci când valoarea lui n devine zero;

InstrucŃiunea do .. while InstrucŃiunea do .. while este o instrucŃiune iterativa cu test final şi are următoarea sintaxa: do instrucŃiune; while (<condiŃie>)

Mod de funcŃionare: • se executa corpul instrucŃiunii; • se evaluează condiŃia: dacă aceasta este adevărata se reia execuŃia, altfel se trece la următoarea instrucŃiune din program;

Deosebirea esenŃială faŃă de instrucŃiunea while este aceea ca expresia se evaluează după iteraŃie. În cazul în care condiŃia este falsă de la început, corpul instrucŃiunii se executa o singura dată. Utilizarea

instrucŃiunii do .. while este mai puŃin frecventa (se foloseşte pentru acele prelucrări care trebuiesc executate cel puŃin o dată).

Dacă rescriem exemplul 1 utilizând do .. while, obŃinem: …………………………. do { cin>>a; suma+=a; i++; } while(i<=n); ………………………….

InstrucŃiunea for Una dintre cele mai puternice instrucŃiuni iterative ale limbajului C (şi nu numai) este instrucŃiunea for, care are

următoarea sintaxa: for (expresie1; expresie2; expresie3) [instrucŃiune]; unde: expresie1, expresie2, expresie3 - expresii valide în C++; instrucŃiune - orice instrucŃiune a limbajului C++;

Parantezele pătrate semnifica faptul ca instrucŃiunea este opŃionala; Mod de execuŃie: • expresiile au următoarea semnificaŃie generala:

• expresie1 - expresie de iniŃializare; • expresie2 - condiŃia de continuare a execuŃiei ciclului; • expresie3 - expresie de actualizare;

• atât timp cat expresie2 este adevărata se executa corpul ciclului; • de fiecare dată se evaluează expresia de actualizare, care are rolul esenŃial de a determina ca, după un număr

de iteraŃii, expresie2 să devină falsă; • expresie1 se evaluează o singura dată;

Exemplul 3: Reluăm exemplul 1 folosind instrucŃiunea for: #include <iostream.h> void main() { int i, n; float a, suma=0; cin>>n; for(i=1;i<=n;i++) {

cin>>a; suma+=a;

}

13

cout<<”suma =”<<suma; }

ObservaŃii: • Variabila i este utilizata pe post de “contor” al instrucŃiunii for, numărând la a câta iteraŃie s-a ajuns. • ExecuŃia instrucŃiunii for se încheie atunci când numărul de iteraŃii devine egal cu n. IniŃializarea lui i cu 1 se realizează o singura dată, la început; i <= n este condiŃia de continuare a execuŃiei; i++ se efectuează după fiecare execuŃie a ciclului (postincrementare). • Aceasta forma a instrucŃiunii for este cea mai utilizata. Un alt mod de a descrie execuŃia acesteia este următorul: pentru i de la 1 la n se executa corpul instrucŃiunii. • Nu este obligatoriu ca valoarea lui i să se mărească de fiecare dată cu o unitate. • Nu este obligatorie utilizarea tuturor celor trei expresii din for, dar este obligatorie scrierea separatorului “;” .

Exemplul de mai sus se poate rescrie astfel: …………………………… for( ;n--; ) {

cin>>a; suma+=a;

} ……………………………

NoŃiunea de tablou În laboratorul precedent explicam de ce nu putem să utilizam 2500 de variabile distincte atunci când dorim să

însumam 2500 de numere. Rezolvarea propusa atunci se baza pe citirea repetata a cate unei valori, folosind o variabila a, urmata de adăugarea acesteia la suma parŃiala. Dezavantajul metodei este acela ca nu se pot memora toate valorile citite ci doar ultima (citind o valoare intr-o variabila, vechea valoare a acesteia se pierde). Cele mai multe programe presupun prelucrări complexe asupra datelor de intrare, deci va fi nevoie să memoram şirul nostru de numere astfel încât să poată fi utilizat şi în alte prelucrări, nu numai pentru calcularea sumei.

Pentru a rezolva astfel de situaŃii s-a introdus în limbajele de programare noŃiunea de tablou. Tablourile ne permit memorarea unui număr mare de valori utilizând o singura variabila.

Prin tablou se înŃelege un număr de elemente de acelaşi tip, numit tip de baza, stocate intr-o zona compacta de memorie.

Un tablou poate fi definit astfel: tip_de_baza nume [dimensiune1] [dimensiune2] … [dimensiune_n]; unde: tip_de_baza = tipul elementelor tabloului; n = numărul de dimensiuni al tabloului; [dimensiune_i] = numărul de elemente pe dimensiunea I tabloul are dimensiune1*…*dimensiune_n elemente

NoŃiunea de tablou multidimensional poate fi înŃeleasă mai bine după parcurgerea noŃiunilor referitoare la vectori şi matrice.

Tablouri unidimensionale Declararea unui tablou unidimensional:

tip_de_baza nume[dimensiune]; unde dimensiune specifica numărul de elemente al vectorului.

De exemplu: int a[30]; declara un vector ce conŃine 30 de elemente de tip int, float b[50]; declara un vector cu 50 elemente reale; “Numerotarea” elementelor se face de la 0 la dimensiune-1, adică cele 30 de elemente ale primului tablou sunt: a[0], a[1], a[2], …, a[29].

Spunem ca tabloul este o variabila indexata, deoarece fiecare element al tabloului poate fi “găsit” / “utilizat” cunoscând numărul sau de ordine. Vectorul este un şir de valori în care se cunoaşte precis care este primul, al doilea, ….,ultimul element. “Numărul de ordine” al unui element se numeşte indice. Exemplul 1: Să se calculeze minimul elementelor unui şir de n numere, utilizând vectori.

#include <iostream.h> void main() {

int n; //numărul de elemente

14

int a[50]; //se defineşte o variabila de tip tablou cu maxim 50 de elemente, deci n va trebui // sa fie mai mic decât 50 int min; //variabila ce va memora minimul int i; //contor în instrucŃiunea for cout<<”n=”; cin>>n; /* se citesc elementele şirului */ for(i=0;i<n;i++) {

cout<<”a[“<<i<<”]=”; cin>>a[i];

} // se calculează minimul min=a[0]; //iniŃializam minimul cu primul element din şir for(i=1;i<n;i++)

if (a[i]<min) min=a[i];

//afişare minim cout<<”Minimul este=”<<min;

}

După cum se poate observa din programul de mai sus, fiecare element al şirului se poate utiliza ca şi cum ar fi o variabila de tip int independenta, deci valoarea unui element al vectorului poate fi modificata independent de celelalte elemente. Să presupunem ca utilizatorul introduce pentru n valoarea 4. IniŃial, elementele vectorului nu au o valoare bine definita; putem reprezenta grafic vectorul astfel:

Să presupunem ca utilizatorul introduce valorile 3, 7, 2, 9 pentru cele patru elemente ale vectorului. Reprezentarea vectorului a va fi următoarea:

a[0] a[1] a[2] a[3]

3 7 2 9 Valoarea oricărui element al vectorului poate fi modificata fie printr-o atribuire, fie prin introducerea unei

valori (folosind funcŃia cin, de exemplu) de la tastatura. Dacă vom introduce atribuirea a[2]=23;

valoarea elementului al treilea din vectorul a nu va mai fi 2 (vechea valoare) ci 23. De asemenea, dacă se scrie: cin>>a[2];

valoarea elementului va fi cea introdusa de utilizator de la tastatura. Exemplul 2: Se considera n numere întregi introduse de la tastatura. Să se afle cate numere sunt pare şi cate impare.

#include <iostream.h> #include <conio.h> void main() { int n; //numărul de elemente int v[30]; //vector cu maxim 30 elemente întregi int pare, impare; //variabile ce memorează nr. Elementelor pare, respectiv impare int j; //variabila folosita în instrucŃiunea for clrscr(); //citim numărul de elemente cout<<”n=”; cin>>n; /* se citesc elementele şirului */ for(i=0;i<n;i++) {

cout<<”v[“<<i<<”]=”; cin>>v[i];

} //iniŃializam variabilele pare=0; impare=0; //luam fiecare element din v şi testam dacă acesta este sau nu par for(j=0;j<n;j++)

if (v[j] % 2 = =0) pare++;

15

else impare++; //afişam rezultatul cout<<”Am găsit “<<pare<<” numere pare şi “<<impare; }

În programul de mai sus verificam, pentru fiecare element, dacă acesta se împarte exact la doi, caz în care am mai descoperit un element par. În caz contrar, numărul elementelor impare se măreşte cu unu.

Am utilizat operatorul % , numit şi modulo aritmetic, care are ca rezultat restul împărŃirii lui v[j] la 2. Exemplul 3: Să se introducă de la tastatura un cuvânt şi să se afişeze.

#include <iostream.h> #include <conio.h> void main() { char cuvânt[30]; clrscr(); cout<<”Introduceti cuvantul:”; cin>>cuvant; cout<<”Cuvantul introdus este:”<<cuvant; }

ObservaŃi cu atenŃie cum am declarat variabila ce va memora cuvântul: folosim un vector cu elemente de tip caracter. Acest mod de declarare ne permite să lucrăm cu oricare dintre caracterele ce formează cuvântul. De exemplu, dacă utilizatorul introduce cuvântul salariu, vectorul nostru de caractere arata cam aşa:

Dacă dorim să modificam puŃin cuvântul putem scrie: cuvant[6]=’i’; şi vom obŃine cuvântul salarii. Exemplul 4: Să se citească un cuvânt şi să se găsească numărul de vocale pe care le conŃine.

#include <iostream.h> #include <conio.h> # include <string.h> void main() { char c[30]; //vector pentru memorarea cuvântului int vocale; //variabila ce va memora numărul vocalelor int j; clrscr(); cout<<”Introduceti cuvantul:”; cin>>c; vocale=0; //căutam vocalele for(j=0;j<strlen(c);j++)

if ( c[j]==’a’ || c[j]==’e’ || c[j]==’i’ || c[j]==’o’ || c[j]==’u’) vocale++; cout<<”Am gasit “<<vocale<<” vocale.”;

}

ObservaŃii: • Am utilizat funcŃia strlen, care are ca rezultat numărul de caractere al şirului dat ca parametru. FuncŃia poate fi utilizata doar dacă a fost inclus fişierul antet string.h, fişier ce conŃine funcŃiile ce acŃionează asupra şirurilor de caractere. • “Mecanismul “algoritmului este următorul: se ia cate un caracter din şirul introdus şi se verifica dacă elementul respectiv conŃine unul dintre caracterele a, e, i, o, u. De fiecare dată când condiŃia este adevărata se incrementează numărul de vocale.

Mai multe despre şirurile de caractere vom spune după capitolul dedicat pointerilor. Exemplul 5 (Căutare secvenŃiala) Se considera un şir de n elemente întregi şi un număr întreg x. Să se verifice

dacă numărul x face parte din şirul considerat. #include <iostream.h> #include <conio.h> void main() { int v[25]; int n;

16

int x; int j; int gasit; //variabila logica ce indica dacă x aparŃine sau nu lui v clrscr(); //citim numărul de elemente cout<<”n=”; cin>>n; /* se citesc elementele şirului */ for(j=0;j<n;j++) {

cout<<”v[“<<j<<”]=”; cin>>v[j];

} //se citeste elementul x cout<<”x=”; cin>>x; gasit=0; j=0; //cautam x în şirul v while( (j<n)&&(!gasit)) {

if (v[j]==x) gasit=1; j++;

} if(gasit) cout<<”Elementul apartine şirului dat !”; else cout<<”Elementul nu aparŃine şirului !”; }

Am utilizat instrucŃiunea while, condiŃia de efectuare a ciclului fiind (j<n) && (!găsit). Corpul instrucŃiunii while se va executa atât timp cat nu s-a ajuns la sfârşitul şirului şi elementul x nu a fost găsit în v. CondiŃia de mai sus devine falsă în doua cazuri: fie am epuizat elementele şirului (j a ajuns egal cu n), fie am găsit un element egal cu x. După executarea ciclului while testam dacă variabila găsit este ne nula (adevăr), caz în care x aparŃine lui v, altfel x nu aparŃine şirului. Exemplul 6. (sortare) Se considera un şir cu n elemente reale. Să se aranjeze elementele în ordine crescătoare utilizând acelaşi vector.

#include <iostream.h> #include <conio.h> void main() { double v[40]; int n; int j, k; cout<<”n=”; cin>>n; for(j=0;j<n;j++) {

cout<<”v[“<<j<<”]=”; cin>>v[j];

} //sortarea crescatoare a şirului v for(j=0;j<n-1;j++)

for(k=j+1; k<n;k++) if (v[j]>v[k]) {

//interschimbam valorile v[j] şi v[k] temp=v[j]; v[j]=v[k]; v[k]=temp;

} //afisarea valorilor sortate crescator for(k=0;k<n;k++) cout<<v[k]<<”\t”;

17

}

Tablouri bidimensionale (matrice) Pe lângă vectori, cel mai utilizat tip de tablou de numere este tabloul bidimensional, numit de cele mai multe ori

matrice. Declararea unei matrice se face astfel: tip_de_baza nume[dimensiune_1][dimensiune_2];

Exemplu: double a[10][5]; //tablou cu 10 linii şi 5 coloane de elemente reale int a[3][2]; //tablou cu 3 linii şi 2 coloane de elemente întregi Pentru a putea avea acces la valoarea unui element al matricei, trebuie să precizam linia şi coloana pe care se

afla acesta. Un element poate fi specificat prin a[i][j], i - reprezentând linia şi j - coloana. În cazul vectorilor citeam o valoare reprezentând numărul de elemente. Pentru matrice vom citi o valoare m - numărul maxim de linii şi o valoare n - numărul maxim de coloane. O matrice cu m linii şi n coloane va avea m * n elemente.

Dacă m = n atunci matricea se numeşte matrice pătrata de ordin n. Exemplul 7. Să se citească elementele unei matrice şi să se afişeze.

#include <iostream.h> #include <conio.h> void main() { int a[20][20]; //matrice cu elemente întregi int m, n; //numărul de linii, respectiv coloane int i, j; //variabile folosite în instr. For //citim numărul de linii şi coloane cout<<”Numărul de linii:”; cin>>m; cout<<”Numărul de coloane:”; cin>>n; //se citesc elementele matricei for(i=0;i<m;i++)

for(j=0;j<n;j++) {

cout<<”a[“<<i<<”][“<<j<<”]=”; cin>>a[i][j];

} //afisarea elementelor matricei for(i=0;i<m;i++) {

for(j=0;j<n;j++) cout<<a[i]][j]<<”\t”; cout<<”\n”;

} }

Exemplul 8. Se dau doua matrice cu m linii şi n coloane. Să se calculeze matricea suma. ………………………………………………. int a[20][20], b[20][20], c[20][20]; int m,n; int i, j; ……………………………………………….. //se citesc dimensiunile m, n şi cele doua matrice a şi b ………………………………………………. //calculam matricea suma for(i=0;i<m;i++) for(j=0;j<n;j++) c[i][j]=a[i][j]+b[i][j]; //se afiseaza matricea c ………………………………………………..

Atunci când lucrăm cu matrice avem nevoie de doi indici: i pentru a parcurge liniile matricei şi j pentru a parcurge coloanele acesteia. Pentru fiecare valoare a lui i, j ia toate valorile intre 0 şi n-1, deci se parcurge linia i.

În ultimul exemplu am utilizat trei matrice. Pentru mai multa claritate, putem declara un tip ale cărui elemente să fie matrice:

typedef int matrice[20][20]; matrice a, b, c;

18

Am definit un tip de date (tip de date definit de utilizator) ale cărui elemente sunt matrice cu maxim 20 de linii şi coloane cu elemente întregi. Numele noului tip este matrice. Declararea variabilelor de acest tip se poate face oriunde în programul în care apare definiŃia. Definirea unui tip de date se poate face numai prin utilizarea cuvântului cheie typedef înaintea declaraŃiei. Dacă definim mai multe tipuri se va folosi typedef pentru fiecare definiŃie.

NoŃiunea de pointer Pointerii au fost introduşi în limbajele de programare pentru a putea rezolva mai eficient anumite probleme sau

pentru a da mai multa claritate anumitor programe. O prima definiŃie poate fi următoarea:

Pointerul este o variabila ce conŃine adresa unui obiect.

Obiectul a cărei adresa este reŃinuta de pointer poate fi: variabila funcŃie

Fie următorul exemplu: int x; int *px; Am definit o variabila de tip întreg x şi o variabila pointer, care poate conŃine adresa unei variabile de tip întreg.

Simbolul * ce apare În stânga variabilei px arata ca px este o variabila pointer. Prin atribuirea

px=&x; Pointerul va avea ca valoare adresa de memorie alocata variabilei x (vezi laboratorul nr.1, definiŃia variabilei).

Operatorul unar & este utilizat pentru a se obŃine adresa variabilei x (operator unar = are un singur operand) Acum putem să lucrăm cu conŃinutul variabilei x (adică cu valoarea acesteia) prin intermediul pointerului px,

deci indirect, fără să mai folosim variabila x. La prima vedere, aceasta modalitate de lucru poate părea dificila şi nu tocmai utila. Necesitatea utilizării pointerilor va apare cu mai multa claritate în secŃiunea dedicata şirurilor de caractere şi funcŃiilor. Exemplul 1. Fie programul următor:

#include <iostream.h> void main() { int x,y; int *px; cout<<"x="; cin>>x; cout<<"y="; cin>>y; px=&x; cout<<"x are valoarea "<<*px; *px=y; cout<<"\nx a devenit "<<x; }

În programul de mai sus am introdus valorile variabilelor întregi x şi y, am definit un pointer la variabila x şi am atribuit acestuia adresa de memorie alocat variabilei x. Să analizam atent linia:

cout<<"x are valoarea "<<*px; Prin *px se înŃelege valoarea aflata în zona de memorie a cărei adresa este memorata în pointerul px. Valoarea

afişată va fi chiar valoarea introdusa pentru x deoarece, înainte de afişare, pointerul px a primit ca valoare adresa variabilei x, adresa la care se afla valoarea acesteia (valoare dobândita prin utilizarea funcŃiei cin).

Atribuirea *px=y; va modifica valoarea care se afla la adresa memorata de px, valoare care va fi valoarea introdusa de utilizator pentru variabila y. Astfel va fi modificata chiar valoarea pe care o are variabila x.

Fireşte ca era mai simplu să folosim atribuirea x=y; care are acelaşi efect şi ne scuteşte de de-a mai folosi pointeri, insa exemplul este pur didactic.

Operatorul unar * este folosit sub forma *variabila_pointer, valoarea acestei expresii fiind valoarea care se găseşte în memorie la adresa memorata de pointerul ce apare ca operand. În concluzie, prin px avem acces la adresa variabilei x, iar prin *px la valoarea variabilei x.

Vom spune ca un pointer “refera” indirect un obiect sau ca “pointeaza”(arata) la obiectul respectiv. Variabilele pointer pot fi încadrate ca fiind de tip referinŃa.

Exemplul 2. Să se calculeze suma a doua numere reale folosind pointeri. #include <iostream.h> void main()

19

{ double x, y, z; double *px, *py, *pz; cin>>x; cin>>y; px=&x; py=&y; pz=&z; *pz=*px+*py; cout<<"Suma este: "<<*pz; }

Pointeri şi tablouri În limbajul C, exista o foarte strânsa legătura intre pointeri şi tablouri, astfel ca pointerii şi tablourile sunt tratate

la fel. Orice program în care apar tablouri poate fi modificat astfel încât să folosească pointeri în locul tablourilor. În aceasta secŃiune vom discuta despre legătura dintre pointeri şi vectori (tablouri unidimensionale).

Fie următoarele declaraŃii: int a[20]; int *pa; Am declarat o variabila a , care este un vector cu maxim 20 elemente întregi şi un pointer la o variabila de tip

întreg. După cum se ştie, o valoare int are nevoie de 16 biŃi pentru a fi memorata, adică 2 bytes ( o variabila int poate retine numere întregi intre -32768 şi 32767, vezi curs Bazele Informaticii). Pentru tabloul a vor fi alocaŃi 2· 20=40 bytes consecutivi în memorie adică, pentru primul element a[0] sunt alocaŃi primii 2 bytes, pentru a[1] următorii 2 bytes,…, pentru a[19] ultimii 2 bytes din cei 40 alocaŃi. Fie atribuirea: pa=&a[0];

După aceasta atribuire, pointerul pa conŃine adresa primului element al vectorului, adică pa pointeaza la începutul vectorului a.

Dacă scriem pa=&a[3]; atunci pa va referi elementul al 4-lea din vectorul a, iar *pa va conŃine valoarea sa. OperaŃiile care se pot realiza cu pointeri sunt:

• comparaŃia • adunarea unui pointer cu un întreg • scăderea unui întreg dintr-un pointer

Doi pointeri pot fi comparaŃi folosind operatori relaŃionali. În comparaŃia: if(p1==p2) cout<<”Adrese identice”; else cout<<”Adrese diferite”; se verifica dacă adresa memorata de p1 este aceeaşi cu adresa reŃinuta de p2, unde p1 şi p2 sunt pointeri de

acelaşi tip. Se poate compara un pointer cu valoarea NULL (sau 0). Un pointer are valoarea NULL (valoare nedefinita) dacă nu refera nici un obiect. Adunarea unui pointer cu un întreg este definita numai atunci când pointerul refera un tablou (un element al tabloului). Scăderea este definita în acelaşi caz. Exemplul 3. Să se citească elementele unui vector şi să se afişeze acestea utilizând pointeri.

#include <iostream.h> void main() { int a[20]; int *pa; int i,n; cout<<"Numărul de elemente= "; cin>>n; for(i=0;i<n;i++) { cout<<"Elementul"<<i<<"="; cin>>a[i]; } //afişarea vectorului folosind pointeri pa=&a[0]; for(i=0;i<n;i++) { cout<<*pa<<"\n"; pa++; }

20

}

Prima pate a programului nu conŃine elemente noi, doar a doua parte meritând atenŃie. Mai întâi iniŃializam pointerul pa cu valoarea primului element al vectorului a. Ciclul for conŃine următoarele prelucrări: • afişează valoarea aflata la adresa indicata de pointer; • aduna pointerul pa cu 1

Incrementarea pointerului pa are ca efect modificarea adresei memorate în pa. Noua adresa este adresa zonei de memorie corespunzătoare elementului următor, o adresa cu 2 bytes mai mare decât precedenta. Observam ca mărirea pointerului cu o unitate înseamnă de fapt trecerea la următorul element din vector.

Dacă vom introduce pentru n o valoare mai mare decât 20 (numărul maxim de elemente ale vectorului, aşa cum reiese din declaraŃie) atunci pointerul pa va depăşi zona de memorie alocata vectorului şi va referi o adresa la care se pot afla date importante pentru program. Urmările pot fi imprevizibile, de la blocarea programului până la blocarea sau închiderea calculatorului !!!

NoŃiunea de funcŃie. Structura şi definirea funcŃiilor NoŃiunea de funcŃie este o noŃiune de mare importanta în informatica, orice limbaj de programare furnizând

facilităŃi de lucru cu funcŃii. În matematica, funcŃia era definita ca fiind tripletul (A, B, f), unde: A - domeniul de definiŃie; B - codomeniul sau domeniul de valori; f - lege, convenŃie, prin care fiecărui element din domeniul de definiŃie i se asociază un unic element din

codomeniu; În informatica, noŃiunea de funcŃie diferă puŃin de modul matematic de abordare. În limbajul C, orice program

trebuie să conŃină obligatoriu o funcŃie numita main. Dacă prelucrările ce compun programul sunt foarte complexe, utilizarea unei singure funcŃii duce la un program greu de înŃeles şi depanat. În acest caz este bine ca problema de rezolvat să fie împărŃita în sub probleme prin a căror combinare să se obŃină rezolvarea problemei iniŃiale. Pentru rezolvarea fiecărei sub probleme se poate utiliza cate o funcŃie separata. FuncŃia main (“programul principal”) nu va mai fi de mare întindere, ea conŃinând doar apeluri către funcŃiile deja definite.

Decizia de a folosi o funcŃie poate fi luata şi în cazul în care anumite prelucrări trebuiesc realizate de mai multe ori, cum se va vedea şi în exemplul de mai jos.

Exemplul 1. Să se calculeze aria a n triunghiuri, dacă se cunosc lungimile laturilor acestora. #include <iostream.h> #include <conio.h> #include <math.h> float aria(int a, int b, int c) { float p,s; p=(float)(a+b+c)/2; s=sqrt(p*(p-a)*(p-b)*(p-c)); return s; } void main() { int a,b,c; float S; int i,n; cout<<"Numărul de triunghiuri= "; cin>>n; i=1; for(i=1;i<=n;i++) {

cout<<"a="; cin>>a; cout<<"b="; cin>>b; cout<<"c="; cin>>c; S=aria(a,b,c);

cout<<"Aria triunghiului "<<i<<" este "<<S<<"\n";

21

} }

Programul trebuie să calculeze aria a n triunghiuri, deci calculul ariei trebuie realizat de n ori. Am definit funcŃia aria, care calculează aria triunghiului cu lungimile laturilor a, b, c prin formula lui Heron. Structura funcŃiei este următoarea: antet:

float aria(int a, int b, int c) care conŃine următoarele elemente: • tipul rezultatului funcŃiei (codomeniul) - rezultatul funcŃiei va fi o valoare de tipul declarat; • numele funcŃiei: - numele nu poate fi identic cu un cuvânt cheie • lista parametrilor formali - variabilele de care depinde calcularea rezultatului (“argumentele funcŃiei”); pentru fiecare parametru formal se specifica tipul. • corpul funcŃiei:

{ float p,s; p=(float)(a+b+c)/2; s=sqrt(p*(p-a)*(p-b)*(p-c)); return s; } Corpul funcŃiei conŃine declaraŃiile variabilelor utilizate în funcŃie şi prelucrările realizate de funcŃie.

Variabilele utilizate în funcŃia aria, numite şi variabile locale, sunt semi perimetrul p şi aria s. Nu declaram variabilele a, b, c (parametrii formali nu se declara în corpul funcŃiei) şi nici nu citim valori pentru ele în cadrul funcŃiei.

Orice funcŃie care are drept codomeniu un tip diferit de tipul void trebuie să conŃină în corpul funcŃiei o instrucŃiune

return expresie; unde expresie este orice expresie corecta în C cu valoare de tipul declarat pentru codomeniu.

InstrucŃiunea return este utilizata pentru a semnala faptul ca valoarea funcŃiei este valoarea expresiei. În programul principal (funcŃia main) se citeşte numărul de triunghiuri n. InstrucŃiunea for va repeta de n ori

(pentru fiecare triunghi) următoarele prelucrări: • se citesc valori pentru variabilele a, b, c care reprezintă lungimile laturilor triunghiului curent; • se calculează aria triunghiului pentru valorile date; • se afişează valoarea ariei triunghiului curent;

Modul de utilizare al funcŃiei aria este interesant. Atribuirea: S=aria(a,b,c);

are următorul efect; • se evaluează expresia din dreapta atribuirii, expresie ce consta din apelul funcŃiei aria pentru valorile a, ,b, c • evaluarea funcŃiei înseamnă executarea prelucrărilor din funcŃie pentru valorile parametrilor formali a, b, c • valoarea întoarsa de funcŃie este valoarea variabilei s, care apare în return; • valoarea este memorata în zona de memorie a variabilei S.

FuncŃiile pot fi clasificate astfel: • funcŃii predefinite = funcŃii deja definite de autorii mediului de programare C şi grupate, în funcŃie de utilitatea lor, în biblioteci numite fişiere header. De exemplu, în biblioteca math.h sunt grupate funcŃiile matematice, în string.h avem funcŃiile de lucru cu şiruri de caractere, în iostream.h funcŃii pentru introducerea şi afişarea datelor, în malloc.h şi alloc.h • funcŃii pentru alocarea memoriei… • funcŃii definite de utilizator = funcŃii scrise de creatorul unui program pentru acele prelucrări pentru care nu exista funcŃii predefinite (caz destul de frecvent);

O funcŃie poate să aibă drept codomeniu orice tip predefinit scalar (întreg, caracter sau real), tip compus (uniune sau structura), precum şi pointeri la orice tip. Tipul void înseamnă ca funcŃia nu returneaza nici o valoare.

Programatorul poate să strângă funcŃiile definite de el intr-un fişier header propriu, care se poate include în program prin

#include “nume_fisier.h”.

Apelul funcŃiilor şi transferul parametrilor Orice apariŃie a numelui funcŃiei însoŃit de un număr de valori egal cu numărul parametrilor formali se numeşte

apel al funcŃiei. Puteam apela funcŃia şi în modul următor:

cout<<aria(3,4,5);

22

Aceasta instrucŃiune are ca efect afişarea ariei triunghiului cu laturile de lungimi 3, 4, 5. ObservaŃi ca nu este obligatoriu ca parametrii din apel să fie variabile, ci pot fi expresii.

Dacă funcŃia noastră ar apărea intr-o expresie ca 23*aria(3,4,5)-2*aria(2,6,6), evaluarea expresiei ar începe cu executarea funcŃiei aria pentru valorile 3, 4, 5 şi apoi pentru 2, 6, 6; după ce se obŃin rezultatele celor doua apeluri ale funcŃiei se realizează evaluarea celorlalte operatori (înmulŃirile şi apoi scăderea).

FuncŃia în care apare un apel al altei funcŃii se numeşte funcŃie apelanta. Parametrii sunt de doua tipuri:

parametri formali: valoare referinŃa (pointer)

parametri efectivi (actuali) Parametrii sunt utilizaŃi pentru a putea transmite din funcŃia apelanta valorile necesare prelucrărilor efectuate de

funcŃia apelata. Atunci când parametrii formali sunt utilizaŃi doar pentru a transmite valori în funcŃia apelata, aceşti parametrii se numesc parametri valoare. Dacă se doreşte transmiterea ca parametru a unei variabile, în scopul modificării valorii acesteia astfel încât modificarea să fie disponibila în funcŃia apelanta, avem de-a face cu un parametru formal referinŃa (se realizează printr-o variabila de tip pointer).

Pentru a putea apela o funcŃie, trebuie să precizam, pe lângă numele acesteia, valorile parametrilor pentru care se realizează apelul (parametri actuali). Numărul parametrilor actuali dintr-un apel de funcŃie trebuie să fie acelaşi cu numărul parametrilor formali din definiŃia funcŃiei apelate şi să corespunda ca tip.

De exemplu, în programul de mai sus, nu puteam apela funcŃia aria ca s = aria(4.56, 5, 5); deoarece primul parametru formal din definiŃia funcŃiei este definit ca de tip int, iar parametrul actual (4.56) este de tip real (incompatibilitate de tip).

Nu este obligatoriu să existe parametrii formali intr-o funcŃie dacă nu este nevoie. De asemenea, nu toate funcŃiile întorc o valoare. Aceste aspecte sunt tratate în următoarele exemple. Exemplul 2. Să se scrie o funcŃie care afişează pe ecran un număr dat de asteriscuri.

void asterisc(int nr) { int j; for(j=1;j<=nr;j++)

cout<<”* ”; }

FuncŃia are un singur parametru formal, un întreg nr reprezentând numărul de asteriscuri ce trebuie afişate. FuncŃia poate fi apelata prin asterisc(10); care are ca efect afişarea a 10 asteriscuri.

FuncŃia nu întoarce nici o valoare, deoarece nu este necesar (n-are sens să întoarcem vreo valoare), deci codomeniul va fi tipul void. Din moment ce funcŃia nu întoarce vreo valoare, nu se va mai utiliza return. Exemplul 3. ScrieŃi o funcŃie care să afişeze un mesaj.

void mesaj( ) { cout<<”Traiasca Reforma !!!”; }

FuncŃia mesaj nu întoarce nici o valoare şi nici nu conŃine parametrii formali (nu exista valori care să fie necesare execuŃiei funcŃiei). Apelul funcŃiei se va face prin: mesaj(), exact ca şi pentru funcŃia pre definită clrscr( ).

Dacă am dori ca funcŃia să afişeze un mesaj dat, obŃinem: void mesaj(char s[80]) { cout<<s; }

Apelul funcŃiei poate fi: mesaj(“Trăiască!!!”); Exemplul 4. ScrieŃi o funcŃie care stabileşte dacă un număr este prim. #include <iostream.h> int este_prim(int n) { int j; int este; este=1; //presupunem ca numărul este prim for(j=1;j<=n-1;j++)

if(n%j==0) este=0; return este; }

23

void main() { int număr; cout<<”Introduceti numărul=”; cin>>număr; if(este_prim(număr)!=0)

cout<<”Numărul este prim !”; else

cout<<”Numărul nu este prim !”; }

ExerciŃiul 1: FolosiŃi funcŃia este_prim pentru a afişa toate numerele prime mai mici decât un număr întreg dat. Exemplul 5. ScrieŃi o funcŃie care să citească un vector de numere întregi.

void citeste(int a[30], int n) { int k; for(k=0;k<n; k++)

cin>>a[k]; }

FuncŃia are doi parametri: variabila de tip vector care va retine numerele citite şi variabila n, care ne spune cate elemente trebuiesc citite. FuncŃia main poate să arate astfel:

void main () { int b[30]; int n; cout<<”n=”; cin>>n; citeste(a,n); }

ExerciŃiul 6: ScrieŃi o funcŃie pentru afisarea elementelor unui vector şi adăugaŃi-o exemplului precedent. Exemplul 7. ScrieŃi o funcŃie care calculează suma elementelor dintr-un vector. int suma(int a[40], int n) { int k; int s; s=0; for(k=0;k<n;k++)

s=s+a[k]; return s;

}

Este necesar să introducem ca parametru şi numărul de elemente din vector n. ExerciŃiul 8: FolosiŃi funcŃia de mai sus în programul de la exerciŃiul precedent. Exemplul 9. ScrieŃi o funcŃie care calculează ax, unde a real şi x întreg pozitiv. float putere(float a, int x) { int k; int p; //retine puterea p=1; for(k=1;k<=x;k++)

p=p*a; return p; }

24

ExerciŃiul 10. ModificaŃi funcŃia din exemplul 7 astfel încât să poată ridica pe a şi la puteri negative. Exemplul 11. ScrieŃi o funcŃie pentru a calcula cel mai mare divizor comun a 2 numere întregi folosind

algoritmul lui Euclid. #include <iostream.h> int cmmdc(int m, int n) { int r; int temp; if(n>m) {

temp=m; m=n; n=temp;

} do {

r=m%n; m=n; n=r;

}while(r!=0); return m; } void main() { int a,b; cout<<"Primul număr="; cin>>a; cout<<"Al doilea număr="; cin>>b; cout<<cmmdc(a,b);

}

Exemplul 12 Să se scrie o funcŃie care verifica dacă un întreg x aparŃine unui vector v. int cauta(int v[50], int n) { int k; int apartine; apartine=0; //se presupune ca x nu este element în v for(k=0;k<n;k++)

if(v[k]==x) apartine=1; return apartine; }

Exemplul 13. Să se scrie o funcŃie care realizează suma a doua matrice cu m linii şi n coloane. void suma_mat(int a[20][20], int b[20][20], int c[20][20], int m, int n) { int j, k; //variabile contor în for for(j=0;j<m;j++)

for(k=0;k<n;k++) c[j][k]=a[j][k]+b[j][k]; }

Parametrii de care depinde rezolvarea sarcinii sunt: a - prima matrice b - a doua matrice c - matricea suma (rezultatul sumei) m - numărul de linii n - numărul de coloane

ExerciŃiul 5. Să se scrie funcŃia main corespunzătoare funcŃiei de mai sus, precum şi funcŃii pentru citirea şi afişarea unei matrice.

O situaŃie interesanta apare atunci când vrem ca variabilele ce apar ca parametri formali să poată fi modificate în cadrul funcŃiei, modificările fiind disponibile în funcŃia apelanta.

25

Să luam următorul exemplu: Exemplul 14. Să se scrie o funcŃie care interschimbă valorile a doua variabile întregi.

Varianta următoare este greşita: void schimba(int x, int y) { int temp; temp=x; x=y; y=temp; } void main() { int a, b; cin>>a; cin>>b; schimba(a,b); cout<<a; cout<<b; }

La prima vedere funcŃia pare corecta, insa lucrurile stau tocmai pe dos. Dacă introducem valorile 5 pentru a şi 7 pentru b, programul ar trebui să schimbe intre ele valorile celor doua variabile (a trebuie să devină 7, iar b să devină 5). Programul de mai sus nu va realiza acest lucru. ExplicaŃia este ca, atunci când parametri formali sunt parametri valoare, chiar dacă se modifica valoarea lor în cadrul funcŃiei aceste modificări nu vor avea efect în funcŃia apelanta (în cazul nostru, în funcŃia main nu va fi sesizabila schimbarea realizata în funcŃia schimba).

Problema se poate rezolva dacă parametrii din funcŃia schimba vor fi parametri referinŃa (pointeri). Varianta corecta este următoarea: void schimba(int *x, int *y) { int temp; temp=*x; *x=*y; *y=temp; }

Singura schimbare din funcŃia main este apelul funcŃiei, care devine schimba(&a, &b);

ExplicaŃia corectitudinii acestei variante este aceea ca se lucrează cu adresele variabilelor, deci orice modificare a conŃinutului zonelor de memorie alocate variabilelor x şi y va fi resimŃită şi în funcŃia main.

ParcurgeŃi din nou exemplul 10 şi priviŃi cu atenŃie antetul funcŃiei suma_mat. Parametrul formal c este o matrice calculata ca suma matricelor a şi b, deci valoarea elementelor lui c este modificata în cadrul funcŃiei, dar parametrul formal este corect ? Răspunsul este afirmativ deoarece, după cum ştiŃi, tablourile sunt tratate exact ca şi pointerii, deci tablourile care apar ca parametrii formali se considera parametri referinŃa.

Variabile locale şi variabile globale Un program C este compus din una sau mai multe funcŃii (cel puŃin funcŃia main) repartizate în unul sau mai

multe fişiere. Structura de principiu a unui program C este următoarea: • directive de preprocesare (de exemplu #include) • declaraŃii de tipuri şi variabile globale (imediat după directivele de preprocesare, în afara oricăror funcŃii) • definiŃii de funcŃii • funcŃia main()

Toate variabilele declarate în afara oricărei funcŃii se numesc variabile globale, acestea putând fi utilizate în orice funcŃie din program. Variabilele definite în interiorul unei funcŃii se numesc variabile locale şi pot fi utilizate doar în funcŃia unde au fost declarate. Putem declara o variabila k în mai multe funcŃii, fără să fie influenŃata corectitudinea programului. Este de preferat ca variabilele globale să fie în număr limitat, doar atunci când este nevoie neapărata. Folosirea neatenta a variabilelor globale poate duce la erori greu depistabile.

26

Bibliografie

Suport de curs Universitatea de Vest Vasile Goldis Liviu Nergrescu Limbajul C++ Editura Albastra Cluj Napoca 1999 Doina Hrinciuc Logofatu C++ probleme rezolvate si algoritmi Editura Polirom 2001 Ana Intuneric Cristina Sichim Informatica Teste grila C/C++ Polirom 2003 Mariana Milosescu Informatica Editura Didactica si Pedagocica 2005

UVVG ARAD Suport de curs pentru forma de invatamant ID (preluare de pe CD)