You are on page 1of 214

Introducere in ANSI C++

Introducere
Initial, aceasta lucrare a fost conceputa avand ca instrument de lucru mediul de
programare Borland C++ 3.1, varianta de DOS. Aparitia standardelor ANSI pentru
C si C++ si in primul rand introducerea suportului pentru acest standard in
majoritatea compilatoarelor (gcc, g++, bcc32 etc.), a dus la faptul ca unele dintre
sursele existente sa nu mai fie viabile.
Capitolele au fost modificate in asa fel incat un utilizator familiarizat cu mediul
BC++ 3.1 sa poate face intr-un mod accesibil trecerea de la acest mediu spre
variantele free oferite pe piata cu suport ANSI C++.
Lucrarea a fost editata in intregime sub programul OpenOffice Writer, oferit in
(probabil) toate distributiile gratuite de Linux. In acest caz, sistemul pe care s-a
lucrat este SUSE 9.3.
Am folosit pentru editarea programelor sursa utilitarul Kate, avand optiunile de
editare specifice C++ activate, pentru compilare compilatorul g++, iar pentru
depanare Kdbg, o interfata pentru gdb, depanatorul GNU.
Urmatoarele volume vor contine:

– Prezentarea bilbiotecii standard ANSI C++

– Programare orientate obiect in ANSI C++

– STD (Standard Template Library)

-1-
Introducere in ANSI C++

Capitolul 1 – Primul program

1.1 Structura generala a unui program C++


In general, structura surselor C++ ce apar in lucrare este urmatoarea:

// Comentariu (enuntul problemei)

# directive_preprocesor

prototipuri_functii;
declaratii_variabile globale;

int main(){
declaratii_variabile_locale;
instructiuni;
}

definire_functii

Sursele C++ reprezinta fisiere text care contin codul pe care dorim sa il rulam
pe calculator. Scrierea acestora se poate face in orice editor de text care permite
salvarea intr-un format text „curat”, fara detalii de formatare cum ar fi cele
introduse de catre un procesor de text (MS Word, OpenOffice Write etc.). Textul
sursa va fi salvat sub un nume sugestiv si cu extensia cpp.
Pentru a putea fi rulat, textul sursa trebuie sa fie „tradus” intr-o forma
executabila de catre calculator. Fara a intra in amanunte, sursa trebuie compilata,
apoi link-editata, obtinand un program executabil. In Figura 1.1 dam o schema
simplificata a acestui proces.

-2-
Introducere in ANSI C++

Compilare

Linkeditare

nume.cpp nume.exe

Figura 1.1 – Trecerea de la textul sursa la fisierul executabil

1.2 Hi man!
Ca prim program vom implementa urmatoarea problema:

P1. Realizati un program C++ care afiseaza mesajul „Hi man!” pe ecran.
Vom rezolva problama in trei variante, una specifica C, a doua folosind mediul
Borland C++ 3.1 si a treia varianta respectand standardul ANSI C++.

// P1_1. Realizati un program C++ care afiseaza mesajul „Hi man!” pe ecran.

#include <stdio.h> // linia 1

int main(){ // linia 2


printf("Hi man!"); // linia 3
} // linia 4

Limbajele C si C++ nu dispun de catre instructiuni de intrare/iesire. Pentru a


putea citi valori de la tastatura sau pentru afisa pe ecran vom folosi biblioteci care
„imbogatesc” limbajul cu diferite functii utile. In acest caz, linia 1 include
biblioteca standard stdio.h (standard input/output).

Orice program C++ contine o functie numita main, functie cu care incepe
executia programului. Linia 2 contine antetul acestei functii. Sfarsitul liniei 2
contine '{', care reprezinta inceputul unui bloc, terminat in linia 4.
Intre acolade sunt scrise instructiunile programului, in acest caz linia 3, linie pe
care apelam functia printf, functie care realizeaza afisarea mesajului dorit pe
ecran.

-3-
Introducere in ANSI C++

In varianta urmatoare vom folosi biblioteca iostream, introdusa in C++ si care


implementeaza asa numitele fluxuri de intrare/iesire.

#include <iostream.h> // linia 1

int main(){ // linia 2


cout << "Hi man!"; // linia 3
} // linia 4

Diferentele fata de primul exemplu le constatam in linia 1, unde am inclus o alta


biblioteca ce ne ofera acees la operatiile de intrare iesire, respectiv in linia 3, unde,
pentru afisare folosim o altfel de constructie.
Cei obisnuiti cu compilatoarele mai vechi, cum ar fi bcc.exe, compilatoriul care
vine cu mediul Borland C++ 3.1, vor ramane surprinsi ca sursa de mai sus nu
functioneaza (iar daca main ar fi returnat void, am fi avut doua erori!).
Varianta care respecta standardul ANSI C++ este urmatoarea:

#include <iostream> // linia 1

int main(){ // linia 2


std::cout << "Hi man!"; // linia 3
} // linia 4

Observam lipsa extensiei „.h” din linia 1, respectiv specificarea spatiului de


nume std in linia 3.

1.3 Compilarea si rularea programului

1.3.1 In mediul Borland C++ 3.1


In cazul in care avem pornit mediul, putem rula programul prin apasarea
combinatiei Ctrl+F9. Mediul va a apela automat compilatorul, apoi linkeditorul, va
genera fisierul executabil, apoi il va rula. Pentru vizualizarea efectiva a
rezultatului, apasam Alt+F5 pentru vizualizarea iesirii.

-4-
Introducere in ANSI C++

In cazul in care am editat sursa intr-un alt editor, de exemplu notepad, pentru a
rula aplicatia dorita vom realiza manual trecerea spre fisierul executabil, in felul
urmator:
pas 1. Copiem sursa in directorul c:/borlandc/bin (pas facultativ, dar in acest
mod simplificam explicatiile)
pas 2. .. > bcc p01.cpp (in cazul in care sursa a fost corecta, obtinem la acest
pas fisierul p01.obj)
pas 3. .. > tlink p01.obj (obtinem p01.exe)
pas 4. .. > p01.exe (este rulat programul)

1.3.2 Folosind compilatorul g++


Rulam comanda g++ p01.cpp, din directorul in care avem textul sursa, si
obtinem fisierul executabil a.out, care poate fi lansat in executie prin comanda
./a.out .

Daca dorim specificarea unui alt nume de fisier executibail, comanda de


compilare va contine optiunea -o. De exemplu g++ -o Hi_Man p01.cpp va genera
executabilul Hi_Man, iar rularea se va face prin ./Hi_Man .

-5-
Introducere in ANSI C++

Capitolul 2 – Notiuni de baza

2.1 Notiunea de algoritm


Numim algoritm o succesiune de pasi care rezolva o clasa de probleme. Vorbim
de clase de probleme in urmatorul sens: daca 2x+3=0, respectiv x-4=0 reprezinta
probleme, ax+b=0 va reprezenta clasa de probleme ce formeaza ecuatia de
gradul I.
Un algoritm este caracterizat prin sintagma „noi muncim, nu gandim!”, in
sensul ca executia pasilor algoritmului are loc fara nici un efort creator.
In general, in cadrul unui algoritm avem trei sectiuni distincte: date e intrare,
rezolvarea efectiva a problemei si date de iesire, conform Figurii 2.1.

Rezolvarea
Date de intrare Date de iesire
problemei

Figura 2.1 – Forma generala a unui algoritm


Pentru a evidentia pasii de urmat vom lua ca exemplu urmatoarea problema.

P1. Realizati un algoritm care calculeaza suma a doua valori.


Inainte de a incepe rezolvarea problemei trebuie sa ne fie clar care sunt datele
initiale de la care se pleca, respectiv ce anume se cere. In acest caz, datele de
intrare sunt reprezentate de catre a si b, iar data de iesire va fi S, care respecta
datele problemei (adica S=a+b).

-6-
Introducere in ANSI C++

Algortimul este:
Date de intrare (a,b)
citeste a si b

Rezolvarea problemei
S=a+b

Date de iesire (S)
afiseaza S

Intelegerea clara a enuntului unei probleme este vitala in rezolvarea acesteia.


Daca nu sunt clare care sunt datele de intrare, respectiv cele de iesire ale unui
algoritm, cel mai probabil rezolvarea nu va fi corecta, sau vom rezolva o alta
problema decat cea ceruta.

2.2 Citirea si afisarea datelor


In subcapitolul anterior am citit datele de intrare ale algoritmului, respectiv am
afisat rezultatul. In cazul descrierii algoritmului in cuvinte, acest lucru a fost
realizat prin simpla enuntare a operatiei de executat (scrie S). In cazul in care
dorim implementarea algoritmului intr-un limbaj de programare, in cazul nostru
C++, trebuiesc respectate o serie de reguli clare, deoarece compilatorul trebuie sa
”inteleaga” ceea ce dorim sa facem.
Limbajul C++ nu ofera instructiuni de intrare/iesire. In schimb avem la
dispozitie biblioteca de functii standard, prin care, putem realiza aceste operatii.
Compilatoarele C++ actuale vin cu bilbioteca standard.
Am ales, pentru simplitatea in utilizare, functii1 din cadrul bibliotecii iostream.
Pentru afisare vom folosi constructii de forma:
cout << ce_vrem_sa_afisam; sau:
cout << ceva << altceva << ... << ultima_chestie;

1 De fapt sunt obiecte, dar in acest moment ce sa zic... asteptati volumele viitorre ale lucrarii pentru
explicatii suplimentare (merge si asa ;)), sau vezi [1], [3].

-7-
Introducere in ANSI C++

P2. Afisati textul "text de test!" pe ecran.

// P2_1. Afisarea textului 'text de test!' pe ecran.

#include <iostream>
using namespace std;

int main(){
cout << "text"; //afisarea unui text
cout << " de";
cout << " te" << "st!";
}

Linia a doua din sursa va face ca folosirea specificarii spatiului de nume std 
(std::cout) sa nu fie obligatorie.
In cazul in care folositi mediul Borland C++ 3.1 inlocuiti

#include <iostream>
using namespace std;

cu

#include <iostream.h>

in rest programul ramand nechimbat.


Pentru citire vom folosi constructii de forma:
cin >> in_ce_citim; sau:
cin >> v1 >> v1 >> ... >> vn ;

Exemple de citire vom da mai tarziu, dupa introducerea notiunii de variabila.

-8-
Introducere in ANSI C++

2.3 Tipuri de date. Variabile si constante.


Algorimii lucreaza cu date. In exemplul cu suma, datele de lucru au fost a,b si S.
Datele cu care lucreaza algoritmii au ca si corespondent in C++ constantele si
variabilele. Fiecare constanta sau variabila din C++ are asociata un tip.
Tipurile fundamentale ale C++ sunt prezentate in Tabelul 2.1:

Tip Constante Observatii

void - - indica absenta informatiei

'A' - defineste un caracter


'B' - in memoria calculatorului, stocarea unui caracter se
char 'a' face folosind codul lui ASCII
'+' - poate fi folosit si pentru a memora numere intregi
'3' mici

3 - numar intreg cu semn


int 123 - intervalul acoperit de acest tip poate diferi de la un
-1020 calculator la altul

3.0 - folosit pentru memorarea numerelor reale


float 123.456 - este memorat in format cu virgula mobila (float) in
- 100.001 simpla precizie

3.0 - numere reale


double 123.456 - il folosim pentru numere foarte mari sau pentru o
- 100.001 precizie mai mare dupa virgula

10 - tip care apare in ANSI C++


bool
true false - nu este recunoscut in Borland C++ 3.1
Tabelul 2.1 – Tipurile de baza in C++

-9-
Introducere in ANSI C++

Pe langa aceste tipuri de baza, C++ ofera asa numitii modificatori de tip, folositi
pentru a scimba domeniul valorilor pe are le poate pastra o variabila, prezentati in
Tabelul 2.2:

Modificator Efect

signed - forteaza existenta semnului

unsigned - daca dorim doar memorarea a valori pozitive intr-o


variabila
- prin disparitia semnului, este dublat numarul de valori
pozitive de memorat

short - reduce intervalul de reprezentare

long - mareste intervalul de reprezentare


Tabelul 2.2 – Modificatorii de tip
Tipurile de date sunt folosite pentru a defini variabilele cu care dorim sa lucram
in program.
Pe langa constantele prezentate in Tabelul 2.1, vom folosi si constante de tip sir
de caractere, reprezentand succesiuni de caractere cuprinse intre ghilimele.
Exemplu de siruri de caractere pot fi: ”ABC”, ”Sunt un sir de caractere!”,
”1+2=3”.
Prin variabila intelegem o entitate capabila sa-si modifice valoarea. In C++,
inainte de a folosi o variabila, aceasta trebuie declarata. Forma generala a unei
declaratii este:
tip nume; sau:
tip v1, v2, ..., vn;

In momentul declaratiei, C++ permite initializarea variabilei, declaratia devenind:


tip nume=valoare;

Folosirea cuvantului cheie const inainte de declaratia unei variabile va spune


compilatorului ca valoarea acesteia nu poate fi modificata in cadrul programului.

- 10 -
Introducere in ANSI C++

const tip  nume=valoare;

Pentru exemplificare fie urmatoarea problema:

P3. Definiti cel putin 5 variabile de tipuri diferite, initializati-le si apoi afisati
valoarile pe ecran.

#include <iostream>
using namespace std;

int main(){
char c='A'; // tip caracter
int i=-123; // intreg "obisnuit"
long int l=12356789; // intreg "mare"
unsigned int u=98; // intreg pozitiv
unsigned long int U=12345678; // intreg mare fara semn
float f=3.14; // numar real
double d=-21.344; // alt numar real

cout << "Sunt caracterul: " << c << endl;


cout << "Sunt intregul: " << i << endl;
cout << "Sunt intregul mare: " << l << endl;
cout << "Sunt intregul fara semn: " << u << endl;
cout << "Sunt intregul mare fara semn: " << U << endl;
cout << "Sunt numarul real: " << f << endl;
cout << "Numar real (da' mai mare, daca vreau): "<<d<< endl;
}

In urma executiei sa va afisa pe ecran:


Sunt caracterul: A
Sunt intregul: ­123
Sunt intregul mare: 12356789
Sunt intregul fara semn: 98
Sunt intregul mare fara semn: 12345678
Sunt numarul real: 3.14
Numar real (da' mai mare, daca vreau): ­21.344

Pentru „cosmetizarea” afisarii am folosit cout << endl pentru a trece la rand


nou. In cazul in care lipseste tipul in cadrul declaratiei si punem doar
modificatorul, acesta va fi aplicat pe tipul int, deci unsigned, respectiv unsigned 
int reprezinta aceeasi declaratie.

Pentru a determina cantitatea de spatiu ocupata de catre fiecare tip de data,


introducem operatorul sizeof, operator care returneaza numarul de octeti ocupati

- 11 -
Introducere in ANSI C++

in memoria calculatorului.

P4. Verificati cat ocupa in memoria calculatorului dumneavoastra diverse tipuri


de date.

#include <iostream>
using namespace std;

int main(){
int i=123;

cout << "Un caracter ocupa "<<sizeof(char)<<" octet" << endl;


cout << "Un intreg ocupa " << sizeof(i) << " octeti" << endl;
cout <<"Tipul float ocupa "<<sizeof(float)<<" octeti"<< endl;
cout <<"Tipul double ocupa "<<sizeof(double)<<" octeti";
}

Programul va afisa:
Un caracter ocupa 1 octet
Un intreg ocupa 4 octeti
Tipul float ocupa 4 octeti
Tipul double ocupa 8 octeti

Rezultatele pot sa difere de la calculator la calculator.


In acest moment avem toate datele pentru a implementa algoritmul cerut in
problema 1 (cea de la inceputul capitolului). O posibila implementare este:

// P2_4. Se citesc doua anumere intregi. Afisati pe ecran suma lor.

#include <iostream>
using namespace std;

int main(){
int a,b,S; // declararea variabilelor

cin >>a;
cin >>b; // citirea datelor de intrare

S=a+b; // calcularea sumei

cout << S; //afisarea rezultatului


}

- 12 -
Introducere in ANSI C++

La rularea aplicatiei avem impresia ca ea s-a blocat, avand in fata doar un cursor
care clipeste. Motivul este cel ca, dupa declaratii, se executa instructiunea cin>>a; 
iar programul se opreste din executie in asteptarea unei valori introduse de la
tastatura. Acest lucru se realizeaza prin scrierea unei valori urmata de apasarea
tastei Enter. In acest moment variabila a preia valoarea introdusa, apoi se trece la
urmatoarea instructiune. Tratand analog si cea de a doua citire, obtinem in final
afisarea sumei valorilor introduse.
O posibila rulare a aplicatiei va arata de forma:
3
5
8

Observam ca varianta prezentata nu arata deloc bine, o „cosmetizare” fiind bine


venita:

P5. Calculati valoare expresiei 2*(a-b)+c, realizand o interfata prietenoasa cu


utilizatorul.

#include <iostream>
using namespace std;

int main(){
int a,b,c,E; // declararea variabilelor

cout << endl; // trecem la rand nou


cout << "a="; // scriem un mesaj ajutator
cin >>a; // citim prima variabila

cout << "b="; cin >>b; // analog pentru celelalte


cout << "c="; cin >>c; // date de intrare

E=2*(a-b)+c; // calcularea expresiei

cout << "E=2*(" << a << "-"; //afisarea rezultatului


cout << b << ")+" << c << "=" << E;
}

In acest moment, executia va afisa ceva de forma:


a=3
b=5
c=2
E=2*(3­5)+2=­2

- 13 -
Introducere in ANSI C++

2.4 Secvente escape


Secventele escape sunt succesiuni de caractere care incep cu caracterul '\',
fiecare secventa fiind interpretata ca un singur caracter special. Secventele escape
sunt folosite pentru a introduce entitati imposibil de afisat in alt mod, cum ar fi
trecerea la rand nou sau tab-ul.
Tabelul 2.3 da o serie de secvente escape uzuale.

Secventa escape Efect


\n - trecere la rand nou
- echivalent cu endl
\t - tab orizontal
\' - un caracter ' (apostrof)
\\ - un caracter \ (backslash)
\” - un caracter ” (ghilimea)
\b - backspace
\a - sunet de alerta
\nnn - nnn reprezinta un cod ASCII in baza 8
Tabelul 2.3 – Secvente escape

Secventele escape pot aparea sub forma de caractere de sine statatoare, de forma
'\n'sau '\\', sau in cadrul unor siruri de caractere, cum ar fi ” abc\n\”abc\” ”.
Urmatoarele doua surse rezolva aceeasi problema:

- 14 -
Introducere in ANSI C++

P6. Afisati un romb din caracterul '$' pe ecran.

#include <iostream>
using namespace std;

int main(){
cout << " $ " << endl;
cout << " $$$ " << endl;
cout << " $$$$$ " << endl;
cout << " $$$ " << endl;
cout << " $ " << endl;
}

   $
  $$$
 $$$$$
  $$$
   $

#include <iostream>
using namespace std;

int main(){
cout << " $ \n $$$ \n $$$$$ \n" << endl;
cout << " $$$ \n $ " << endl;
}

   $
  $$$
 $$$$$
  $$$
   $

- 15 -
Introducere in ANSI C++

2.5 Referinte (alias-uri)


C/C++ permite definirea unor alias-uri ale variabilelor. Forma generala este:
tip a;
tip &porecla=a;

Din momentul definirii unei referinte, variabila initiala va putea fi accesata atat
cu numele ei cat si cu alias-ul. Folosirea referintelor reluata in Capitolul 8, referitor
la functii.

P7. Exemplu de lucru cu referinte.

#include <iostream>
using namespace std;

int main(){
int a=123; // variabila intreaga a
int &copie_a=a; // un alt nume pentru a
int &porecla=a; // tot a

cout << "Sunt variabila a:" << a << endl;


cout << "Sunt tot variabila a:" << copie_a << endl;
cout << "Sunt a, si mi se spune:" << porecla << endl;
}

Sunt variabila a:123
Sunt tot variabila a:123
Sunt a, si mi se spune:123

- 16 -
Introducere in ANSI C++

2.6 Probleme propuse

Pp1. Afisati pe ecran un bradulet folosind caracterul '*'.


Pp2. Cititi de la tastatura trei numere intregi, apoi afisati-le in ordine inversa,
cate unul pe un rand.
Pp3. Calculati media aritmetica a doua valori intregi citite de la tastatura. Citirea
si afisarea sa fie prietenoasa cu utilizatorul.
Pp4. Calculati si afisati, in acelasi program si intr-o varianta prietenoasa cu
utilizatorul, urmatoarele expresii:
M(a,b,c) = (a+b+c)/3
F(a,b) = (a+3)/2 +b
E(a,b,c,d) = (a+b)/2 + (d­c)/3

Pp5. Folositi secvente escape pentru a afisa pe ecran:


Ma numesc ”ghilimea” si nu arat asa '.
Eu, adica \, sunt un backslash. 
Acum voi face beep de 3 ori, dupa ce am 'sarit' un tab.

- 17 -
Introducere in ANSI C++

Capitolul 3 – Expresii C++


Numim expresie valida in C++ orice succesiune corecta de variabile, constante,
operatori si apeluri de functii evaluabila la o valoare unica.

3.1 Atribuirea
Forma generala a operatiei de atribuire este:
variabila = expresie;

Modul in care limbajul realizeaza atribuirea este urmatorul:


Pas 1. Este evaluata valoarea expresiei din dreapta (daca variabila din stanga
apare in cadrul expresiei, va fi folosita valoarea curenta)
Pas 2. Valoarea calculata este atribuita variabilei din stanga

P1. Exemple de atribuiri simple

#include <iostream>
using namespace std;

int main(){
int i;
char c;
float f;
i=3; // intregul i ia valoarea 3
c='A'+2; // caracterul c ia valoarea 'C' (65)
f=2+1.14; // realul f ia valoarea 3.14
cout << "\ni=" << i;
cout << "\nc=" << c;
cout << "\nf=" << f;
}

La rulare vom avea:


i=3
c=C
f=3.14

Interesant este faptul ca in C/C++, spre deosebire de alte limbaje, atribuirea este
o expresie, deci pe locul in care folosim atribuirea apare o valoare. Valoarea

- 18 -
Introducere in ANSI C++

returnata de catre oparatia de atribuire este valoarea expresiei din dreapta. Deci,
daca avem atribuirea a=3, pe locul atribuirii apare valoarea 3. Putem folosi acest
fapt pentru a realiza atribuiri multiple, de forma urmatoare:
variabila1 = variabila2 = ... = variabilan = expresie;

P2. Alte exemple de atribuiri

#include <iostream>
using namespace std;

int main(){
int i;
int a,b;
cout << "Rezultatul atribuirii i=3 este:" << (i=3);
i=i+5; // in partea dreapta i are valoare 3, apoi devine 8
a=b=i+2;// a si b vor lua valoarea 10 (i nu se modifica)
cout << "\ni=" << i;
cout << "\na=" << a;
cout << "\nb=" << b;
}

Se va afisa:
Rezultatul atribuirii i=3 este:3
i=8
a=10
b=10

Pentru expresia a=b=i+2 avem urmatoarea ordine a operatiilor:


Pas 1. Initial avem a = expresie, unde expresie este b=i+2.
Pas 2. Se evalueaza expresie:
- variabila b ia valoarea i+2 (10 in exemplul nostru)
- expresie returneaza valoarea 10
Pas 3. variabila a ia valoarea 10

- 19 -
Introducere in ANSI C++

3.2 Conversii de tip


Este posibil ca tipul expresiei sa nu fie identic cu tipul variabilei unde memoram
rezultatul, caz in care este realizata o conversie implicita de tip si, in unele cazuri,
vom avea un avertisment la compilare. In general, conversia de tip este realizata
fara probleme daca variabila si expresia sunt ambele de tip intreg (int, char, long
etc.) sau de tip real (float, double etc.), iar variabila este reprezentata pe un numar
egal sau mai mare de octeti decat rezultatul expresiei.
In urmatoare doua exemple vom evidentia cele doua cazuri de conversie
implicita.

P3. Conversie implicita de tip, fara pierdere de informatie

#include <iostream>
using namespace std;

int main(){
int i=12345;
char c='A';
float f=97.14;
f=i;
i=c;
cout << "\ni=" << i;
cout << "\nc=" << c;
cout << "\nf=" << f;
}

i=65
c=A
f=12345

- 20 -
Introducere in ANSI C++

P4. Conversie implicita de tip, cu pierdere de informatie

#include <iostream>
using namespace std;

int main(){
int i=12345;
char c='A';
float f=97.14;
c=i;
i=f;
cout << "\ni=" << i;
cout << "\nc=" << c;
cout << "\nf=" << f;
}

La compilare, avem:
p04.cpp: In function `int main()':
p04.cpp:11: warning: converting to `int' from `float'

La rulare:
i=97
c=9
f=97.14

Observatie: c contine caracterul '9', nu valoarea intreaga 9.

C si C++ permit conversii explicite de tip, de forma:


(tip) expresie sau:
tip(expresie)

- 21 -
Introducere in ANSI C++

P5. Conversia explicita de tip

#include <iostream>
using namespace std;

int main(){
int i=12345;
float f=97.14;
cout << "\ni=" << float(i+3);
cout << "\nc=" << (char) 97;
cout << "\nf=" << int(f);
}

i=12348
c=a
f=97

O aplicatie directa a conversiei explicite de tip este:

P6. Se citeste un caracter. Afisati codul ASCII corespunzator caracterului citit

#include <iostream>
using namespace std;

int main(){
char c;
cout << "Dati caracterul:"; cin >>c;
cout << "Caracterul \'" << c;
cout << "\' are codul ASCII " << int(c);
}

Doua posibile rulari ale aplicatiei:


Dati caracterul:a
Caracterul 'a' are codul ASCII 97

Dati caracterul:9
Caracterul '9' are codul ASCII 57

- 22 -
Introducere in ANSI C++

3.3 Expresii aritmetice


Forma generala este, in functie de operator:
operator operand sau
operand1 operator operand2

Operatorii uzuali folositi in cadrul expresiilor aritmetice si care se comporta asa


cum ne asteptam sunt '+', '­', '*'.
Operatorul '/' (impartirea) reactioneaza in mod diferit in functie de tipul
operanzilor. Astfel, daca cel putin unul dintre operanzi este de tip real, rezultatul
este real. Daca ambii operanzi sunt intregi, este realizata impartirea intreaga. In
acest ultim caz are sens sa vorbim despre restul impartirii, dat de operandul '%' 
(modulo). Operatorul modulo nu poate fi aplicat tipurilor reale.
Urmatoare problema da exemple de folosire a impartirii:

P7. Expresii aritmetice. Impartirea reala si intreaga.

#include <iostream>
using namespace std;

int main(){
int i=123,a;
float f;
cout << -i <<"\n"; // operatorul unar -
a=2*i; // operatorul binar *
f=a;
cout << i << "/" << a << "=" << i/a << "\n";
// impartire intrega
cout << i << "/" << f << "=" << i/f; // impartire reala
}

 ­123
123/246=0
123/246=0.5

In cazul in care dorim ca raportul a doua expresii de tip intreg sa dea o valoare
reala vom folosi conversia explicita de tip, de forma:
float(operator_intreg1) / (operator_intreg2)

In acest context, 7/2 are valoarea 3, dar 7./2 sau float(7)/2 au valoarea 3.5.

- 23 -
Introducere in ANSI C++

Exista o serie de operatori de atribuire speciali (forma scurta a atribuirii),


operatori ce vor avea forma generala:
 variabila op= expresie

unde op poate fi orice operator aritmetic prezentat anterior.


Atribuirea este echivalenta cu:
 variabila = variabila op expresie

P8. Forma scurta a atribuirii

#include <iostream>
using namespace std;

int main(){
int i=123;
i+=2; cout << i << "\t";
i-=25; cout << i << "\t";
i*=2; cout << i << "\t";
i/=10; cout << i << "\t";
}

125     100     200     20      

Alti operatori, specifici C si C++, sunt cei de incrementare si decrementare:


variabila++
++variabila
variabila­­
variabila­­

Operatorul ++ realizeaza incrementarea variabilei pe care este aplicat, adica este


similar atribuirii variabila=variabila+1, in timp ce –­ realizeaza
decrementarea, adica variabila=variabila­1.
Diferenta intre cele doua forme (sufix sau prefix), consta in faptul ca, in cazul
sufix, valoarea variabilei este folosita neschimbata in expresia din care face parte,
apoi aceasta este incrementata, in timp ce in cazul prefix, valoarea variabilei este
incrementata, apoi este folosita in expresia din care face parte.

- 24 -
Introducere in ANSI C++

P9. Incrementarea si decrementarea

#include <iostream>
using namespace std;

int main(){
int i=123,a,b;
i++; // daca nu apare intr-o expresie este similar cu ++i;
a=++i;// incrementam i, apoi il atribuim lui a
b=i++;// atribuim lui a valoarea lui i, apoi incrementam i
cout << i << "\t" << a << "\t"<< b << "\t";
}

126     125     125     

3.4 Expresii logice


Sunt acele expresii in care rezultatul este interpretat ca adevarat sau fals.
Daca in ANSI C++ avem definit un tip specific (bool), compilatoarele mai vechi
(bcc) nu suporta acest tip. In orice caz, regula care se respecta este faptul ca
valoarea 0 inseamna fals din punct de vedere logic, iar orice valoare diferita de 0
(de obicei valoarea 1) este interpretata ca adevarat, asa cum arata si exemplul
urmator.

P10. Valoarea expresiilor logice

#include <iostream>
using namespace std;

int main(){
bool b;
b=true;
cout << "true=" << b << "\n";
b=false;
cout << "false=" << b;
}

true=1
false=0

- 25 -
Introducere in ANSI C++

Un caz particular de expresii logice il reprezinta expresiile relationale, expresii


in care sunt comparate doua valori. Operatorii relationali sunt dati in tabelul
urmator:

Operator Semnificatie Exemplu


< mai mic 3<5

> mai mare (4+1) > (2*2)

<= mai mic sau egal 2<=3

>= mai mare sau egal 3>=3

!= diferit 2!=3

== egal 3==3

Tabelul 3.1 – Operatorii relationali


Observam ca testarea egalitatii a doua expresii nu se face folosind '=', operator
reprezentand atribuirea.

Diferite expresii logice pot fi reunite folosind operatorii logici din Tabelul 3.2.

Operator Semnificatie Exemplu


&& si logic (x>=2)&&(x<=5), adica x∈[2,5]
|| sau logic (x<2)||(x>5), adica x∉[2,5]
! negatie logica !(x>=2), adica x<2
Tabelul 3.2 – Operatorii logici

- 26 -
Introducere in ANSI C++

P11. Se citesc trei valori intregi de la tastatura. Verificati unde se gaseste prima
valoare citita in raport cu intervalul determinat de ultimele doua valori.

#include <iostream>
using namespace std;

int main(){
int i,a,b;
cout << "Dati valoarea:"; cin >>i;
cout << "Dati intervalul [a,b]\na="; cin >> a;
cout << "b="; cin >> b;
cout << "apartine intervalului:" << (i>=a)&&(i<=b));
cout << "\nnu apartine intervalului:" << (i<a)||(i>b);
}

