Sunteți pe pagina 1din 38

SUPORT DE CURS – Semestrul I

CLASA: a XII-a Df (2021-2022)

DISCIPLINA: INFORMATICA

CONȚINUTURI

I. Tablouri bidimensionale

II. Șiruri de caractere

III. Structuri de date neomogene (struct/record)

IV. Subprograme

V. Recursivitate

Prof. Zaharciuc Viorica


Colegiul Național „Calistrat Hogaș” Piatra-Neamț

I.TABLOURI BIDIMENSIONALE
Tablourile bidimensionale funcţionează ca o matrice şi se pot declara astfel:
• La fel ca şi în cazul tablourilor unidimensionale, şi în cazul tablourilor bidimensionale, la
declarare, se trece dimensiunea maximă a liniilor (dim_linie) şi dimensiunea maximă a
coloanelor (dim_coloana).
Exemplu:
Prezentăm în continuare câteva declarări de tablouri bidimensionale:
int a[10][10]; // declararea unui tablou bidimensional cu maxim 100 de // elemente (10*10),
fiecare de tip întreg;
float x[5][5]; // declararea unui tablou bidimensional cu maxim 25 de // elemente(5*5),
fiecare de tip real simplă precizie;
char s[20][10]; // declararea unui tablou bidimensional cu maxim 200 de // elemente(20*10),
fiecare de tip caracter;

Compilatorul C++ alocă un spaţiu de memorie egal cu numărul de linii înmulţit cu numărul
de coloane ale tabloului, rezervând bineînţeles octeţi în funcţie de tipul de bază al fiecărui
tablou.
• Accesul la fiecare element al tabloului se face prin numele acestuia urmat între
paranteze, de indicele liniei şi indicele coloanei (adică poziţia pe care o ocupă în tablou).

Iniţializarea elementelor unui tablou se poate face total sau parţial la declararea lor:
int b[2][3]={ {1, 2, 3}, {4, 5, 6} };
• Astfel, elementul b[0][0] are valoarea 1, elementul b[0][1] are valoarea 2, elementul b[0][2]
are valoarea 3, elementul b[1][0] are valoarea 4, elementul b[1][1] are valoarea 5, elementul
b[1][2] are valoarea 6.
Colegiul Național „Calistrat Hogaș” Piatra-Neamț

CITIREA ELEMENTELOR UNEI MATRICE:

cout<<"m = "; cin>>m;


cout<<"n = "; cin>>n;
for(i=1; i<=m; i++)
for(j=1; j<=n; j++)
{
cout<<"a["<<i<<"][ "<<j<<"] = ";
cin>>a[i][j];
}

AFIȘAREA ELEMENTELOR UNEI MATRICE:

cout<<"Elementele matricei A sunt : “<<endl;


for(i=1; i<=m; i++)
{
for(j=1; j<=n; j++)
cout<<a[i][j]<<" ";
cout<<endl;
}
Colegiul Național „Calistrat Hogaș” Piatra-Neamț

II. ȘIRURI DE CARACTERE

O constantă de tip șir de caractere se declară între două caractere “. În memoria internă, o
constantă de acest tip este reținută sub forma unui vector de caractere. Fiecare componentă a șirului
(începând cu cea de indice 0) reține codul ASCII al caracterului pe care îl memorează. Convenția este ca
ultimul octet să rețină 0 (codul caracterului nul). Caracterul nul este memorat automat. Trebuie rezervate
lungimea_șirului+1 caractere char (+1 pentru caracterul nul).
Limbajul C/C++ permite inițializarea unui tablou de caractere printr-o constanta șir, care include automat
caracterul NULL.

Exemplu :
char vect[11]=”calculator”;
char vect[]=”calculator”; (compilatorul face calculul numărului de octeți necesari)
char vect[100]=”calculator”; (s-au rezervat mai mulți octeți decât era necesar)

Șirurile de caractere sunt de fapt tablouri de caractere, care au ca ultim element un terminator de șir, caracterul
NULL.

Exemplu:
char tc[5] = {’a’, ’b’, ’c’, ’d’, ’e’}; // tablou de caractere
char sc[5] = {’a’, ’b’, ’c’, ’d’, ’\0’}; // sir de caractere cu elementele abcd

Ultima inițializare este echivalentă cu:


char sc[5] = ”abcd”; //sau char sc[] = ”abcd”;
char sc1[5] = ”abcd”;
char s[10];
cout<<sc<<endln; //afiseaza abcd
cout<<tc<<endl; //eroare: tabloul de caractere nu conține terminatorul de șir, deci nu poate fi afișat
ca șir
cout<<s<<endl; // eroare: tablou neinițializat
cout<<sc1[0]; // afișează primul caracter din șirul sc1
cout<<sc1[2]; // afișează al treilea element din șirul sc1
sc1[1]=’K’; // elementului din sir de indice 1 i se atribuie valoarea ‘K’;
Colegiul Național „Calistrat Hogaș” Piatra-Neamț

CITIREA / AFISAREA ȘIRURILOR DE CARACTERE

Șirurile de caractere pot fi inițializate încă de la declarare sau citite pe parcursul programului.
a. Citirea unui șir de caractere se poate face ca citirea oricărui tablou, într-un for, caracter cu
caracter (deși nu este recomandată). În acest caz, terminatorul de șir nu este memorat automat, el
trebuie pus explicit după ultimul caracter din șir.

Exemplu:
char c[20];
for(int i=0;i<=5;i++)
cin>>c[i];
cout<<c<<endl; //se va afișa șirul format din cele 6 caractere, urmat de caractere
//„reziduale”, inițializate implicit la compilare, din cauza ca n-a fost pus
//terminatorul de șir
c[6]=0;
cout<<c<<endl; //a fost pus terminatorul de șir, deci șirul va fi afișat corect

b. Se poate face pur și simplu, folosind cin>>. Caracterul nul este adăugat automat.
Dezavantajul este că, în acest fel, nu se pot citi șiruri care conțin mai multe cuvinte
separate prin spații. Citirea șirului se sfârșește la întâlnirea primului caracter alb (de ex,
daca se citește “ora de informatica”, variabila c va reține numai “ora”).
Exemplu
char c[30];
cin>>c;
cout<<c;

c. Se poate folosi o funcție specială pentru citirea șirurilor de caractere, inclusă în biblioteca
string.h (varianta recomandată).
Exemplu
char a[30],x;int nr;
cin.get(a,nr,x);
Funcția cin.get citește un șir de caractere sau până când au fost citite nr-1 caractere, sau dacă
s-a întâlnit caracterul x. Al treilea parametru poate lipsi, caz în care el este implicit caracterul
’\n’ (new line). Sunt citite și caracterele albe, caracterul NULL este inserat automat, iar
caracterul transmis ca ultim parametru nu este inserat în șir.
Exemplu
char a[30];
cin.get(a,5,’s’); //daca se citește șirul “maimuta”, variabila a va reține “maim”
cin.get(a,15,’s’); //dacă se citește șirul “maimuta”, variabila a va reține “maimuta”
cin.get(a,15,’t’); //dacă se citește șirul“maimuta”, variabila a va reține “maimu”
cin.get(a,4,’t’); //dacă se citește șirul “maimuta”, variabila a va reține “mai”
cin.get(a,10); //daca se citește șirul “maimuta”, variabila a va reține “maimuta”

Funcția cin.get( ) fără parametri are rolul de a citi un caracter (alb sau nu).
Funcția cin.get(char c) are rolul de a citi un caracter (alb sau nu) pe care îl încarcă în variabila
c.
Colegiul Național „Calistrat Hogaș” Piatra-Neamț

Observație: În cazul utilizării repetate a funcției cin.get(a,nr,x), după fiecare folosire


trebuie citit caracterul de la sfârșitul fiecărui șir , adică ’\n’ (in caz contrar, acest caracter va fi
încărcat la începutul următorului șir, a cărui citire se termină la caracterul Enter, deci citirea
celui de-al doilea șir se termină înainte de a începe, iar al doilea șir va fi șirul vid). Această
citire a caracterului ’\n’ se realizează folosind cin.get() fără parametri.

Exemplu
char a[30],b[30];
cin.get(a,15);
cin.get(b,10);
Dacă se încearcă citirea șirurilor „sarbatoare” și „vacanta”, se observă ca a=”sarbatoare”, b=””
(nici nu apucăm să citim șirul b). Varianta corectă este:
cin.get(a,15);
cin.get();
cin.get(b,10);

Afișarea unui șir de caractere se face folosind cout.


cout<<a;
Se poate afișa și caracter cu caracter, ca în cazul tablourilor, dar această variantă nu este
recomandată.
Colegiul Național „Calistrat Hogaș” Piatra-Neamț

FUNCȚII PENTRU OPERAȚII CU ȘIRURI DE CARACTERE

Funcțiile pentru operații cu șiruri se găsesc în header-ul <string.h>.

 Funcția strlen
int strlen(nume_sir); – returnează lungimea efectivă a unui șir (fără a număra terminatorul de
șir).
Exemplu:
char a[50]=”ora de informatica”;  strlen(a) = 18

 Functia strcpy
strcpy(sir_destinatie,sir_sursa); – copiază șirul sir_sursa în sir_destinatie (se
simulează atribuirea a=b).

ATENTIE!! Nu este permisă atribuirea între două șiruri de caractere folosind operatorul =.
Atribuirea se face folosind funcția strcpy.

Exemplu:
char a[50]=”primul sir”,b[40]=”al doilea sir”;
a=b; //eroare
strcpy(a,b);  a = ”al doilea sir”; b=”al doilea sir”;

 Funcția strcat
strcat(dest,sursa); – adaugă șirului dest șirul sursa. Șirul sursa rămâne nemodificat.
Operația se numește concatenare și nu este comutativș.
Exemplu:
char *a=”vine ”,*b=”vacanta?”;
strcat(a,b);  a = ”vine vacanta?”;

 Funcția strncat
strncat(dest,sursa,nr); – adaugă dest primele nr caractere din șirul sursa. Șirul sursa
rămâne nemodificat.
Exemplu:
char *a=”vine ”,*b=”vacanta?”;
strncat(a,b,4);  a = ”vine vaca”;

 Funcția strchr
strchr(sir,c); – are rolul de a căuta caracterul c în șirul sir. Căutarea se face de la stânga la
dreapta, iar funcția întoarce adresa subșirului care începe cu prima apariție a caracterului c. Dacă
nu este găsit caracterul, funcția returnează 0. Diferența dintre adresa șirului inițial și cea a
subșirului returnat reprezintă chiar poziția caracterului căutat în șirul dat.
Colegiul Național „Calistrat Hogaș” Piatra-Neamț