Dati intervalul [a,b]
a=2
b=5
apartine intervalului:1
nu apartine intervalului:0

Observam ca valoarea de adevar a afirmatiilor este data sub forma 0-fals si 1-


adevarat.

3.5 Operatorul conditional


Are forma generala:
expresie1?expresie2:expresie3

Daca expresie1 este evaluata la adevarat, expresia returneaza expresie2, altfel


returneaza expresie3.
In unele cazuri particulare poate fi un inlocuitor pentru instructiunea if.

- 27 -
Introducere in ANSI C++

P12. Calculati expresia E(x)=1/x daca e posibil, afisand valoarea 0 in caz


contrar.
#include <iostream>
using namespace std;

int main(){
int x;
float E;
cout << "x="; cin >>x;
E = (x!=0) ? 1./x : 0;
cout << "1/" << x << " = " << E;
}

x=2
1/2 = 0.5

P13. Calculati expresia max(a,b), unde a si b sunt valori reale citite de la


tastatura.

#include <iostream>
using namespace std;

int main(){
float a,b,max;
cout << "a="; cin >>a;
cout << "b="; cin >>b;
max = (a>b) ? a : b;
cout << "max(" << a << "," << b << ")=" << max;
}

a=5
b=2
max(5,2)=5

P14. Se citesc doua valori intregi de la tastatura. Interschimbati cele doua


valori, apoi afisati rezultatul pe ecran.

- 28 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

int main(){
int a,b,t;
cout << "a="; cin >>a;
cout << "b="; cin >>b;
t=a; a=b; b=t;
cout << "-- dupa interschimbare --\n";
cout << "a=" << a << "\t" << "b=" << b ;
}

a=2
b=5
­­ dupa interschimbare ­­
a=5     b=2

Ordinea de efectuare a operatiilor in cazul unei expresii complexe este data de


prioritatea operatorilor, respectiv de folosirea parantezelor. Tabele cu prioritatea
operatorilor gasiti in [1],[5] etc. De cate ori nu stiti exact ordinea in care se vor
executa diferite operatii intr-o expresie, folositi parantezele.

P15. Necesitatea folosirii parantezelor. Acest program NU va verifica


apartenenta valorii a intervalului [1,5], desi in unele cazuri pare sa functioneze !!!

#include <iostream>
using namespace std;

int main(){
int a,rez;
cout << "a="; cin >> a;
rez=(2<=a<=5);
// rez=((2<=a)&&(a<=5));
cout << a << " apartine intervalului [1,5]:" << rez ;
}

a=8
8 apartine intervalului [2,5]:1

- 29 -
Introducere in ANSI C++

Observam ca la conditia care pare "8 apartine lui [2,5]" rezultatul este adevarat
(1). Motivul este urmatorul:
Expresia 2<=a<=5 este evaluata de la stanga la dreapta, deci primul lucru
evaluat este 2<=a, adevarat pentru a=8, adica 1 in context C/C++. Urmeaza apoi
comparatia 1<=5, deci rezultatul final este adevarat. Rezolvarea corecta este cea
data in comentariu.

3.6 Operatorul virgula


Are forma generala:
expresie1 , expresie2,... , expresien 

Expresiile sunt evaluate de la deapta la stanga, valoarea returnata la final fiind


valoarea si tipul dat de expresien.

P16. Simulati operatorii de preincrementare si postincrementare folosind


operatorul virgula (b=a++ si b=++a).

#include <iostream>
using namespace std;

int main(){
int a,b,t;
cout << "a="; cin >> a;
b=(t=a,a+=1,t); // b=a++
cout << a << " " << b << "\n";
b=(a+=1,a); // b=++a
cout << a << " " << b << "\n";
}

a=3
4 3
5 5

- 30 -
Introducere in ANSI C++

3.7 Operatori care actioneaza la nivel de bit


Tabelul 3.3 da operatorii pe biti acceptati in C/C++:

Operator Semnificatie Exemplu

x&1 – reseteaza toti bitii, in afara


& si pe biti
celui mai putin semnificativ

x|1– seteaza bitul cel mai putin


| sau pe biti
semnificativ

x^0 – complementeaza toti bitii


^ sau exclusiv
x^x – valoare nula pentru orice x
~ negatie pe biti ~x – complementeaza toti bitii
>> deplasare la dreapta x<<2 – similar cu x*=2
<< deplasare la stanga x>>3 – similar cu x/=3
Tabelul 3.3 – Operatori logici pe biti
Exemplele din tabel sunt date pentru x de tip intreg.

- 31 -
Introducere in ANSI C++

3.8 Probleme propuse


Pp1. Se citeste un numar real x, strict pozitiv, de la tastatura. Calculati si afisati
rezultatul expresiei (x-1)/x2 .

Pp2. Se citeste un numar real de la tastatura. Folosind conversii de tip, afisati


partea fractionara a numarului.
Pp3. Se citesc doua numere a si b de la tastatura, valori intregi strict pozitive.
Afisati rezultatul expresiei E(a,b)=(a-b)/(a+b).
Pp4. Folosind operatorul conditional, determinati minimul a doua valori intregi
citite de la tastatura.
Pp5. Se citeste un numar real x de la tastatura. Folosind operatorul conditional,
calculati si afisati rezultatul expresiei E(a)=max(min(a,7),|a-7|).
Pp6. Se citesc trei numere intregi de la tastatura. Afisati valoarea "din mijloc",
adica valoarea care nu este nici minimul, nici maximul celor trei valori date.
Pp7. Se citesc trei numere intregi de la tastatura. Afisati pe ecran suma celor mai
mici doua valori.

- 32 -
Introducere in ANSI C++

Capitolul 4 – Instructiuni conditionale


Daca dorim executia unor instructiuni doar daca o conditie este adevarata sau
daca dorim ramificarea executiei programului, folosim instructiuni conditionale.

4.1 Instructiunea if
Exista doua forme ale instructiunii if:
if (expresie) instructiune

In acest caz, daca expresie este evaluata la adevarat (o valoare nenula), atunci
se executa instructiunea care urmeaza.
if (expresie) instructiune1
else instructiune2

Daca expresie este evaluata la adevarat se executa instructiune1, altfel se


executa instructiune2.
De obicei expresia dintre paranteze este o expresie logica, dar, datorita
conventiilor C referitoare la notiunile de adevarat si fals, expresia poate fi de orice
tip, inclusiv expresii aritmetice sau atribuiri. In urmatoarele exemple vom arata
diverse moduri de a realiza comparatii in C.

P1. Se citeste un numar intreg de la tastaura. Verificati daca acesta este nul,
pozitiv sau negativ.

#include <iostream>
using namespace std;

int main(){
int a;
cout << "a="; cin >> a;
if (a==0) cout << a << " este nul.";
if (a<0) cout << a << " este negativ.";
if (a>0) cout << a << " este pozitiv.";
}

a=123
123 este pozitiv.

- 33 -
Introducere in ANSI C++

sau:
a=0
0 este nul.

P2. Se citeste un numar intreg de la tastaura. Verificati daca acesta este nul sau
nu.

#include <iostream>
using namespace std;

int main(){
int a;
cout << "a="; cin >> a;
if (a) cout << a << " este nenul.";
else cout << a << " este nul.";
}

a=123
123 este nenul.

Sa vedem putin ce se intampla in acest caz. Conditia "ciudata" din if, va fi


evaluata in felul urmator:
- daca a este diferit de zero, atunci, conform conventiilor C, reprezinta true, deci
se va executa prima ramura a if-ului
- daca a este nul, adica corespunde valorii false, se executa cea de a doua ramura.
In general, verificarea unei expresii daca este adevarata sau falsa, se realizeaza
prin simpla scriere a expresiei intre parantezele if-ului, de forma:
if (expresie)

Nu este nevoie sa scriem varianta echivalenta:


if (expresie != 0) sau
if (expresie != false)

- 34 -
Introducere in ANSI C++

P3. Se citesc de la tastaura doua numere intregi si un caracter reprezentand


operatiile matematice '+', '-'. Afisati valoarea corespunzatoare aplicarii operatiei
date asupra intregilor cititi.

#include <iostream>
using namespace std;

int main(){
int a,b;
char op;
cout << "a="; cin >> a;
cout << "b="; cin >> b;
cout << "operatia:"; cin >> op;
if (op=='+') cout << a << '+' << b << '=' << a+b;
else if (op=='-') cout << a << '-' << b << '=' << a-b;
else cout << "Operatiei neimplementata!";
}

a=2
b=3
operatia:+
2+3=5

In problema 3, observam ca instructiunea de pe ramura fals a primului if este o


alta instructiune if. Vom denumi acest caz ca imbricarea instructiunii if si vom
folosi alinierea else cu if-ul corespunzator pentru a imbunatatii lizibilitatea
programului.
Daca dorim executia a mai multe instructiuni pe o ramura a instructiunii if, vom
grupa aceste instructiuni intr-un bloc (instructiune compusa). Vom numi bloc zona
cuprinsa intre acolade ({...}). In cazul scrierii instructiunilor intr-un bloc, acestea
vor fi tratate in mod unitar, ca o singura instructiune. In legatura cu sugestii privind
indentarea codului studiati Anexa 3.

- 35 -
Introducere in ANSI C++

P4. Se citesc de la tastaura trei numere intregi. Calculati maximul si minimul


valorilor.

#include <iostream>
using namespace std;

int main(){
int a,b,c;
int max,min;
cout << "a="; cin >> a;
cout << "b="; cin >> b;
cout << "c="; cin >> c;
// calculam minimul si maximul primelor doua valori
if (a>b){
min=b;
max=a;
}
else{
min=a;
max=b;
}
// "ajustam" minimul si maximul in functie de a treia valoare
if (c>max) max=c;
if (c<min) min=c;

cout << "min("<<a<<","<<b<<","<<c<<")="<<min;


cout << "\nmax("<<a<<","<<b<<","<<c<<")="<<max;
}

a=2
b=3
c=1
min(2,3,1)=1
max(2,3,1)=3

Datorita faptului ca putem avea mai multe nivele de imbricare a instructiunilor


if, unele avand else si altele nu, trebuie acordata o atentie deosebita
corespondentei if­else dorite. Fiecare else va fi in corespondenta cu primul if 
care se gaseste inaintea lui in textul sursa cu proprietatea ca nu ii corespunde nici
un else si nu este inclus in instructiunea if care il precede.
Mai mult, o aliniere corecta nu va tine locul de bloc.

- 36 -
Introducere in ANSI C++

P5. Exemple de erori de compilare la surse care par corecte.

#include <iostream>
using namespace std;

int main(){
int a;
cout << "a="; cin >> a;
if (a<3)
cout << "E mai mic ca trei\n"; //[1]
cout << "Pacat doar ca nu va merge niciodata..."; //[2]
else
cout << "E mai mare ca trei";
}

p05.cpp: In function `int main()':
p05.cpp:12: error: syntax error before `else'

Desi, datorita imbricarii, pare ca pe ramura true vor fi executate cele doua
instructiuni, compilatorul va interpreta if-ul ca fiind fara else (pe ramura true se
executa o singura instructiune), deci nu va gasi corespondet pentru else. Linia [2]
din cod ar trebui aliniata cu instruciunea if, afisarea fiind executata in afara
acestuia.

P6. Varianta corecta a problemei 5.

#include <iostream>
using namespace std;

int main(){
int a;
cout << "a="; cin >> a;
if (a<3){
cout << "E mai mic ca trei\n"; //[1]
cout << "Nu mai da eroare ;) "; //[2]
}
else
cout << "E mai mare ca trei";
}

a=2
E mai mic ca trei
Nu mai da eroare ;)

Acum liniile [1] si [2] sunt grupate intr-un bloc, deci pe ramura true se executa
o singura instructiune, iar else isi gaseste corespondent.

- 37 -
Introducere in ANSI C++

In multe probleme, folosirea expresiilor logice compuse reprezinta o alegere


evidenta.

P7. Determinati daca patru numere intregi citite de la tastatura sunt in ordine
crescatoare sau nu.

#include <iostream>
using namespace std;

int main(){
int a,b,c,d;
cout << "Introduceti patru numere intregi:\n";
cin >> a >> b >> c >> d;
if ((a<=b) && (b<=c) && (c<=d))
cout << "Numerele citite sunt in ordine crescatoare";
else
cout << "Numerele citite nu sunt in ordine crescatoare";
}

Introduceti patru numere intregi:
2 4 5 8
Numerele citite sunt in ordine crescatoare

Putem folosi o variabila booleana pentru a memora rezultatul unor exepresii


logice complexe, apoi sa folosim acea variabila ca o conditie in cadrul instructiunii
if. Acelasi efect il putem obtine folosind o variabila de tip intreg in locul celei
booleene.

P8. Determinati daca patru numere intregi formeaza o progresie aritmetica.


Daca da, afisati ratia.

- 38 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

int main(){
int a,b,c,d;
bool progresie;
cout << "Introduceti patru numere intregi:\n";
cin >> a >> b >> c >> d;

progresie = (2*b==a+c); // verificam daca primele trei


formeaza o progresie
progresie = progresie && (2*c==b+d); // acum
urmatoarele...

if (progresie){
cout << "Numerele citite sunt in progresie\n";
cout << "aritmetica, cu ratia: " << b-a;
}
else
cout << "Nu avem o progresie aritmetica";
}

Introduceti patru numere intregi:
2 4 6 8
Numerele citite sunt in progresie
aritmetica, cu ratia: 2

Un caz uzual in care apare folosirea conditiei multiple este verificarea


apartenentei unui numar unui interval dat.

P9. Calculati urmatoarea functie:

x pentru x∈[10,20 ]
f  x =−x pentru x ∈−20,0
0   inrest

- 39 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

int main(){
int x,F;
cout << "x="; cin >> x;

if ((x>=10)&&(x<=20)) F=x;
else if ((x>-20)&&(x<0)) F=-x;
else F=0;

cout << "f(" << x << ")=" << F;


}

x=3
f(3)=0

Nu este recomandata verificarea egalitatii intre doua numere reale. Datorita


erorilor de calcul, este posibil ca rezultatele calculelor sa nu fie exacte. In acest caz
se recomanda folosirea unor conditii de forma abs(a­b) < eps, unde eps este o
valoare mica.

4.2 Instructiunea switch


In unele aplicatii dorim sa comparam valoarea unei variabile sau a unei expresii
cu mai multe valori sau expresii constante. In acest caz solutia oferita de catre
instructiunile if imbricate poate fi greoaie, instructiunea switch fiind mai eleganta.
Forma generala a instructiunii switch este:
switch (expresie){
case constanta1:  instructiuni;
case constanta2:  instructiuni;
. . . 
case constantan:  instructiuni;
default: instructiune;
}

Optiunea default este optionala.


Executia instructiunii are loc in urmatorul mod:

- 40 -
Introducere in ANSI C++

- se evalueaza expresie, apoi se compara, pe rand cu fiecare constanta