Exemplu:
char *a=”acesta este un sir”,b=’t’,c=’x’,d;
cout<<strchr(a,b);  se tipareste ”ta este un sir”;
cout<<strchr(a,c);  nu se tipareste nimic (se tipareste 0 daca se face o conversie la
int a lui strchr(a,c) ;
d= strchr(a,b);
cout<<”Caracterul apare prima data la pozitia ”<<d-a;

 Funcția strrchr
strrchr(sir,c); – are același rol cu strchr, cu deosebirea că returnează adresa ultimei apariții
a caracterului (căutarea se face de la dreapta spre stânga; r = right)

 Functia strcmp
int strcmp(sir1,sir2); – are rolul de a compara două șiruri de caractere. Valoarea returnată
este <0 (dacă sir1<sir2), =0 (dacă sir1=sir2) și >0 (dacă sir1>sir2). Funcția strcmp face
distincție între literele mari și cele mici ale alfabetului.
Obs: Funcția strcmp returnează diferența dintre codurile ASCII ale primelor caractere care nu
coincid.

 Funcția stricmp
int stricmp(sir1,sir2); – are același rol cu strcmp, cu deosebirea cș nu face distincție între
literele mari și cele mici ale alfabetului (i = ignore).

 Funcția strstr
strstr(sir1,sir2); – are rolul de a identifica dacă șirul sir2 este subșir al șirului sir1. Dacă
este, funcția returnează adresa de început a subșirului sir2 în șirul sir1, altfel returnează adresa
0. În cazul în care sir2 apare de mai multe ori în sir1, se returnează adresa de început a primei
apariții. Căutarea se face de la stânga la dreapta.

 Funcția strtok
strtok(sir1,sir2); – are rolul de a separa șirul sir1 în mai multe șiruri (cuvinte) separate între
ele prin unul sau mai multe caractere cu rol de separator. Șirul sir2 este alcătuit din unul sau mai
multe caractere cu rol de separator.
Funcția strtok acționează în felul următor:
o Primul apel trebuie să fie de forma strtok(sir1,sir2); Funcția întoarce adresa primului caracter
al primei entități. După prima entitate, separatorul este înlocuit automat prin caracterul nul.
o Următoarele apeluri sunt de forma strtok(NULL,sir2); De fiecare dată, funcția întoarce adresa
de început a următoarei entități, adăugând automat după ea caracterul nul.
o Când șirul nu mai conține entități, funcția returnează adresa nulă.
Colegiul Național „Calistrat Hogaș” Piatra-Neamț

Exemplu:
//Sa se separe cuvintele dintr-un text.
#include <iostream.h>
#include <conio.h>
#include <string.h>
void main()
{char text[100],cuv[10][10],*p,*r,separator[]=",. !?";int i=0,nr=0;
clrscr();
cout<<"Dati sirul:";cin.get(text,100);
strcpy(p,text);
p=strtok(p,separator);
while (p)
{strcpy(cuv[++nr],p);
p=strtok(NULL,separator);}
cout<<"Sunt "<<nr<<" cuvinte:"<<endl;
for (i=1;i<=nr;i++) cout<<cuv[i]<<endl;
getch();}

 Funcția strspn cu forma generală


int strspn(sir1,sir2); – are rolul de a returna numărul de caractere ale șirului sir1
(caractere consecutive care încep obligatoriu cu primul caracter) care se găsesc în șirul sir2.
Exemplu:
strspn(“AB2def”,”1B3AQW”);  returnează 2, pentru că primele 2 caractere ‘A’ și ‘B’
din sir1 se găsesc în sir2.
strspn(“FAB2def”,”16A32BF”);  returnează 0, deoarece caracterul ‘F’ cu care începe sir1
nu se găsește în sir2.

 Funcția strcspn cu forma generală


int strspn(sir1,sir2); – are rolul de a returna numărul de caractere ale șirului sir1
(caractere consecutive care încep obligatoriu cu primul caracter) care nu se găsesc în șirul sir2.
Exemplu:
strspn(“AB2def”,”123”);  returnează 2, pentru ca primele 2 caractere din sir1 nu se
găsesc în sir2.

 Funcția strlwr cu forma generală


strlwr(sir); – are rolul de a converti toate literele mari din sir în litere mici. Restul
caracterelor rămân neschimbate.

 Funcția strupr cu forma generală


strupr(sir); – are rolul de a converti toate literele mici din sir în litere mari. Restul
caracterelor rămân neschimbate.
Colegiul Național „Calistrat Hogaș” Piatra-Neamț

 Funcția strbrk cu forma generală


strpbrk(sir1,sir2); – acționează în felul următor:
o Caută primul caracter al șirului sir1 în sir2. Dacă este găsit, returnează adresa sa din cadrul
șirului sir1 și execuția se termină. Altfel, se trece la pasul următor.
o Caută al doilea caracter al șirului sir1 în sir2. Dacă este găsit, returnează adresa sa din
cadrul șirului sir1 și execuția se termină. Altfel, se trece la pasul următor.
o …
o Dacă nici un caracter al șirului sir1 nu aparține șirului sir2, funcția returnează adresa nulă.

 Funcția atof cu forma generală


double atof(sir); – convertește un șir către tipul double. Dacă această conversie eșuează (se
întâlnește un caracter nenumeric), valoarea întoarsă este 0. Această funcție (ca și cele similare)
necesită includerea librăriei stdlib.h.

 Funcția atold cu forma generală


long double _atold(sir); – convertește un șir către tipul long double. Dacă această conversie
eșuează, valoarea întoarsă este 0.

 Funcția atoi cu forma generală


int atoi(sir); – convertește un șir către tipul int. Dacă această conversie eșuează (se întâlnește
un caracter nenumeric), valoarea întoarsă este 0.

 Funcția atol cu forma generală


long atol(sir); – convertește un șir către tipul long. Dacă această conversie eșuează (se
întâlnește un caracter nenumeric), valoarea întoarsă este 0.

 Funcția itoa cu forma generală


itoa(int valoare,sir,int baza); – convertește o valoare de tip int în șir, care este memorat
în variabila sir. Baza reține baza de numerație către care se face conversia. În cazul bazei 10,
șirul reține și eventualul semn -.

 Funcția ltoa cu forma generală


ltoa(long valoare,sir,int baza); – convertește o valoare de tip long int în șir, care este
memorat în variabila sir.

 Funcția ultoa cu forma generală


ultoa(unsigned long valoare,sir,int baza); – convertește o valoare de tip unsigned long
în șir, care este memorat în variabila sir.
Colegiul Național „Calistrat Hogaș” Piatra-Neamț

III. STRUCTURI DE DATE NEOMOGENE


TIPUL STRUCT

O structură este un ansamblu format din una sau mai multe variabile grupate
împreună sub un singur nume. Structurile se deosebesc de tablouri prin următoarele
aspecte:
o elementele unei structuri pot avea tipuri diferite,
o structurile pot fi atribuite,
o funcţiile pot returna structuri,
o elementele unui structuri nu sunt variabile anonime ci au câte un nume,
o referirea unui element al unei structuri se realizează cu operatorul de selecţie
( . ) şi nu cu operatorul de indexare ( [ ] ).
Dacă dorim să prelucrăm date referitoare la mai mulţi elevi, pentru fiecare elev trebuie
să cunoaştem:
 Numele – char[20]
 Prenumele – char[20]
 Nota matematică - float
 Nota informatică - float
 Vârsta - int

În C++ există un tip de date, numit struct, care permite ca fiecărui elev să-i
corespundă o singură înregistrare.
Colegiul Național „Calistrat Hogaș” Piatra-Neamț

Forma generală este:


struct [nume structura]
{
[<tip> <nume variabila [, nume variabila, ……]>];
[<tip> <nume variabila [, nume variabila, ……]>];

} [lista de variabile];

Structura o denumim elev şi este:


struct elev
{ char nume[20], prenume[20];
float nota_mate, nota_info;
int varsta;
};

Există două posibilităţi de declarare a variabilelor care alcătuiesc structura:


1. Scriind la sfârşit numele variabilelor:
struct elev
{ char nume[20], prenume[20];
float nota_mate, nota_info;
int varsta;
} inr1,inr2;
2. Declarând variabilele aşa cum suntem obişnuiţi:
elev inr1, inr2;
Colegiul Național „Calistrat Hogaș” Piatra-Neamț

Definiţia structurii poate fi făcută:


 În cadrul funcţiei main()
 Înaintea funcţiei main() (caz recomandat)
Pentru accesul la câmpurile unei variabile de tip struct se foloseşte operatorul de
selecţie directă, notat cu ‘.’, operator cu prioritate maximă.

Dacă inr este o variabilă de tipul elev. Atunci:


 inr.nume – reprezintă şirul nume al variabilei inr;
 inr.nume[0] - reprezintă primul caracter al şirului nume;
 inr.nota_mate – reprezintă câmpul nota_mate al variabilei inr.
Între două variabile de acelaşi tip struct se poate folosi atribuirea.
Dacă inr1, inr2 sunt două variabile de tip elev, prin atribuirea inr1=inr2, variabila inr1
ia aceeaşi valoare ca variabila inr2.
O astfel de atribuire se mai numeşte copiere bit cu bit.

Înregistrările imbricate
 Putem avea un tip structurat ce conţine în interiorul său un alt tip structurat.
struct elev
{ char nume[20], prenume[20];
struct
{ int clasa;
float note[20];
} situatie;
int varsta;
};
Dacă inr este o variabilă de tipul elev. Atunci accesarea elementelor situate în
interiorul structurii se face astfel:
 inr.situatie.clasa – se accesează câmpul clasa al substructurii
 inr.situatie.note[0] – se accesează prima notă a vectorului inclus în substructură
Colegiul Național „Calistrat Hogaș” Piatra-Neamț

IV. SUBPROGRAME

Pentru proiectarea unei aplicaţii mai complexe este necesară descompunerea


problemei ce trebuie rezolvată în subprobleme relativ independente, pentru fiecare dintre
aceste subprobleme scriindu-se module de program mai simple. Pentru ca programul să
funcţioneze, în final, modulele de program trebuie asamblate. Într-o etapă anterioară a
implementării se face o analiză a problemei de rezolvat, se stabilesc subproblemele,
modulele de program care trebuie să rezolve aceste subprobleme, precum şi modalităţile în
care acestea trebuie să comunice între ele.
De asemenea, în rezolvarea problemelor apar frecvent operaţii care se repetă. În
aceste situaţii ar fi bine să scriem secvenţa de program corespunzătoare unei astfel de
operaţii o singură dată şi să o folosim ori de câte ori este nevoie de ea.
În limbajele C şi C++, subprogramele sunt denumite funcţii. Într-un program C/C++
toate prelucrările sunt organizate ca o ierarhie de apeluri de funcţii, baza acestei ierarhii
fiind funcţia main().

Definirea unei funcţii – este constituită dintr-un antet, care conţine numele funcţiei,
tipul rezultatului returnat de funcţie, lista parametrilor funcţiei şi un bloc de instrucţiuni,
care descrie prelucrările efectuate de funcţie.

Formatul general al definiţiei unei funcţii este:


tip nume (lista_parametri_formali)
{
declaraţii variabile locale;
instrucţiuni;
}
unde:
tip – reprezintă tipul rezultatului returnat de funcţie
nume – reprezintă numele funcţiei
Colegiul Național „Calistrat Hogaș” Piatra-Neamț

lista_parametri_formali – este constituită din una sau mai multe declaraţii


de parametri formali, separate prin virgulă, sau poate lipsi.

O declaraţie de parametru formal specifică tipul şi numele parametrului, sub forma


tip nume.
Parametrii unei funcţii constituie o interfaţă prin intermediul căreia funcţia
comunică cu exteriorul. Parametrii formali sunt denumiţi astfel deoarece cu ajutorul lor se
descriu formal operaţiile la care vor fi supuse datele ce vor fi transmise de programul
apelant spre subprogram.
În blocul funcţiei trebuie să existe instrucţiunea return, cu formatul general:
return expresie;
Efect – se evaluează expresia şi se încheie execuţia funcţiei, returnând funcţiei
apelante valoarea expresiei. În cazul în care expresia este vidă, funcţia nu returnează nici o
valoare.
Colegiul Național „Calistrat Hogaș” Piatra-Neamț

Apelul funcţiilor

Apelul unei funcţii se poate realiza în două moduri – printr-o instrucţiune de apel
sau ca operand într-o expresie.
Instrucţiunea de apel a unei funcţii are următorul format general:
nume (lista_parametri_actuali);
unde nume reprezintă numele funcţiei, iar lista parametrilor actuali este formată dintr-o
succesiune de expresii separate prin virgulă.
Utilizăm instrucţiuni de apel atunci când funcţia apelată nu returnează nici o valoare
sau atunci când nu dorim să utilizăm valoarea returnată de funcţie, ci ne interesează doar
efectuarea prelucrărilor descrise de funcţie.
În cazul în care dorim să utilizăm valoarea returnată de funcţie, apelăm funcţia ca
operand într-o expresie.
La apelul unei funcţii, valorile parametrilor actuali sunt atribuite parametrilor
formali corespunzători. Parametri actuali trebuie să corespundă cu parametrii formali ca
număr, ordine şi tip.

Variabilele globale – sunt declarate în exteriorul oricărei funcţii, li se alocă memorie


în segmentul de date al programului, memoria rămâne alocată până la sfârşitul execuţiei
programului, sunt vizibile din momentul declarării până la sfârşitul programului, în toate
modulele acestuia.

Variabilele locale – sunt declarate în blocul unei funcţii, li se alocă memorie pe stivă,
memoria rămâne alocată până la sfârşitul execuţiei blocului în care este declarată variabila,
sunt vizibile numai în blocul în care sunt declarate.
Colegiul Național „Calistrat Hogaș” Piatra-Neamț

Declararea funcţiilor – informează despre existenţa funcţiilor şi formatul acestora. O


declaraţie de funcţie specifică numele funcţiei, tipul rezultatului returnat de funcţie şi
parametrii acesteia:
tip nume(lista_parametri);

O declaraţie de funcţie este constituită din antetul funcţiei, urmat de „;”, nu de


blocul de instrucţiuni al funcţiei. În declaraţie lista parametrilor nu conţine în mod
obligatoriu şi numele parametrilor, ci este permisă doar specificarea tipurilor parametrilor.
Declaraţia unei funcţii se mai numeşte şi prototip.

Transmiterea parametrilor se face prin corespondenţă, din acest motiv între


parametrii formali şi parametrii efectivi trebuie să existe o anumită concordanţă:
- numărul parametrilor formali trebuie să coincidă cu numărul parametrilor efectivi;
- ordinea parametrilor formali trebuie să fie aceeaşi cu cea a parametrilor efectivi;
- tipul parametrilor efectivi trebuie să coincidă cu tipul parametrilor formali.
Din punctul de vedere al modului de transmitere a parametrilor putem împărţi
parametrii în două categorii:

Parametri transmişi prin valoare – au rolul de a transmite date din zona de program
în care s-a apelat funcţia înspre funcţie. Funcţia va memora aceste date pe segmentul de
stivă pus la dispoziţie. După terminarea execuţiei funcţiei, segmentul de stivă se eliberează
şi astfel programul nu mai are acces la variabilele memorate pe stivă. Din acest motiv
parametrii transmişi prin valoare nu pot transmite datele modificate în cadrul funcţiei
înspre zona de program de unde a fost apelată funcţia.
La apel, aceşti parametrii pot fi: valori, variabile, expresii şi chiar funcţii.
Colegiul Național „Calistrat Hogaș” Piatra-Neamț

Parametrii transmişi prin referinţă – au rolul ca la revenirea din funcţie, variabila


transmisă să reţină valoarea modificată în timpul execuţiei funcţiei. Pentru ca un
parametru să fie transmis prin referinţă numele lui trebuie să fie precedat de caracterul
ampersand &, la declararea parametrilor, în antetul funcţiei. Atunci când o variabilă este
transmisă prin referinţă, nu se face o copie a ei pe segmentul de stivă, ci se reţine adresa
variabilei.
O funcţie poate avea unul sau ai mulţi parametri transmişi prin referinţă, iar
parametrii efectivi corespunzători trebuie să fie nume de variabile.
Colegiul Național „Calistrat Hogaș” Piatra-Neamț

Liste liniare

O listă colecţie de elemente de acelaşi tip aflate într-o relaţie de ordine: x1, x2, … xn.
Caracteristica principală a listelor liniare în opoziţie cu tablourile unidimensionale, este aceea
că numărul de elemente nu este cunoscut de la început.
Deşi există posibilitatea implementării listelor cu ajutorul tablourilor unidimensionale, se
utilizează mai puţin acest mod de reprezentare. În practică, listele se implementează utilizând
alocarea dinamică a memoriei.
Operaţiile specifice prelucrării listelor:
- adăugarea unui element la sfârşitul listei
- inserarea unui element în listă
- accesul la un element al listei
- ştergerea unui element din listă

Pentru lista liniară vom reprezenta înlănţuirea elementelor listei memorate într-un tablou
unidimensional cu reutilizarea spaţiului eliberat în urma operaţiilor de ştergere. În cadrul fiecărui
element al listei vom memora două categorii de informaţii: informaţia utilă pe care o conţine
elementul listei şi indicele de tablou corespunzător elementului următor din listă. Un element al
listei astfel organizat se numeşte nod.

nod

indicele nodului următor


informaţia utilă

În cadrul ultimului nod al listei, indicele care desemnează elementul următor are valoarea -1,
marcând astfel sfârşitul listei. Pentru gestionarea unei astfel de liste este necesar să memorăm
indicele primului nod din listă. Deoarece una dintre operaţiile posibile asupra unei liste liniare este
ştergerea unui nod, pot rămâne zone de memorie neutilizate ale tablourilor. Astfel se impune
gestionarea spaţiului liber al tabloului în scopul reutilizării lui. Pentru aceasta, vom folosi un
vector caracteristic s definit astfel:
1 dacă lista[i] - contine un nod al listei
s[i]  
0 dacă lista[i] - nu contine un nod al listei
Colegiul Național „Calistrat Hogaș” Piatra-Neamț

Implementarea listelor liniare


Considerăm informaţia utilă din cadrul unui nod ca fiind un număr întreg.
struct nod
{ int inf;
int urm;
};

Vom memora nodurile listei în tabloul unidimensional numit lista.


Vectorul caracteristic pentru gestionarea spaţiului liber îl numim s.
Pentru a memora indicele primului nod al listei vom utiliza variabila prim.
Dacă lista este vidă (nu conţine nici un nod), variabila prim este -1.

Cazuri particulare de liste

Stiva este o listă liniară care funcţionează după principiul ultimul intrat este primul ieşit
(LIFO).
Operaţiile ce se pot efectua asupra unei stive sunt:
- adăugarea unui element în vârful stivei
- extragerea unui element din stivă
Operaţiile ce se efectuează asupra unei stive se realizează numai la vârful stivei, prin urmare
este suficient să memorăm indicele nodului din vârful stivei într-o variabilă vf. Dacă vf este -1,
atunci vom spune că stiva este vidă.

Coada este o listă liniară ce funcţionează după principiul primul intrat este primul ieşit
(FIFO).
Operaţiile ce se pot efectua asupra unei cozi sunt:
- adăugarea unui element la sfârşitul cozii
- extragerea unui element din coadă
Pentru gestionarea unei liste liniare de tip coadă avem nevoie de două variabile: prim şi
ultim. Dacă prim > ultim atunci coada este vidă.
Colegiul Național „Calistrat Hogaș” Piatra-Neamț

V. RECURSIVITATEA

„- Ești de acord că orice om are dreptul la un pahar de cognac?


- Da.
- Bei paharul, îl pui jos. Ești alt om. Și cum orice om are dreptul la un
pahar de cognac... și așa mai departe.”
(Grigore Moisil)

Recursivitatea este una dintre noţiunile fundamentale ale informaticii. Utilizarea frecventă a
recursivităţii s-a făcut după anii '80. Multe dintre limbajele de programare evoluate şi mult utilizate
(Fortran, Cobol) nu permiteau scrierea programelor recursive.
Noţiunea de recursivitate din programare derivă în mod natural, din noţiunea matematică
cunoscută sub numele de recurenţă. O noţiune este definită recurent dacă în cadrul definiţiei apare
noţiunea care se defineşte.
În linii mari, recursivitatea este un mecanism general de elaborare a programelor. Ea a apărut din
necesităţi practice (transcrierea directă a formulelor matematice
recurente) şi reprezintă acel mecanism prin care un subprogram
(procedură, funcţie) se autoapelează.
Un algoritm recursiv are la bază un mecanism de gândire
diferit de cel cu care ne-am obişnuit deja. Atunci când scriem un
algoritm recursiv este suficient să gândim ce se întâmplă la un anumit
nivel, pentru că, la orice nivel, se întâmplă exact acelaşi lucru.
Un algoritm recursiv corect trebuie să se termine; contrar,
programul se va termina cu eroare şi nu vom primi rezultatul aşteptat.
Condiţia de terminare va fi pusă de programator.
Un rezultat matematic de excepţie afirmă că, pentru orice algoritm iterativ, există şi unul recursiv
echivalent şi invers. Pentru orice algoritm recursiv există şi unul iterativ echivalent.
Pentru a putea implementa recursivitatea, se foloseşte structura de date numită stivă.
Mecanismul unui astfel de program poate fi generalizat cu uşurinţă pentru obţinerea recursivităţii.
Atunci când un subprogram se autoapelează, se depun în stivă:
 valorile parametrilor transmişi prin valoare;
 adresele parametrilor transmişi prin referinţă;
 valorile tuturor variabilelor locale (declarate la nivelul subprogramului).

Structura unui funcţii recursive:

tip nume_funcţie(lista parametri)


{…
if(condiţie de continuare sau de oprire)

nume_funcţie(lista parametri)

}
Colegiul Național „Calistrat Hogaș” Piatra-Neamț

Exemple:

1. La un televizor, se cuplează o cameră video care filmează ecranul televizorului. Pe ecran se va


vedea un televizor care va prezenta un televizor... Vom vedea o serie de televizoare din ce în ce mai mici.
Întâlnim procese care se exprimă în termeni recursivi sau, în matematică, apar frecvent relaţii
recursive, denumite şi relaţii de recurenţă.

2. Cea mai simplă şi mai familiară funcţie exprimată în termeni recursivi este factorialul:
n! = 1 dacă n=0 sau n! = n * (n - 1)! dacă n > 0.
unsigned long fact (int n)
{
if (n==0) return 1;
else return n * fact (n-1);
}

3. Şirul Fibonacci: 0, 1, 1, 2, 3, 5, 8, 13, 21, ..., în care primii doi termeni sunt 0 si 1, iar, în rest,
fiecare termen se obţine însumând cei doi termeni care îl preced.
Prin urmare, o definiţie recursivă pentru şirul lui Fibonacci este:
fib: N -> N
fib(n) = n, dacă n<=1 şi fib(n) = fib(n-1) + fib(n-2), dacă n > 1.

unsigned long fib ( int n)


{
if (n <= 1) return x;
else return fib(n-2) + fib(n-1);
}

Mecanismul de realizare a recursivităţii

Autoapelarea se poate realiza în două moduri: direct (în corpul funcţiei apare explicit un apel
recursiv) sau indirect (în corpul funcţiei apare apelul unei alte funcţii care, la rândul său, apelează direct
sau indirect funcţia respectivă).
Mecanismul care face posibilă recursivitatea derivă din modul de funcţionare a funcţiilor. Ca şi în
cazul oricărui apel de funcţie, şi în cazul funcţiilor recursive se alocă o zonă de memorie pe stivă pentru
valorile parametrilor, precum şi pentru valorile variabilelor locale. Această zonă de memorie rămâne
alocată pe tot parcursul execuţiei apelului funcţiei, fiind eliberată la momentul revenirii în funcţia
apelantă. Stiva nu este gestionată explicit de către programator, ci de către sistem.
Recursivitate
1. Se citeste un vector a cu n elemente numere naturale. Sa se calculeze elementul maxim
din vector. Se va folosi o functie recursiva pentru citire si una recursiva pentru determinarea
elementului maxim.

#include<iostream>
using namespace std;

int max(int a[100], int i, int j){


if(i==j) return a[i];
else { int m=(i+j)/2;
int m1=max(a,i,m);
int m2=max(a,m+1,j);
if(m1<m2) return m2;
else return m1; }}

void citire(int a[100], int n)


{
if(n>0) { citire(a,n-1);
cin>>a[n]; } }

void afis(int a[100],int n){


if(n>0) { afis(a,n-1);
cout<<a[n]<<" "; } }

int main()
{ int n,a[100];
cin>>n;
citire(a,n);
afis(a,n);
cout<<max(a,1,n);
system("pause");
return 0;
}

2. Sa se calculeze CMMDC al doua numele naturale folosind o functie recursiva.


#include<iostream>
using namespace std;

int cmmdc(int x, int y)


{ if(x%y==0) return y;
else return cmmdc(y,x%y);
}
int main(){
cout<<cmmdc(15,55);
system("pause");
return 0;}

3. Sa se determine cifra maxima a unui numar natural folosind o functie recursiva.


#include<iostream>
using namespace std;

int max(int n)
{ if ( n <= 9 ) return n;
else
{
int m = max(n/10);
if ( m > n%10 )
return m;
else
return n%10; }}

int main(){
cout << max(23614);
system("pause");
return 0;}

4. Sa se scrie o functie recursiva pentru calculul rasturnatului unui numar natural.


using namespace std;

int rast(int n, int r)


{ if ( n == 0 ) return r;
else
return rast(n/10,r*10+n%10);}

int main(){
cout <<rast(23456,0);
system("pause");
return 0;
}

5. Sa se scrie o functie recursiva care calculeaza cate cifre are un numar natural.

#include<iostream>
using namespace std;

int NC(int n){


if ( n <= 9 ) return 1;
else
return NC(n/10)+1;}

int main()
{ cout << NC(2405);
system("pause");
return 0;}

6. Sa se calculeze recursiv suma 1 + 1/2 + 1/3 + ... +1/n.


#include<iostream.h>

using namespace std;

float suma(int n)
{ if (n==0) return 0;
else return suma(n-1) + 1.0/n;}

int main(){
cout<<suma(5);
system("pause");;
return 0;
}

7. Sa se calculeze recursiv suma 1*2 + 2*3 + ... + n*(n+1).


#include<iostream.h>

using namespace std;

int suma(int n)
{ if (n==0) return 0;
else return suma(n-1) + n*(n+1);}

int main(){
cout<<suma(3);
system("pause");;
return 0;}

8. Sa se calculeze recursiv suma


1/1 + 2/2 + 3/3 + 5/4 + 8/5 + ... + fib(n)/n
unde fib(n) este al n-lea termen din sirul lui Fibonacci.
#include<iostream.h>

using namespace std;

int fib(int n)
{ if(n==1 || n==2) return 1;
else return fib(n-1)+fib(n-2);}
float suma(int n)
{ if (n==0) return 0;
else return suma(n-1) + (float)fib(n)/n;}

int main(){
cout<<suma(5);
system("pause");;
return 0;}

9. Sa se calculeze recursiv suma primelor n patrate perfecte.


#include<iostream>

using namespace std;


int suma(int n){
if(n==0) return 0;
else return suma(n-1)+n*n;}

int main(){
int n;
cin>>n;
cout<<suma(n);
system("pause");
return 0;}

10. Sa se calculeze recursiv 2 la puterea n.


#include<iostream>

using namespace std;

int putere(int n){


if(n==0) return 1;
else return putere(n-1)*2;}

int main(){
int n;
cin>>n;
cout<<putere(n);
system("pause");
return 0;
}

11.Sa se calculeze recursiv de cate ori apare o valoare intreaga x intr-un vector a cu n
elemente intregi.

#include<iostream>
using namespace std;

int a[100],n,x;

int nrap(int n, int x){


if(n==0) return 0;
else if(a[n]==x) return 1+nrap(n-1,x);
else return nrap(n-1,x); }

int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
cin>>x;
cout<<nrap(n,x);
system("pause");
return 0;}

12. Sa se scrie o functie recursiva care numara cate vocale mici are un cuvant transmis ca
parametru.
#include<iostream>

using namespace std;

int vocale(char s[20]){


if(strlen(s)==0) return 0;
else if(strchr("aeiou",s[0])) return 1 + vocale(s+1);
else return vocale(s+1);}

int main(){ cout<<vocale("anamaria");


return 0;}

13. Sa se calculeze recusiv suma


S=1/2+2/1+2/3+3/2+...+n/(n+1)+(n+1)/n.
#include<iostream>

using namespace std;

float suma(int n)
{ if (n==0) return 0;
else return suma(n-1) + (float)n/(n+1)+(float)(n+1)/n;}

int main(){ int n;


cin>>n;
cout<<suma(n);
system("pause");
return 0;}
14. Sa se stearga din fiecare element al unui vector toate aparitiile cifrei maxime. Se vor
folosi functii recursive pentru urmatoarele prelucrari:
- citirea elementelor vectorului
- determinarea cifrei maxime a unui numar
- stergerea tuturor aparitiilor unei cifre dintr-un numar
- parcurgerea vectorului si modificarea elementelor conform cerintei
- afisarea vectorului
Ex: 7
37 443 13 160 31 11 140
se vor afisa valorile: 3 3 1 10 1 0 10
#include<fstream>
using namespace std;
ifstream fin("date.in");
ofstream fout("date.out");