- daca este realizata egalitatea, se executa setul de instructiuni ce urmeaza
- daca dupa executarea unei secvente dorim iesirea din switch, se foloseste
instructiunea break
Cum de obicei se intampla acest lucru, forma generala devine:
switch (expresie){

case constanta1:  instructiuni; break;
case constanta2:  instructiuni; break;
. . . 
case constantan:  instructiuni;
default: instructiune;

P10. Se citesc de la tastatura doua numere intregi si un caracter. Daca acest


caracter este ‘+’, ‘-’, ‘*’ sau ‘/’, realizati operatia respectiva intre intregiii de
intrare, apoi afisati rezultatul pe ecran.

#include <iostream>
#include <math.h>
using namespace std;

int main(){
int a,b;
float R;
char op;
cout << "a="; cin >>a;
cout << "b="; cin >>b;
cout << "operator:"; cin >>op;

switch (op){
case '+': R=a+b; break;
case '-': R=a-b; break;
case '*': R=a*b; break;
case '/': if (b!=0) { R=float(a)/b; break;}
else {cout << "Impartire la zero!"; return(1);}
default:cout << "Operator necunoscut!"; return(1);
}
cout << a << op << b << "=" << R;
}

- 41 -
Introducere in ANSI C++

a=2
b=4
operator:/
2/4=0.5

P11. Se citeste de la tastatura ziua din saptamana corespunzatoare date de 1 ale


unei luni (1 – pentru luni, 2 – pentru marti, etc). Afisati ce zi din saptamana va
avea o alta data a lunii respective.

#include <iostream>
using namespace std;

int main(){
int prima_zi, zi;

cout << "Ziua corespunzatoare datei de 1 a lunii:"; cin


>>prima_zi;
cout << "Data de verificat:"; cin >> zi;

zi=(zi+prima_zi-1)%7;

cout << "Data corespunde unei zi de ";


switch(zi){
case 0: cout <<"luni"; break;
case 1: cout <<"marti"; break;
case 2: cout <<"miercuri"; break;
case 3: cout <<"joi"; break;
case 4: cout <<"vineri"; break;
case 5: cout <<"SAMBATA"; break;
case 6: cout <<"DUMINICA"; break;
}

Ziua corespunzatoare datei de 1 a lunii:0
Data de verificat:14
Data corespunde unei zi de DUMINICA

- 42 -
Introducere in ANSI C++

4.3 Probleme propuse


Pp1. Dati un exemplu de problema in care expresia conditionala nu poate tine
locul instructiunii if.
Pp2. Calculati:

f  x , y = xy pentru x0


x∗y pentru x≥0
Pp3. Se citesc patru numere intregi de la tastatura. Afisati valorile distincte
citite.
Pp4. Sa se determine ultimele doua cifre ale produsului a*b, a si b citite de la
tastatura.
Pp5. Se citeste x intreg. Sa se calculeze ultima cifra a lui 2x.
Pp6. Rezolvati ecuatia de gradul 1.
Pp7. Se citesc 3 numere intregi de la tastatura. Daca toate nuemerele citite sunt
pozitive, afisati-le in ordine crescatoare. Daca nu, afisati mesajul "We have a
problem!".
Pp8. Folosind instructiunea switch, afisati numele unei luni cu numarul de
ordine citit de la tastatura.

- 43 -
Introducere in ANSI C++

Capitolul 5 – Instructiuni repetitive


Daca dorim executia unor instructiuni de mai multe ori, in functie de o conditie,
folosim instructiunile repetitive. Acestea sunt while, do­while si for.

5.1 Instructiunea while


Forma generala a instruciunii while:
while (expresie) instructiune;

Expresia poate fi de orice tip, inclusiv expresii aritmetice sau atribuiri, dar, ca si
la instruciunea if, sunt de preferat expresii logice. Daca se doreste executarea unui
grup de instructiuni se va folosi un bloc care sa formeze corpul instructiunii while.
Executia instructiunii:
- se evalueaza expresie
- daca rezultatul este true (diferit de 0), se executa instructiune, apoi se
revine la primul pas
- daca rezultatul este false (0), se continua executia cu instructiunea
urmatoare
Poate cea mai simpla problema care se poate rezolva folosind structuri
repetitive este afisarea valorilor intregi din [1,10]. In acest caz, o rezolvare de
forma:
... cout << 1 << 2 << 3 << ...

poate fi utilizata doar daca intervalul dat este mic si definit de catre constante.
La afisarea valorilor dintr-un interval [a,b], a,b variabile intregi citite de la
tastatura aceasta metoda nu poate fi folosita.

- 44 -
Introducere in ANSI C++

P1. Afisati numerele de la 1 la 10 pe ecran.

#include <iostream>
using namespace std;

int main(){
int i;

i=1;
while (i<=10){
cout << i<< " ";
i++;
}
}

 citesc1 2 3 4 5 6 7 8 9 10 

P2. Afisati urmatoarele serii de numere pe ecran (a,b,n sunt intregi citite de la
tastatura, a<b)

• 1 2 4 8 ... - valori mai mici sau egale citesc cu n

• a, a+1, ..., b

• n valori echidistante din intervalul [a,b]

• 1 0 1 0 1 ... - n valori

- 45 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

int main(){
int i,a,b,n;
float pas,k;

cout << "n="; cin >>n;


cout << "a="; cin >>a;
cout << "b="; cin >>b;

i=1;
while (i<=n){
cout << i<< " ";
i=2*i;
}

cout << endl;


i=a;
while (i<=b){
cout << i << " ";
i++;
}

cout << endl;


pas=float(b-a)/n;
k=a;
while (k<=b){
cout << k << " ";
k=k+pas;
}

cout << endl;


i=1;
while (i<=n){
cout << i%2 << " ";
i++;
}

n=10
a=2
b=7
1 2 4 8
2 3 4 5 6 7
2 2.5 3 3.5 4 4.5 5 5.5 6 6.5 7
1 0 1 0 1 0 1 0 1 0 

- 46 -
Introducere in ANSI C++

In unele cazuri corpul instructiunii while poate sa fie vid. In acest caz
vomverondela folosi intructiunea vida ; .

P3. Se citeste un numar intreg de la tastatura. Afisati cel mai mare numar
multiplu de 10 mai mic ca numarul citit. (while fara corp)

#include <iostream>
using namespace std;

int main(){
int n;
cout << "n="; cin >>n;
while ((n--)%10!=0); // while cu corp vid
cout << n+1;
}

n=123
120

5.2 Instructiunea do-while


Forma generala a instruciunii do ­ while:
do 
instructiune;

while (expresie); 

Observatiile de la instructiunea while raman valabile si pentru aceasta


instructiune. Diferenta dintre while si do-while este aceea ca, in cazul instructiunii
do- while instructiunea se executa cel putin o data, chiar si in cazul in care expresie
este falsa la prima iteratie.
Modul de executie al instructiunii:
- se executa instructiune
- se evalueaza expresie
- daca rezultatul este true (diferit de 0) se revine la primul pas
- daca rezultatul este false (0) se incheie instructiunea si se continua
programul

- 47 -
Introducere in ANSI C++

Urmatoarele secvente de instructiuni sunt echivalente:


  if (expresie)
      do    while (expresie) 
    instructiune; instructiune;
    while (expresie); 

Figura 5.1

P4. Se citesc de la tastatura doua caractere. Afisati pe ecran caracterele si


codurilor lor ASCII din intervalul dat de catre caracterele citite.

#include <iostream>
using namespace std;

int main(){
char c1,c2,t,c;
cin >> c1 >> c2;
if (c1>c2){t=c1; c1=c2; c2=t;}

c=c1;
do{
cout << c << " - " << int(c) << endl;
c++;
}while(c<=c2);
}

 A C
A ­ 65
B ­ 66
C ­ 67

P5. Se citeste de la tastatura un numar real cu 3 zecimale. "Mutati" virgula pe


toate pozitiile interioare posibile in cadrul numarului initial. Afisati pe ecran
rezultatul, cate un numar pe un rand.

- 48 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

int main(){
float n;
cout << "n="; cin >> n;

n=n*100;
do{
cout << n << endl;;
n=n/10;
} while(n>1);

n=12.789
1278.9
127.89
12.789
1.2789

5.3 Instructiunea for


In general instructiunile while si do-while poarta numele de cicluri cu numar
necunoscut de pasi. Instructiunea for este instructiunea ce implementeaza in C
ciclul cu numar cunoscut de pasi (desi vom vedea ca nu este limitata la acest tip de
cicluri).
Forma generala a instruciunii for:
for(expr1; expr2; expr3) instructiune;

sau, de obicei:
for(init; cond_de_oprire ; reinit) instructiune;

Modul de executie al instructiunii:


- se executa init
- cat timp expresie este adevarata

- 49 -
Introducere in ANSI C++

- se executa instructiune
- se executa reinit
Instructiunea for este folosita, in principal, pentru parcurgerea seriilor de
numere.

P6. Afisati urmatoarele serii de numere pe ecran (a,b,n sunt intregi citite de la
tastatura, a<b):

– 1,2,3,...,10

– n, n-1, ..., 2, 1, 0, -1, -2, ..., -n

– valorile intregi din intervalul [a,b], in ordine crescatoare

– puterile lui 2 mai mici decat n

– primele n puteri ale lui 2

#include <iostream>
using namespace std;

int main(){
int n,a,b,i,p;
cin >> n >> a >> b;

for(i=1;i<=10;i++) cout << i << " ";


cout << endl;

for(i=n;i>=-n;i--) cout << i << " ";


cout << endl;

for(i=a;i<=b;i++) cout << i << " ";


cout << endl;

for(i=1;i<=n;i=2*i) cout << i << " ";


cout << endl;

p=1;
for(i=1;i<=n;i++){
cout << p << " ";
p=2*p;
}
}

5 3 8
1 2 3 4 5 6 7 8 9 10

- 50 -
Introducere in ANSI C++

5 4 3 2 1 0 ­1 ­2 ­3 ­4 ­5
3 4 5 6 7 8
1 2 4
1 2 4 8 16 

P7. Afisati, folosind trei metode diferite urmatoarea serie de numere pe ecran:

1 0 1 0 1 0 ..., in total n valori

#include <iostream>
using namespace std;

int main(){
int n,i,b;
cout << "n="; cin >> n;

for(i=1;i<=n/2;i++) cout << 1 << " " << 0 << " ";
if (n%2==1) cout << 1;
cout << endl;

for(i=1;i<=n;i++) cout << i%2 << " ";


cout << endl;

b=1;
for(i=1;i<=n;i++){
cout << b << " ";
b=!b;
}

n=7
1 0 1 0 1 0 1
1 0 1 0 1 0 1
1 0 1 0 1 0 1 

Cum partea de reinitializare din cadrul buclei for contine orice expresie, nu
numai incrementare/decrementare, instructiunea for devine echivalenta ca
functionalitate cu bucla while.
In figura 5.2 este data echivalenta dintre instructiunile for si while:

- 51 -
Introducere in ANSI C++

  expr1;
  while (expr2){   for(expr1;expr2;expr3)
instructiune;
      instructiune;
      expr3;
  }

Figura 5.2
Folosirea expresiei virgula reprezinta o varianta prin care putem controla mai
multe variabile in cadrul aceleiasi bucle for.

P8. Afisati urmatoarele serii de numere pe ecran:

• 1 9 2 8 3 7 ... 9 1

• 1 2 4 8 ... , in total n valori

#include <iostream>
using namespace std;

int main(){
int n,i,j,p;
cout << "n="; cin >> n;

for(i=1,j=9; i<10 ;i++,j--)


cout << i << " " << j << " ";
cout << endl;

for(i=1,p=1; i<=n; i++,p*=2) cout << p << " ";


}

n=5
1 9 2 8 3 7 4 6 5 5 6 4 7 3 8 2 9 1
1 2 4 8 16 

Putem folosi, in cadrul instructiunii for, mai multi contori, eventual de tipuri
diferite. In plus, toate partile din for sunt optionale, urmatoarea bucla fiind bucla
infinita:
for(;;);

P10. Afisati tabela cu codurile ASCII, cate 10 pe un rand.

- 52 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

int main(){
unsigned char c;

for(c=0;c<255;c++){
cout << c << "-" << int(c) << "\t";
if (c%10==9) cout << endl;
}
}

.............
<­60    =­61    >­62    ?­63    @­64    A­65    B­66    C­67    D­68    E­69
F­70    G­71    H­72    I­73    J­74    K­75    L­76    M­77    N­78    O­79
................

5.4 break si continue


In cazul care se doreste iesirea din bucla curenta imediat, eventual in functie de
o alta conditie decat cea din bucla, folosim instructiunea break. De obicei vom
folosi instructiunea break pentru a nu complica conditia din bucla.
Sintaxa:
break;

Instructiunea break va cauza iesirea doar din cadrul buclei curente, in cazul in
care avem mai multe bucle imbricate, iesirea facandu-se in bucla imediat
superioara.
Tot pentru controlul fluxului de executie putem folosi instructiunea continue.
Sintaxa:
continue;

Analog instructiunii break, fluxul executiei din cadrul buclei curente este
intrerupt, dar executie revine la conditia de oprire din bucla.

- 53 -
Introducere in ANSI C++

P11. Afisati pe ecran numerele prime mai mici decat n.

#include <iostream>
using namespace std;

int main(){
int n,d,i;
bool prim;
cout << "n="; cin >>n;

for(i=1;i<=n;i++){
prim=true;
for(d=2;d<=i/2;d++)
if (i%d==0){prim=false; break;}
if (prim) cout << i << " ";
}
}

n=20
1 2 3 5 7 11 13 17 19 

P12. Afisati pe ecran urmatoarele numere, cu doua zecimale exacte:

• 1/10, 1/9, 1/8, ... 1/1, 1/-1, 1/-2, ... 1/-10

#include <iostream>
using namespace std;

int main(){
int i;

for(i=10;i>=-10;i--){
if (i==0) continue;
cout.precision(2); cout << 1./i << " ";
}
}

0.1 0.11 0.12 0.14 0.17 0.2 0.25 0.33 0.5 1 ­1 ­0.5 ­0.33 ­0.25 ­0.2 
­0.17 ­0.14 ­0.12 ­0.11 ­0.1 

- 54 -
Introducere in ANSI C++

5.5 instructiunea goto


Trecerea fluxului de executie la o pozitie oarecare, identificata printr-o eticheta
se poate realiza prin instructiunea goto.
Definirea etichetei se face in felul urmator:
eticheta:

iar utilizarea instructiunii goto:


goto eticheta;

Chiar daca este o instructiune pusa la dispozitie in cadrul limbajului C, folosirea


acesteia nu este recomandata, folosirea instructiunilor if, if­else si while 
putand realiza acelasi lucru, iar depanarea este mai facila.

#include <iostream>
using namespace std;

int main(){
int i,a,b;
cin >> a >> b;

i=a;
salt:
cout << i << " ";
i++;
if (i<=b) goto salt; // se revine la eticheta salt
}

P13. Folosind instructiunea goto, afisati pe ecran numerele intregi din intervalul
[a,b].
3 6
3 4 5 6 

- 55 -
Introducere in ANSI C++

5.6 Probleme tip


In acest subcapitol vom prezenta o serie de algoritmi ce vor fi rezolvati folosind
instruciuni repetitive. Vom prezenta o serie de "scheme generale" de rezolvari de
algoritmi. Aceste scheme sunt reguli de forma: "daca o problema suna asa,
rezolvarea este, de obicei, cam asa".

5.6.1 Probleme pe cifrele unui numar


Acest gen de probleme prelucreaza numerele intregi la nivel ce cifre
componente. Accesul la cifrele unui numar este dat de Figura 5.3

n
1234 10
1230 123
4
n%10 n/10
Figura 5.3
De aici obtinem urmatoarele:

c= n% 10 – calculul ultimei cifre
n=n/10 – eliminarea ultimei cifre

Si mai departe, parcurgerea unui numar intreg pozitiv, cifra cu cifra:

while (n>0){ // cat timp mai avem cifre
c= n% 10; 
foloseste(c);
n=n/10;
}

unde foloseste(c) este o secventa de instructiuni dependenta de enuntul


problemei.

- 56 -
Introducere in ANSI C++

O alta varianta este cea folosind instructiunea for:

for(;n>0;n=n/10) foloseste(n%10);

P14. Afisati cifrele unui numar, cate o cifra pe un rand.

#include <iostream>
using namespace std;

int main(){
int n,c;
cout << "n="; cin >> n;

while(n>0){
c=n%10;
cout << c << endl;;
n=n/10;
}

// for(;n;n/=10) cout << n%10 << endl;


}

n=1942
2
4
9
1

Ultima instructiune for (cea comentata) rezolva acceasi problema intr-o


varianta compacta.

- 57 -
Introducere in ANSI C++

5.6.2 Probleme de divizibilitate


Un numar n este divizibil cu numar d daca restul impartirii lui n la d este zero,
deci:

n%d==0  ­ verificarea daca d|n

Plecand de la aceasta conditie, parcurgerea divizorilor unui numar intreg pozitiv


n:

for(d=1;d<=n;d++) // dintre toti divizorii posibili
if (n%d==0) foloseste(d); // selectam divizorii

P15. Afisati divizorii unui numar intreg pozitiv citit de la tastatura.

#include <iostream>
using namespace std;

int main(){
int n,d;
cout << "n="; cin >> n;

for(d=1;d<=n;d++)
if (n%d==0) cout << d << " ";
}

n=120
1 2 3 4 5 6 8 10 12 15 20 24 30 40 60 120

P16. Se citeste de la tastatura un numar intreg pozitiv.

• Verificati daca este prim

• descompuneti-l in factori primi

- 58 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

int main(){
int n,d;
bool prim;
cout << "n="; cin >> n;

prim=true;
for(d=2;d<=n/2;d++)
if (n%d==0){
prim=false;
break;
}

if (prim) cout << n << " este prim\n";


else cout << n << " nu este prim\n";

d=2;
while(n>1)
if (n%d==0){
cout << d << " ";
n=n/d;
}
else d++;
}

n=120
120 nu este prim
2 2 2 3 5

P17. Se citesc doua numere intregi pozitive de la tastatura. Calculati


cmmdc(a,b) si cmmmc(a,b).

- 59 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

int main(){
int a,b,cmmdc,cmmmc,r,aa,bb;
cin >> a >> b;

aa=a; bb=b;
while(bb!=0){
r=aa%bb;
aa=bb;
bb=r;
}

cmmdc=aa;
cmmmc=(a*b)/cmmdc;

cout << "cmmdc(" <<a <<"," << b <<")=" << cmmdc << endl;
cout << "cmmmc(" <<a <<"," << b <<")=" << cmmmc;
}

24 36
cmmdc(24,36)=12
cmmmc(24,36)=72

5.6.3 Sume, produse, numarari


Avem urmatoarele scheme generale:
Suma:

S=0
Pentru toate valorile X de insumat
S=S+X

Produsul:

P=1
Pentru toate valorile X de inmultit
P=P*X

- 60 -
Introducere in ANSI C++

Numarari (contorizari):

ct=0
Pentru toate valorile X de parcurs
if (conditie(X)) ct++

P18. Se citesc doua numere intregi a si b (a<b). Calculati:

• Suma numerelor pare din interval

• a!

• S=1/a+1/(a+1)+ ... 1/b (in cazul impartirii la 0 termenul nu apare)

#include <iostream>
using namespace std;

int main(){
int a,b,Sm,fact,i;
float S;
cin >> a >> b;

for(Sm=0,i=a; i<=b ;i++) Sm+=i;

for(fact=1,i=1; i<=a; i++) fact*=i;

for(S=0,i=a; i<=b; i++) S+=1./i;

cout << Sm << " " << fact << " " << S;
}

4 11
60 24 1.18654

P19. Se citeste un numar intreg pozitiv de la tastatura. Calculati:

• Suma cifrelor numarului

• Produsul cifrelor pare

• Prima cifra a numarului

- 61 -
Introducere in ANSI C++

• De cate ori apare prima cifra in numar

#include <iostream>
using namespace std;

int main(){
int n,nn,S,P,pc,ct,c;
cin >> n;
nn=n;

for(S=0,P=1; n ;n/=10){
c=n%10;
S+=c;
if (c%2==0) P*=c;
}

for(n=nn;n>=10;n/=10);
pc=n;

for(n=nn,ct=0; n ;n/=10)
if (n%10 == pc) ct++;

cout << S << " " << P << " " << pc << " " << ct;

12141
9 8 1 3

P20. Se citeste un numar intreg pozitiv n de la tastatura. Calculati:

• Suma divizorilor numarului

• Cate numere prime mai mici ca n exista

- 62 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

int main(){
int n,d,S,ct,i;
bool prim;

cout << "n="; cin >> n;

S=0;
for(d=1;d<=n;d++)
if (n%d==0) S+=d;
cout << S << " ";

ct=0;
for(i=2;i<n;i++){
prim=true;
for(d=2;d<=i/2;d++)
if (i%d==0) prim=false;
if (prim) ct++;
}
cout << ct;
}

n=10
18 4

5.6.4 Maxime si minime


Calcularea valorile minime sau maxime dintr-o serie de valori reprezinta o
problema des intalnita in practica.Avem:
Maxime:

max = ­infinit
Pentru toate valorile X de parcurs
if (X>max) max=X

Minime:

min = infinit
Pentru toate valorile X de parcurs
if (X<min) min=X

- 63 -
Introducere in ANSI C++

In aceste scheme, infinit reprezinta valoarea minima pe care o poate lua X si


depinde de tipul de date cu care lucram.
Biblioteca values.h ofera in acest sens o serie de constante predefinite utile, cum
ar fi MAXINT, -MAXINT, MAXFLOAT etc.

P21. Se citeste un numar intreg pozitiv de la tastatura. Calculati:

• Cifra maxima a numarului

• De cate ori apara cifra minima

#include <iostream>
using namespace std;

int main(){
int n,nn,S,P,pc,ct,c;
cin >> n;
nn=n;

for(S=0,P=1; n ;n/=10){
c=n%10;
S+=c;
if (c%2==0) P*=c;
}

for(n=nn;n>=10;n/=10);
pc=n;

for(n=nn,ct=0; n ;n/=10)
if (n%10 == pc) ct++;

cout << S << " " << P << " " << pc << " " << ct;

25221
12 8 2 3

5.6.5 Citirea mai multor numere de la tastatura


In cazul in care dorim prelucrarea a mai multe numere citite, avem urmatoarele
rezolvari:
a. Utilizatorul, ca prima faza, introduce numarul de valori ce vor fi citite
ulterior:

- 64 -
Introducere in ANSI C++

cin >> n; // numarul de valori de citit
for(i=1;i<=n;i++){ // de n ori
cin >> X; // citim numarul
foloseste(X); // il utilizam conform enuntului
}

b. Se cunoaste o conditie cat timp se vor citi valori:

cin >> X; // citim valoare
while (cond(X)){ // cat timp conditia e respectata
foloseste(X); // il utilizam conform enuntului
cin >> X; // citim numarul
}

P22. Se citeste un numar n, apoi n valori reale de la tastatura. Calculati:

• maximul

• produsul

#include <iostream>
#include <values.h>
using namespace std;

int main(){
int n,x,i,max,P;

max=-MAXINT; P=1;
cin >> n;
for(i=1;i<=n;i++){
cin >> x;
P=P*x;
if (x>max) max=x;
}

cout << max << " " << P;


}

5
1 1 5 2 1
5 10

- 65 -
Introducere in ANSI C++

P23. Se citesc numere intregi pana la intalnirea valorii 0. Calculati:

• Suma valorilor pare

• Minimul si de cate ori apare acesta

#include <iostream>
#include <values.h>
using namespace std;

int main(){
int x,i,min,ct_min,S;

min=MAXINT; ct_min=0; S=0;


cin >> x;
while (x!=0){
if (x%2==0) S=S+x;

if (x==min) ct_min++;
else if (x<min){
min=x;
ct_min=1;
}

cin >> x;
}

cout << S << endl;


cout << min << " apare de " << ct_min << " ori";
}

2 3 1 4 6 1 1 1 6 1 12 0
30
1 apare de 5 ori

5.6.6 Generarea unor serii complexe de numere


P24. Se citeste n (intreg pozitiv). Afisati pe ecran:

a: 1 1 2 1 2 3 ... 1 2...n

b: 1 2 2 3 3 3 ... n n ...n

- 66 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

int main(){
int n,i,k;
cin >>n;

for(k=1;k<=n;k++){
for(i=1;i<=k;i++) cout << i << " ";
cout << " ";
}
cout << endl;

for(k=1;k<=n;k++){
for(i=1;i<=k;i++) cout << k << " ";
cout << " ";
}
}

5
1  1 2  1 2 3  1 2 3 4  1 2 3 4 5
1  2 2  3 3 3  4 4 4 4  5 5 5 5 5 

P25. Se citeste n (intreg pozitiv). Afisati pe ecran, sub forma data:

1 1:1 12345
121 2:1,2 23456
12321 .... 34567
.................... 6: 1,2,3,6 – numarul urmat de divizori 45678
1 ................ 1 ...... 5 6 7 8 9 (n=5)

- 67 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

int main(){
int n,i,k,d;
cin >>n;

for(k=1;k<=n;k++){
for(i=1;i<=n-k;i++) cout << " ";
for(i=1;i<=k;i++) cout << i << " ";
for(i=k-1;i>=1;i--) cout << i << " ";
cout << endl;
}
cout << "-------------" <<endl;

for(k=1;k<=n;k++){
cout << k << ": ";
for(d=1;d<=k/2;d++) if (k%d==0) cout << d << ",";
cout << k << endl;
}
cout << "-------------" << endl;

for(k=1;k<=n;k++){
for(i=1;i<=n;i++) cout << i+k << " ";
cout << endl;
}
}

4
      1
    1 2 1
  1 2 3 2 1
1 2 3 4 3 2 1
­­­­­­­­­­­­­
1: 1
2: 1,2
3: 1,3
4: 1,2,4
­­­­­­­­­­­­­
2 3 4 5
3 4 5 6
4 5 6 7
5 6 7 8

- 68 -
Introducere in ANSI C++

5.7 Probleme propuse


Pp1. Refaceti solutiile propuse ale problemelor rezolvate in acest capitol, astfel
incat sa folositi alt tip de instructiune repetitiva fata de cea utilizata in rezolvarea
initiala (de exemplu in loc de for folositi while).
Pp2. Se citeste numarul intreg pozitiv n de la tastatura. Calculati valoarea
urmatoarele expresii, folosind pentru fiecare expresie un alt tip de instructiune
repetitiva:
E = n + n/2 + n/3 + ... + 1
P = 1! + 2! + ... +n!
S = 12 + 42 + 72 + ... + (3n-2)2
Pp3. Se citesc doua numere intregi de la tastatura. Determinati daca cele doua
numere sunt formate din aceleasi cifre, indiferent de cate ori apar. De exemplu 123
si 11321 sunt formate din aceleasi cifre.
Pp4. Calculati ultima cifra a expresiei E= ab, a si b valori intregi pozitive citite
de la tastatura.
Pp5. Se citesc numere intregi de la tastatura pana la intalnirea unui numar
negativ. Afisati numarul citit care are cei mai multi divizori.
Pp6. Se citeste de la tastatura un numar intreg n. Afisati pe ecran urmatoarele
serii de numere, pastrand formatul:

1 1:1 10101
212 2:2,2 01010
32123 3:3,3,3 10101
.................... ...... 01010
n ......1....... n n:n,n,n,...,n 1 0 1 0 1 (n=5)
Pp7. Afisati pe ecran tabla inmultirii pana la 10.
Pp8. Se citeste n intreg, apoi n numere intregi de la tastatura. Afisati:

– cel mai mare si cel mai mic numar prim

– suma numerelor care au cifrele in ordine crescatoare

- 69 -
Introducere in ANSI C++

Capitolul 6 – Vectori (matrici)


In momentul in care complexitatea programelor creste, devine evidenta
necesitatea folosirii unor tipuri de date complexe. Folosirea variabilelor simple
permite stocarea unei singure valori, iar acest lucru devine un impediment major in
momentul in care, sa zicem, avem nevoie de stocarea si realizarea de diferite
operatii pe 100 de numere intregi.
Un vector (tablou unidimensiunal) este o structura de date care poate stoca mai
multe valori de acelasi tip.

6.1 Declararea si initializarea


Exact ca si in cazul variabilelor simple, daca dorim utilizarea unui vector acesta
trebuie sa fie declarat. C++ ofera mai multe moduri de a declara/initializa un
vector, sub forma urmatoare:
tip nume[dimensiune] sau
tip nume[dimensiune]={v1,...,vn}, unde vi au un tip convertibil la tip sau
tip nume[]={v1,v2,...,vn}, unde vi au un tip convertibil la tip

P1. Exemple de declarari/initializari de vectori si cat ocupa acestia in memorie.

#include <iostream>
using namespace std;

int main(){
int A[100]; // vector de intregi neinitilalizat
int B[10]={1,2,3,4};// vector de intregi partial initializat
float X[]={3.14, 5, 2.5};// vector de reali complet initializat

cout << "Vectorul A ocupa " << sizeof(A) << " octeti";
cout << "Vectorul B ocupa " << sizeof(B) << " octeti";
cout << "Vectorul X ocupa " << sizeof(X) << " octeti";
cout << "Vectorul X are " << sizeof(X)/sizeof(int)<< " valori";

Vectorul A ocupa 400 octeti
Vectorul B ocupa 40 octeti

- 70 -
Introducere in ANSI C++

Vectorul X ocupa 12 octeti
Vectorul X are 3 valori

Observam ca specificarea dimensiunii va duce la alocarea unui spatiu de


memorie suficient pentru a pastra toate valorile din vector, iar in cazul in care nu
avem specificata dimensiunea aceasta este data de numarul de valori cu care
initializam vectorul.
Accesul la elementele unui vector se face folosind indici. Fie urmatorea
declaratie de vector:
int A[10]={1,2,3,4};

In acest caz se aloca in memorie un numar de 10 intregi, primele patru valori


fiind initializate. In memorie situatia va asemanatoare cu cea descrisa in figura 6.1:

1 2 3 4 ? ... ?

A[0] A[1] A[9]


Figura 6.1
Observam ca primul element este A[0], al doilea A[1], si, in final, ultimul
element valid va fi A[9]. Primele patru elemente, cele initializate, au valori
cunoscute, in rest nu stim ce valori exista in vector. In functie de compilator, s-ar
putea ca ele sa fie initializate cu valoare 0, dar este mai bine sa nu contam pe acest
fapt.
Daca, in continuare, avem urmatoarele atribuiri:
A[0]=5;
A[9]=A[1]+A[2]+A[3];

vom avea urmatoarea situatie (Figura 6.2):

5 2 3 4 ? ... 9

A[0] A[1] A[9]


Figura 6.2

- 71 -
Introducere in ANSI C++

6.2 Citirea si scrierea vectorilor


Vom prezenta in continuare primele operatii pe vectori.
In cazul in care dorim sa realizam citirea si afisarea unui vector, exista
posibilitatea de a accesa vectorul elemente cu element prin intermediul unor indici
constanti, asa cum se observa in problema urmatoare:

P2. Se citesc cinci valori ale unui vectori de intregi. Afisati vectorul in ordine
inversa.

#include <iostream>
using namespace std;

int main(){
int A[5];

cout << "Dati elementele vectorului A:";


cin >> A[0] >> A[1] >> A[2] >> A[3] >> A[4];

cout << "A: " << A[4] << " " << A[3] << " ";
cout << A[2] << " " << A[1] << " " << A[0];

Dati elementele vectorului A:2 4 1 3 5
A: 5 3 1 4 2

Aceasta abordare nu acopera urmatoarele cazuri:


- daca avem un numar mare de elemente in vector
- daca numarul de elemente din vector difera de la rulare la rulare
Pentru a rezolva aceste situatii, in loc sa accesam valorile din vector folosind
indici constanti, vom folosi o variabila ca indice. Accesul la elementele vectorului
se va face folosind o notatie de forma A[i], unde i va fi o valoare intrega ce
reprezinta un indice valid in vector, adica o valoare din multimea {0,1,...,n-1}.
Citirea unui element va fi de forma:
cin >> A[i];

unde i va parcurge indicii vectorului.

- 72 -
Introducere in ANSI C++

P3. Se citesc cinci valori ale unui vectori de intregi. Afisati vectorul in ordine
inversa. (varianta 2)

#include <iostream>
using namespace std;

int main(){
int A[5];
int i;

cout << "Dati elementele vectorului A:";


for(i=0;i<5;i++) cin >> A[i];

cout << "A: ";


for(i=4;i>=0;i--) cout << A[i] << " ";

Dati elementele vectorului A:3 4 5 6 7
A: 7 6 5 4 3

In general, pentru a creste flexibilitatea programului, vom da posibilitatea


utilizatorului sa foloseasca vectori de lungime variabila, lungime limitata doar de
modul in care am declarat vectorul. De acum inainte, atunci cand ne referim la un
vector, ne vom referi la o pereche de forma (A,n), unde A este vectorul, iar n este
lungimea actuala a acestuia.

P4. Se citeste un vector de la tastatura. Afisati vectorul pe ecran.

#include <iostream>
using namespace std;

int main(){
int A[100],n,i;// vectorul si lungimea curenta (0<= n <=100)

cin >>n; // citim lungimea vectorului


for(i=0;i<n;i++)
cin >> A[i]; // apoi vectorul, element cu element

for(i=0;i<n;i++)
cout << A[i] << " "; // afisarea, element cu element
}

4
3 4 1 2
3 4 1 2

- 73 -
Introducere in ANSI C++

Aspectul „sec” al aplicatiei este remediat in exemplul urmator:

P5. Se citeste un vector de la tastatura. Afisati vectorul pe ecran. (varianta


cosmetizata)

#include <iostream>
using namespace std;

int main(){
int A[100],n;
int i;

cout << "n="; cin >>n;


for(i=0;i<n;i++){
cout << "A[" << i << "]=";
cin >> A[i];
}

cout << "A=(";


for(i=0;i<n-1;i++)
cout << A[i] << ",";
cout << A[n-1] << ")";

n=3
A[0]=7
A[1]=15
A[2]=9
A=(7,15,9)

In general recomand folosirea variantei simple daca lucram programul „pe


foaie”, orice varianta practica, pe calculator, folosind o varianta de citire/scriere
user-friendly.
Dupa cum observam in ultimele exemple, accesul la elementele vectorului (A,n)
respecta, in general, urmatoarea schema generala:

for(i=0;i<n;i++)
foloseste(A[i]);

Modul in care folosim elementele vectorului depinde de la problema la


problema.

- 74 -
Introducere in ANSI C++

6.3 Generari de vectori


Uneori elementele vectorilor nu vor fi valori citite de la tastatura ci valori
construite in functie de enunt. Urmatoarele exemple ilustreaza cateva cazuri mai
des intalnite in practica.
In problema urmatoare exploatam relatia dintre indicele si valoarea memorata
pe pozitia respectiva:

P6. Se citeste de la tastatura un numar intreg 1<=n<=100. Generati si afisati


pe ecran urmatorii vectori de lungime n.
A: 1,2,3,4,...

B: 0,2,0,4,0,6,...

C: n-1,n-2, ..., 2,1,0

D: 0,1,0,1,0,...

#include <iostream>
using namespace std;

int main(){
int A[100],B[100],C[100],D[100],n;
int i;

cout << "n="; cin >>n;

for(i=0;i<n;i++) A[i]=i+1;
for(i=0;i<n;i++) B[i]= (i%2==0)? 0:i;
for(i=0;i<n;i++) C[i]=n-1-i;
for(i=0;i<n;i++) D[i]=i%2;

cout << "A:"; for(i=0;i<n;i++) cout << A[i] << " ";
cout << "\nB:"; for(i=0;i<n;i++) cout << B[i] << " ";
cout << "\nC:"; for(i=0;i<n;i++) cout << C[i] << " ";
cout << "\nD:"; for(i=0;i<n;i++) cout << D[i] << " ";
}

n=10
A:1 2 3 4 5 6 7 8 9 10
B:0 1 0 3 0 5 0 7 0 9
C:9 8 7 6 5 4 3 2 1 0
D:0 1 0 1 0 1 0 1 0 1 

- 75 -
Introducere in ANSI C++

Generarea recursiva a vectorilor este o varianta intuitiva de rezolvare, daca


enuntul problemei permite folosirea unei relatii prin care construim un element in
functie de cele deja generate.

P7. Se citeste de la tastatura un numar intreg 1<=n<=20. Generati recursiv,


apoi afisati pe ecran urmatorii vectori de lungime n.
A: 1,2,3,4,...

B: 1,1,2,3,5,8,...

C: 1,2,4,8,16,...

D: 0,1,0,1,0,...

#include <iostream>
using namespace std;

int main(){
int A[20],B[20],D[20],n,i;
long C[20];

cout << "n="; cin >>n;

A[0]=1;
for(i=1;i<n;i++) A[i]=A[i-1]+1;
B[0]=B[1]=1;
for(i=2;i<n;i++) B[i]= B[i-1]+B[i-2];
C[0]=1;
for(i=1;i<n;i++) C[i]=2*C[i-1];
D[0]=0;
for(i=1;i<n;i++) D[i]=!D[i-1];

cout << "A:"; for(i=0;i<n;i++) cout << A[i] << " ";
cout << "\nB:"; for(i=0;i<n;i++) cout << B[i] << " ";
cout << "\nC:"; for(i=0;i<n;i++) cout << C[i] << " ";
cout << "\nD:"; for(i=0;i<n;i++) cout << D[i] << " ";
}

n=10
A:1 2 3 4 5 6 7 8 9 10
B:1 1 2 3 5 8 13 21 34 55
C:1 2 4 8 16 32 64 128 256 512
D:0 1 0 1 0 1 0 1 0 1 

- 76 -
Introducere in ANSI C++

Generarea de valori aleatoare in vectori poate fi utila daca dorim testarea unor
algoritmi pe vectori si dorim sa evitam introducerea de valori de la tastatura.

P8. Generati un vector de lungime citita de la tastatura, continand valori


aleatoare in intervalul [a,b], a<b, numere pozitive.

#include <iostream>
using namespace std;

int main(){
int A[100],n;
int i,a,b;

cout << "n="; cin >>n;


cout << "a="; cin >>a;
cout << "b="; cin >>b;

for(i=0;i<n;i++) A[i]=a + rand()%(b-a+1);

cout << "A:"; for(i=0;i<n;i++) cout << A[i] << " ";
}

n=10
a=30
b=40
A:36 40 36 32 31 34 30 36 33 31

Functia rand(), definita intr-o biblioteca standard ANSI C++, stdlib, va


returna un numar de tip long int pseudo-aleator. Operatia modulo va face ca
valoarea aleatoare „sa cada” in intervalul ales de noi, in cazul acesta [0,b-a].
Adunand la aceasta valoare a, vom obtine valoarea aleatoare in intervalul dorit.

6.4 Cateva probleme simple


Vom da mai departe cateva probleme simple cu vectori, probleme intalnite des
in practica.

P9. Se citeste un vector de la tastatura. Afisati:

a. suma valorilor din vector


b. produsul elementelor pare din vector

c. maximul valorilor din vector

- 77 -
Introducere in ANSI C++

d. minimul valorilor pozitive

#include <iostream>
using namespace std;

int main(){
int A[100],n,i;
int S,P;

cout << "n="; cin >>n;


for(i=0;i<n;i++) cin >> A[i];

S=0;P=1;
for(i=0;i<n;i++){
S=S+A[i];
if (A[i]%2==0) P=P*A[i];
}

cout << "Suma: " << S;


cout << "\nProdusul valorilor pare: " << P;

n=6
1 ­1 2 ­2 3 ­3
Suma: 0
Produsul valorilor pare: ­4
Maximul: 3
minimul valorilor pozitive: 1

P10. Generati un vector aleator de 2n elemente din [1,10], n citit de la tastatura,


n<10. Calculati si afisati pe ecran:

E=A[0]/A[1]+A[2]/A[3]+ ... +A[2n-2]/A[2n-1]

F=max(A[0]) + max(A[0],A[1]) + ...max(A[0],A[1],...,A[2n-1])

- 78 -
Introducere in ANSI C++

#include <iostream>
#include <values.h>
using namespace std;

int main(){
int A[20],n,i;
float E;
int F,max;

cout << "n="; cin >>n;


for(i=0;i<2*n;i++) A[i]=1+rand()%10;

E=0;
for(i=0;i<2*n-1;i+=2)
E = E + float(A[i])/A[i+1];

max=-MAXINT;
F=0;
for(i=0;i<2*n;i++){
if(A[i]>max) max=A[i];
F=F+max;
}

cout << "Vectorul:";


for(i=0;i<2*n;i++)
cout << A[i] << " ";
cout << "\nE: " << E;
cout << "\nF: " << F;

n=2
Vectorul:4 7 8 6
E: 1.90476
F: 27

P11. Verificati daca un vector citit de la tastatura este sau nu:

a. sortat crescator

b. este sir Fibonacci (primele doua vaori sunt 1, in rest fiecare element de
obtine insumand cele doua valori anterioare)

c. simetric

- 79 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

int main(){
int A[100],n,i,j;
bool cresc, fibo, sim;

cout << "n="; cin >>n;


for(i=0;i<n;i++) cin >> A[i];

cresc=true;
for(i=0;i<n-1;i++)
if (A[i]>A[i+1]) cresc=false;

if ((A[0]==1)&&(A[1]==1)) fibo=true;
for(i=2;fibo && i<n-1;i++)
if (A[i]!=A[i-1]+A[i-2]) fibo=false;

sim=true;
for(i=0,j=n-1;sim && i<j;i++,j--)
if (A[i]!=A[j]) sim=false;

cout << "Vectorul dat ";


if (!cresc) cout << "nu ";
cout << "este crescator, ";
if (!fibo) cout << "nu ";
cout << "este Fibonacci, ";
if (!sim) cout << "nu ";
cout << "este simetric.";

n=5
1 1 2 3 5
Vectorul dat este crescator, este Fibonacci, nu este simetric.

sau:
n=6
1 6 2 2 6 1
Vectorul dat nu este crescator, nu este Fibonacci, este simetric.

- 80 -
Introducere in ANSI C++

6.5 Sortarea si interclasarea


Problema sortarii unui vector, este problema reasezarii elementelor in asa fel
incat ele sa respecte o relatie de ordine (crescatoare). Problema este bine
reprezentata in literatura de specialitate (vezi [1], [4], [6], [8]). Prezentam in
continuare trei metode de sortare consacrate.

P12. Sortarea prin selectie

#include <iostream>
using namespace std;

int main(){
int A[100],n,i,j,t;

cout << "n="; cin >>n;


for(i=0;i<n;i++) cin >> A[i];

for(i=0;i<n-1;i++)
for(j=i+1;j<n;j++)
if (A[j]<A[i]){
t=A[i]; A[i]=A[j]; A[j]=t;
}

cout << "Vectorul sortat: " ;


for(i=0;i<n;i++) cout << A[i] << " ";

n=5
2 4 5 1 3
Vectorul sortat: 1 2 3 4 5

Ideea „din spatele”algoritmului este urmatoarea:


- aducem pe prima pozitie elementul minim din vector, prin interschimbarea lui
A[0] cu acele elemente dintre A[1],A[2],...A[n-1] care sunt mai mici ca A[0].
- repetam algoritmul descris la pasul anterior pe cazul general, aducand pe
pozitia A[i] minimul dintre A[i],A[i+1],...,A[n-1]
- la sfarsit toate valorile sunt pe pozitiile corecte

- 81 -
Introducere in ANSI C++

P13. Bubble Sort

#include <iostream>
using namespace std;

int main(){
int A[100],n,i,k,t;

cout << "n="; cin >>n;


for(i=0;i<n;i++) cin >> A[i];

for(k=1;k<=n-1;k++)
for(i=0;i<n-1;i++)
if (A[i]>A[i+1]){
t=A[i]; A[i]=A[i+1]; A[i+1]=t;
}

cout << "Vectorul sortat: " ;


for(i=0;i<n;i++) cout << A[i] << " ";

n=5
2 4 5 1 3
Vectorul sortat: 1 2 3 4 5

Ideea este urmatoarea:


- comparam, rand pe rand, toate valorile succesive din vector
- daca elementul din stanga este mai mare ca cel din dreapta, atunci
interschimbam elementele
- in urma primei treceri prin vector, elementul maxim a ajuns sigur pe ultima
pozitie
- repetari succesive ale algoritmului vor duce la deplasari ale elementelor mari
spre sfarsit, pana la ocuparea pozitiei corecte
- cum la fiecare trecere cel putin un element ajunge la locul corect, din maxim
n-1 treceri vor avea vectorul sortat crescator

- 82 -
Introducere in ANSI C++

P14. Sortarea prin numarare


Pentru a putea aplica sortarea prin numarare, se stie ca intervalul in care A[i]
poare lua valori este de forma [0,m], cu m cunoscut si nu foarte mare. Pentru
problema noastra am considerat m=10.

#include <iostream>
using namespace std;

int main(){
int A[100],n,i,k,j;
int ct[100];

cout << "n="; cin >>n;


for(i=0;i<n;i++) A[i]=rand()%10;

cout << "Vectorul initial: ";


for(i=0;i<n;i++) cout << A[i] << " ";

// contorizarea valorilor din vector


for(i=0;i<10;i++) ct[i]=0;
for(i=0;i<n;i++) ct[A[i]]++;

// completarea valorilor in vector


i=0;
for(k=0;k<10;k++)
for(j=1;j<=ct[k];j++)
A[i++]=k;

cout << "\nVectorul sortat: " ;


for(i=0;i<n;i++) cout << A[i] << " ";

n=10
Vectorul initial: 3 6 7 5 3 5 6 2 9 1
Vectorul sortat: 1 2 3 3 5 5 6 6 7 9 

Functionarea algoritmului:
- numaram fiecare valoare de cate ori apare in vector
- odata avut vectorul de contori, nu avem decat sa completam valorile, de la cea
mai mica la cea mai mare, de cate ori trebuie in vectorul rezultat

- 83 -
Introducere in ANSI C++

Interclasarea se definiste ca fiind algoritmul care, primind doi vectori sortati,


obtine un al treilea vector sortat continand elementele vectorilor initiali.

P15. Interclasarea vectorilor

#include <iostream>
using namespace std;

int main(){
int A[100],B[100],n,m,i,j;
int C[100],k;

n=2+rand()%10; A[0]=2;
for(i=1;i<n;i++) A[i]=A[i-1]+1+rand()%3;

m=2+rand()%10; B[0]=1;
for(i=1;i<m;i++) B[i]=B[i-1]+1+rand()%4;

cout << "A: "; for(i=0;i<n;i++) cout << A[i] << " ";
cout << "\nB: ";for(i=0;i<m;i++) cout << B[i] << " ";

i=j=k=0;
while ((i<n)&&(j<m))
if (A[i]<A[j]) C[k++]=A[i++];
else C[k++]=B[j++];

while(i<n) C[k++]=A[i++];
while(j<m) C[k++]=B[j++];

cout << "\nC: ";for(i=0;i<m+n;i++) cout << C[i] << " ";

A: 2 4 5 7 10
B: 1 4 5 7 9 12 16
C: 1 2 4 4 5 5 7 7 9 12 16 10 

Vectorii au fost generati aleator, dar in ordine crescatoare.

- 84 -
Introducere in ANSI C++

6.6 Declararea matricilor


Limbajul C++ permite, pe langa matricile unidimensionale (vectorii), matrici
bidimensionale si multidimensionale.
Declararea unei matrici:
tip nume[dimensiune1][dimensiune2]  sau, mai general,
tip nume[dimensiune1][dimensiune2]...[dimensiunen]

Cele mai folosite, pe langa vectori, sunt matricile bidimensionale, numite de


acum, din comoditate, matrici.
Exista posibilitatea initializarii elementelor unei matrici, dand un „vector de
vectori” de valori, valori ce vor fi completate in matrice pe linii.

P16. Declarari de matrici. Cantitatea de memorie ocupata de matrici.

#include <iostream>
using namespace std;

int main(){
int A[10][10];
float B[4][3]={{1,2},
{3,4},
{5,6}};

cout << "A[10][10] ocupa " << sizeof(A) << " octeti";
cout << "\nB[4][3] ocupa " << sizeof(B) << " octeti";

A[10][10] ocupa 400 octeti
B[4][3] ocupa 48 octeti

6.7 Citirea si afisarea matricilor


Accesul la elementele unei matrici se face tot prin intermediul indicilor. Astfel,
pentru o declaratie de forma int A[10][10] indicii corespunzatori sunt dati in
Figura 6.3.

- 85 -
Introducere in ANSI C++

Coloana 0

Coloana 1

Coloana 9
Linia 0 A[0][0] A[0][1] A[0][2] ... A[0][9]

Linia 1 A[1][0] A[1][1] A[1][2] ... A[1][9]

...

...

...
...

Linia 9 A[9][0] A[9][1] A[9][2] ... A[9][9]

Figura 6.3

P17. Se citeste o matrice de la tastatura. Afisati matricea.

#include <iostream>
using namespace std;

int main(){
int A[10][10],n,m,i,j;

cout << "n=";cin >>n;


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

for(i=0;i<n;i++){
for(j=0;j<n;j++)
cout << A[i][j] << " ";
cout << endl;
}
}

n=2
m=2
A[0][0]=1
A[0][1]=2

- 86 -
Introducere in ANSI C++

A[1][0]=3
A[1][1]=4
1 2
3 4

Analog citirii vectorilor, citirea efectiva a elementelor din matrice este


precedata de specificarea numarului de linii si de coloane. Primul indice reprezinta
linia, iar al doilea coloana.
In general, parcurgerea pe linii a unei matrici are loc astfel:

for(i=0;i<n;i++)
for(j=0;j<m;j++)
foloseste(A[i][j]);

6.8 Probleme cu matrici


P18. Afisati pe coloane o matrice initializata din cod

#include <iostream>
using namespace std;

int main(){
int A[10][10]={ {1,2,3},
{4,5,6},
{7,8,9}};
int n=3,m=3,i,j;

for(j=0;j<n;j++){
for(i=0;i<n;i++)
cout<<A[i][j]<<" ";
cout << endl;
}
}
1 4 7
2 5 8
3 6 9

- 87 -
Introducere in ANSI C++

P19. Generati si afisati urmatoarele matrici:


1   1   1   1 1   0   1   0 1   2   3   4  
2   2   2   2 0   1   0   1 5   6   7   8  
3   3   3   3 1   0   1   0 9   10  11  12  
4   4   4   4 0   1   0   1 13  14  15  16  

#include <iostream>
using namespace std;

int main(){
int A[10][10], B[10][10], C[10][10];
int n,m,i,j,v;

cout << "n="; cin >> n;


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

v=1;
for(i=0;i<n;i++)
for(j=0;j<n;j++){
A[i][j]=i+1;
B[i][j]=(i+j+1)%2;
C[i][j]=v++;
}

for(i=0;i<n;i++){
for(j=0;j<n;j++)
cout << A[i][j] << " ";
cout << endl;
}

for(i=0;i<n;i++){
for(j=0;j<n;j++)
cout << B[i][j] << " ";
cout << endl;
}

for(i=0;i<n;i++){
for(j=0;j<n;j++)
cout << C[i][j] << " ";
cout << endl;
}
}

- 88 -
Introducere in ANSI C++

In cazul in care numarul de linii si cel de coloane este identic spunem despre
matrice ca este patratica. In acest caz, vorbim despre diagonala principala si cea
secundara. Relatia dintre indici raportata la diagonale este data in Figura 6.4:

i+j<n-1
i>j

1
n-
i=

==
=j

j
i+
i<j
i+j>n-1

Figura 6.4

P20. Completati o matrice sub forma:


1 2 2 2 2 1
5 1 2 2 1 3
5 5 1 1 3 3
5 5 1 1 3 3
5 1 4 4 1 3
1 4 4 4 4 1

#include <iostream>
using namespace std;

int main(){
int A[10][10], n,i,j;
cout << "n="; cin >> n;

for(i=0;i<n;i++)
for(j=0;j<n;j++){
if (i<j)
if (i+j<n-1) A[i][j]=2;
else A[i][j]=3;
else
if (i+j<n-1) A[i][j]=5;
else A[i][j]=4;
if ((i==j)||(i+j==n-1)) A[i][j]=1;
}

for(i=0;i<n;i++){
for(j=0;j<n;j++)
cout << A[i][j] << " ";
cout << endl;
}
}

- 89 -
Introducere in ANSI C++

P21. O matrice contine cifre pe primele n-1 linii. Considerand fiecare rand al
matricii ca fiind numarul in baza 10 corespunzator, completati pe ultima linie
suma numerelor zecimale de pe liniile date.

#include <iostream>
using namespace std;

int main(){
int A[10][10], n,i,j,t;

cout << "n="; cin >> n;


for(i=0;i<n-1;i++)
for(j=0;j<n;j++)
cin >> A[i][j];

t=0;
for(j=n-1;j>=0;j--){
for(i=0;i<n-1;i++)
t+=A[i][j];
A[n-1][j]=t%10;
t=t/10;
}

for(i=0;i<n;i++){
for(j=0;j<n;j++)
cout << A[i][j] << " ";
cout << endl;
}
}

0 2 4 5
0 0 9 1
1 2 3 4
1 5 7 0

- 90 -
Introducere in ANSI C++

6.9 Probleme propuse


Pp1. Generati si afisati vectorii (n intreg citit de la tastatura):
a: 1 0 2 0 3 0 ...
b: 1 2 3 5 7 11 ... (primele n numere prime)
c: 1 1 1 3 5 9 17 ... (tribonacci :))
Pp2. Se citeste un vector de la tastatura. Calculati:
S=a[0]*a[1]+a[1]*a[2] + ... + a[n-2]*a[n-1]
E = suma valorilor cu indice prim
F = produsul ultimelor cifre
Pp3. Se citesc doi vectori de intregi de la tastatura. Determinati daca cei doi
vectori sunt formate din aceleasi valori, indiferent de ordine si cate ori apar. De
exemplu a: 1,2,3 si b:1,1,3,2,1 satisfac proprietatea ceruta.
Pp4. Un vector contine cifre. Care este cel mai mare numar de trei cifre care
poate fi format din cifrele vectorului?
Pp5. Generati un vector continand n valori intregi in intervalul [-100,100].
Mutati valorile pozitive la incepu si cele negative la sfarsitul vectorului (dintr-o
singura parcurgere).
Pp6. Se citeste o matrice de la tastaura. Verificati daca elementele de pe
diagonale sunt in ordine crescatoare sau descrescatoare, afisand mesaje sugestive
pe ecran.
Pp7. Se citesc o matrice patratica de nxn si un vector de lungime n. Verificati de
cate ori regasim vectorul in matrice, ca linie sau coloana.
Pp8. O matrice contine valori in intervalul [1,100]. Generati un vector continand
valori din [1,100] care NU se regasesc in matrice, in ordine descrescatoare.

- 91 -
Introducere in ANSI C++

Capitolul 7 – Siruri de caractere


Datorita gradului de utilizare, acestui tip structurat de date i s-a acordat o atentie
deosebita; exista functii de citire/scriere specifice, plus o serie functii de uz general
pe siruri de caractere definite in biblioteca standard.

7.1 Declaratie si initializare


Forma generala a declaratiei unui sir de caractere este:
char nume[dimensiune] sau
char nume[dimensiune]=”c1c2...cn”, sau
char nume[]=”c1c2...cn”

Urmatorul stil de initializare nu este recomandat, desi este suportat de catre


compilator:
char nume[dimensiune]={c1,c2,...,cn}

P1. Exemple de declarari/initializari de siruri.

#include <iostream>
using namespace std;

int main(){
char S[100]; // sir neinitilalizat
char s[20]="Ana are laptop";// sir initializat
char X[]="abc"; // initializare corecta
char Y[]={'x','y','z'}; // initializare nerecomandata

cout << "Vectorul S ocupa " << sizeof(S) << " octeti\n";
cout << "Vectorul s ocupa " << sizeof(s) << " octeti\n";
cout << "Vectorul X ocupa " << sizeof(X) << " octeti\n";
cout << "Vectorul Y ocupa " << sizeof(X) << " octeti";

Vectorul S ocupa 100 octeti
Vectorul s ocupa 20 octeti
Vectorul X ocupa 4 octeti
Vectorul Y ocupa 4 octeti

- 92 -
Introducere in ANSI C++

Vom exemplifica in constinuare modul de memorare a sirurilor de caractere in


C. In exemplul anterior observam ca, in urma declaratiei
char X[]=”abc”;

in memorie X ocupa 4 octeti. Cum unui caracter ii este necesar un octet pentru a
fi memorat, observam ca s-a alocat un octet in plus. Motivul este cel ca in limbajul
C este folosit terminatorul NULL pentru a marca sfarsitul unui sir de caractere.
Pentru exemplul de mai sus avem urmatoarea situatia dinfigura 7.1:

‘ a’ ‘ b’ ‘ c’ ‘ \0’ ? ...

X[0] X[1]
Figura 7.1
Acelasi lucru se intampla atunci cand folosi constante de tip sir de caractere,
compilatorul adaugand automat terminatia NULL. Caracterul ‘\0’ este caracterul
cu codul ASCII egal cu zero si este diferit de caracterul ‘0’.
In general, in cazul in care declaram o variabila de tip sir de caractere, trebuie
tinut cont de terminatorul NULL, deci practic trebuie sa declaram cu dimensiune
cu 1 mai mare decat a sirului efectiv.
Diferenta de reprezentare dintre un caracter si sirul de caractere identic este
evidentiat de exemplul urmator.

P2. Diferenta dintre un caracter si sirul de caractere corespunzator.

#include <iostream>
using namespace std;

int main(){

cout << "Caracterul \'A\' ocupa " << sizeof('A') << " octeti\n";
cout << "Sirul \"A\" ocupa " << sizeof("A") << " octeti\n";

Caracterul 'A' ocupa 1 octeti
Sirul "A" ocupa 2 octeti

Este necesara folosirea secventelor escape pentru afisarea ‘ si ”.

- 93 -
Introducere in ANSI C++

Diferenta de reprezentare este evidentiata de Figura 7.2:

‘ A’ ‘ A’ ‘ \0’

Caracterul ‘ A’ Sirul de caractere “A”


Figura 7.2

7.2 Operatii de citire/scriere pe siruri de caractere


Citirea si scrierea sirurilor de caractere este mult simplificata fata de citirea
vectorilor, nu mai este necesara memorarea lungimii actuale (datorita
terminatorului NULL) si nu trebuie sa citim caracter cu caracter. Urmatorul
exemplu da diferite moduri de citire/scriere:

P3. Citirea/scierea sirurilor de caractere.

#include <iostream>
using namespace std;

int main(){

char S1[100],S2[100];

cout << "Introduceti un sir: ";


cin.getline(S1,100); // citeste inclusiv spatiile
cout << "Introduceti inca un sir: ";
cin >> S2; // citeste pana la primul caracter "alb"

cout << "Primul sir introdus: " << S1 << "\n";


cout << "Al doilea sir introdus: " << S2;

Introduceti un sir: Ana are laptop
Introduceti inca un sir: Ana are laptop
Primul sir introdus: Ana are laptop
Al doilea sir introdus: Ana

- 94 -
Introducere in ANSI C++

Observam ca citirea nu trebuie facuta caracter cu caracter. Daca S este un sir de


caractere, folosind o constructie de forma
cin >> S; 

citirea se opreste la primul caracter „alb” (spatiu, tab, enter).


Citirea intregului rand, adica pana la apasarea tastei Enter se face folosind:
cin.getline(S,dimensiune);

unde dimensiune este numarul maxim de caractere care va fi citit.


La citire, adaugarea terminatorului NULL este realizata in mod automat. Daca
dorim citirea caracter cu caracter, acest lucru este posibil (in stilul citirii
vectorilor), dar trebuie sa avem grija de terminatorul NULL, functiile pe siruri de
caractere tinand cont de acesta.

7.3 Accesul la caracterele unui sir


Daca dorim parcurgerea unui sir de caractere, flosim urmatoare schema
generala:

for(i=0;S[i];i++)
foloseste(S[i]);

Observam conditia de oprire S[i], echivalenta cu S[i]!=NULL. In cuvinte,


schema de mai sus ar fi: „de la primul caracter si pana la caracterul NULL,
foloseste caracterul curent”. Alte scheme utile:
Verificarea daca un caracter este sau nu cifra:

If ((c>=’0’)&&(c<=’9’))
foloseste(c);

Verificarea daca un caracter este sau nu litera mare:

If ((c>=’A’)&&(c<=’Z’))
foloseste(c);

- 95 -
Introducere in ANSI C++

P4. Se citeste un sir de caractere fara spatii. Inlocuiti literele mici cu litere mari
si invers.

#include <iostream>
using namespace std;

int main(){
char S[100];
int i;

cout << "Introduceti un sir: ";


cin >> S;

for(i=0;S[i];i++){
if ( (S[i]>='a')&&(S[i]<='z') ) S[i] = S[i] - 'a' + 'A';
else if ( (S[i]>='A')&&(S[i]<='Z') ) S[i] = S[i] - 'A' + 'a';
}

cout << S;
}

Introduceti un sir: abcDEF123
ABCdef123

P5. Se citeste un sir de caractere cantinand cuvinte separate de unul sau mai
multe spatii. Afisati numarul de cuvinte.

#include <iostream>
using namespace std;

int main(){
char S[100];
int i,ct;

cout << "Introduceti un sir: ";


cin.getline(S,100);

if (S[0]!=' ') ct=1;


else ct=0;

for(i=1;S[i];i++)
if ( (S[i-1]==' ') && (S[i]!=' ') ) ct++;

cout << "Numarul de cuvinte:"<<ct;


}

Introduceti un sir: Ana are laptop
Numarul de cuvinte:3

- 96 -
Introducere in ANSI C++

In problema P5, numarul de cuvinte este determinat numarand cate succesiuni


de forma spatiu-caracter avem in sir, primul cuvant fiind numarat separat daca
sirul nu incepe cu spatiu.

7.4 Functii specifice sirurilor de caractere


In biblioteca standard string.h sunt definite o serie de functii utile pe siruri de
caractere . Cele mai utilizate sunt date in Tabelul 7.1:

Functie Efect Exemple

Returneaza lungimea sirului strlen("trei") ­> 4


strlen(S)
dat ca paramentru
strcpy(S1,S2) Copiaza S2 peste S1 strcpy(S,"abcd")

Concaterneaza S2 la S2 strcpy(S,"Imi place ");
strcat(S1,S2)
strcat(S,"C++");

Compara lexicografic if (strcmp(S1,S2)==0)


    cout << "Egale";
sirurile date ca parametri. else
Returneaza     cout << "Diferite";
strcmp(S1,S2)
0 daca S1==S2
<0 daca S1<S2
>0 daca S1>S2

Returneaza numarul intreg i=atoi("123")


atoi(S)
corespunzator sirului dat

Returneaza o valoare if (strchr(S,c))


   cout << "L­am gasit!"
strchr(S,c) pozitiva daca un caracter
strstr(S1,S2) (respectiv sir) apare intr-un
sir, 0 in caz contrar

Depoziteaza in S sirul itoa(S,"123",10)


itoa(S,nr,baza) corespunzator numarului nr,
in baza baza
Tabelul 7.1

- 97 -
Introducere in ANSI C++

Observatii:

– itoa nu este implementata in standardul ANSI C++, dar este suportata de


multe compilatoare.
Mai departe dam implementari posibile ale acestor functii, rezolvand
problemele date atat folosind functiile de bilbioteca cat si implementand din cod.

P6. Se citeste un sir de caractere. Afisati lungimea acestuia.

#include <iostream>
#include <string.h>
using namespace std;

int main(){
char S[100];
int i;

cout << "Introduceti un sir: ";


cin.getline(S,100);

for(i=0;S[i];i++);// i va contine la sfarsit lungimea

cout << "Lungimea:"<< i << "\n";


cout << "Lungimea (strlen):"<< strlen(S);

Introduceti un sir: Ana are laptop
Lungimea:14
Lungimea (strlen):14

Observam ca functia strlen nu contorizeaza si terminatorul NULL. Nu este


recomandata parcurgerea unui sir de caractere sub forma
for(i=0;i<strlen(S);i++) ...

apelul functie strlen parcurgand de fiecare data tot sirul, astfel scazand
eficienta algoritmului.

- 98 -
Introducere in ANSI C++

P7. Se citeste un sir de caractere. Copiati-l in alt sir.

#include <iostream>
#include <string.h>
using namespace std;

int main(){
char S[100],X[100],Y[100];
int i;

cout << "Introduceti un sir: ";


cin.getline(S,100);

for(i=0;S[i];i++) X[i]=S[i]; // copiere din cod


X[i]='\0';

strcpy(Y,S);

cout << "X: :"<< X << "\n";


cout << "Y (strcpy):"<< Y;

Introduceti un sir: Ana are laptop
X:        :Ana are laptop
Y (strcpy):Ana are laptop

In cazul in care facem copierea din cod, trebuie sa avem grija de terminator, in
caz contrar alte operatii pe sir, cum ar fi afisarea, nu vor actiona dupa asteptari.
Atribuire directa intre doua siruri de caractere (posibila in alte limbaje), de
forma: S1=S2;
va da un mesajul de eroaren1=atoi(S1);
p07.cpp:21: error: ISO C++ forbids assignment of arrays

P8. Concaternati doua siruri de caractere.


In implementarea urmatoare am comentat apelul functiei strcat. Analog
exemplelor anterioare, observam ca folosirea functiei de biblioteca simplifica mult
programul. O atribuire de forma: X=S1+S2; va da mesajul de eroare:
p09.cpp:23: error: invalid operands of types ‘char [100]’ and ‘char 
[100]’ to binary ‘operator+

- 99 -
Introducere in ANSI C++

#include <iostream>
#include <string.h>
using namespace std;

int main(){
char nume[100],S[100];
int i,j;

cout << "Introduceti numele: ";


cin.getline(nume,100);

strcpy(S,"Salut ");

j=strlen(S);
for(i=0;nume[i];i++) S[j++]=nume[i];
S[j]='\0';

// strcat(S,nume);

cout << S;
}

Introduceti numele: Ana
Salut Ana

Exista posibilitatea de a compara doua siruri de caractere. In acest caz se va tine


cont de ordinea lor lexicografica (cea din dictionar), iar litera mare va fi
considerata mai mica fata de litera mica corespunzatoare (conform codurilor
ASCII). Urmatoare exemple sunt sugestive:
"A" < "a"
"unu" == "unu"
"pom" < "pomisor"
"trei" > "patru"  !!!!

P9. Se citesc doua siruri de caractere.Verificati ordinea lor lexicografica.


Am comentat in acest caz varianta in care am rezolvat fara apelul functiei
strcmp.

- 100 -
Introducere in ANSI C++

#include <iostream>
#include <string.h>
using namespace std;

int main(){
char S1[100],S2[100];
int i,j;
cout << "Introduceti sirul 1: "; cin.getline(S1,100);
cout << "Introduceti sirul 2: "; cin.getline(S2,100);

// for(i=0;S1[i] && S2[i] && S1[i]==S2[i];i++);


// if (S1[i]==S1[i]) cout << "EGALE!"
// else if (S1[i]<S2[i]) cout << "S1<S2"
// else cout << "S1>S2";

cout << "\""<<S1<<"\"";;


if (strcmp(S1,S2)==0) cout << " este egal cu ";
else if (strcmp(S1,S2)<0) cout << " este mai mic ca ";
else cout << " este mai mare ca ";
cout << "\""<<S2<<"\"";;
}

Introduceti sirul 1: trei
Introduceti sirul 2: patru
"trei" este mai mare ca "patru"

P10. Se citesc doua siruri de caractere reprezentand numere intregi. Faceti


suma lor, apoi afisati pe ecran rezultatul.

#include <iostream>
#include <string.h>
using namespace std;

int main(){
char S1[10],S2[10];
int rez,n1,n2;
cout << "Introduceti numarul 1: "; cin.getline(S1,10);
cout << "Introduceti numarul 2: "; cin.getline(S2,10);

n1=atoi(S1);
n2=atoi(S2);
rez=n1+n2;

cout << S1 << " + " << S2 << " = " << rez;
}

Introduceti numarul 1: 123
Introduceti numarul 2: 234
123 + 234 = 357

- 101 -
Introducere in ANSI C++

P11. Verificati daca un nume apare intr-un sir.

#include <iostream>
#include <string.h>
using namespace std;

int main(){
char nume[10],S[100];
int rez,n1,n2;

cout << "Introduceti numele: "; cin.getline(nume,10);


cout << "Introduceti sirul: "; cin.getline(S,100);

if (strstr(S,nume))
cout << "\"" << nume << "\" apare in sirul \"" << S << "\"";
else
cout << "\"" <<nume<< "\" nu apare in sirul \"" << S << "\"";

Introduceti numele: Radu
Introduceti sirul: Toni Alina Radu Cristi
"Radu" apare in sirul "Toni Alina Radu Cristi"

7.5 Matrici de caractere


Utilizarea unui numar mare de siruri de caractere intr-o aplicatie implica
folosirea unui sir de siruri de caractere. Urmatoarele exemple arata definirea si
initalizarea unei matrici de caractere:
char S[10][10]={"Ana", "are","laptop"};

Pentru exemplul de mai sus, S[0] este "Ana", S[1] este "are", S[2] este
"laptop", iar S[3],...,S[9] sunt siruri vide.
In general, fiecare rand al unei matrici de caractere reprezinta un sir de
caractere.

- 102 -
Introducere in ANSI C++

P12. Se citesc doua siruri reprezentand zile ale saptamanii. Folosind o matrice
de caractere initializata cu zilele saptamanii, afisati zilele curinse intre cele citite
de la tastatura.

#include <iostream>
#include <string.h>
using namespace std;

int main(){
char zile[7][10]={ "luni", "marti", "miercuri", "joi",
"vineri", "sambata", "duminica" };

char z1[10],z2[10];
int poz1,poz2,i;

cout << "Introduceti ziua 1: "; cin.getline(z1,10);


cout << "Introduceti ziua 2: "; cin.getline(z2,10);

poz1=poz2=-1;
for(i=0;i<7;i++){
if (strcmp(z1,zile[i])==0) poz1=i;
if (strcmp(z2,zile[i])==0) poz2=i;
}

cout << "-----------------------\n";


if ((poz1==-1)||(poz2==-1)) cout << "Zile incorecte!";
else
for(i=poz1;i<=poz2;i++) cout << zile[i] << "\n";
}

Introduceti ziua 1: marti
Introduceti ziua 2: joi
­­­­­­­­­­­­­­­­­­­­­­­
marti
miercuri
joi

- 103 -
Introducere in ANSI C++

7.6 Alte aplicatii


P13. Se citeste un sir de caractere de la tastatura. Afisati toate prefixele si
sufixele acestuia.

#include <iostream>
#include <string.h>
using namespace std;

int main(){
char cuvant[100];
char copie[100];
int i,j;

cin >> cuvant;

cout << "Prefixe:\n";

strcpy(copie,cuvant);
for(i=strlen(cuvant);i>0;i--){
copie[i]='\0'; // "mutam" sfarsitul cuvantului la stanga
cout << copie<< " ";
}

cout << "\nSufixe:\n";

for(i=0;cuvant[i];i++){
for(j=i;cuvant[j];j++) cout << cuvant[j];
cout << " ";
}
}

abcdef
Prefixe:
abcdef abcde abcd abc ab a
Sufixe:
abcdef bcdef cdef def ef f 

- 104 -
Introducere in ANSI C++

P14. Se citesc de la tastatura siruri de caractere pana la intalnirea sirului


"stop". Afisati cuvantul de lungime maxima.

#include <iostream>
#include <string.h>
using namespace std;

int main(){
char S[100],Smax[100];

cin >> S;
strcpy(Smax,S);

while (strcmp("stop",S)){
if (strlen(S)>strlen(Smax)) strcpy(Smax,S);
cin >>S;
}

cout << "Cuvantul cel lung: " << Smax;


}

mic mare scurt lung stop
Cuvantul cel lung: scurt

- 105 -
Introducere in ANSI C++

7.7 Probleme propuse


Pp1. Se citesc de la tastatura doua siruri de caractere continand doar cifre.
Considerand sirurile ca fiind numere in baza 10, calculati suma lor in alt sir.
Pp2. Se citeste de la tastatura un sir de caractere continand litere mici si spatii.
Afisati cuvintele conponente, cate unul pe un rand.
Pp3. Un sir de caractere contine doar litere mici si litere mari. Prin operatie
elementara intelegem transformarea din litera mica in litera mare sau invers. Care
este numarul minim de operatii elementare astfel incat sa obtinem din sirul initial
unul avand toate literele mici sau toate literele mari.
Pp4. Se citesc de la tastatura cuvinte (fara spatii), pana la citirea cuvantului
"gata". Afisati cel mai lung cuvant care contine doar vocale.
Pp5. Se citeste un sir S, continand cuvinte separate de exact un spatiu si doua
cuvinte, C1 si C2. In locuiti toate aparitiile cuvantului C1 din testul S cu cuvantul
C2.
Pp6. O matrice de caractere contine cate un cuvant pe un rand. Sortati cuvintele
lexicografic, apoi afisati-le pe ecran.

- 106 -
Introducere in ANSI C++

Capitolul 8 – Structuri si alte tipuri utilizator


Dupa cum am vazut, un vector grupeaza sub un nume mai multe valori de
acelasi tip. In acest capitol vom urmarii gruparea informatiilor corelate de tipuri
diferite.

8.1 Structuri
Gruparea informatiilor corelate de tipuri diferite se face prin utilizarea
structurilor. Avem:
struct nume_structura{
declaratii_de_variabile;
} lista_variabile;

Atat nume_structura cat si lista_variabile sunt optionale, dar pot lipsi


ambele in acelasi timp.
In C++, prin aceasta, nume_structura devine un nou tip de data, tip care poate
fi folosit la declararea unor variabile.
nume_structura lista_variabile;

Sintaxa permite declararea directa, in momentul definirii unei structuri a unor


variabile de acel tip.
Daca lipseste nume_structura, avem o structura omonima:
struct {
declaratii_de_variabile;
} lista_variabile;

In acest caz vom folosi in program doar variabilele definite, neexistand


posibilitatea definirii altor variabile de forma data.
Variabilele definite in bloc repezinta datele ce dorim sa le grupam.
Accesul la elementele unei structuri se face folosind operatorul ‘.’:
variabila.nume_data

- 107 -
Introducere in ANSI C++

Exista posibilitatea de a face atribuiri intre doua variabile de tip structura, daca
cele doua variabile sunt de acelasi tip. Deci daca avem:
nume_structura V1,V2;

atunci atribuirea V1=V2; este valida.


Initializarea unei structuri se face intr-o maniera analoaga initializarii vectorilor.

P1. Definiti structura persoana, continand (nume, prenume, varsta). Definiti o


variabila initializata de tipul persoana, mariti varsta cu 1, apoi afisati pe ecran.

#include <iostream>
using namespace std;

// definirea structurii cerute


struct persoana{
char nume[20];
char prenume[20];
int varsta;
};

int main(){
persoana P={"Gates","Gheorghe",30};
P.varsta++;
cout << P.nume << " " << P.prenume << " " << P.varsta;
}

Gates Gheorghe 31

In memorie o variabila de tip structura ocupa o zona continua de memorie.


Figura 8.1 ilustreaza reprezentarea in memorie a unei structuri.

struct persoana{
nume char[20]; nume 20 bytes
int varsta;
float inaltime; varsta sizeof(int) bytes
}; inaltime
sizeof(int) bytes
Figura 8.1
Tipurile de date definite prin cuvantul cheie struct pot fi transmise ca parametri
sau pot fi returnate din functii.

- 108 -
Introducere in ANSI C++

P2. Definiti structura complex (re,im). Implementati functiile suma, produs si


modul.

#include <iostream>
#include <math.h>
using namespace std;

struct complex{
float re;
float im;
};

complex suma(complex,complex);
complex produs(complex,complex);
float modul(complex);

int main(){
complex z1={1,2},z2={5,-1},S,P; // z1= 1+2i si z2=5-i
float m;

S=suma(z1,z2);
P=produs(z1,z2);
m=modul(z1);

cout << "S=" << S.re << "+i*" << S.im << endl;
cout << "P=" << P.re << "+i*" << P.im << endl;
cout << "m=" << m;
}

complex suma(complex x, complex y){


complex T;
T.re = x.re + y.re;
T.im = x.im + y.im;
return T;
}

complex produs(complex x, complex y){


complex T;
T.re = x.re*y.re - x.im*y.im;
T.im = x.re*y.im + x.im*y.re;
return T;
}

float modul(complex x){


return sqrt(x.re*x.re + x.im*x.im);
}

S=6+i*1
P=7+i*9
m=2.23607

- 109 -
Introducere in ANSI C++

Putem defini vectori de structuri sau structuri care contin alte structuri.

P3. Definiti structura persoana (nume, data_nasterii), unde data nasterii este o
alta structura (zi,luna,an). Cititi de la tastatura 3 persoane, apoi afisati-le in
ordine crescatoare dupa anul nasterii.

#include <iostream>
using namespace std;

struct data{
int zi,luna,an;
};

struct persoana{
char nume[20];
data datan;
};

int main(){
persoana P[10],t;
int j,i,nr=3;

for(i=0;i<nr;i++){
cin >> P[i].nume;
cin >> P[i].datan.zi >> P[i].datan.luna >> P[i].datan.an;
}

for(i=0;i<nr-1;i++)
for(j=i+1;j<nr;j++)
if (P[i].datan.an > P[j].datan.an){
t=P[i]; P[i]=P[j]; P[j]=t;
}

for(i=0;i<nr;i++){
cout << P[i].nume << " " << P[i].datan.zi << "/";
cout << P[i].datan.luna << "/" << P[i].datan.an << endl;
}

Ana  12 8 2003
Luci 21 5 1998
Tom  5 12 2000
Luci  21/5/1998
Tom  5/12/2000
Ana  12/8/2003

- 110 -
Introducere in ANSI C++

8.2 Uniuni
Dupa cum am vazut, in cazul structurilor se aloca memorie pentru fiecare
variabila declarata in structura, cantitatea totala de memorie obtinandu-se adunand
cantitatea de memorie necesara fiecarei variabile componente in parte.
In cazul care grupam date folosind uniuni, datele interne vor ocupa aceeasi zona
de memorie, in total uniunea ocupand cat ocupa cea mai mare (dinpunct de vedere
al necesarului de memorie) variabila componenta.
Sintaxa:
union nume_structura{
declaratii_de_variabile;
} lista_variabile;

P4. Definiti o uniune constinand un intreg si un sir de 4 caractere. Folositi


uniunea pentru a modifica octetii din componenta intregului.

- 111 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

union intreg{
unsigned int i;
char c[4];
};

int main(){
intreg I;

I.i=0;
cout << "0000h = " << I.i << endl;

I.c[3]=255;
cout << "F000h = " << I.i << endl;

I.c[3]=0; I.c[2]=255;
cout << "0F00h = " << I.i << endl;

I.c[2]=0; I.c[1]=255;
cout << "00F0h = " << I.i << endl;

I.c[1]=0; I.c[0]=255;
cout << "000Fh = " << I.i;

0000h = 0
F000h = 4278190080
0F00h = 16711680
00F0h = 65280
000Fh = 255

- 112 -
Introducere in ANSI C++

P5. Definiti o uniune prin care putem memora oricare dintre figurile geometrice
urmatoare: cerc, triunghi, dreptunghi.

#include <iostream>
using namespace std;

struct punct{
int x,y;
};

struct cerc{
punct P;
int r;
};

struct triunghi{
punct A,B,C;
};

struct dreptunghi{
punct A,B;
};

union figura{
cerc C;
triunghi T;
dreptunghi D;
};

int main(){
figura F;

F.C.P.x=10; F.C.P.y=10; F.C.r=5; // cerc


cout << "Cerc:" << F.C.P.x <<"," << F.C.P.y <<"," << F.C.r
<< endl;

F.D.A.x=1; F.D.A.y=2; // dreptunghi


F.D.B.x=15; F.D.B.y=20;
cout << "Dreptunghi: (" << F.D.A.x <<"," << F.D.A.y <<") ";
cout << " (" << F.D.B.x <<"," << F.D.B.y <<") ";
}
Cerc:10,10,5
Dreptunghi: (1,2)  (15,20) 

- 113 -
Introducere in ANSI C++

8.3 Campuri de biti


C++ permite alocarea de variabile la nivel de bit.
struct nume_structura{
unsigned var1:nr_biti;
unsigned var2:nr_biti;
...
}lista_variabile;

Tipul variabilelor din campul de biti trebuie sa fie unsigned int.

P6. Definiti si utilizati un camp de biti pentru stocarea unei date calendaristice.

#include <iostream>
using namespace std;

struct data{
unsigned zi:5;
unsigned luna:4;
unsigned an:7;
};

int main(){
data D={29,4,73};

cout << D.zi << " " << D.luna << " " << D.an;
}

29 4 73

Pentru acest exemplu avem urmatoare situatie in memorie:

struct data{
unsigned zi:5;
unsigned luna:4; zi luna an
unsigned an:7; 0 4 5 8 9 15
};
Figura 8.2

- 114 -
Introducere in ANSI C++

8.4 Tipul enumerat


Pentru o mai mare claritate, putem defini tipuri enumerate:
enum nume_enumerare {lista_nume};

Analog structurilor, nume_enumerare devine un tip de data care poate fi folosit


ulterior. Implicit, numele dintre acolade vor fi asociate cu valori de la 0 din 1 in 1.
Datele de tip enumerare sunt considerate de tip int.
Putem forta valorile dorite prin atribuiri.

P7. Definiti si utilizati o enumerare pentru lucrul cu zilele saptamanii.

#include <iostream>
using namespace std;

enum saptamana {luni, marti, miercuri,


joi, vineri, sambata, duminica};

void Mesaj(int);

int main(){
saptamana S;
int i,ct;

for(i=luni; i<=duminica; i++)


Mesaj(i);
}

void Mesaj(int S){


if ((S>=luni)&&(S<=vineri))
cout << "treaba ";
else
cout << "liber ";
}

treaba treaba treaba treaba treaba liber liber 

- 115 -
Introducere in ANSI C++

P8. Definiti si utilizati o enumerare care asociaza notele si calificativele.

#include <iostream>
using namespace std;

enum calificative {
insuficient=4,
suficient=5,
bine=7,
excelent=10
};

int main(){
int nota;
cout << "Dati o nota:"; cin >> nota;

if (nota<=insuficient)
cout << "mai incearca!";
else if (nota<=suficient)
cout << "la limita!";
else if (nota==excelent)
cout << "perfect!";
else cout << "e ok!";
}

Dati o nota:8
e ok!

- 116 -
Introducere in ANSI C++

8.5 Probleme propuse


Pp1. Definiti o structura de lucru cu numare rational si implementati operatiile
de adunare, scadere si inmultire.
Pp2. O structura contine numele si numarul de selectii ale unui jucator de fotbal.
Definiti un vector continand elemente de acest tip, cititi de la tastatura 5 valori,
apoi afisati in ordine crescatoare dupa numarul de selectii.
Pp3. O structura contine coordonatele (intregi) stanga sus si dreapta jos ale unui
dreptunghi. Se citeste o matrice de dreptunghiuri astfel definite. Afisati
dreptunghiul cu aria maxima.
Pp4. O structura contine numele si data nasterii unei persoane, sub forma an,
luna,zi. Se citeste de la tastatura un vector de elemente de tipul definit anterior.
Sortati crescator dupa varsta, apoi afisat pe ecran.

- 117 -
Introducere in ANSI C++

Capitolul 9 – Functii
Daca pana acum am folosit la scrierea programelor noastre doar functia main,
functie in care am scris tot codul dorit, este evident ca in cazul problemelor
complexe este necesare o impartire in module a programului. Modularizarea poate
fi realizata in C/C++ folosind functii. O functie reprezinta o colectie de declaratii si
instructiuni de sine statatoare care rezolva o anumita subproblema. Vom prezenta
mai departe modul de utilizare a functiilor (prototip, definire, parametri de intrare,
parametri de iesire, valoare returnata, apel) si vom clasifica functiile in functie de
utilizarea lor.

9.1 Generalitati
Forma generala a unui algoritm este urmatoarea:
date de intrare date de iesire
Algoritm

Figura 9.1
Cum o functie modeleaza un algoritm (subalgoritm), forma generala a unei
functii este data de:

date de intrare date de iesire


Functie

Figura 9.2
Inainte de utilizarea unei functii, aceasta trebuie sa fie cunoscuta de catre
compilator. Acest lucru se poate realiza definind functia inainte de locul apelului.
A doua modalitate, folosita in acest material, este folosirea prototipurilor. Un
prototip reprezinta pentru o functie ceva similar declaratiei de variabila pentru o
variabila. Folosind un prototip vom descrie comportamentul functiei, fara a scrie
rezolvarea, altfel spus, vom descrie datele de intrare si cele de iesire din functie.
Forma generala a unui prototip al unei functii asociata algoritmului general din
figura 9.2 este:

- 118 -
Introducere in ANSI C++

tip_returnat nume_functie(lista_parametri);

Numele functie poate fi orice identificator valid. Tipul returnat si lista


parametrilor vor da catalogarea din subcapitolele urmatoare.
Definirea functiei, poate avea loc in orice zona a codului sursa, mai putin in
ainteriorul altei functii. Definirea unei functii este de forma
functie = antet + bloc

sau, pe larg:
tip_returnat nume_functie(lista_parametri){
declaratii si instructiuni
}

Apelul sau utilizarea efectiva a functie are loc sub forma:


nume_functie(lista_parametri);

Pe locul apelului va aparea o valoare de tip tip_returnat;

9.2 Functii care nu primesc si nu returneaza nimic


Forma generala a unei astfel de functii este:

Functie

Figura 9.3
Specificam lipsa valorii returnate folosind tipul de date void.
Prototipurile aasociate acestui caz sunt de forma:
void nume_functie(); sau
void nume_functie(void);

Observam ca, in cazul parametrilor, tipul void poate sa lipseasca. Daca in loc de
tip returnat nu scriem nimic, tipul returnat implicit este int.
Apelul functiei, pentru acest caz, va fi de forma:
nume_functie();

- 119 -
Introducere in ANSI C++

Parantezele de dupa numele functiei nu sunt optionale.

In general acest tip de functii vor afisa ceva pe ecran.


Faptul ca functia nu primeste date de intrare nu ne impiedica sa folosim o serie
de variabile de lucru pentru rezolvarea problemei, variabile declarate in cadrul
blocului functiei.

P1. Realizati o functie care afiseaza un mesaj de intampinare pe ecran.

#include <iostream>
using namespace std;

void Mesaj(void);

int main(){
Mesaj();
}

void Mesaj(){
cout << "*******************" << endl;
cout << "* Bine ati venit! *" << endl;
cout << "*******************" << endl;
}

*******************
* Bine ati venit! *
*******************

P2. Realizati o functie care sterge ecranul prin trecerea la rand nou de 30 de
ori, apoi afisati, folosind o alta functie, un bradulet pe ecran.

- 120 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

void Sterge();
void Bradulet();

int main(){
Sterge();
Bradulet();
}

void Sterge(){
int i;
for(i=1;i<=30;i++) cout << endl;
}

void Bradulet(){
cout << " * " << endl;
cout << " *** " << endl;
cout << " ***** " << endl;
cout << " ******* " << endl;
cout << " | " << endl;
}

    *
   ***
  *****
 *******
    |

9.3 Functii care nu returneaza nimic, dar primesc date de


intrare
Analog cazului anterior acest ip de functii vor afisa de obicei rezultatele pe
ecran. Forma generala este:
date de intrare
Functie

Figura 9.4
Prototipul:
void nume_functie(lista_parametri);

iar apelul:

- 121 -
Introducere in ANSI C++

nume_functie(lista_parametri);

Vom descrie pentru acest caz, pas cu pas, ce se intampla in cazul apelului unei
functii. Fie urmatoare problema:

P3. Realizati o functie care, primind ca parametri doua numere intregi a si b,


afiseaza pe ecran valorile pare din intervalul [a,b].

#include <iostream>
using namespace std;

void afisare(int,int); // prototip

int main(){
afisare(2,7); // apel
}

void afisare(int a, int b){ // antet


int i;
for(i=a;i<=b;i+=2)
cout << i;
}

246

Se observa ca atunci cand scriem prototul functiei se specifica doar tipul


parametrilor de intrare. La scrierea antetului vom da si numele parametrilor de
intrare, nume prin care vor fi accesati acestia in blocul functiei.
Stiva, o zona de memorie speciala in care sunt salvate, in momentul apelului o
serie de informatii despre functia apelata, cum ar fi adresa de revenire, parametri si
variabilele declarate in functie (variabile locale). Avem urmatorii pasi:
Pas 1. Inainte de apel:

Pozitia in program Stiva

int main(){

afisare(2,7); vf

}
Figura 9.5

- 122 -
Introducere in ANSI C++

Pas 2. Apelul (intrarea in functie)

Pozitia in program Stiva

int main(){

afisare(2,7);
} vf ? i
void afisare(int a, int b){ 7 b
2 a
int i;
...
}

Figura 9.5
In momentul apelului, se aloca pe stiva variabilele ce reprezinta parametri de
intrare si variabilele definite in functie. Parametri a si b ai functiei (numiti
parametri formali) vor prelua valorile date la apel (parametri actuali). In cazul in
care apelul are ca parametri expresii, acestea trebuie sa aiba un tip compatibil cu al
parametrilor formali. In acest caz, are loc evaluarea expresiei, rezultatul fiind
atribuit parametrului corespunzator. Acest tip de apel poarta numele de apel prin
valoare.
Pas 3. Inainte de revenire

Pozitia in program Stiva

int main(){

afisare(2,7);
} vf 8 i
void afisare(int a, int b){ 7 b
2 a
int i;
...
}

Figura 9.6

- 123 -
Introducere in ANSI C++

Observam modificarea valorii variabilei locale i, conform instructiunilor


executate.
Pas 4. Revenirea din functie

Pozitia in program Stiva

int main(){

afisare(2,7); vf

Figura 9.7

La iesire din functie, stiva revine la nivelul anterior apelului, iar variabilele
locale si parametri formali dispar.
Programul continua cu prima instructiune de dupa apel.

P4. Realizati o functie care afiseaza un bradulet pe ecran, cu dimensiunea data


de un parametru.

- 124 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

void Bradulet(int);
void Spatii(int);
void Stelute(int);

int main(){
Bradulet(3);
Bradulet(5);
}

void Spatii(int n){


int i;
for(i=1;i<=n;i++) cout << " ";
}

void Stelute(int n){


int i;
for(i=1;i<=n;i++) cout << "*";
}

void Bradulet(int n){


int i;
cout << endl;
for(i=1;i<=n;i++){
Spatii(n-i);
Stelute(2*i-1);
cout << endl;
}
Spatii(n-1); cout << "|" ;
}

  *
 ***
*****
  |
    *
   ***
  *****
 *******
*********
    |

- 125 -
Introducere in ANSI C++

P5. Folosind functii, afisati pe ecran urmatoare piramida de numere:

1
121
12321
....................

#include <iostream>
using namespace std;

void Spatii(int);
void Crescator(int);
void Descrescator(int);
void Piramida(int);

int main(){
Piramida(5);
}

void Piramida(int n){


int i;
for(i=1;i<=n;i++){
Spatii(n-i);
Crescator(i);
Descrescator(i-1);
cout << endl;
}
}
void Crescator(int n){
int i;
for(i=1;i<=n;i++) cout << i;
}
void Spatii(int n){
int i;
for(i=1;i<=n;i++) cout << " ";
}
void Descrescator(int n){
int i;
for(i=n;i>=1;i--) cout << i;
}

    1
   121
  12321
 1234321
123454321

- 126 -
Introducere in ANSI C++

9.4 Functii care nu primesc date de intrare dar returneaza


o valoare
Forma generala este:

date de iesire
Functie

Figura 9.8
Prototipul:
tip_returnat nume_functie(); sau:
tip_returnat nume_functie(void); , 

Valoarea va fi returnata din functie folosind instructiunea return, moment in


care se iese din functie. La revenirea din apel, pe locul apelului "apare" valoarea
returnata. Forma generala a definirii functiei:
tip_returnat nume_functie(){
....
return expresie;
}

unde expresie este convertibil la tip_returnat.


Exemple de apeluri:
var=nume_functie(); // var compatibil cu tip_returnat
if (expresie == nume_functie()) ...
cout << nume_functie();

P6. Realizati o functie care returneaza valoarea lui Pi cu doua zecimale exacte.

- 127 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

float Pi();

int main(){
cout << Pi();
}

float Pi(){
return 3.14;
}

3.14

P7. Realizati o functie care citeste de la tastatura valori intregi (<1000) pana la
intalnirea valorii 1000 si returneza minimul acestor valori.

#include <iostream>
using namespace std;

int max();

int main(){
cout << max();
}

int max(){
int X,mx;

cin >> X; mx=X;


while(X<1000){
if (X>mx) mx=X;
cin >> X;
}

return mx;
}

12 45 29 1000
45

- 128 -
Introducere in ANSI C++

9.5 Functii care primesc un numar oarecare de parametri


de intrare si returneaza o singura valoare
Este probabil cea mai utilizata varianta de functie.
Forma generala:

date de intrare data de iesire


Functie

Figura 9.9
Prototipul:
tip_returnat nume_functie(lista_parametri);

Exemple de apeluri:
var = nume_functie(lista_parametri); sau:
if (nume_functie(lista_parametri)==expresie) sau:
cout << nume_functie(lista_parametri)

Valoarea este returnata din functie prin folosirea instructiunii return. La


intalnirea acestei instructiuni, se revine automat din functie, iar pe locul apelului va
aparea valoarea returnata.

P8. Realizati urmatoarele functii:

• max(a,b)

• modul(a)

• min(a,b,c)

- 129 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

int max(int, int);


int modul(int);
float min(float, float, float);

int main(){
int a,b,c;
float x;
cout << "a="; cin >>a;
cout << "b="; cin >>b;
cout << "c="; cin >>c;

cout << "max(" << a << "," << b << ")=" << max(a,b) <<
endl;

cout << "|"<< a+b+c << "|=" << modul(a+b+c)<< endl;

x=min(float(a)/b , float(b)/c, float(c)/a);


cout << "min=" << x<< endl;
}

int max(int a, int b){


if (a>b) return a;
else return b;
}

int modul(int x){


return (x>0)?x:-x;
}

float min(float x, float y, float z){


if (x<y) return (x<z)?x:z;
else return (y<z)?y:z;
}

a=­6
b=3
c=1
max(­6,3)=3
|­2|=2
min=­2

Observam diferite modalitati de a apela functiile cerute in enunt.

P9. Realizati functiile cu urmatoarele prototipuri:

• int sumac(int); // suma cifrelor unui numar

- 130 -
Introducere in ANSI C++

• int sumadiv(int); // suma divizorilor unui numar

• int primac(int); // prima cifra a unui numar

• int fact(int); // factorialul unui numar

#include <iostream>
using namespace std;

int sumac(int); // suma cifrelor unui numar


int sumadiv(int); // suma divizorilor unui numar
int primac(int); // prima cifra a unui numar
int fact(int); // factorialul unui numar

int main(){
int a,b;
cout << "a="; cin >> a;
cout << "b="; cin >> b;

cout << "sumac(" << a << ")=" << sumac(a) << endl;
cout << "sumadiv(" << a << ")=" << sumadiv(a) << endl;
cout << "primac(" << a << ")=" << primac(a) << endl;
cout << "fact(" << b << ")=" << fact(b) << endl;
}

int sumac(int n){


int S;
S=0;
for(;n>0;n/=10) S+=n%10;
return S;
}
int sumadiv(int n){
int d,S;
S=0;
for(d=1;d<=n;d++)
if (n%d==0) S=S+d;
return S;
}
int primac(int n){
while (n>=10) n=n/10;
return n;
}
int fact(int n){
int i,P;
P=1;
for(i=1;i<=n;i++) P*=i;
return P;
}

a=5123

- 131 -
Introducere in ANSI C++

b=4
sumac(5123)=11
sumadiv(5123)=5280
primac(5123)=5
fact(4)=24

P10. Realizati urmatoarele functii ce returneaza valori logice:

bool prim(int); // verifica daca un numar este prim sau nu

bool perfect(int); // verifica daca un numar este egal cu suma divizorilor sai

#include <iostream>
using namespace std;

bool prim(int);
bool perfect(int);
int sumad(int);

int main(){
int x;
cout << "x="; cin>>x;

if (prim(x)==true) cout << x << " este prim \n";


else cout << x << " nu este prim \n";

if (perfect(x)) cout << x << " este perfect \n";


else cout << x << " nu este perfect \n";

bool prim(int n){


int d;
for(d=2;d<=n/2;d++)
if (n%d==0) return false;
return true;
}
bool perfect(int n){
return sumad(n)==n;
}
int sumad(int n){
int S,d;

for(S=0,d=1;d<=n/2;d++)
if (n%d==0) S+=d;

return S;
}

x=28

- 132 -
Introducere in ANSI C++

28 nu este prim
28 este perfect

P11. Folosind functii, afisati cel mai mare numar prim mai mic ca n (numar
intreg citit de la tastatura).

#include <iostream>
using namespace std;

bool prim(int);
int prim_mic(int);

int main(){
int x;
cout << "x="; cin>>x;

cout << "Cel mai mare numar prim mai mic ca " << x;
cout << " este " << prim_mic(x);
}

bool prim(int n){


int d;
for(d=2;d<=n/2;d++)
if (n%d==0) return false;
return true;
}

int prim_mic(int n){


while(!prim(n)) n--;
return n;
}

x=100
Cel mai mare numar prim mai mic ca 100 este 97

9.6 Functii ce returneaza mai multe valori


Forma generala:

date de intrare date de iesire


Functie

Figura 9.10
Vom prezenta in continuare doua variante de realizare.

- 133 -
Introducere in ANSI C++

O prima varianta este folosirea structurilor. Vom grupa sub numele unei
structuri datele care vor fi returnate de catre functie, iar prototipul va fi de forma:
nume_structura  nume_functie(lista_parametri);

Apelul va fi de forma:
nume_structura var;
....
var = nume_functie(lista_parametri);

Definirea functiei va respecta urmatoarea structura:


nume_structura  nume_functie(lista_parametri){
nume_structura  T;
...
return T;
}

Structura T din cadrul functiei va contine datele de returnat.

P12. Realizati o functie care calculeaza suma si produsul a doua numere reale.

- 134 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

struct doua_numere{
float suma;
float produs;
};

doua_numere sp(float,float);

int main(){
doua_numere a;

a=sp(3,5);
cout << a.suma << " " <<a.produs;
}

doua_numere sp(float a, float b){


doua_numere T;

T.suma=a+b;
T.produs=a*b;

return T;
}

8 15

A doua varianta este folosirea referintelor (2.5). In acest caz, prototipul ca fi de


forma:
void nume_functie(lista_parametri_intrare, lista_parametri_iesire);
sau:
void nume_functie(lista_parametri_intrare_si_iesire);
Apelul:
nume_functie(lista_parametri);

Dupa cum am vazut, transferul parametrilor prin valoare nu duce la modificarea


parametrilor actuali, chiar daca acestia sunt variabile (se lucreaza cu copii pe
stiva). In cazul in care dorim modifiarea lor, vom folosi parametri referinte. In
acest caz, parametrul formal devine un alias al celui actual, medificarea acestuia
modificand de fapt paramatrul actual.

- 135 -
Introducere in ANSI C++

Evident, in acest caz paramatri actuali trebuie sa fie variabile de un tip


compatibil parametrul formal corespunzator. Valorile vor fi deci "returnate" prin
modificarea variabilelor din apel.

P13. Realizati o functie care returnezeaza maximul si minimul a doua valori


intregi.

#include <iostream>
using namespace std;

struct alte_doua_numere{
int min,max;
};
alte_doua_numere sp(int,int);
int main(){
alte_doua_numere a;
a=sp(6,2);
cout << a.min << " " <<a.max;
}
alte_doua_numere sp(int a, int b){
alte_doua_numere T;

T.min=(a<b)?a:b;
T.max= (a+b)-T.min;

return T;
}

2 6

P14. Functie care interschimba doua variabile.

- 136 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

void interschimbare(int& , int&);

int main(){
int a,b;

cout << "a="; cin >>a;


cout << "b="; cin >>b;

interschimbare(a,b);

cout << a << " " << b;


}

void interschimbare(int& a, int& b){


int t;
t=a;a=b;b=t;
}

a=2
b=5
5 2

9.7 Variabile locale si globale. Durata de viata si domeniu


de vizibilitate
Durata de viata a unei variabile reprezinta timpul cat timp aceasta este alocata in
memorie, iar domeniul de vizibilitate este zona in care putem utiliza variabila
respectiva.
Definirea variabilelor in cadrul blocurilor va face ca variabilele sa fie locale
acelui bloc. Chiar daca putem defini variabile in orice bloc, este consacrat ca
variabilele locale sa fie asociate cu blocurile functiilor.
Am vazut ca o variabila locala este alocata pe stiva, apare la intrarea in bloc
(functie) si dispare la iesirea din bloc (functie). Deci durata de viata a unei
variabile locale este din momentul declaratiei si pana la sfarsitul blocului.
Domeniul de vizibilitate este dat de blocul variabilei, mai putin alte blocuri
interioare in care declaram o variabila cu acelasi nume.

P15. Variabile locale (fara folosirea functiilor).

- 137 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

int main(){
int a=11,b=12;

{ int a=5;
cout << a << " " <<b << endl;
// a din bloc si b din blocul main

{ int b=100;
cout << a << " " << b << endl;
// a din blocul exterior si b din blocul interior
}
}

{ int b=6;
cout << a << " " << b << endl;
// b din bloc si a din blocul main
}

5 12
5 100
11 6

Variabilele globale sunt variabile declarate in afara oricarui bloc. Durata de


viata este din momentul declararii si pana la incheierea programului. Domeniu de
vizibilitate este intreg programul, mai putin blocurile in care a fost definita o
variabila locala cu acelasi nume. Totusi, chiar si in cazul in care variabila globala
este "acoperita" de catre una locala cu acelasi nume, putem folosi operatorul scope,
::, pentru a accesa variabila globala din cadrul zonei respective.
In acest caz var va fi variabila locala, iar ::var cea globala.
In general nu este recomandata folosirea variabilelor globale, posibilitatea
modificarii acestora din cadrul oricarei functii putand duce la erori logice (bugs)
greu de depanat.

- 138 -
Introducere in ANSI C++

P16. Variabile locale si variabile globale

#include <iostream>
using namespace std;

int a=2; // variabila globala

void f(){
int a=5; // locala in f
cout << a << " " << ::a << endl;
}

int main(){
int b=100; // locala in main
f();
cout << a << " " << b << endl;
}

5 2
2 100

Folosirea variabilelor globale nu este recomandata, accesibilitatea acesteia din


orice functie putand duce la erori logice greu de depanat. Urmatoarea problema
ilustreaza un astfel de bug datorat folosirii variabilei globale in locul unora locale.
Desi nu vom avea erori de compilare, modificarea variabilei contor din main in
cadrul functiei apelate va duce la o bucla infinita.

P17. La afisarea unei piramide de numere, folosirea variabielor globale poate


duce la erori logice.

Varianta 1 – in cazul folosirii variabilelor locale

- 139 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

// int i; // i declarat global

void Descrescator(int);

int main(){
int i; // i declarat local
for(i=1;i<=4;i++){
Descrescator(i);
cout << endl;
}
}

void Descrescator(int n){


int i; // i declarat local
for(i=n;i>=1;i--) cout << i;
}

1
21
321
4321

Varianta 2 –in cazul folosirii variabilelor globale

#include <iostream>
using namespace std;

int i; // i declarat global

void Descrescator(int);

int main(){
// int i; // i declarat local
for(i=1;i<=4;i++){
Descrescator(i);
cout << endl;
}
}

void Descrescator(int n){


// int i; // i declarat local
for(i=n;i>=1;i--) cout << i;
}

1
1

- 140 -
Introducere in ANSI C++

.... (se intra in bucla infinita)

9.8 Supradefinirea functiilor


C++ permite folosirea a mai multe functii cu acelasi nume. Diferentierea dintre
functii va fi facuta dupa tipul si/sau numarul parametrilor.

P18. Calculati max(a,b,c), folosind max(a,b).

#include <iostream>
using namespace std;

int max(int,int);
int max(int,int,int);

int main(){
cout << max(2,5,1);
}

int max(int a, int b, int c){


return max(max(a,b),c);
}

int max(int a, int b){


return (a>b)?a:b;
}

P19. Alt exemplu de supradefinire a functiilor

- 141 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

void este(int);
void este(float);
void este(char);

int main(){
este(int(123));
este(float(3.14));
este(char('e'));
}

void este(int n){


cout << n << " este un intreg" << endl;
}

void este(float n){


cout << n << " este un real" << endl;
}

void este(char n){


cout << n << " este un caracter" << endl;
}

123 este un intreg
3.14 este un real
e este un caracter

In cazul in care am fi avut apeluri ca in exemplul de mai jos

...........
int main(){
este(123);
este(3.14);
este('e');
}
...........

am fi obtinut erori de compilare de forma:
p19.cpp: In function ‘int main()’:
p19.cpp:14: error: call of overloaded ‘este(double)’ is ambiguous
p19.cpp:6: note: candidates are: void este(int)
p19.cpp:7: note:                 void este(float)
p19.cpp:8: note:                 void este(char)

- 142 -
Introducere in ANSI C++

Deci apelurile in cazul functiilor supradefinite nu au voie sa introduca


ambiguitati, functia care va fi apelata fiind unic determinata in momentul apelului.

9.9 Functii cu parametri impliciti


In cazul in care apelul unei functii se face de obicei cu aceleasi valori, putem
folosi parametri impliciti pentru acea functie. In acest caz, valorile parametrilor
lipsa vor fi date de valorile implicite.
Valorile implicite vor fi specificate in prototip, sub forma:
tip_ret nume_functie(param_neinitializati, param_initializati);

sau:
tip_ret nume_functie(param_initializati);

In momentul apelului, putem omite parametri cu valori implicite, de la dreapta


la stanga.

P20. Functie cu parametri impliciti care afiseaza un interval, cu un pas dat.

#include <iostream>
using namespace std;

void afisare(int a,int b,int pas=1);

int main(){
afisare(1,8,2);
afisare(1,8);// in acest caz ultimul parametru ca fi cel implicit
}

void afisare(int a,int b,int pas){


int i;
for(i=a;i<=b;i+=pas) cout << i << " ";
cout << endl;
}

1 3 5 7
1 2 3 4 5 6 7 8

- 143 -
Introducere in ANSI C++

P21. Functie cu parametri impliciti care calculeaza minimul a maxim patru


valori.

#include <iostream>
#include <values.h>
using namespace std;

int mx(int, int);


int max(int a=-MAXINT,int b=-MAXINT,int c=-MAXINT,int d=-MAXINT);

int main(){
cout << max(5,2) << endl;
cout << max(1,5,8,3) << endl;
}

int mx(int a,int b){


return (a>b)?a:b;
}
int max(int a, int b, int c, int d){
return mx(mx(a,b),mx(c,d));
}

5
8

In cazul in care functia ajutatoare ce calculeaza maximul a doua valori ar fi avut


numele max (supradefinind functia cu parametri impliciti), ar fi existat o
ambiguitate si am fi avut o eroare de forma:
p21.cpp: In function ‘int main()’:
p21.cpp:10: error: call of overloaded ‘max(int, int)’ is ambiguous
p21.cpp:6: note: candidates are: int max(int, int)
p21.cpp:7: note:                 int max(int, int, int, int)

9.10 Parametri vectori


Prototipul ca fi de forma:
tip_returnat nume_functie(tip [], alti_parametri);

Apelul:
nume_functie(Vector, alti_parametri);

De obicei numarul efectiv de valori din vector va fi transmis printr-un alt

- 144 -
Introducere in ANSI C++

parametru.

Parametri nu se aloca pe stiva ca o variabila simpla, deci un vector de lungime


100 nu va ocupa din stiva 100*sizeof(tip) octeti. Transmiterea vectorului va a
vea un comportament analog transmiterii prin referinta, modificarile facute pe
elementele vectorului in cadrul functiei fiind regasite in vectorul cu care s-a apelat
functia.

P22. Functii care realizeaza urmatoarele operatii pe vectori:

• initializare cu valori aleatoare

• citire

• afisare

• suma elementelor

- 145 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

void initializare(int [], int &);


void citire(int [], int &);
void afisare(int [], int);
long suma(int [], int);

int main(){
int a[100],n; // vectorul a de lungime efectiva n
int b[10],m;

initializare(a,n);
afisare(a,n);

citire(b,m);
cout << suma(b,m);
}

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


int i;
cout << "\nn="; cin >> n;
for(i=0;i<n;i++) cin >> a[i];
}

void initializare(int a[], int &n){


int i;
cout << "\nn="; cin >> n;
for(i=0;i<n;i++) a[i]=random()%100;
}

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


int i;
cout << endl;
for(i=0;i<n;i++) cout << a[i] << " ";
}

long suma(int a[], int n){


int i,S;
for(S=i=0;i<n;i++) S+=a[i];
return S;
}

n=3
83 86 77
n=4
1 2 3 4
10

- 146 -
Introducere in ANSI C++

P23. Fie doi vectori reprezentand multimi de valori intregi. Realizati functii care
fac: intersectia, reuniunea, diferenta

#include <iostream>
using namespace std;
void afisare(int [],int);
void intersectia(int [], int, int [], int, int [], int&);
void reuniunea(int [], int, int [], int, int [], int&);
void diferenta(int [], int, int [], int, int [], int&);
bool este(int [],int,int);// verifica daca o valoare este sau nu intr-o
multime

int main(){
int a[]={2,4,8},n=3; // prima multime
int b[]={1,4,8,14},m=4; // a doua multime
int c[10],l;// multimea in care tine rezultatul operatiilor

intersectia(a,n,b,m,c,l); afisare(c,l);
reuniunea(a,n,b,m,c,l); afisare(c,l);
diferenta(a,n,b,m,c,l); afisare(c,l);
}
bool este(int a[],int n,int val){
int i;
for(i=0;i<n;i++)
if (a[i]==val) return true;
return false;
}
void intersectia(int a[], int n, int b[], int m, int c[], int&l){
int i;
l=0;
for(i=0;i<n;i++)
if (este(b,m,a[i])) c[l++]=a[i];
}
void reuniunea(int a[], int n, int b[], int m, int c[], int&l){
int i;
for(i=0;i<n;i++) c[i]=a[i]; // completam prima multime
l=n;
for(i=0;i<m;i++)
if (!este(a,n,b[i])) c[l++]=b[i];
}
void diferenta(int a[], int n, int b[], int m, int c[], int&l){
int i;
l=0;
for(i=0;i<n;i++)
if (!este(b,m,a[i])) c[l++]=a[i];
}
void afisare(int a[], int n){
cout << endl;
for(int i=0;i<n;i++) cout << a[i] << " ";
}

- 147 -
Introducere in ANSI C++

4 8
2 4 8 1 14

9.11 Probleme propuse


Ppx. Reluati toate problemele rezolvate de pana cum, si, acolo unde este posibil,
refaceti rezolvarile folosind functii.

- 148 -
Introducere in ANSI C++

Capitolul 10 – Recursivitate
Numim functie recursiva o functie care se autoapeleaza (direct sau indirect).

10.1 Recursivitatea directa


In cazul in care functia contine in corpul ei un apel la ea insasi vorbim despre
recursivitate directa.
In practica, forma generala a unei functii recursive va fi urmatoarea:
tip_returnat nume_functie(lista_parametri_formali){
if (!conditie_de_oprire){

...
... nume_functie(lista_parametri_actuali)

}

Recursivitatea poate fi utilizată pentru a rezolva elegant multe probleme, dar


funcţiile recursive sunt adesea mai lente decât corespondentele lor nerecursive:

- la fiecare apel depun în stivă valorile parametrilor (dacă există) şi adresa de


revenire (Cap. 9)

- complexitatea algoritmilor recursivi este de obicei mai mare decat a


"fratilor" iterativi.

P1. Sa se realizeze o functie recursiva ce calculeaza n!

1, n = 0
Plecam de la formula recursiva de calcul n!=  .
n ⋅ (n − 1)!, n > 0
Rescriind formula intr-o varianta mai apropiata de implementarea C/C++, avem:

- 149 -
Introducere in ANSI C++

1, n = 0
fact (n) = 
n * fact (n − 1), n > 0
Trecerea la următorul program este naturala:

#include <iostream>
using namespace std;

long fact(int);

int main(){
int n;
cin >> n;
cout << n << "!=" << fact(n);
}

long fact(int n){


if(n==0) return 1; //conditia de oprire
return n*fact(n-1); //apel recursiv: n!=n(n-1)!
}

4
4!=24

La orice funcţie recursivă trebuie precizată o condiţie de ieşire. În problema


factorialului, condiţia de ieşire este 0! care, prin definiţie, este 1. Dacă parametrul
primit de fact este 0, atunci funcţia returnează 1, altfel returnează rezultatul
înmulţirii dintre valoarea parametrului şi factorialul apelat cu valoarea
parametrului minus 1.
Pentru fact(3) avem urmatoarea succesiune de operatii:
(1) calculeaza 3*fact(2), ceea ce duce la primul apel recursiv
(2) calculeaza 2*fact(1) – apel recursiv
(3) calculeaza 1*fact(0) – apel recursiv
(4) returneaza 1 – revenire din fact(0)
(5) returneaza 1 – revenire din fact(1)
(6) returneaza 2 – revenire din fact(2)
(7) returneaza 6 – revenire din fact(3)

- 150 -
Introducere in ANSI C++

Figura 10.1 ilustreaza succesiune de apeluri recursive:

long fact(3){
if(3==0) return 1;
return 3*fact(2);
} vf 3 n

long fact(2){
if(2==0) return 1;

Intrarea in recursivitate
Iesirea in recursivitate

return 2*fact(1);
vf 2 n
}
3 n

long fact(1){
if(1==0) return 1; 1 n
vf 2 n
return 1*fact(0); 3 n
}

long fact(0){ 0 n
1 n
if(0==0) return 1; vf 2 n
return n*fact(n-1); 3 n
}

Figura 10.1

P2. Realizati o functie recursiva care calculeaza 2n.

- 151 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

long doila(int);

int main(){
int n;
cin >> n;
cout << "2^"<< n << "=" << doila(n);
}

long doila(int n){


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

3
2^3=8

P3. Calculati fibo(n) intr-o functie recursiva (cel de-al n-lea termen din sirul
lui Fibonacci). Cate apeluri recursive au avut loc?

#include <iostream>
using namespace std;

long fibo(int);
int nr_apeluri; // retinem numarul de apeluri ale functiei

int main(){
int n;
cin >> n;
nr_apeluri=0;

cout << "fibo("<< n << ")=" << fibo(n) << endl;


cout << "Nr. apeluri:" << nr_apeluri;
}

long fibo(int n){


nr_apeluri++;
if(n<=2) return 1;
return fibo(n-1)+fibo(n-2);
}

6
fibo(6)=8
Nr. apeluri:15

- 152 -
Introducere in ANSI C++

Folosirea variabilei globale a permis contorizarea simpla a intrarilor in functia


recursiva. Numarul mare de apeluri recursive, numar care creste exponential, face
ca aceasta implementare sa nu fie practica.
Urmatoarea aplicatie va folosi faptul ca variabilele locale sunt alocate pe stiva,
iar prin adaugarea de valori apoi scoaterea lor din stiva, acestea isi inverseaza
ordinea.

P4. Inversarea unui text citit de la tastatura folosind o functie recursiva.

#include <iostream>
using namespace std;

void invers();

int main(){
invers();
}

void invers(){
char c;
c=getchar();
if (c!='\n') invers();
cout << c;
}

abcd

dcba

- 153 -
Introducere in ANSI C++

10.2 Recursivitatea indirecta


In cazul in care apelul recursiv se face prin intermediul unei alte functii, numim
acest tip de apel recursivitate indirecta.

P5. Calculati:

f  x , y = x , pentru x≥y
g  x , y−1 , pentru x y
unde

g x , y = xy−5, pentru xy≥5


2∗ f 0, y  , pentru x y5

#include <iostream>
using namespace std;

int f(int,int);
int g(int,int);

int main(){
cout << f(5,20);
}

int f(int x,int y){


if (x>=y) return x;
else return g(x,y-1);
}

int g(int x,int y){


if ((x+y)>=5) return x+y-5;
else return 2*f(0,y);
}

19

- 154 -
Introducere in ANSI C++

10.3 Probleme propuse


Pp1. Realizati o functie recursiva pentru a afisa primii n termeni ai sirului A,
definit ca:
A[n]=3*A[n-1]+2*A[n-2], pentru n>=2
A[0]=A[1]=1
Pp2. Functie recursiva care afiseaza cifrele unui numar.
Pp3. Functie recursiva care descompune un numar in factori primi.
Pp4. Fie un vector de numere intregi pozitive definit global. Realizati o functie
recursiva care calculeaza cmmdc-ul elementelor din vector.
Pp5. Scrieti functii recursive pentru a afisa urmatoare piramida de numere:
1
12
12 3
..........
Pp6. Fie n numar natural citit de la tastatura. Afisati f(n) si g(n), pentru f si g
definite:
f(0)=f(1)=1
g(0)=2, g(1)=1
g(n+2)=5*f(n)-g(n)
f(n+1)=g(n+1)-f(n-1)

- 155 -
Introducere in ANSI C++

Capitolul 11 – Fisiere
Pana acum am citit datele de intrare de la tastatura, iar cele de iesire au fost
afisate pe ecran. Tastatura si ecranul reprezinta dispozitivele standard de intrare,
respectiv iesire.

stdin stdout

Algoritm

Figura 11.1

11.1 Redirectarea intrarii/iesirii


Probabil cea mai simpla posibilitate de a citi date dintr-un fisier, respectiv de a
scrie datele de iesire in altul, este modificare intrarii si iesirii standard. In acest caz,
cin si cout, vor accesa de fapt fisierele care au devenit intrari si iesiri standard.

Vom avea ceva de forma:

stdin stdout

35 Suma:
9 12 Algoritm 29

Figura 11.2
Functia care permite redirectarea stdin si stdout este freopen.
Pentru redirectarea intrarii avem:
freopen(nume_fisier, "r",stdin);

Dupa executarea functiei, intrarea standard va fi nume_fisier.


Pentru redirectarea iesirii avem:
freopen(nume_fisier, "w",stdout);

Dupa executarea functiei, iesirea standard va fi nume_fisier.

- 156 -
Introducere in ANSI C++

P1. Fisierul "intrare.txt" contine numere 2 numere intregi. Scrieti in fisierul


"iesire.txt" suma acestor doua numere.

#include <iostream>
using namespace std;

int main(){
int a,b;

freopen("intrare.txt","r",stdin);
freopen("iesire.txt","w",stdout);

cin >> a >> b;


cout << a+b;
}

intrare.txt: 2 5
iesire.txt: 7

P2. Se citeste de la tastatura numele unui fisier care contine 10 numere intregi.
Afisati pe ecran suma lor.

#include <iostream>
using namespace std;

int main(){
int x,i,S;
char FileName[20];
cout << "Dati fisierul de intrare:"; cin >> FileName;

freopen(FileName,"r",stdin);

S=0;
for(i=1;i<=10;i++){
cin >> x;
S += x;
}

cout << S;
}

Dati fisierul de intrare:intrare.p02
55

- 157 -
Introducere in ANSI C++

11.2 Fluxuri de intrare/iesire


C++ pune la dispozitie fluxurile fisier ifstream (pentru date de intrare) si
ofstream (iesire). ifstream si ofstream sunt clase definite in biblioteca fstream si
permit declararea unor variabile care vor fi asociate cu fisierele cu care dorim sa
lucram. Declaratiilor vor fi de forma:
ifstream flux_intrare; sau:
ifstream flux_intrare(nume_fisier);

respectiv:
ofstream flux_iesire; sau:
ofstream flux_iesire(nume_fisier);

In cazul in care se specifica un nume de fisier, acel fisier va fi deschis in mod


automat si va fi accesibil prin intermediul variabilei flux_iesire sau
flux_intrare.

Daca nu, sau daca dorim, la nu moment dat sa schimbat fiserul asociat cu o
anumita variabila flux, folosim apeluri de forma:
flux.open(nume_fisier);

In acest moment, daca fluxul este de intrare, fisierul este deschis si este
pozitionat la inceput, iar daca este de iesire, fiserul este deschis si eventualele date
existente sunt sterse.
Accesul la fluxuri de va face analog lucrului cu cin si cout, folosind operatorii
>> si <<:
flux_intrare >> variabila;
flux_iesire << expresie;

Citirea unei variabile va fi incheiata la intalnirea unui caracter alb (spatiu, enter,
tab), iar caracterele albe dintre doua variabile consecutive citite vor fi ignorate.
Daca dorim citirea unui sir de caractere, inclusiv spatii, vom folosi:
flux_intrare.getline(sir, nr);

Mai sus sir va fi sirul de caractere in care va fi realizata citirea, iar nr reprezinta
numarul maxim de caractere care va fi citit.

- 158 -
Introducere in ANSI C++

P3. Fisierul "intrare.txt" contine numere 2 numere intregi. Scrieti in fisierul


"iesire.txt" suma acestor doua numere. (identic cu P1, dar rezolvare cu fluxuri)

#include <fstream>
using namespace std;

int main(){
int a,b;
ifstream fin("intrare.txt");
ofstream fout("iesire.txt");

fin >> a >> b;


fout << a+b;
}

intrare.txt: 2 5
iesire.txt: 7

P4. Fisierul "intrare.p04" contine 5 nume de persoane, date pe cate un rand sub
forma nume prenume. Afisati pe ecran persoanele care au numele de patru
caractere.

#include <fstream>
#include <iostream>
using namespace std;

int main(){
int i;
char nume[20], prenume[20];
ifstream f("intrare.p04");

for(i=1;i<=5;i++){
f >> nume >> prenume;
if (strlen(nume)==4)
cout << nume << " " << prenume << endl;
}

intrare.p04: Voinea Mircea
 Tica Silviu
 Toth Haralambie
 Ion Ion
 Gheorghe Gheorghe
ecran:
Tica Silviu

- 159 -
Introducere in ANSI C++

Toth Haralambie

11.3 Citirea unui numar cunoscut de valori dintr-un fisier


La multe probleme, enuntul va da ca fiserul de intrare un fisier in care, ca prima
valoare se va da numarul de valori care vor fi citite ulterior din fisier. In acest caz,
avem urmatoarea abordare:

flux_intrare >> Nr_valori;
for(i=1;i<=Nr_valori;i++){
flux_intrare >> X;
foloseste(X);
}

P5. Fisierul "numere.p05" contine, pe primul rand un numar intreg n, iar pe


urmatorul separat de cate un spatiu, n numere reale. Scrieti numere in alt fisier, in
ordine crescatoare, cate 5 pe un rand.

#include <fstream>
using namespace std;

int main(){
int i,n,x;
ifstream fin("numere.p05");
ofstream fout("iesire.p05");

fin >> n;
for(i=1;i<=n;i++){
fin >> x;
fout << x << " ";
if (i%5==0) fout << endl;
}

numere.p05
8
1 2 3 4 1 2 3 4
iesire.p05
1 2 3 4 1 
2 3 4 

- 160 -
Introducere in ANSI C++

P6. Fisierul "matrice.txt" contine, pe primul rand un numar intreg n, iar pe


urmatorele n randuri cate n numere intregi care vor forma informatii dintr-o
matrice scrisa pe linii. Afisati pe ecran matricea.

#include <fstream>
#include <iostream>
using namespace std;

int main(){
int i,j,n,x,a[10][10];
ifstream f("matrice.txt");

f >> n;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
f >> a[i][j];

for(i=0;i<n;i++){
for(j=0;j<n;j++)
cout << a[i][j] << " ";
cout << endl;
}
}

matrice.txt
3
1 2 3
4 5 6
7 8 9
ecran
1 2 3
4 5 6
7 8 9

11.4 Citirea pana la sfarsitul fisierului


Daca fluxul a ajuns la sfarsit sau daca a avut loc o eroare la citirea unei valori
din flux, atunci o instructiunea flux_intrare >> var; returneaza NULL.
Folosindu-ne de aceasta vom avea:

while (flux_intrare >> X)
foloseste(X);

- 161 -
Introducere in ANSI C++

O alta varianta implica testarea sfarsitului de fisier folosint functia:


flux_intrare.eof()

Aceasta functie va returna true daca s-a ajuns la sfarsitul fluxului si false in caz
contrar. Vom avea:

while (!flux_intrare.eof()){
flux_intrare >> X;
foloseste(X);
}

P7. Se citeste numele unui fisier text de la tastatura. Realizati o copie a acestuia

in fiserul "copie.txt".

#include <fstream>
#include <iostream>
using namespace std;

int main(){
ifstream f;
ofstream g("copie.txt");
char FileName[20],linie[250];
cout << "Dati numele fisierului:"; cin >> FileName;

f.open(FileName);
while(!f.eof()){
f.getline(linie,250);
g << linie << endl;
}
}

P8. Fie fisierul "intrare.p08". Scrieti in fisierul "frecv.p08" caracterele care


apar in fiserul de intrare si de cate ori apar ele.

- 162 -
Introducere in ANSI C++

#include <fstream>
using namespace std;

int main(){
ifstream f("intrare.p08");
ofstream g("frecv.p08");
char S[100];
int ct[256],i;

for(i=0;i<256;i++) ct[i]=0;

while(!f.eof()){
f.getline(S,100);
for(i=0;S[i];i++) ct[S[i]]++;
}

for(i=0;i<256;i++)
if (ct[i]) g << char(i) << " " << ct[i] << endl;
}

intrare.p08
abc abc
abc dede
ffffffffff
frecv.p08
  2
a 3
b 3
c 3
d 2
e 2
f 10

- 163 -
Introducere in ANSI C++

11.5 Probleme propuse


Pp1. Un fisier contine nu text in limba engleza. Contorizati literele mici care
apar in text, apoi afisati literele mici din ext, in ordine crescatoare dupa frecvente.
Pp2. Verificati daca n fisiere citite de la tastatura sunt identice ca si continut.
Pp3. Numarati cuvintele dintr-un fiser text. Separatorii dintre cuvinte sunt Enter,
‘,’ si ‘.’.
Pp4. Un fisier contine numere intregi. Scrieti numerele pare intr-un fiser si cele
impare in altul.
Pp5. Cititi o matrice dintr-un fisier. Scrieti inversa matricii in alt fisier.
Pp6. Inversati liniile unui fisier text al carui nume este citit de la tastatura,
scriind rezultatul in alt fisier.

- 164 -
Introducere in ANSI C++

Capitolul 12 – Pointeri
Accesul la o locatie de memorie folosita de program este realizata printr-o
adresa unica. Un pointer este o variabila care contine o adresa de memorie.

12.1 Declaratie si operatii elementare


La declararea unei variabile, acesteia i se asociaza o locatie de memorie.
Determinarea adresei la care se gaseste o variabila se face folosind operatorul &.
&variabila = "adresa la vare este memorata variabila"

In cazul in care avem o constructie de forma &variabila, acesta poate insemna:

– o referinta, daca apare in context de declaratie de variabila

– adresa unei variabile, daca este o instructiune (nu o declaratie)


Pentru a putea lucra direct cu adresele de memorie declaram pointeri:
tip *pointer1, *pointer2, ..., pointern;

unde tip este un tip de data oarecare (int, float, tip definit de utilizator, etc.).
Pentru a utiliza valoarea care este memorata intr-o locatie indicata de un
pointer, se foloseste operatorul de redirectare *.
Semnul * poate sa insemne:

– declaratie de pointer, daca apare in context de declaratie

– valoarea care se gaseste la adresa indicata de un pointer, in context de


instructiune
Prin simpla declaratie a unui pointer, valoarea acestuia nu este initializata,
pointerul indicand o zona de memorie oarecare. Acest tip de pointer se numeste
pointer liber, iar folosirea acestuia inainte de initializare poate avea rezultate
dezastruoase (nu poate folosi nimanui modificarea unei zone oarecare de
memorie!).

- 165 -
Introducere in ANSI C++

In cazul in care dorim sa specificam ca un pointer nu indica o adresa valida vom


folosi constanta NULL.
p=NULL; // initializarea pointerului nul

Conditia de testarea daca un pointer este valid va fi:


if (p!=NULL) ... sau, echivalent:
if (p) ...

Observam ca pointerii liberi vor aparea ca pointeri valizi!


Exista posibilitatea de a initializa un pointer la declarare, cu NULL sau cu
adresa unei variabile anterior declarate:
int *p=NULL;
int *q=&var;  

P1. Operatii elementare cu pointeri

#include <iostream>
using namespace std;

int main(){
int a=1,b=2; // declararea variabilelor intregi a si b
int &copie_a = a; // copie_a este un alias al lui a
int *p,*q; // declararea pointerilor la intregi p si q

cout << p << endl;// afisarea unui pointer liber!!!

p=&a; // p contine adresa lui a


*p=*p+10; // a=a+10

q=&b; // q contine adresa lui b


++(*q); // ++b;

cout << &p << " " << &q << endl;
cout << &a << " " << p << " " << &b << " " << q<< endl;
cout << a << " " << *p << " " << b << " " << *q;
}

0x8048906
0xbff9eefc 0xbff9eef8
0xbff9ef04 0xbff9ef04   0xbff9ef00 0xbff9ef00
11 11   3 3

La rulari succesive adresele afisate pot sa difere.

- 166 -
Introducere in ANSI C++

Starea memoriei in cazul problemei P1 poate fi urmatoarea:


1. Dupa declaratii:
copie_a
q p b a
... ? 0x8048906 2 1 ...
0xbff9eef8 0xbff9eefc 0xbff9ef00 0xbff9ef04
Figura 12.1
Observam ca p indica o adresa oarecare din memorie, variabilele a si b sunt
initializate, a si copie_a sunt de fapt una si aceeasi variabila.
2. Dupa atribuiri:
copie_a
q p b a
... 0xbff9ef00 0xbff9ef04 3 11 ...
0xbff9eef8 0xbff9eefc 0xbff9ef00 0xbff9ef04

Figura 12.2
In acest moment, pointerii p si q vor avea valori valide, modificarea locatiilor de
memorie indicate ducand la modificarea valorii variabilelor a si b.
Desi pointerii se comporta similar unor variabile obisnuite (au o adresa asociata
in memorie, contin valori etc.), in urmatoarele figuri in care vor mai aparea
pointeri, acestia vor fi desenati ca in Figura 12.3, pentru a creste claritatea.

copie_a
b a
... 3 11 ...

q p

Figura 12.3
Incercarea de a asocia pointeri de un anumit tip cu adresele unor variabile de
tipuri diferite va duce la erori de compilare.

- 167 -
Introducere in ANSI C++

P2. Tipul indicat de un pointer

#include <iostream>
using namespace std;

int main(){
int a,*p; // intreg si pointer la int
double b,*q; // intreg si pointer la double

p=&a;
q=&b;

// p=&b; // aceste atribuiri nu sunt valide


// q=&a;

In cazul in care vom scoate comentariile, ultimelPointeri void si utilizarea lore


doua atribuiri vor da urmatoarele erori:
p02.cpp: In function ‘int main()’:
p02.cpp:13: error: cannot convert ‘double*’ to ‘int*’ in assignment
p02.cpp:14: error: cannot convert ‘int*’ to ‘double*’ in assignment

O categorie aparte de pointeri sunt pointerii void:


void *pointer;

La prima vedere, acest tip de pointer pare sa aiba un grad de utilizare redus. Cu
toate acestea, in combinatie cu operatorul de conversie explicita de tip (cast), ofera
o flexibilitate crescuta aplicatiilor noastre. Acest tip de pointer va putea indica
zone de memorie de dimensiune variabila (dimensiune data in cazul altor pointeri
de tipul de data indicat), ceea ce va duce la urmatoarea problema: dereferentierea
nu va putea fi facuta direct, fiind obligatoriei folosirea operatorului cast pentru a
specifica tipul indicat in acel moment de pointerul void.

P3. Pointerii void si modul lor de utilizare

- 168 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

int main(){
int i=1;
double d=12.34;
char c='a';
void *p;

cout << i << " " << d << " " << c << endl;

p=&i;
(*(int *)p)++;

p=&d;
(*(double *)p) = (*(double *)p)*3;

p=&c;
(*(char *)p) = 'b' ;

cout << i << " " << d << " " << c;
}

1 12.34 a
2 37.02 b

Vom explica mai departe urmatoarea expresie: (*(int *)p)++.


Pointerul p este de tip void, deci ca prim pas trebuie sa specificam tipul spre
care pointeaza, in cazul nostru int:
(int *)p

Pentru a accesa zona de memorie vom dereferentia pointerul de mai sus:


*(int *)p sau *((int *)p)

La sfarsit, aplicam operatorul de incrementare, efectul fiind incrementarea


intregului indicat de pointerul p:
(*(int *)p)++

O situatie aparte o reprezinta pointerii la pointeri, urmatoarea aplicatiei ilustrand


un astefel de caz.

- 169 -
Introducere in ANSI C++

P4. Pointeri la pointeri.

#include <iostream>
using namespace std;

int main(){
int i=123;

int *p; // pointer la int


int **q; // pointer la pinter la int
int ***t; // pointer la pointer la pointer la int :)

p=&i;
q=&p;
t=&q;

cout << i << " " <<***t;


}

123 123

Situatia din problema anterioara este descrisa in Figura 12.4.


i
t q p 123

Figura 12.4

12.2 Aritmetica pointerilor


In subcapitolul anterior am folosit operatori de referentiere/dereferentiere pentru
a lucra cu pointeri. In C++ exista o serie de alte operatii specifice lucrului cu
variabile de tip pointer.

12.2.1 Atribuirea
Operatorul = se comporta analog atribuirii dintre doua variabile oarecare. O
Expresie de forma:
p1 = p2 = ... = pn

va face ca pointerii p1, p2, ... , pn sa indice toti locatia de memorie indicata
initial de pn.

- 170 -
Introducere in ANSI C++

123 123
? ?

p1 p2 ... pn p1 p2 ... pn
Figura 12.5
Pointerii care apar in expresia de atribuire trebuie sa fie de acelasi tip. O situatie
aparte apare in cazul in care utilizam pointeri void, acestia putand retine valoarea
oricaror pointeri, indiferent de tipul lor de baza.

P5. Atribuirea pointerilor

#include <iostream>
using namespace std;

int main(){
int i=123;

int *p1,*p2,*p3;
double *p4;
void *pv;

p3=&i;

p1=p2=p3;
pv=p1; // atribuire corecta
// p4=p1; // eroare la compilare (pointerii nu au acelasi tip)

cout << i << " " << *p1 << " " << *p2 << " ";
cout << *p3 << " " << *((int *)pv);
}

123 123 123 123 123

12.2.2 Operatorii relationali


Operatorii ==, !=, < , >, <=, >= pot fi folositi cu operanzi pointeri. Primii
doi operatori verifica daca doi pointeri indica sau nu aceeasi locatie de memorie,
iar ultimii verifica daca un pointer indica o locatie de memorie mai mica sau mai
mare fata de alt pointer. In general expresii relationale apar intre pointeri care
indica acelasi obiect in memorie (vezi 12.5).

P6. Afisati locatia cea mai mica si locatia cea mai mare de memorie alocate in

- 171 -
Introducere in ANSI C++

program.

#include <iostream>
using namespace std;

int main(){
double a;
int b;
int *q;
void *p, *pmic, *pmare;

cout << &a << " "<< &b << " "<< &q << " ";
cout << &p << " "<< &pmic << " "<< &pmare << endl;

pmic=pmare=&a;

q=&b;
if (pmic<q) pmic=q; // comparatie dintre doi pointer
de tipuri diferite
if (pmare>=q) pmare=q;

p=&q; pmic=(p<pmic)?p:pmic; pmare=(p>pmare)?p:pmare; //


comparatie dintre pointeri de acelasi tip

p=&p; pmic=(p<pmic)?p:pmic; pmare=(p>pmare)?p:pmare; //


p indica p !!!

pmic=(&pmic<pmic)?p:pmic; pmare=(&pmic>pmare)?&pmic:pmare;
// comparatie dintre un pointer si o referentiere

p=&pmare; pmic=(p<pmic)?p:pmic; pmare=(p>pmare)?p:pmare;

cout << pmic << " " << pmare;

// if (p>0x10000); // comparatie dintre un


pointer si un intreg (eroare)

0xbff6f618 0xbff6f614 0xbff6f610 0xbff6f60c 0xbff6f608 0xbff6f604
0xbff6f604 0xbff6f614

Observatii:

– in program am alocat variabile de 4 tipuri diferite, deci e obligatorie


folosirea pointerilor void

– pointerii sunt alocati in memorie ca orice alta variabila; adresa cea mai
mica este data de pointerul in care retinem adresa cea mai mare :)

- 172 -
Introducere in ANSI C++

– putem compara direct un pointer si adresa unei variabile oarecare

12.2.3 Scaderea si adunarea cu un intreg


Operatiile de scadere si de adunare dintre un pointer vor "deplasa" pointerul in
memorie inapoi sau inainte fata de pozitia initiala, in functie de tipul de baza al
pointerului. Acest tip de operatii nu vor putea avea ca operanzi pointeri void.
tip *p;
p++ ; // p indica urmatoarea locatie de memorie de tipul dat
p­­;  // p indica locatia de memorie anterioara de tipul dat
p = p + i; // p "sare" spre dreapta in memorie cu i pozitii 
q = p ­ i; // q indica la stanga lui p cu i pozitii 

Practic, valoarea efectiva cu care se modifica pointerul la aceste operatii este un


multiplu de sizeof(tip). Este permisa folosirea formelor scurte de atribuire += si
­=.

P7. Adunarea si scaderea dintre un pointer si un intreg

#include <iostream>
using namespace std;

int main(){
int a,b;
int *p=&a,*q=&b;

cout << p << " " << q << endl;

p++;
q=q+10;
cout << p << " " << q << endl;

--p;
q-=10;
cout << p << " " << q << endl;

0xbfcb90ac 0xbfcb90a8
0xbfcb90b0 0xbfcb90d0
0xbfcb90ac 0xbfcb90a8

- 173 -
Introducere in ANSI C++

Pentru exemple utile vezi 12.5.

12.2.4 Diferenta a doi pointeri


Daca p si q sunt doi pointeri cu acelasi tip de baza (diferit de void) operatia:
p­q

returneaza un intreg si va da numarul de obiecte de tipul indicat de p si q care se


gasesc intre cei doi pointeri (vezi 12.5 pentru exemple).

12.3 Alocarea dinamica a memoriei


Pana in acest moment, toate programele noastre au folosit variabile alocate
static. Variabilele globale sunt alocate in momentul compilarii si cele locale sunt
alocate pe stiva la rulare, in ambele cazuri cunoscandu-se exact cantitatea de
memorie necesara. In situatiile in care cantitatea de memorie necesara alocarii
datelor cu care lucram nu este cunoscuta decat in timpul rularii se folosesc functii
de alocare/dealocare dinamica a memoriei.
C++ ofera operatorii new si delete pentru a aloca dinamic memoria.
new tip - aloca o zona de memorie de dimensiune sizeof(tip) si returneaza un
pointer la zona alocata, respectiv NULL daca nu s-a putut realiza
alocarea
delete p  - dealoca o zona de memorie indicata de un pointer, de dimensiunea
tipului de baza a pointerului p
In general, alocarea dinamica trebuie facuta intr-o constructie de forma:
if (p=new tip){
foloseste p
delete p;
}
else 
trateaza eroarea la alocare

- 174 -
Introducere in ANSI C++

P8. Alocarea dinamica a memoriei

#include <iostream>
using namespace std;

int main(){
int *p,*q;

if ((p= new int) && (q= new int)){

cin >> *p >> *q;


cout << *p << "+" << *q << "=" << *p+*q;

delete p; delete q;
}
else
cout << "Eroare la alocare!";
}

2
3
2+3=5

Pentru a aloca/dealoca mai multe obiecte de acelasi tip, se pot folosi


urmatoarele forme ale operatorilor new si delete (vezi 12.5 pentru exemple):
p = new tip[nr] - aloca o zona de memorie de dimensiune sizeof(tip)*nr si
returneaza un pointer la zona alocata, respectiv NULL daca
nu s-a putut realiza alocarea
delete [] p  - dealoca zona de memorie alocata anterior

12.4 Pointeri la structuri


O situatie relativ speciala este cazul in care tipul de baza al unui pointer este o
structura. In acest caz este introdus operatorul ­>, urmatoarele doua notatii fiind
echivalente pentru p un pointer la o structura:
(*p).membru
p­>membru

P9. Folosirea pointerilor la structuri.

- 175 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

struct complex{
float re,im;
};

int main(){
complex z,*p;
z.re=2; z.im=-1;

p=&z;

cout << "z= " << (*p).re << char((p->im<0)?' ':'+');


cout << p->im << "*i";
}

z= 2 ­1*i

12.5 Legatura dintre pointeri si tablouri

12.5.1 Accesul la elementele unui tablou folosind pointeri


In C si in C++ numele unui tablou este un pointer constant la primul element al
tabloului. Deci, in cazul declaratiei:
int A[10];

A este un pointer la primul intreg din vector. Faptul ca A este un pointer constant
implica faptul ca acesta nu va putea fi modificat in program. Figura 12.6 ilustreaza
o situatie posibila in memorie in cazul declaratiei anterioare.

10 intregi
? ? ? ? ? ... ?

A
Figura 12.6
A fiind un pointer, *A va reprezenta valoarea primului element, notatiile A[0] si
*A fiind echivalente. Folosind aritmetica pointerilor si faptul ca A este pointer la
primul element, accesul la elementele tabloului va putea fi realizat intr-o varietate
de forme, ca in Figura 12.7:

- 176 -
Introducere in ANSI C++

10 intregi
? ? ? ? ? ... ?

*A A[1] *(A+2) *(3+A) 4[A]


Figura 12.7

P10. Diferite modalitati de acces la elementele unui tablou

#include <iostream>
using namespace std;

int main(){
int A[10]={11,12,13,14,15,16};
int *p;
p=A+5;

cout << "A:" << *A << " " << A[1] << " ";
cout << *(A+2) << " " << *(3+A) << " ";
cout << 4[A] << " " << *p << " ";

A:11 12 13 14 15 16 

Parcurgerea unui tablou A, de lungime n, se poate face fara a folosi notatia


indexata folosind urmatoarea schema generala:

for(p=A;p­A<n;p++)
foloseste(*p);

O alta variantaimplica pozitionarea unui pointer pe pozitia imediat urmatoare


ultimului element din tablou si folosirea acestui pointer la verificarea sfarsitului de
vector:

sf=A+n; // sau sf=&A[n];
for(p=A;p<sf;p++)
foloseste(*p);

P11. Impementati functiile de initializare random, de citire si de afisare a


vectorilor fara a folosi notatia indexata.

- 177 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

void init(int [], int);


void citeste(int [], int &);
void afiseaza(int [], int);

int main(){
int A[10],n;
int B[10],m;

n=5;
init(A,n);
citeste(B,m);

afiseaza(A,n);
afiseaza(B,m);
}

void init(int A[], int n){


int *p;
for(p=A;p-A<n;p++)
*p=rand()%10;
}

void citeste(int A[], int &n){


int *p, *sf;

cout << "n="; cin >> n;

sf=A+n;
for(p=A;p<sf;p++)
cin >> *p;
}

void afiseaza(int A[], int n){


int i;
for(i=0;i<n;i++)
cout << *(A+i) << " ";
cout << endl;
}

n=3
10 20 30
3 6 7 5 3
10 20 30

- 178 -
Introducere in ANSI C++

12.5.2 Alocarea dinamica a tablourilor

Pnetru a aloca un vector abia dupa ce cunoastem numarul exact de elemente,


folosim urmatoarea schema generala, A fiind un pointer la tip:

cin >> n;
A= new tip[n];
foloseste(A,n);
delete []A;

Accesul la elementele vectorului poate fi facut indexat sau folosind pointeri.

P12. Fie un vector alocati dinamic si initializat cu valorile 0 si 1. Mutati valorile


de 0 la inceput si cele de 1 la sfarsitul vectorului.

- 179 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

void init(int [], int);


void rezolva(int [], int &);
void afiseaza(int [], int);

int main(){
int *A,n;

cout << "n="; cin >> n;


A=new int[n];

init(A,n);
afiseaza(A,n);
rezolva(A,n);
afiseaza(A,n);

delete []A;
}

void init(int A[], int n){


int i;
for(i=0;i<n;i++) A[i]=rand()%2;
}

void rezolva(int A[], int &n){


int *st, *dr;
st=A; dr=A+n-1;
while(st<dr){
while ((st<dr)&&(*st==0)) st++;
while ((st<dr)&&(*dr==1)) dr--;
if (st<dr){*st=0; *dr=1;}
}
}

void afiseaza(int A[], int n){


int i;
for(i=0;i<n;i++) cout << A[i] << " ";
cout << endl;
}

n=10
1 0 1 1 1 1 0 0 1 1
0 0 0 1 1 1 1 1 1 1

- 180 -
Introducere in ANSI C++

12.5.3 Vectori de pointeri


Declararea unui vector de pointeri se face similar declaratiei unui vector de un
tip oarecare:
tip *Vector[N];

unde N este o constanta de tip intreg.


In acest caz, Vector[0], Vector[1],... Vector[n­1] vor fi pointeri spre tip.
Fie urmatoarea declaratie de matrice:
int A[10][10];

Pe exemplul dat, A[0] va fi un pointer la primul element al vectorului ce


reprezinta prima linie a matricii. Analog, A[i] este un pointer spre linia i a matricii.

A[0] A[0][0] A[0][1] A[0][2] ... A[0][9]

A[1] A[1][0] A[1][1] A[1][2] ... A[1][9]


...

...

...
...

A[9] A[9][0] A[9][1] A[9][2] ... A[9][9]

Figura 12.8

P13. Fie o matrice patratica de intregi initializata random. Sortati crescator


fiecare linie a matricii.

- 181 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

int init(int [10][10], int &);


int afis(int [][10], int);
int sort(int [], int);

int main(){
int A[10][10],n,i;

init(A,n);
afis(A,n);

for(i=0;i<n;i++) sort(A[i],n);

cout << endl; afis(A,n);


}
int init(int A[10][10], int &n){
int i,j;
n=4;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
A[i][j]=rand()%10;
}
int afis(int A[][10], int n){
int i,j;
for(i=0;i<n;i++){
cout << endl;
for(j=0;j<n;j++)
cout << A[i][j] << " ";
}
}
int sort(int A[], int n){
int i,j,t;
for(i=0;i<n-1;i++)
for(j=i+1;j<n;j++)
if (A[i]>A[j]){ t=A[i]; A[i]=A[j]; A[j]=t; }
}

3 6 7 5
3 5 6 2
9 1 2 7
0 9 3 6

3 5 6 7
2 3 5 6
1 2 7 9
0 3 6 9

- 182 -
Introducere in ANSI C++

Un caz in care folosirea vectorilor de pointeri se dovedeste utila este cazul in


care lucram cu matrici de caractere.

P14. Fie o matrice de caractere initializata cu zilele saptamanii. Afisati zilele in


ordine lexicografica.

#include <iostream>
#include <string>
using namespace std;

void afis(char [7][10]);


void inter(char *, char *);
void sort(char [7][10]);

int main(){
char Zi[7][10]={"luni", "marti", "miercuri", "joi",
"vineri", "sambata", "duminica"};

afis(Zi);
sort(Zi);
afis(Zi);

void afis(char Zi[7][10]){


for(int i=0;i<7;i++) cout << Zi[i] << " ";
cout << endl;
}

void inter(char *s1, char *s2){


char t[10];
strcpy(t,s1); strcpy(s1,s2); strcpy(s2,t);
}

void sort(char Zi[7][10]){


int i,j;
char t[10];
for(i=0;i<6;i++)
for(j=i+1;j<7;j++)
if (strcmp(Zi[i],Zi[j])>0) inter(Zi[i], Zi[j]);
}

luni marti miercuri joi vineri sambata duminica
duminica joi luni marti miercuri sambata vineri

- 183 -
Introducere in ANSI C++

12.6 Legatura dintre pointeri si functii


In C/C++ avem posibilitatea de a transmite parametri de tip pointer unei functii,
de a returna pointeri din functie si de a defini un pointer la o functie. Acesta ultima
facilitate va permite apelul functiei folosind pointerul si ofera posibilitatea de a
transmite parametri de tip functie.

12.6.1 Functii cu parametri pointeri


Prototipul unei functii care are ca parametri pointeri este de forma:
tip_returnat nume_functie(..., tip*, ...);

La apel, parametrul efectiv corespunzator parametrului formal pointer trebuie sa


fie un pointer care acelasi tip de baza, mai putin situatia in care tip este void. 
Parametrul pointer se comporta ca orice alt tip de parametru. El va fi alocat pe
stiva (e variabila locala), dar in general utilizarea pointerului in cadrul functiei se
va face in varianta dereferentiata. Folosirea pointerilor sau a referintelor, in cazul
in care dorim modificarea unor parametri in cadrul unei functii va conduce la un
rezultat similar. Urmatoarele doua definitii de functii sunt echivalente:
tip_returnat nume_functie(..., tip *p, ...){
foloseste(*p);
}

si
tip_returnat nume_functie(..., tip &p, ...){
foloseste(p);
}

In cazul in care se doreste modificare pointerului (nu a valorii indicate de catre


acesta) se va folosi o referinta la pointer:
tip_returnat nume_functie(..., tip*&, ...);

P15. Functie care realizeaza interschimarea a doua variabile de tip intreg,


folosind parametri pointeri.

- 184 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

void inter(int *, int *);

int main(){
int x=1,y=2;
cout << x << " " << y << endl;

inter(&x,&y);
cout << x << " " << y << endl;
}

void inter(int *a, int *b){


int t;
t=*a; *a=*b, *b=t;
}

1 2
2 1

Observam ca apelul trebuie facut cu adresele variabilelor de interschimbat!

P16. Functie care interschimba doi pointeri la int.

#include <iostream>
using namespace std;

void inter(int *&, int *&);

int main(){
int x=1,y=2;
int *p=&x, *q=&y;

cout << *p << " " << *q << endl;

inter(p,q);
cout << *p << " " << *q << endl;
}

void inter(int *&a, int *&b){


int *t;
t=a; a=b; b=t;
}

1 2
2 1

Daca nu am fi folosit referinte la pointeri interschimarea ar fi avut loc doar in

- 185 -
Introducere in ANSI C++

cadrul functiei. Urmatoarea varianta este echivalenta.

P17. Functie care interschimba doi pointeri la int (varianta 2).

#include <iostream>
using namespace std;

void inter(int **, int **);

int main(){
int x=1,y=2;
int *p=&x, *q=&y;

cout << *p << " " << *q << endl;

inter(&p,&q);
cout << *p << " " << *q << endl;
}

void inter(int **a, int **b){


int *t;
t=*a; *a=*b; *b=t;
}

1 2
2 1

Un caz de transmitere de pointer a fost discutat anterior, in 9.10. Am stabilit ca


numele unui vector este un pointer la primul sau element, deci tranmiterea acestui
nume este un caz particular e tranmitere de parametru pointer.

P18. Realizati o functie care, primind ca parametri doi vectori alocati static si
lungimile acestora, realizeaza interschimbarea lor (ca si continut).

- 186 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

void inter(int [], int &, int [], int *);


void copiaza(int [], int &, int [], int);
void afis(int [], int );

int main(){
int A[10]={1,2,3,4},n=4, B[10]={10,20,30},m=3;

cout << "A:"; afis(A,n); cout << "B:"; afis(B,m);

inter(A,n,B,&m);

cout << "A:"; afis(A,n); cout << "B:"; afis(B,m);

void inter(int A[], int &n, int B[], int *m){


int T[100],l;
copiaza(T,l,A,n); copiaza(A,n,B,*m); copiaza(B,*m,T,l);
}

void copiaza(int A[], int &n, int B[], int m){


n=m;
for(int i=0;i<n;i++) A[i]=B[i];
}

void afis(int A[], int n){


for(int i=0;i<n;i++) cout << A[i] << " ";
cout << endl;
}

A:1 2 3 4
B:10 20 30
A:10 20 30
B:1 2 3 4

In problema anterioara, simpla interschimbare a pointerilor reprezentand


numele vectorilor este imposibila, acestia fiind pointeri constanti.

P19. Realizati o functie care, primind ca parametri doi vectori alocati dinamic si
lungimile acestora, realizeaza interschimbarea lor (ca si continut).

- 187 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

void inter(int *&, int &, int *&, int &);


void afis(int [], int );

int main(){
int *A=new int[4],n=4, *B=new int[3],m=3;

for(int i=0;i<n;i++) A[i]=i+1;


for(int i=0;i<m;i++) B[i]=(i+1)*10;

cout << "A:"; afis(A,n); cout << "B:"; afis(B,m);

inter(A,n,B,m);

cout << "A:"; afis(A,n); cout << "B:"; afis(B,m);

void inter(int *&A, int &n, int *&B, int &m){


int *T,t;
t=n; n=m; m=t;
T=A; A=B; B=T;
}

void afis(int A[], int n){


for(int i=0;i<n;i++) cout << A[i] << " ";
cout << endl;
}

A:1 2 3 4
B:10 20 30
A:10 20 30
B:1 2 3 4

In acest caz inteschimbarea are loc mult mai simplu, nefiind necesare mutarea in
memorie a elementelor tablourilor, simpla interschimbare a pointerilor
reprezentand vectorii si a lungimii acestora fiind suficienta. Din nou este de
remarcat folosirea referintelor la pointeri!

12.6.2 Functii care returneaza pointeri


Prototipul unei functii care returneaza pointeri este de forma urmatoare:
tip * nume_functie(lista_parametri);

- 188 -
Introducere in ANSI C++

O astfel de functie poate fi apelata din orice loc al programului in care are sens
sa apara un pointer care nu se va modifica.

P20. Functii de alocare/dealocare dinamica a vectorilor.

#include <iostream>
using namespace std;

void afis(int [], int);


int * creare(int &);
void stergere(int *,int);

int main(){
int *A,n;

A=creare(n);
cout << "A:"; afis(A,n);
stergere(A,n);
}

void afis(int A[], int n){


for(int i=0;i<n;i++) cout << A[i] << " ";
cout << endl;
}

int * creare(int &n){


int *T;
cin >> n;
if (!(T= new int[n])){
cout << "Eroare la alocare!";
exit(1);
}
for(int i=0;i<n;i++) cin >> T[i];
return T;
}

void stergere(int *A, int n){


if (A) delete []A;
}

5
1 2 3 4 5
A:1 2 3 4 5

P21. Afisati prima linie dintr-o matrice patratica ce contine cel putin o valoare
nula (se stie ca matricea contine cel putin un zero).

- 189 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

void afis(int *, int);


int * prima(int [4][4],int );

int main(){
int A[4][4]={{1,2,3,4},
{2,3,4,5},
{1,2,0,3},
{0,1,0,2}},n=4;

afis(prima(A,n),n);
}

void afis(int A[], int n){


for(int i=0;i<n;i++) cout << A[i] << " ";
}

int * prima(int A[4][4],int n){


int i,j;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
if (A[i][j]==0) return A[i];
}

1 2 0 3 

In aceasta problema, o functie (afis), primeste ca parametru un pointer rezultat


un urma apelului unei alte functii (prima).

12.6.3 Pointeri la functii


O facilitate foarte puternica oferita de C/C++ este posibilitatea definirii si
folosirii pointerilor la functii. In plus, numele unei functii (fara paranteze si
parametri) este un pointer. Acest pointer va putea fi transmis ca parametru, deci o
functie va putea primi ca parametru o alta functie!
Forma generala a unei declaratii de pointer la functie:
tip_returnat (* nume_pointer) (lista_parametri);

Parantezele care cuprind * si numele pointerului nu sunt optionale, acestea


facand diferentierea dintre o declaratie de pointer la functie si un prototip de
functie care returneaza un pointer.

- 190 -
Introducere in ANSI C++

P22. Apelul unei functii folosind un pointer la functie.

#include <iostream>
using namespace std;

int dublu(int);
int triplu(int);

int main(){
int (* p)(int); // declaratie pointer la functie

p=dublu; cout << p(10) << " ";

p=triplu; cout << p(10);

int dublu(int x){return 2*x;}


int triplu(int x){return 3*x;}

20 30 

P23. Functie are primeste ca parametru alta functie.

#include <iostream>
#include <cmath>
using namespace std;

double calcul(double,double);
void afisare(char *, double (* )(double), double);
void afisare(char *, double (* )(double,double), double,double);

int main(){
afisare("sin",sin,0);
afisare("pow",pow,2,3);
afisare("functia mea", calcul, 2,3);
}

double calcul(double x, double y){return x*x+y*y;}

void afisare(char *text, double (* p)(double), double x){


cout << endl << text << "(" << x << ")=";
cout << p(x);
}

void afisare(char *text, double (* p)(double,double), double x,


double y){
cout << endl << text << "(" << x << "," << y<< ")=";
cout << p(x,y);
}

sin(0)=0

- 191 -
Introducere in ANSI C++

pow(2,3)=8
functia mea(2,3)=13

P24. Folosirea unui vector de pointeri la functii.

#include <iostream>
#include <cmath>
using namespace std;

typedef double (* Tip_pointer_functie)(double);

int main(){
int i,x;
Tip_pointer_functie p[4]={sin,cos,tan,abs};

cout << "x sin cos tan abs\n";


for(x=0;x<=30;x+=10){
cout << x << " ";
for(i=0;i<4;i++){
cout.width(6); cout.precision(2);
cout << p[i](x);
}
cout << endl;
}
}

x     sin    cos   tan   abs
0      0     1     0     0
10  ­0.54 ­0.84  0.65    10
20   0.91  0.41   2.2    20
30  ­0.99  0.15  ­6.4    30 

12.6.4 Functii cu numar variabil de parametri


In anumite situatii, numarul si tipul parametrilor ai unei functii este cunoscut
inainte de apelul efectiv. In acest caz, folosim functii cu numar variabil de
parametri:
tip_returnat nume(lista_parametri,...);

unde lista_parametri contine cel putin un parametru, iar cele trei puncte
"anunta" compilatorul ca s-ar putea sa mai apara si alti parametri.
Compilatorul nu poate face nici un fel de verificare asupra parametrilor

- 192 -
Introducere in ANSI C++

nespecificati explicit si accesul la acestia trebuie facut "de mana", in functie de


informatii auxiliare oferite in cadrul parametrilor clar specificati (vezi situatia
functiei printf din cstdio).
Pentru a vedea cum anume putem accesa parametri nespecificati, tinem cont de
urmatoarele:

– parametri se aloca pe stiva

– parametri se aloca in ordine inversa a scrierii lor in lista de parametri

– stiva creste in memorie de sus in jos


Figura 12.9 ilustreaza un posibil caz de apel:
Stiva

...
...
... parametri
... necunoscuti
...
pn
parametri
p2 cunoscuti
p1
Figura 12.9
Conform observatiilor anterioare, situatie memorie este:
p1 p2 pn ... ...

parametri parametri
cunoscuti necunoscuti
Figura 12.10
Observam ca parametri necunoscuti se gasesc la adrese imediat urmatoare
ultimului parametru cunoscut, deci, daca se poate determina la rulare numarul si
tipul parametrilor necunoscuti (prin informatii date de parametri cunoscuti), acestia
vor putea fi accesati folosind pointeri.

P25. Functie cu numar variabil de parametri care calculaeza o expresie de


forma: c1 op1 c2 op2 c3 ... opn cn+1, unde ci sunt intregi si opi este + sau -.

- 193 -
Introducere in ANSI C++

#include <iostream>
using namespace std;

int calcul(char *, ...);

int main(){

cout << calcul("+++",1,2,3,4) << endl;


cout << calcul("-+-+",-1,2,-3,4,-5) << endl;
cout << calcul("+",1); // apel incorect, imposibil de
detectat de catre compilator

int calcul(char *op, ...){


int E,i;
char **t,*s;
int *p; // pointer prin care accesam operanzii

t=&op;
t++;
p=(int *) t; // pozitionam p pe primul parametru necunoscut

E=*p; p++; // initializam E si mutam p pe al doiela param. nec.

for(s=op;*s;s++,p++) // ne "deplasam" in paralel pe


//operanzi si pe operatori
if (*s=='+') E+=*p;
else E-=*p;

return E;
}

10
­15
11403253

Observatii:

– pozitionarea pe primul parametru necunoscut se poate face si mai simplu

– compilatorul nu poate verifica daca functia a fost corect apelata, dupa cum
se vede la ultimul apel, unde lipseste un parametru

– in acest caz folosim o valoare oarecare, un interg care este peste varful
stivei!

- 194 -
Introducere in ANSI C++

Un caz particular de functie cu numar variabil de parametri este cazul in care


ultimul parametru cunoscut este un intreg care specifica numarul de parametri
necunoscuti care urmeaza, paramentri nocunoscuti fiind de tip int. Forma generala
pentru de lucru cu astfel de functie este:

tip_returnat nume(int nr, ...){
tip *p=&nr;
for(int i=1;i<=nr;i++)
foloseste(p[i]);
}

In acest caz, parametri sunt dati practic de elementele vectorului p: p[1], 


p[2], ...,p[nr].

P26. Functie cu numar necunoscut de parametri care realizeaza suma valorilor


(primul parametru da numarul de parametri necunoscuti).

#include <iostream>
using namespace std;

int suma(int, ...);

int main(){

cout << suma(4,1,2,3,4) << endl;


cout << suma(5,-1,2,-3,4,-5) << endl;

int suma(int nr, ...){


int S,*p,i;

p=&nr;
S=0;
for(i=1;i<=nr;i++) S+=p[i];

return S;
}

10
­3

- 195 -
Introducere in ANSI C++

12.7 Probleme propuse


Pp1. Rescrieti functiile de la problemele rezolvate din capitolele cu vectori si cu
siruri de caractere folosind pointeri (fara acces indexat).
Pp2. Realizati o functie cu numar variabil de parametri care calculeaza cmmdc-
ul parametrilor.
Pp3. Realizati o functie care primeste ca parametri:

– o functie de forma int f(int)

– un vector de intregi

– lungimea vectorului
si returneaza valoare minima atinsa de functia f pentru parametri fiind valorile din
vector.

- 196 -
Introducere in ANSI C++

Anexe

A1. Shortcut-uri uzuale folosite in mediul Borland C++ 3.1

Shortcut Efect
F1 - help
^F1 - help context sensitive
- va da informatii despre cuvantul pe care se gaseste in acel
moment cursorul de editare
F2 - save
- la prima salvare se deschide fereastra save as...
F3  - open
- permite deschiderea unei text sursa salvat anterior
alt+F3  - close
- inchide fereastra curenta
F5  - maximizare fereastra curenta
alt+F5 - afisarea ferestrei output
- in acest mod putem vizualiza rezultatele afisate pe ecran
F6 - navigare intre ferestre
F10 - intrare in meniuri
- navigarea prin meniuri se face cu cursorii si tasta Enter
pentru selectare
^F9 - rularea programului
Tabelul A1 – Shortcut-uri generale

- 197 -
Introducere in ANSI C++

Shortcut Efect
Shift + Cursori - selectare text
^Insert - copy
- este copiata in clipboard zona selectata
Shift + Insert - paste
- copiere din clipboard la pozitia cursorului

^Delete - stergerea zonei selectate


Alt+Backspace - undo
- se revine cu un pas inapoi in procesul de editare
- Atentie: la salvare se sterge istoricul Undo
Shift+Alt+Backspace - redo
- se merge cu un pas inainte in procesul de editare
- este activat doar dupa operatii Undo
Tabelul A2 - Scurtaturi legate de editor

A2 Erori uzuale si cauze posibile (Borland C++ 3.1)

Eroare Cauza posibila


Declaration terminated  ';' dupa main(), inainte de '{'
incorrectly

Declaration syntax error lipseste ';' dupa o declaratie

Statement missing ; lipseste ';' cu un rand mai sus

- 198 -
Introducere in ANSI C++

Eroare Cauza posibila


Undefined symbol _main in  s-a gresit numele functiei main (de
module c0.ASM
exemplu s-a scris mein)

Undefines symbol 'cout' s-a uitat #include <iostream.h>

Illegal structure operation schimbati '<<' cu '>>' sau invers

Function 'cutarescu' should  lipseste o directiva #include sau am


have a prototype
gresit numele functiei (de exemplu
crlscr in loc de clrscr)

Undefined symbol 'a' trebuie declarata variabila

Possibly incorrect assignment  intr-o conditie s-a pus = in loc de == 


(este de fapt un warning, dar in 99%
din cazuri programul nu va functiona
corect)

A3 Indentarea programelor C++


Cand scrii cod, nu conteaza cat de scurt si de simplu ti se pare, scrie-l intr-o
maniera care il face usor de citit. Foloseste un standard al indentarii pentru codul
tau si nu te abate de la el de-a lungul intregului program.

A3.1. Regulile de baza ale indentarii


De fiecare data indenteaza corpul unei instructiuni cu o distanta constanta fata
de primul caracter al instructiunii (prin corp al unei instructiuni intelegem setul de
actiuni pe care le controleaza acea instructiune). Instructiunile care au corp includ
buclele, instructiunile conditionale si subprogramele.
De exemplu, fie urmatoarea instructiune if-else:

- 199 -
Introducere in ANSI C++

if  (a==0) {
z_aparitii++;
printf(“Zero a aparut de %d ori\n”,z_aparitii);
}
else {
nz_aparitii++;
printf(“valori diferite de zero sunt %d\n”,z_aparitii);
}

Motivul pentru care folosim indentarea devine evident daca studiem alternativa
urmatoare:
if  (a==0) {
z_aparitii++;
printf(“Zero a aparut de %d ori\n”,z_aparitii);
} else {
nz_aparitii++;
printf(“valori diferite de zero sunt %d\n”,z_aparitii);
}

Chiar daca vom intelege pana urma ce face sursa data, timpul necesar va fi
sensibil mai mare fata de primul caz.
Care este numarul de spatii cu care ar trebui sa indentati corpul unei
instructiuni?
In principiu, o indentare eficienta respecta regulile urmatoare:

- cel putin 2 spatii (1 spatiu nu va faca o diferenta notabila)

- nu mai mult de 8 spatii (altfel ramaneti fara spatiu pentru instructiuni)

- aplicand aceeasi indentare in toata sursa

Sugerez folosirea TAB-ului (setat, daca permite editorul, pe 4 spatii), fiind mai
usor de folosit.
In cazul functiilor definite de utilizator, respectiv functia main, aplicati regulile
de mai sus. De exemplu:
int main(){
int a,b; // declaratii de variabile
float r;
printf(“Dati numitorul:”);

- 200 -
Introducere in ANSI C++

scanf(“%d”,&b);
. . .
}

Celelalte subprograme vor fi aliniate la functia main. In cazul in care numarul


de parametri este mare, este posibil ca antetul functiei sa nu incapa pe in rand. In
acest caz, indentarea parametrilor se va face in asa fel incat numele si tipul returnat
de functie sa fie usor de cazut. Deci,

int o_functie_oarecare(int indice_de_plecare, int contor_folositor, 
    arbore *radacina,informatie_utila Info[]);

sau:

int o_functie_oarecare( int indice_de_plecare, 
int contor_folositor, 
        arbore *radacina,
informatie_utila Info[]);

dar nu:

int o_functie_oarecare(int indice_de_plecare, int contor_folositor, 
arbore *radacina,informatie_utila Info[]);

A3.2 Stiluri de indentare ale blocurilor


Printre multitudinea de variante, s-au remarcat doua:

A3.2.1 Aliniaza “{“ cu “}”


Prin alinierea acoladelor, cititorul nu va avea dubii in legatura cu blocul din care
face parte o anumita instructiune. De exemplu:
if  (a==0)
{
z_aparitii++;
printf(“Zero a aparut de %d ori\n”,z_aparitii);
}
else 
{

- 201 -
Introducere in ANSI C++

nz_aparitii++;
printf(“valori diferite de zero sunt %d\n”,z_aparitii);
}

Un dezavantaj minor al acestei abordari este acela ca numarul de linii ocupat


este mare. Programatorilor le place sa vada cat mai mult cod pe ecran la un
moment dat, iar aceasta metoda “pierde” linii.

A3.2.2 Aliniaza “}” cu instructiunea ce controleaza blocul

In programare, blocurile au rolul de a grupa instructiuni ce formeaza corpul unei


instructiuni. Deci “}” marcheaza, atat sfarsitul blocului cat si sfarsitul corpului
instructiunii. Folosind aceasta observatie, devine logica alinierea acoladei inchise
la instructiunea a carei corp o inchide. Acolada deschisa va fi amplasata la sfarsitul
primei linii a instructiunii.
Exemplu:
if  (a==0)  {
z_aparitii++;
printf(“Zero a aparut de %d ori\n”,z_aparitii);

else {
nz_aparitii++;
printf(“valori diferite de zero sunt %d\n”,z_aparitii);
}

A3.3 Instructiuni de selectie: if, if-else si switch

A3.3.1 if cu corp simplu


Daca nu avem decat o singura instructiune de executat, nu este necesara
prezenta acoladelor. Daca instructiunea este indeajuns de scurta, este acceptabila
amplasarea ei pe aceeasi linie cu if-ul. Oricare dintre urmatoarele varianta poate fi
considerata o optiune buna:
if (numar < 0) numar = 0;
sau:
if (numar < 0) 

- 202 -
Introducere in ANSI C++

numar = 0;
sau:
if (numar < 0) {
numar = 0;
}

Pentru ultima varianta, folosirea acoladelor, chiar daca nu este neaparat


necesara, poate duce la cresterea lizibilitatii sursei.

A3.3.2 if cu corp compus


if (contor > 0) {
printf(“Numar pozitiv la orizont!”);
contor­­;
}

A3.3.3 if-else cu corp simplu


Exact ca in cazul if-ului simplu, folosirea acoladelor nu este necesara, dar nici nu
deranjeaza.
if (numar > 0)
printf(“Sunt pozitiv!”);
else 
printf(“Sunt negativ sau zero!”);
sau:
if (numar > 0) {
printf(“Sunt pozitiv!”);
} else {
printf(“Sunt negativ sau zero!”);
}

A3.3.4 if-else cu corp compus


Evident, in acest caz acoladele sunt necesare. O varianta posibila ar fi cea data
in sectiunea (2.2). Repet, alegeti o varianta care vi se potriveste, apoi folositi-o de
fiecare data.

A3.3.5 if-else in combinatia corp simplu si corp compus


Daca ati ales varianta in care folositi acoladele chiar si pentru corpuri simple,
acesta este unul din cazurile in care isi dovedeste utilitatea. Aveti de ales intre:

- 203 -
Introducere in ANSI C++

if (numitor < 0) {
printf(“Numitor negativ!”);
numitor = ­ numitor;
}
else
printf(“Totul e OK”);

si:
if (numitor < 0) {
printf(“Numitor negativ!”);
numitor = ­ numitor;
}
else {
printf(“Totul e OK”);
}

A3.3.6 Instructiunea switch


Se poate pleca de la premiza ca instructiunea switch are corpuri multiple, daca ne
gandim ca fiecare case este inceputul unui alt bloc de cod. Cele doua variante
consacrate ar fi:
switch (litera) {
case ‘ ‘:  printf(“Spatiu \n”);
break;
case ‘a’:
case ‘e’:
case ‘i’:
case ‘o’:
case ‘u’: printf(“Vocala \n”);
break;
default: printf(“Nimic interesant.”);
}
respectiv:
switch (litera) {
case ‘ ‘: printf(“Spatiu \n”);
break;
case ‘a’:
case ‘e’:
case ‘i’:
case ‘o’:
case ‘u’: printf(“Vocala \n”);
break;
default: printf(“Nimic interesant.”);

- 204 -
Introducere in ANSI C++

A3.4 Instructiuni repetitive: while, for si do-while

A3.4.1 while fara corp


Desi pare ciudat pentru un incepator, instructiuni repetitive fara corp (mai ales
for) se regasesc in C++ mai des decat ar parea la prima vedere. Urmatoarea
secventa de program, pozitioneaza indicele din vector pe prima valoare pozitiva:
i=0;
while ( (vector[i++]<0) && (i<numar_elemente) ) ;

Pentru a nu ignora punct-virgula de la sfarsitul randului (si deci a avea impresia


ca instructiunea ce urmeaza while-ului face parte din corpul instructiunii), se
recomanda variantele:
i=0;
while ( (vector[i++]<0) && (i<numar_elemente) ) 
;

sau:
i=0;
while ( (vector[i++]<0) && (i<numar_elemente) ) {
;
}

O alta posibilitate ar fi cea de a insera un comentariu prin care se indica blocul


vid:
i=0;
while ( (vector[i++]<0) && (i<numar_elemente) ) {
/* sunt un bloc vid */;
}

A3.4.2 while cu corp simplu


Observatiile de la sectiunea anterioara raman valabile. Deci, daca corpul este
destul de mic, avem urmatoarele situatii:

- 205 -
Introducere in ANSI C++

i = 0;
while ((i<numar_elemente) && (vector[i] != valoare_cautata)) i++;

i = 0;
while ((i<numar_elemente) && (vector[i] != valoare_cautata)) 
i++;

i = 0;
while ((i<numar_elemente) && (vector[i] != valoare_cautata)) {
i++;
}

A3.4.3 while cu corp compus


Nu exista variante altele decat cele discutate in (3).
i=1;
while ( i < Maxim ) {
printf(“%d” , i);
i=i*2;
}

A3.4.4 for in toate variantele


Nimic nou sub soare; respectati regulile de la while.

A3.4.5 do-while fara corp sau cu corp simplu


Avem variantele:
i = ­1;
do i++; while ((i< numar_elemente)&&(a[i]<0));

sau:
i = ­1;
do 
i++;
while ((i< numar_elemente)&&(a[i]<0));
sau:
i = ­1;
do {
i++; 
} while ((i< numar_elemente)&&(a[i]<0));

- 206 -
Introducere in ANSI C++

Este de preferat ultima varianta, while la inceput de rand putand duce la confuzii.

A3.4.6 do-while cu corp compus


Nimic nou de remarcat.

A3.5 Indentarea instructiunilor imbricate


Indentarea este cu atat mai importanta in cazul in care avem instructiuni
complexe ce fac parte din alte instructiuni complexe. Fara imbricare, vom putea
usor considera o instructiune ca finnd in afara unei bucle, desi ea face parte din
corpul ei.
Considerand fiecare TAB de la inceput de rand ca fiind nivelul indentarii, putem
avea urmatoarea situatie:
[0] int main (void)
[0] {
[1]        int   i;
[1]        int   suma = 0 , numar;

[1]        printf("\nIntroduceti cinci numare intregi pozitive\n");

[1]        for (i=1; i<=5; i++) {
[2]        scanf("%d",&numar);
[2]        if (numar>0) 
[3] suma += numar;
[2]        else {
[3] suma ­= numar;

[1]        }
[1]        printf("\nSuma este:%d\n”,suma );
[0] }

Se poate enunta urmatoarea regula: “fiecare corp se indenteaza cu un nivel in


plus”.
Un caz special il reprezinta instructiunile if-else imbricate. Daca numarul de
imbricari nu este mare, nu avem nici o problema. In caz contrar ne trezim in
situatia de a nu mai avea spatiu in partea dreapta a randului. Urmatorul exemplu da
o posibila solutie:
 if (nota >= 9)

- 207 -
Introducere in ANSI C++

printf(“Foarte Bine”);
else if (nota >= 8)
printf(“Bine”);
else if (score >= 7)
printf(“OK”);
else if (score >= 6)
printf(“Satisfacator”);
else if (score >= 5)
printf(“La limita”);
else
printf(“Nasol”);

A4 Precedenta operatorilor

Nivel Operator Descriere Grupare

Left­to­
1 :: scope
right

() [] . ­> ++ ­­ 
dynamic_cast static_cast  Left­to­
2 postfix
reinterpret_cast  right
const_cast typeid

++ ­­ ~ ! sizeof new 
unary (prefix)
delete
Right­
3 indirection and 
* & to­left
reference (pointers)

+ ­ unary sign operator

Right­
4 (type) type casting
to­left

Left­to­
5 .* ­>* pointer­to­member
right

Left­to­
6 * / % multiplicative
right

Left­to­
7 + ­ additive
right

Left­to­
8 << >> shift
right

- 208 -
Introducere in ANSI C++

Left­to­
9 < > <= >= relational
right

Left­to­
10 == != equality
right

Left­to­
11 & bitwise AND
right

Left­to­
12 ^ bitwise XOR
right

Left­to­
13 | bitwise OR
right

Left­to­
14 && logical AND
right

Left­to­
15 || logical OR
right

Right­
16 ?: conditional
to­left

= *= /= %= += ­= >>= <<=  Right­
17 assignment
&= ^= != to­left

Left­to­
18 , comma
right

A5 Cuvintele cheie
Lista cu cuvintele cheia ANSI C++ este:
and, and_eq, asm, auto, bitand, bitor, bool, break, case, catch, 
char, class, compl, const, const_cast, continue, default, delete, do, 
double, dynamic_cast, else, enum, explicit, export, extern, false, 
float, for, friend, goto, if, inline, int, long, mutable, namespace, 
new, not, not_eq, operator, or, or_eq, private, protected, public, 
register, reinterpret_cast, return, short, signed, sizeof, static, 
static_cast, struct, switch, template, this, throw, true, try, 
typedef, typeid, typename, union, unsigned, using, virtual, void, 
volatile, wchar_t, while, xor, xor_eq 

- 209 -
Introducere in ANSI C++

Bibliografie
[1] Kris Jamsa, Lars Klander - „Totul despre C si C++”, editura Teora, 2001
[2] Bjarne Stroustrup – „C++”, editura Teora, 2003
[3] Breazu Macarie – „Programarea Orientata pe Obiecte – Principii”, editura
ULBS, 2002
[4] Bogdan Patrut - „Aplicatii in C si C++”, editura Teora, 2001
[5] Dragos Acostachioaie - „Programare C si C++ sub Linux”, Editura Polirom,
2002
[6] Thomas H. Cormen, Charles E. Leiserson, Ronald R.Rovest - „Introducere
in algoritmi”, editura Agora, 2000
[7] Carmen Popescu - „Culegere de probleme de informatica”, editura Donaris,
2002

- 210 -
Introducere in ANSI C++

Cuprins
Introducere...............................................................................................................1
Capitolul 1 – Primul program................................................................................2
1.1 Structura generala a unui program C++.........................................................2
1.2 Hi man!.........................................................................................................3
1.3 Compilarea si rularea programului................................................................4
1.3.1 In mediul Borland C++ 3.1...................................................................4
1.3.2 Folosind compilatorul g++....................................................................5
Capitolul 2 – Notiuni de baza.................................................................................6
2.1 Notiunea de algoritm......................................................................................6
2.2 Citirea si afisarea datelor...............................................................................7
2.3 Tipuri de date. Variabile si constante............................................................9
2.4 Secvente escape............................................................................................14
2.5 Referinte (alias-uri)......................................................................................16
2.6 Probleme propuse.........................................................................................17
Capitolul 3 – Expresii C++....................................................................................18
3.1 Atribuirea.....................................................................................................18
3.2 Conversii de tip............................................................................................20
3.3 Expresii aritmetice.......................................................................................23
3.4 Expresii logice.............................................................................................25
3.5 Operatorul conditional.................................................................................27
3.6 Operatorul virgula........................................................................................30
3.7 Operatori care actioneaza la nivel de bit......................................................31
3.8 Probleme propuse.........................................................................................32
Capitolul 4 – Instructiuni conditionale................................................................33
4.1 Instructiunea if.............................................................................................33
4.2 Instructiunea switch.....................................................................................40
4.3 Probleme propuse.........................................................................................43
Capitolul 5 – Instructiuni repetitive.....................................................................44
5.1 Instructiunea while.......................................................................................44
5.2 Instructiunea do-while.................................................................................47
5.3 Instructiunea for...........................................................................................49

- 211 -
Introducere in ANSI C++

5.4 break si continue..........................................................................................53


5.5 instructiunea goto.........................................................................................55
5.6 Probleme tip.................................................................................................56
5.6.1 Probleme pe cifrele unui numar..........................................................56
5.6.2 Probleme de divizibilitate....................................................................58
5.6.3 Sume, produse, numarari.....................................................................60
5.6.4 Maxime si minime...............................................................................63
5.6.5 Citirea mai multor numere de la tastatura...........................................64
5.6.6 Generarea unor serii complexe de numere .........................................66
5.7 Probleme propuse.........................................................................................69
Capitolul 6 – Vectori (matrici)..............................................................................70
6.1 Declararea si initializarea.............................................................................70
6.2 Citirea si scrierea vectorilor.........................................................................72
6.3 Generari de vectori.......................................................................................75
6.4 Cateva probleme simple...............................................................................77
6.5 Sortarea si interclasarea...............................................................................81
6.6 Declararea matricilor...................................................................................85
6.7 Citirea si afisarea matricilor.........................................................................85
6.8 Probleme cu matrici.....................................................................................87
6.9 Probleme propuse.........................................................................................91
Capitolul 7 – Siruri de caractere..........................................................................92
7.1 Declaratie si initializare...............................................................................92
7.2 Operatii de citire/scriere pe siruri de caractere............................................94
7.3 Accesul la caracterele unui sir.....................................................................95
7.4 Functii specifice sirurilor de caractere.........................................................97
Capitolul 8 – Structuri si alte tipuri utilizator..................................................107
8.1 Structuri......................................................................................................107
8.2 Uniuni.........................................................................................................111
8.3 Campuri de biti..........................................................................................114
8.4 Tipul enumerat...........................................................................................115
8.5 Probleme propuse.......................................................................................117
Capitolul 9 – Functii............................................................................................118
9.1 Generalitati.................................................................................................118
9.2 Functii care nu primesc si nu returneaza nimic.........................................119

- 212 -
Introducere in ANSI C++

9.3 Functii care nu returneaza nimic, dar primesc date de intrare...................121


9.4 Functii care nu primesc date de intrare dar returneaza o valoare..............127
9.5 Functii care primesc un numar oarecare de parametri de intrare si
returneaza o singura valoare............................................................................129
9.6 Functii ce returneaza mai multe valori......................................................133
9.7 Variabile locale si globale. Durata de viata si domeniu de vizibilitate......137
9.8 Supradefinirea functiilor............................................................................141
9.9 Functii cu parametri impliciti.....................................................................143
9.10 Parametri vectori......................................................................................144
9.11 Probleme propuse.....................................................................................148
Capitolul 10 – Recursivitate................................................................................149
10.1 Recursivitatea directa...............................................................................149
10.2 Recursivitatea indirecta............................................................................154
10.3 Probleme propuse.....................................................................................155
Capitolul 11 – Fisiere...........................................................................................156
11.1 Redirectarea intrarii/iesirii.......................................................................156
11.2 Fluxuri de intrare/iesire............................................................................158
11.3 Citirea unui numar cunoscut de valori dintr-un fisier..............................160
11.4 Citirea pana la sfarsitul fisierului.............................................................161
11.5 Probleme propuse.....................................................................................164
Capitolul 12 – Pointeri.........................................................................................165
12.1 Declaratie si operatii elementare..............................................................165
12.2 Aritmetica pointerilor..............................................................................170
12.2.1 Atribuirea........................................................................................170
12.2.2 Operatorii relationali.......................................................................171
12.2.3 Scaderea si adunarea cu un intreg...................................................173
12.2.4 Diferenta a doi pointeri...................................................................174
12.3 Alocarea dinamica a memoriei................................................................174
12.4 Pointeri la structuri...................................................................................175
12.5 Legatura dintre pointeri si tablouri..........................................................176
12.5.1 Accesul la elementele unui tablou folosind pointeri.......................176
12.5.2 Alocarea dinamica a tablourilor......................................................179
12.5.3 Vectori de pointeri...........................................................................181
12.6 Legatura dintre pointeri si functii............................................................184

- 213 -
Introducere in ANSI C++

12.6.1 Functii cu parametri pointeri...........................................................184


12.6.2 Functii care returneaza pointeri.......................................................188
12.6.3 Pointeri la functii.............................................................................190
12.6.4 Functii cu numar variabil de parametri...........................................192
12.7 Probleme propuse.....................................................................................196
Anexe.....................................................................................................................197
A1. Shortcut-uri uzuale folosite in mediul Borland C++ 3.1...........................197
A2 Erori uzuale si cauze posibile (Borland C++ 3.1)......................................198
A3 Indentarea programelor C++......................................................................199
A3.1. Regulile de baza ale indentarii.........................................................199
A3.2 Stiluri de indentare ale blocurilor......................................................201
A3.3 Instructiuni de selectie: if, if-else si switch.......................................202
A3.4 Instructiuni repetitive: while, for si do-while..................................205
A3.5 Indentarea instructiunilor imbricate...................................................207
A4 Precedenta operatorilor..............................................................................208
A5 Cuvintele cheie...........................................................................................209
Bibliografie...........................................................................................................210

- 214 -

You might also like