int cmax(int n){


if(n<=9) return n;
else if(cmax(n/10)>n%10) return cmax(n/10);
else return n%10;}

int delcif(int n, int c){


if(n==0) return 0;
else if(n%10==c) return delcif(n/10,c);
else return delcif(n/10,c)*10+n%10;}

void s(int a[100], int n){


if(n>0) {
s(a,n-1);
a[n]=delcif(a[n],cmax(a[n]));}}

void citire(int a[100], int n){


if(n>0) {
citire(a,n-1);
fin>>a[n]; }}

void afis(int a[100], int n){


if(n>0) {
afis(a,n-1);
fout<<a[n]<<" "; }}
int main(){
int a[100],n;
fin>>n;
citire(a,n);
s(a,n);
afis(a,n);
fin.close();
fout.close();
return 0;}

15.Sortare cu metoda bulelor - implementare recursiva (tabloul este indexat incepand cu 0)


#include <fstream>
using namespace std;
ifstream is("date.in");
ofstream os("date.out");

void bule_rec(int a[], int n){


int gata=1;
for(int i=0;i<n-1;i++)
if(a[i]>a[i+1])
{
int aux=a[i]; a[i]=a[i+1]; a[i+1]=aux;
gata=0;
}
if(!gata) bule_rec(a,n-1);}

int main(){
int a[100],n;
is>>n;
for(int i=0;i<n;i++)
is>>a[i];
bule_rec(a,n);
for(int i=0;i<n;i++)
os<<a[i]<<" ";
is.close();
os.close();
return 0;}

16.Sortare cu metoda selectiei (metoda elevului) - implementare recursiva (tabloul este


indexat incepand cu 0)
#include <fstream>
using namespace std;
ifstream is("date.in");
ofstream os("date.out");

void elev_rec(int a[], int n, int i, int j){


if(i<n-1) {
if(a[i]>a[j]) {int aux=a[i]; a[i]=a[j]; a[j]=aux;}
if(j<n-1) elev_rec(a,n,i,j+1);
else elev_rec(a,n,i+1,i+2); }}

int main(){
int a[100],n;
is>>n;
for(int i=0;i<n;i++)
is>>a[i];
elev_rec(a,n,0,1);
for(int i=0;i<n;i++)
os<<a[i]<<" ";
is.close();
os.close();
return 0;}

S-ar putea să vă placă și