Descărcați ca pdf sau txt
Descărcați ca pdf sau txt
Sunteți pe pagina 1din 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:
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 -
// Comentariu (enuntul problemei)
# directive_preprocesor
prototipuri_functii;
declaratii_variabile globale;
int main(){
declaratii_variabile_locale;
instructiuni;
}
definire_functii
Introducere in ANSI C++
Figura 1.1 Trecerea de la textul sursa la fisierul executabil
1.2 Hi man!
Ca prim program vom implementa urmatoarea problema:
P
1
. 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++.
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 -
Linkeditare
nume.cpp nume.exe
// 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
Compilare
Introducere in ANSI C++
In varianta urmatoare vom folosi biblioteca iostream, introdusa in C++ si care
implementeaza asa numitele fluxuri de intrare/iesire.
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:
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 -
#include <iostream.h> // linia 1
int main(){ // linia 2
cout << "Hi man!"; // linia 3
} // linia 4
#include <iostream> // linia 1
int main(){ // linia 2
std::cout << "Hi man!"; // linia 3
} // linia 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.
Figura 2.1 Forma generala a unui algoritm
Pentru a evidentia pasii de urmat vom lua ca exemplu urmatoarea problema.
P
1
. 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 -
Date de intrare Date de iesire
Rezolvarea
problemei
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, functii
1
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++
P
2
. Afisati textul "text de test!" pe ecran.
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
cu
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 -
#include <iostream>
using namespace std;
#include <iostream.h>
// 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!";
}
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
char
'A'
'B'
'a'
'+'
'3'
- defineste un caracter
- in memoria calculatorului, stocarea unui caracter se
face folosind codul lui ASCII
- poate fi folosit si pentru a memora numere intregi
mici
int
3
123
-1020
- numar intreg cu semn
- intervalul acoperit de acest tip poate diferi de la un
calculator la altul
float
3.0
123.456
- 100.001
- folosit pentru memorarea numerelor reale
- este memorat in format cu virgula mobila (float) in
simpla precizie
double
3.0
123.456
- 100.001
- numere reale
- il folosim pentru numere foarte mari sau pentru o
precizie mai mare dupa virgula
bool
1 0
true false
- tip care apare in ANSI C++
- 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:
P
3
. Definiti cel putin 5 variabile de tipuri diferite, initializati-le si apoi afisati
valoarile pe ecran.
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 -
#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;
}
Introducere in ANSI C++
in memoria calculatorului.
P
4
. Verificati cat ocupa in memoria calculatorului dumneavoastra diverse tipuri
de date.
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:
- 12 -
#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";
}
// 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
}
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:
P
5
. Calculati valoare expresiei 2*(a-b)+c, realizand o interfata prietenoasa cu
utilizatorul.
In acest moment, executia va afisa ceva de forma:
a=3
b=5
c=2
E=2*(3-5)+2=-2
- 13 -
#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;
}
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++
P
6
. Afisati un romb din caracterul '$' pe ecran.
$
$$$
$$$$$
$$$
$
$
$$$
$$$$$
$$$
$
- 15 -
#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;
}
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.
P
7
. Exemplu de lucru cu referinte.
Sunt variabila a:123
Sunt tot variabila a:123
Sunt a, si mi se spune:123
- 16 -
#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;
}
Introducere in ANSI C++
2.6 Probleme propuse
Pp
1
. Afisati pe ecran un bradulet folosind caracterul '*'.
Pp
2
. Cititi de la tastatura trei numere intregi, apoi afisati-le in ordine inversa,
cate unul pe un rand.
Pp
3
. Calculati media aritmetica a doua valori intregi citite de la tastatura. Citirea
si afisarea sa fie prietenoasa cu utilizatorul.
Pp
4
. 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
Pp
5
. 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
P
1
. Exemple de atribuiri simple
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 -
#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;
}
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:
variabila
1
= variabila
2
= ... = variabila
n
= expresie;
P
2
. Alte exemple de atribuiri
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 -
#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;
}
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.
P
3
. Conversie implicita de tip, fara pierdere de informatie
i=65
c=A
f=12345
- 20 -
#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;
}
Introducere in ANSI C++
P
4
. Conversie implicita de tip, cu pierdere de informatie
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 -
#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;
}
Introducere in ANSI C++
P
5
. Conversia explicita de tip
i=12348
c=a
f=97
O aplicatie directa a conversiei explicite de tip este:
P
6
. Se citeste un caracter. Afisati codul ASCII corespunzator caracterului citit
Doua posibile rulari ale aplicatiei:
Dati caracterul:a
Caracterul 'a' are codul ASCII 97
Dati caracterul:9
Caracterul '9' are codul ASCII 57
- 22 -
#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);
}
#include <iostream>
using namespace std;
int main(){
char c;
cout << "Dati caracterul:"; cin >>c;
cout << "Caracterul \'" << c;
cout << "\' are codul ASCII " << int(c);
}
Introducere in ANSI C++
3.3 Expresii aritmetice
Forma generala este, in functie de operator:
operator operand sau
operand
1
operator operand
2
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:
P
7
. Expresii aritmetice. Impartirea reala si intreaga.
-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_intreg
1
) / (operator_intreg
2
)
In acest context, 7/2 are valoarea 3, dar 7./2 sau float(7)/2 au valoarea 3.5.
- 23 -
#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
}
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
P
8
. Forma scurta a atribuirii
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 -
#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";
}
Introducere in ANSI C++
P
9
. Incrementarea si decrementarea
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.
P
10
. Valoarea expresiilor logice
true=1
false=0
- 25 -
#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";
}
#include <iostream>
using namespace std;
int main(){
bool b;
b=true;
cout << "true=" << b << "\n";
b=false;
cout << "false=" << b;
}
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++
P
11
. Se citesc trei valori intregi de la tastatura. Verificati unde se gaseste prima
valoare citita in raport cu intervalul determinat de ultimele doua valori.
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:
expresie
1
?expresie
2
:expresie
3
Daca expresie
1
este evaluata la adevarat, expresia returneaza expresie
2
, altfel
returneaza expresie
3
.
In unele cazuri particulare poate fi un inlocuitor pentru instructiunea if.
- 27 -
#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);
}
Introducere in ANSI C++
P
12
. Calculati expresia E(x)=1/x daca e posibil, afisand valoarea 0 in caz
contrar.
x=2
1/2 = 0.5
P
13
. Calculati expresia max(a,b), unde a si b sunt valori reale citite de la
tastatura.
a=5
b=2
max(5,2)=5
P
14
. Se citesc doua valori intregi de la tastatura. Interschimbati cele doua
valori, apoi afisati rezultatul pe ecran.
- 28 -
#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;
}
#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;
}
Introducere in ANSI C++
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.
P
15
. Necesitatea folosirii parantezelor. Acest program NU va verifica
apartenenta valorii a intervalului [1,5], desi in unele cazuri pare sa functioneze !!!
a=8
8 apartine intervalului [2,5]:1
- 29 -
#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 ;
}
#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 ;
}
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:
expresie
1
, expresie
2
,... , expresie
n

Expresiile sunt evaluate de la deapta la stanga, valoarea returnata la final fiind
valoarea si tipul dat de expresie
n
.
P
16
. Simulati operatorii de preincrementare si postincrementare folosind
operatorul virgula (b=a++ si b=++a).
a=3
4 3
5 5
- 30 -
#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";
}
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
&
si pe biti
x&1 reseteaza toti bitii, in afara
celui mai putin semnificativ
|
sau pe biti
x|1 seteaza bitul cel mai putin
semnificativ
^
sau exclusiv
x^0 complementeaza toti bitii
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
Pp
1
. Se citeste un numar real x, strict pozitiv, de la tastatura. Calculati si afisati
rezultatul expresiei (x-1)/x
2
.
Pp
2
. Se citeste un numar real de la tastatura. Folosind conversii de tip, afisati
partea fractionara a numarului.
Pp
3
. Se citesc doua numere a si b de la tastatura, valori intregi strict pozitive.
Afisati rezultatul expresiei E(a,b)=(a-b)/(a+b).
Pp
4
. Folosind operatorul conditional, determinati minimul a doua valori intregi
citite de la tastatura.
Pp
5
. 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|).
Pp
6
. 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.
Pp
7
. 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) instructiune
1
else instructiune
2
Daca expresie este evaluata la adevarat se executa instructiune
1
, altfel se
executa instructiune
2
.
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.
P
1
. Se citeste un numar intreg de la tastaura. Verificati daca acesta este nul,
pozitiv sau negativ.
a=123
123 este pozitiv.
- 33 -
#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.";
}
Introducere in ANSI C++
sau:
a=0
0 este nul.
P
2
. Se citeste un numar intreg de la tastaura. Verificati daca acesta este nul sau
nu.
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 -
#include <iostream>
using namespace std;
int main(){
int a;
cout << "a="; cin >> a;
if (a) cout << a << " este nenul.";
else cout << a << " este nul.";
}
Introducere in ANSI C++
P
3
. Se citesc de la tastaura doua numere intregi si un caracter reprezentand
operatiile matematice '+', '-'. Afisati valoarea corespunzatoare aplicarii operatiei
date asupra intregilor cititi.
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 -
#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!";
}
Introducere in ANSI C++
P
4
. Se citesc de la tastaura trei numere intregi. Calculati maximul si minimul
valorilor.
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 -
#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;
}
Introducere in ANSI C++
P
5
. Exemple de erori de compilare la surse care par corecte.
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.
P
6
. Varianta corecta a problemei 5.
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 -
#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";
}
#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";
}
Introducere in ANSI C++
In multe probleme, folosirea expresiilor logice compuse reprezinta o alegere
evidenta.
P
7
. Determinati daca patru numere intregi citite de la tastatura sunt in ordine
crescatoare sau nu.
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.
P
8
. Determinati daca patru numere intregi formeaza o progresie aritmetica.
Daca da, afisati ratia.
- 38 -
#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";
}
Introducere in ANSI C++
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.
P
9
. Calculati urmatoarea functie:
f x=
x pentru x[10,20]
x pentru x20,0
0 inrest
- 39 -
#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";
}
Introducere in ANSI C++
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 constanta
1
: instructiuni;
case constanta
2
: instructiuni;
. . .
case constanta
n
: instructiuni;
default: instructiune;
}
Optiunea default este optionala.
Executia instructiunii are loc in urmatorul mod:
- 40 -
#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;
}
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 constanta
1
: instructiuni; break;
case constanta
2
: instructiuni; break;
. . .
case constanta
n
: instructiuni;
default: instructiune;
}
P
10
. 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.
- 41 -
#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;
}
Introducere in ANSI C++
a=2
b=4
operator:/
2/4=0.5
P
11
. 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.
Ziua corespunzatoare datei de 1 a lunii:0
Data de verificat:14
Data corespunde unei zi de DUMINICA
- 42 -
#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;
}

}
Introducere in ANSI C++
4.3 Probleme propuse
Pp
1
. Dati un exemplu de problema in care expresia conditionala nu poate tine
locul instructiunii if.
Pp
2
. Calculati:
f x , y=
xy pentru x0
xy pentru x0
Pp
3
. Se citesc patru numere intregi de la tastatura. Afisati valorile distincte
citite.
Pp
4
. Sa se determine ultimele doua cifre ale produsului a*b, a si b citite de la
tastatura.
Pp
5
. Se citeste x intreg. Sa se calculeze ultima cifra a lui 2
x
.
Pp
6
. Rezolvati ecuatia de gradul 1.
Pp
7
. 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!".
Pp
8
. 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++
P
1
. Afisati numerele de la 1 la 10 pe ecran.
citesc1 2 3 4 5 6 7 8 9 10
P
2
. 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 -
#include <iostream>
using namespace std;
int main(){
int i;

i=1;
while (i<=10){
cout << i<< " ";
i++;
}
}
Introducere in ANSI C++
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 -
#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++;
}
}
Introducere in ANSI C++
In unele cazuri corpul instructiunii while poate sa fie vid. In acest caz
vomverondela folosi intructiunea vida ; .
P
3
. Se citeste un numar intreg de la tastatura. Afisati cel mai mare numar
multiplu de 10 mai mic ca numarul citit. (while fara corp)
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 -
#include <iostream>
using namespace std;
int main(){
int n;
cout << "n="; cin >>n;
while ((n--)%10!=0); // while cu corp vid
cout << n+1;
}
Introducere in ANSI C++
Urmatoarele secvente de instructiuni sunt echivalente:
if (expresie)
do
instructiune;
while (expresie);
while (expresie)
instructiune;
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.
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 -
#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);
}
Introducere in ANSI C++
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 -
#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);

}
Introducere in ANSI C++
- se executa instructiune
- se executa reinit
Instructiunea for este folosita, in principal, pentru parcurgerea seriilor de
numere.
P
6
. 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
5 3 8
1 2 3 4 5 6 7 8 9 10
- 50 -
#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;
}
}
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
P
7
. Afisati, folosind trei metode diferite urmatoarea serie de numere pe ecran:
1 0 1 0 1 0 ..., in total n valori
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 -
#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;
}

}
Introducere in ANSI C++
expr1;
while (expr2){
instructiune;
expr3;
}
for(expr1;expr2;expr3)
instructiune;
Figura 5.2
Folosirea expresiei virgula reprezinta o varianta prin care putem controla mai
multe variabile in cadrul aceleiasi bucle for.
P
8
. Afisati urmatoarele serii de numere pe ecran:
1 9 2 8 3 7 ... 9 1
1 2 4 8 ... , in total n valori
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(;;);
P
10
. Afisati tabela cu codurile ASCII, cate 10 pe un rand.
- 52 -
#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 << " ";
}
Introducere in ANSI C++
.............
<-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 -
#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;
}
}
Introducere in ANSI C++
P
11
. Afisati pe ecran numerele prime mai mici decat n.
n=20
1 2 3 5 7 11 13 17 19
P
12
. Afisati pe ecran urmatoarele numere, cu doua zecimale exacte:
1/10, 1/9, 1/8, ... 1/1, 1/-1, 1/-2, ... 1/-10
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 -
#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 << " ";
}
}
#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 << " ";
}
}
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.
P
13
. Folosind instructiunea goto, afisati pe ecran numerele intregi din intervalul
[a,b].
3 6
3 4 5 6
- 55 -
#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
}
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
Figura 5.3
De aici obtinem urmatoarele:
Si mai departe, parcurgerea unui numar intreg pozitiv, cifra cu cifra:
unde foloseste(c) este o secventa de instructiuni dependenta de enuntul
problemei.
- 56 -
1234 10
1230
123
4
n
n%10 n/10
c= n% 10 calculul ultimei cifre
n=n/10 eliminarea ultimei cifre
while (n>0){ // cat timp mai avem cifre
c= n% 10;
foloseste(c);
n=n/10;
}
Introducere in ANSI C++
O alta varianta este cea folosind instructiunea for:
P
14
. Afisati cifrele unui numar, cate o cifra pe un rand.
n=1942
2
4
9
1
Ultima instructiune for (cea comentata) rezolva acceasi problema intr-o
varianta compacta.
- 57 -
for(;n>0;n=n/10) foloseste(n%10);
#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;
}
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:
Plecand de la aceasta conditie, parcurgerea divizorilor unui numar intreg pozitiv
n:
P
15
. Afisati divizorii unui numar intreg pozitiv citit de la tastatura.
n=120
1 2 3 4 5 6 8 10 12 15 20 24 30 40 60 120
P
16
. Se citeste de la tastatura un numar intreg pozitiv.
Verificati daca este prim
descompuneti-l in factori primi
- 58 -
n%d==0 - verificarea daca d|n
for(d=1;d<=n;d++) // dintre toti divizorii posibili
if (n%d==0) foloseste(d); // selectam divizorii
#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 << " ";
}
Introducere in ANSI C++
n=120
120 nu este prim
2 2 2 3 5
P
17
. Se citesc doua numere intregi pozitive de la tastatura. Calculati
cmmdc(a,b) si cmmmc(a,b).
- 59 -
#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++;
}
Introducere in ANSI C++
24 36
cmmdc(24,36)=12
cmmmc(24,36)=72
5.6.3 Sume, produse, numarari
Avem urmatoarele scheme generale:
Suma:
Produsul:
- 60 -
S=0
Pentru toate valorile X de insumat
S=S+X
P=1
Pentru toate valorile X de inmultit
P=P*X
#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;
}
Introducere in ANSI C++
Numarari (contorizari):
P
18
. 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)
4 11
60 24 1.18654
P
19
. Se citeste un numar intreg pozitiv de la tastatura. Calculati:
Suma cifrelor numarului
Produsul cifrelor pare
Prima cifra a numarului
- 61 -
ct=0
Pentru toate valorile X de parcurs
if (conditie(X)) ct++
#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;
}
Introducere in ANSI C++
De cate ori apare prima cifra in numar
12141
9 8 1 3
P
20
. Se citeste un numar intreg pozitiv n de la tastatura. Calculati:
Suma divizorilor numarului
Cate numere prime mai mici ca n exista
- 62 -
#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;

}
Introducere in ANSI C++
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:
Minime:
- 63 -
max = -infinit
Pentru toate valorile X de parcurs
if (X>max) max=X
min = infinit
Pentru toate valorile X de parcurs
if (X<min) min=X
#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;
}
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.
P
21
. Se citeste un numar intreg pozitiv de la tastatura. Calculati:
Cifra maxima a numarului
De cate ori apara cifra minima
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 -
#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;

}
Introducere in ANSI C++
b. Se cunoaste o conditie cat timp se vor citi valori:
P
22
. Se citeste un numar n, apoi n valori reale de la tastatura. Calculati:
maximul
produsul
5
1 1 5 2 1
5 10
- 65 -
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
}
cin >> X; // citim valoare
while (cond(X)){ // cat timp conditia e respectata
foloseste(X); // il utilizam conform enuntului
cin >> X; // citim numarul
}
#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;
}
Introducere in ANSI C++
P
23
. Se citesc numere intregi pana la intalnirea valorii 0. Calculati:
Suma valorilor pare
Minimul si de cate ori apare acesta
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
P
24
. 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 -
#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";
}
Introducere in ANSI C++
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
P
25
. Se citeste n (intreg pozitiv). Afisati pe ecran, sub forma data:
1
1 2 1
1 2 3 2 1
....................
1 ................ 1
1:1
2:1,2
....
6: 1,2,3,6 numarul urmat de divizori
......
1 2 3 4 5
2 3 4 5 6
3 4 5 6 7
4 5 6 7 8
5 6 7 8 9 (n=5)
- 67 -
#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 << " ";
}
}
Introducere in ANSI C++
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 -
#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;
}
}
Introducere in ANSI C++
5.7 Probleme propuse
Pp
1
. 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).
Pp
2
. 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 = 1
2
+ 4
2
+ 7
2
+ ... + (3n-2)
2

Pp
3
. 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.
Pp
4
. Calculati ultima cifra a expresiei E= a
b
, a si b valori intregi pozitive citite
de la tastatura.
Pp
5
. Se citesc numere intregi de la tastatura pana la intalnirea unui numar
negativ. Afisati numarul citit care are cei mai multi divizori.
Pp
6
. Se citeste de la tastatura un numar intreg n. Afisati pe ecran urmatoarele
serii de numere, pastrand formatul:
1
2 1 2
3 2 1 2 3
....................
n ......1....... n
1:1
2:2,2
3:3,3,3
......
n:n,n,n,...,n
1 0 1 0 1
0 1 0 1 0
1 0 1 0 1
0 1 0 1 0
1 0 1 0 1 (n=5)
Pp
7
. Afisati pe ecran tabla inmultirii pana la 10.
Pp
8
. 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
P
1
. Exemple de declarari/initializari de vectori si cat ocupa acestia in memorie.
Vectorul A ocupa 400 octeti
Vectorul B ocupa 40 octeti
- 70 -
#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";
}
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:
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):
Figura 6.2
- 71 -
1 2 3 4 ? ? ...
A[0] A[1] A[9]
5 2 3 4 ? 9 ...
A[0] A[1] A[9]
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:
P
2
. Se citesc cinci valori ale unui vectori de intregi. Afisati vectorul in ordine
inversa.
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 -
#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];

}
Introducere in ANSI C++
P
3
. Se citesc cinci valori ale unui vectori de intregi. Afisati vectorul in ordine
inversa. (varianta 2)
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.
P
4
. Se citeste un vector de la tastatura. Afisati vectorul pe ecran.
4
3 4 1 2
3 4 1 2
- 73 -
#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] << " ";

}
#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
}
Introducere in ANSI C++
Aspectul sec al aplicatiei este remediat in exemplul urmator:
P
5
. Se citeste un vector de la tastatura. Afisati vectorul pe ecran. (varianta
cosmetizata)
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:
Modul in care folosim elementele vectorului depinde de la problema la
problema.
- 74 -
#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] << ")";

}
for(i=0;i<n;i++)
foloseste(A[i]);
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:
P
6
. 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,...
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 -
#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] << " ";
}
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.
P
7
. 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,...
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 -
#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] << " ";
}
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.
P
8
. Generati un vector de lungime citita de la tastatura, continand valori
aleatoare in intervalul [a,b], a<b, numere pozitive.
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.
P
9
. 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 -
#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] << " ";
}
Introducere in ANSI C++
d. minimul valorilor pozitive
n=6
1 -1 2 -2 3 -3
Suma: 0
Produsul valorilor pare: -4
Maximul: 3
minimul valorilor pozitive: 1
P
10
. 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 -
#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;

}
Introducere in ANSI C++
n=2
Vectorul:4 7 8 6
E: 1.90476
F: 27
P
11
. 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 -
#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;

}
Introducere in ANSI C++
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 -
#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.";

}
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.
P
12
. Sortarea prin selectie
n=5
2 4 5 1 3
Vectorul sortat: 1 2 3 4 5
Ideea din spatelealgoritmului 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 -
#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] << " ";

}
Introducere in ANSI C++
P
13
. Bubble Sort
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 -
#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] << " ";

}
Introducere in ANSI C++
P
14
. 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.
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 -
#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] << " ";

}
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.
P
15
. Interclasarea vectorilor
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 -
#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] << " ";

}
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[dimensiune
1
][dimensiune
2
] sau, mai general,
tip nume[dimensiune
1
][dimensiune
2
]...[dimensiune
n
]
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.
P
16
. Declarari de matrici. Cantitatea de memorie ocupata de matrici.
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 -
#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";

}
Introducere in ANSI C++
Figura 6.3
P
17
. Se citeste o matrice de la tastatura. Afisati matricea.
n=2
m=2
A[0][0]=1
A[0][1]=2
- 86 -
A[0][0] A[0][1] A[0][2]
A[1][0] A[1][1] A[1][2]
. . .
. . .
A[0][9]
A[1][9]
A[9][0] A[9][1] A[9][2]
. . .
A[9][9]
.

.

.
.

.

.
.

.

.
.

.

.
Linia 0
Linia 1
Linia 9
C
o
l
o
a
n
a

1
C
o
l
o
a
n
a

0
C
o
l
o
a
n
a

9
#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;
}
}
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:
6.8 Probleme cu matrici
P
18
. Afisati pe coloane o matrice initializata din cod
1 4 7
2 5 8
3 6 9
- 87 -
for(i=0;i<n;i++)
for(j=0;j<m;j++)
foloseste(A[i][j]);
#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;
}
}
Introducere in ANSI C++
P
19
. 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
- 88 -
#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;
}
}
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:
Figura 6.4
P
20
. Completati o matrice sub forma:
- 89 -
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
i
=
=
j
i<j
i>j
i
+
j
=
=
n
-
1
i+j<n-1
i+j>n-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;
}
}
Introducere in ANSI C++
P
21
. 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.
0 2 4 5
0 0 9 1
1 2 3 4
1 5 7 0
- 90 -
#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;
}
}
Introducere in ANSI C++
6.9 Probleme propuse
Pp
1
. 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 :))
Pp
2
. 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
Pp
3
. 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.
Pp
4
. Un vector contine cifre. Care este cel mai mare numar de trei cifre care
poate fi format din cifrele vectorului?
Pp
5
. 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).
Pp
6
. Se citeste o matrice de la tastaura. Verificati daca elementele de pe
diagonale sunt in ordine crescatoare sau descrescatoare, afisand mesaje sugestive
pe ecran.
Pp
7
. 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.
Pp
8
. 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]=c
1
c
2
...c
n
, sau
char nume[]=c
1
c
2
...c
n

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


compilator:
char nume[dimensiune]={c1,c2,...,cn}
P
1
. Exemple de declarari/initializari de siruri.
Vectorul S ocupa 100 octeti
Vectorul s ocupa 20 octeti
Vectorul X ocupa 4 octeti
Vectorul Y ocupa 4 octeti
- 92 -
#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";

}
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:
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.
P
2
. Diferenta dintre un caracter si sirul de caractere corespunzator.
Caracterul 'A' ocupa 1 octeti
Sirul "A" ocupa 2 octeti
Este necesara folosirea secventelor escape pentru afisarea si .
- 93 -
a b c \0 ? ...
X[0] X[1]
#include <iostream>
using namespace std;
int main(){

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

}
Introducere in ANSI C++
Diferenta de reprezentare este evidentiata de Figura 7.2:
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:
P
3
. Citirea/scierea sirurilor de caractere.
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 -
A A \0
Caracterul A Sirul de caractere A
#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;

}
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:
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:
Verificarea daca un caracter este sau nu litera mare:
- 95 -
for(i=0;S[i];i++)
foloseste(S[i]);
If ((c>=0)&&(c<=9))
foloseste(c);
If ((c>=A)&&(c<=Z))
foloseste(c);
Introducere in ANSI C++
P
4
. Se citeste un sir de caractere fara spatii. Inlocuiti literele mici cu litere mari
si invers.
Introduceti un sir: abcDEF123
ABCdef123
P
5
. Se citeste un sir de caractere cantinand cuvinte separate de unul sau mai
multe spatii. Afisati numarul de cuvinte.
Introduceti un sir: Ana are laptop
Numarul de cuvinte:3
- 96 -
#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;
}
#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;
}
Introducere in ANSI C++
In problema P
5
, 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
strlen(S)
Returneaza lungimea sirului
dat ca paramentru
strlen("trei") -> 4
strcpy(S1,S2)
Copiaza S2 peste S1
strcpy(S,"abcd")
strcat(S1,S2)
Concaterneaza S2 la S2
strcpy(S,"Imi place ");
strcat(S,"C++");
strcmp(S1,S2)
Compara lexicografic
sirurile date ca parametri.
Returneaza
0 daca S1==S2
< 0 daca S1<S2
> 0 daca S1>S2
if (strcmp(S1,S2)==0)
cout << "Egale";
else
cout << "Diferite";
atoi(S)
Returneaza numarul intreg
corespunzator sirului dat
i=atoi("123")
strchr(S,c)
strstr(S1,S2)
Returneaza o valoare
pozitiva daca un caracter
(respectiv sir) apare intr-un
sir, 0 in caz contrar
if (strchr(S,c))
cout << "L-am gasit!"
itoa(S,nr,baza)
Depoziteaza in S sirul
corespunzator numarului nr,
in baza baza
itoa(S,"123",10)
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.
P
6
. Se citeste un sir de caractere. Afisati lungimea acestuia.
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 -
#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);

}
Introducere in ANSI C++
P
7
. Se citeste un sir de caractere. Copiati-l in alt sir.
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
P
8
. 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 -
#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;

}
Introducere in ANSI C++
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" !!!!
P
9
. 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 -
#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;
}
Introducere in ANSI C++
Introduceti sirul 1: trei
Introduceti sirul 2: patru
"trei" este mai mare ca "patru"
P
10
. Se citesc doua siruri de caractere reprezentand numere intregi. Faceti
suma lor, apoi afisati pe ecran rezultatul.
Introduceti numarul 1: 123
Introduceti numarul 2: 234
123 + 234 = 357
- 101 -
#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<<"\"";;
}
#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;
}
Introducere in ANSI C++
P
11
. Verificati daca un nume apare intr-un sir.
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 -
#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 << "\"";

}
Introducere in ANSI C++
P
12
. 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.
Introduceti ziua 1: marti
Introduceti ziua 2: joi
-----------------------
marti
miercuri
joi
- 103 -
#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";
}
Introducere in ANSI C++
7.6 Alte aplicatii
P
13
. Se citeste un sir de caractere de la tastatura. Afisati toate prefixele si
sufixele acestuia.
abcdef
Prefixe:
abcdef abcde abcd abc ab a
Sufixe:
abcdef bcdef cdef def ef f
- 104 -
#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 << " ";
}
}
Introducere in ANSI C++
P
14
. Se citesc de la tastatura siruri de caractere pana la intalnirea sirului
"stop". Afisati cuvantul de lungime maxima.
mic mare scurt lung stop
Cuvantul cel lung: scurt
- 105 -
#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;
}
Introducere in ANSI C++
7.7 Probleme propuse
Pp
1
. 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.
Pp
2
. Se citeste de la tastatura un sir de caractere continand litere mici si spatii.
Afisati cuvintele conponente, cate unul pe un rand.
Pp
3
. 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.
Pp
4
. Se citesc de la tastatura cuvinte (fara spatii), pana la citirea cuvantului
"gata". Afisati cel mai lung cuvant care contine doar vocale.
Pp
5
. 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.
Pp
6
. 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.
P
1
. Definiti structura persoana, continand (nume, prenume, varsta). Definiti o
variabila initializata de tipul persoana, mariti varsta cu 1, apoi afisati pe ecran.
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.
Figura 8.1
Tipurile de date definite prin cuvantul cheie struct pot fi transmise ca parametri
sau pot fi returnate din functii.
- 108 -
#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;
}
struct persoana{
nume char[20];
int varsta;
float inaltime;
};
nume
varsta
inaltime
20 bytes
sizeof(int) bytes
sizeof(int) bytes
Introducere in ANSI C++
P
2
. Definiti structura complex (re,im). Implementati functiile suma, produs si
modul.
S=6+i*1
P=7+i*9
m=2.23607
- 109 -
#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);
}
Introducere in ANSI C++
Putem defini vectori de structuri sau structuri care contin alte structuri.
P
3
. 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.
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 -
#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;
}

}
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;
P
4
. 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++
0000h = 0
F000h = 4278190080
0F00h = 16711680
00F0h = 65280
000Fh = 255
- 112 -
#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;

}
Introducere in ANSI C++
P
5
. Definiti o uniune prin care putem memora oricare dintre figurile geometrice
urmatoare: cerc, triunghi, dreptunghi.
Cerc:10,10,5
Dreptunghi: (1,2) (15,20)
- 113 -
#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 <<") ";
}
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.
P
6
. Definiti si utilizati un camp de biti pentru stocarea unei date calendaristice.
29 4 73
Pentru acest exemplu avem urmatoare situatie in memorie:
Figura 8.2
- 114 -
#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;
}
struct data{
unsigned zi:5;
unsigned luna:4;
unsigned an:7;
};
zi luna
0 15
an
4 5 8 9
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.
P
7
. Definiti si utilizati o enumerare pentru lucrul cu zilele saptamanii.
treaba treaba treaba treaba treaba liber liber
- 115 -
#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 ";
}
Introducere in ANSI C++
P
8
. Definiti si utilizati o enumerare care asociaza notele si calificativele.
Dati o nota:8
e ok!
- 116 -
#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!";
}
Introducere in ANSI C++
8.5 Probleme propuse
Pp
1
. Definiti o structura de lucru cu numare rational si implementati operatiile
de adunare, scadere si inmultire.
Pp
2
. 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.
Pp
3
. 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.
Pp
4
. 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:
Figura 9.1
Cum o functie modeleaza un algoritm (subalgoritm), forma generala a unei
functii este data de:
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 -
Algoritm
date de intrare date de iesire
Functie
date de intrare date de iesire
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:
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 -
Functie
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.
P
1
. Realizati o functie care afiseaza un mesaj de intampinare pe ecran.
*******************
* Bine ati venit! *
*******************
P
2
. 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 -
#include <iostream>
using namespace std;
void Mesaj(void);
int main(){
Mesaj();
}
void Mesaj(){
cout << "*******************" << endl;
cout << "* Bine ati venit! *" << endl;
cout << "*******************" << endl;
}
Introducere in ANSI C++
*
***
*****
*******
|
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:
Figura 9.4
Prototipul:
void nume_functie(lista_parametri);
iar apelul:
- 121 -
#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;
}
Functie
date de intrare
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:
P
3
. Realizati o functie care, primind ca parametri doua numere intregi a si b,
afiseaza pe ecran valorile pare din intervalul [a,b].
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:
Figura 9.5
- 122 -
#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;
}
int main(){
afisare(2,7);
}
vf
Stiva Pozitia in program
Introducere in ANSI C++
Pas 2. Apelul (intrarea in functie)
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
Figura 9.6
- 123 -
int main(){
afisare(2,7);
}
void afisare(int a, int b){
int i;
...
}
vf
Stiva Pozitia in program
2
7
?
i
b
a
int main(){
afisare(2,7);
}
void afisare(int a, int b){
int i;
...
}
vf
Stiva Pozitia in program
2
7
8
i
b
a
Introducere in ANSI C++
Observam modificarea valorii variabilei locale i, conform instructiunilor
executate.
Pas 4. Revenirea din functie
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.
P
4
. Realizati o functie care afiseaza un bradulet pe ecran, cu dimensiunea data
de un parametru.
- 124 -
int main(){
afisare(2,7);
}
vf
Stiva Pozitia in program
Introducere in ANSI C++
*
***
*****
|
*
***
*****
*******
*********
|
- 125 -
#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 << "|" ;
}
Introducere in ANSI C++
P
5
. Folosind functii, afisati pe ecran urmatoare piramida de numere:
1
1 2 1
1 2 3 2 1
....................
1
121
12321
1234321
123454321
- 126 -
#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;
}
Introducere in ANSI C++
9.4 Functii care nu primesc date de intrare dar returneaza
o valoare
Forma generala este:
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();
P
6
. Realizati o functie care returneaza valoarea lui Pi cu doua zecimale exacte.
- 127 -
Functie
date de iesire
Introducere in ANSI C++
3.14
P
7
. Realizati o functie care citeste de la tastatura valori intregi (<1000) pana la
intalnirea valorii 1000 si returneza minimul acestor valori.
12 45 29 1000
45
- 128 -
#include <iostream>
using namespace std;
float Pi();
int main(){
cout << Pi();
}
float Pi(){
return 3.14;
}
#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;
}
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:
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.
P
8
. Realizati urmatoarele functii:
max(a,b)
modul(a)
min(a,b,c)
- 129 -
Functie
date de intrare data de iesire
Introducere in ANSI C++
a=-6
b=3
c=1
max(-6,3)=3
|-2|=2
min=-2
Observam diferite modalitati de a apela functiile cerute in enunt.
P
9
. Realizati functiile cu urmatoarele prototipuri:
int sumac(int); // suma cifrelor unui numar
- 130 -
#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;
}
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
a=5123
- 131 -
#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;
}
Introducere in ANSI C++
b=4
sumac(5123)=11
sumadiv(5123)=5280
primac(5123)=5
fact(4)=24
P
10
. 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
x=28
- 132 -
#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;
}
Introducere in ANSI C++
28 nu este prim
28 este perfect
P
11
. Folosind functii, afisati cel mai mare numar prim mai mic ca n (numar
intreg citit de la tastatura).
x=100
Cel mai mare numar prim mai mic ca 100 este 97
9.6 Functii ce returneaza mai multe valori
Forma generala:
Figura 9.10
Vom prezenta in continuare doua variante de realizare.
- 133 -
#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;
}
Functie
date de intrare date de iesire
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.
P
12
. Realizati o functie care calculeaza suma si produsul a doua numere reale.
- 134 -
Introducere in ANSI C++
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 -
#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;
}
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.
P
13
. Realizati o functie care returnezeaza maximul si minimul a doua valori
intregi.
2 6
P
14
. Functie care interschimba doua variabile.
- 136 -
#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;
}
Introducere in ANSI C++
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.
P
15
. Variabile locale (fara folosirea functiilor).
- 137 -
#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;
}
Introducere in ANSI C++
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 -
#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
}

}
Introducere in ANSI C++
P
16
. Variabile locale si variabile globale
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.
P
17
. La afisarea unei piramide de numere, folosirea variabielor globale poate
duce la erori logice.
Varianta 1 in cazul folosirii variabilelor locale
- 139 -
#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;
}
Introducere in ANSI C++
1
21
321
4321
Varianta 2 in cazul folosirii variabilelor globale
1
1
- 140 -
#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;
}
#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;
}
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.
P
18
. Calculati max(a,b,c), folosind max(a,b).
5
P
19
. Alt exemplu de supradefinire a functiilor
- 141 -
#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;
}
Introducere in ANSI C++
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
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 -
#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;
}
...........
int main(){
este(123);
este(3.14);
este('e');
}
...........
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.
P
20
. Functie cu parametri impliciti care afiseaza un interval, cu un pas dat.
1 3 5 7
1 2 3 4 5 6 7 8
- 143 -
#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;
}
Introducere in ANSI C++
P
21
. Functie cu parametri impliciti care calculeaza minimul a maxim patru
valori.
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 -
#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));
}
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.
P
22
. Functii care realizeaza urmatoarele operatii pe vectori:
initializare cu valori aleatoare
citire
afisare
suma elementelor
- 145 -
Introducere in ANSI C++
n=3
83 86 77
n=4
1 2 3 4
10
- 146 -
#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;
}
Introducere in ANSI C++
P
23
. Fie doi vectori reprezentand multimi de valori intregi. Realizati functii care
fac: intersectia, reuniunea, diferenta
- 147 -
#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] << " ";
}
Introducere in ANSI C++
4 8
2 4 8 1 14
2
9.11 Probleme propuse
Pp
x
. 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 dect 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!
Plecam de la formula recursiva de calcul

>
=
=
0 , )! 1 (
0 , 1
!
n n n
n
n
.
Rescriind formula intr-o varianta mai apropiata de implementarea C/C++, avem:
- 149 -
Introducere in ANSI C++

>
=
=
0 ), 1 ( *
0 , 1
) (
n n fact n
n
n fact
Trecerea la urm torul program este naturala:
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 -
#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)!
}
Introducere in ANSI C++
Figura 10.1 ilustreaza succesiune de apeluri recursive:
Figura 10.1
P2. Realizati o functie recursiva care calculeaza 2
n
.
- 151 -
long fact(3){
if(3==0) return 1;
return 3*fact(2);
}
3 n vf
long fact(2){
if(2==0) return 1;
return 2*fact(1);
}
3 n
vf
2 n
long fact(1){
if(1==0) return 1;
return 1*fact(0);
}
long fact(0){
if(0==0) return 1;
return n*fact(n-1);
}
I
n
t
r
a
r
e
a

i
n

r
e
c
u
r
s
i
v
i
t
a
t
e
3 n
vf
2 n
1 n
3 n
vf
2 n
1 n
0 n
I
e
s
i
r
e
a

i
n

r
e
c
u
r
s
i
v
i
t
a
t
e
Introducere in ANSI C++
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?
6
fibo(6)=8
Nr. apeluri:15
- 152 -
#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);
}
#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);
}
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.
abcd
dcba
- 153 -
#include <iostream>
using namespace std;
void invers();
int main(){
invers();
}
void invers(){
char c;
c=getchar();
if (c!='\n') invers();
cout << c;
}
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 xy
g x , y1 , pentruxy
unde
g x , y=
xy5, pentru xy5
2f 0, y , pentru xy5
19
- 154 -
#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);
}
Introducere in ANSI C++
10.3 Probleme propuse
Pp
1
. 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
Pp
2
. Functie recursiva care afiseaza cifrele unui numar.
Pp
3
. Functie recursiva care descompune un numar in factori primi.
Pp
4
. Fie un vector de numere intregi pozitive definit global. Realizati o functie
recursiva care calculeaza cmmdc-ul elementelor din vector.
Pp
5
. Scrieti functii recursive pentru a afisa urmatoare piramida de numere:
1
1 2
1 2 3
..........
Pp
6
. 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.
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:
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 -
Algoritm
stdin stdout
Algoritm
stdin
stdout
3 5
9 12
Suma:
29
Introducere in ANSI C++
P
1
. Fisierul "intrare.txt" contine numere 2 numere intregi. Scrieti in fisierul
"iesire.txt" suma acestor doua numere.
intrare.txt: 2 5
iesire.txt: 7
P
2
. Se citeste de la tastatura numele unui fisier care contine 10 numere intregi.
Afisati pe ecran suma lor.
Dati fisierul de intrare:intrare.p02
55
- 157 -
#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;
}
#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;
}
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++
P
3
. Fisierul "intrare.txt" contine numere 2 numere intregi. Scrieti in fisierul
"iesire.txt" suma acestor doua numere. (identic cu P
1
, dar rezolvare cu fluxuri)
intrare.txt: 2 5
iesire.txt: 7
P
4
. 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.
intrare.p04: Voinea Mircea
Tica Silviu
Toth Haralambie
Ion Ion
Gheorghe Gheorghe
ecran:
Tica Silviu
- 159 -
#include <fstream>
using namespace std;
int main(){
int a,b;
ifstream fin("intrare.txt");
ofstream fout("iesire.txt");

fin >> a >> b;
fout << a+b;
}
#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;
}

}
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:
P
5
. 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.
numere.p05
8
1 2 3 4 1 2 3 4
iesire.p05
1 2 3 4 1
2 3 4
- 160 -
flux_intrare >> Nr_valori;
for(i=1;i<=Nr_valori;i++){
flux_intrare >> X;
foloseste(X);
}
#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;
}

}
Introducere in ANSI C++
P
6
. 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.
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:
- 161 -
#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;
}
}
while (flux_intrare >> X)
foloseste(X);
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:
P
7
. Se citeste numele unui fisier text de la tastatura. Realizati o copie a acestuia
in fiserul "copie.txt".
P
8
. Fie fisierul "intrare.p08". Scrieti in fisierul "frecv.p08" caracterele care
apar in fiserul de intrare si de cate ori apar ele.
- 162 -
#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;
}
}
while (!flux_intrare.eof()){
flux_intrare >> X;
foloseste(X);
}
Introducere in ANSI C++
intrare.p08
abc abc
abc dede
ffffffffff
frecv.p08
2
a 3
b 3
c 3
d 2
e 2
f 10
- 163 -
#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;
}
Introducere in ANSI C++
11.5 Probleme propuse
Pp
1
. 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.
Pp
2
. Verificati daca n fisiere citite de la tastatura sunt identice ca si continut.
Pp
3
. Numarati cuvintele dintr-un fiser text. Separatorii dintre cuvinte sunt Enter,
, si ..
Pp
4
. Un fisier contine numere intregi. Scrieti numerele pare intr-un fiser si cele
impare in altul.
Pp
5
. Cititi o matrice dintr-un fisier. Scrieti inversa matricii in alt fisier.
Pp
6
. 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 *pointer
1
, *pointer
2
, ..., pointer
n
;
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;
P
1
. Operatii elementare cu pointeri
0x8048906
0xbff9eefc 0xbff9eef8
0xbff9ef04 0xbff9ef04 0xbff9ef00 0xbff9ef00
11 11 3 3
La rulari succesive adresele afisate pot sa difere.
- 166 -
#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;
}
Introducere in ANSI C++
Starea memoriei in cazul problemei P
1
poate fi urmatoarea:
1. Dupa declaratii:
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:
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.
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 -
...
0xbff9ef00 0xbff9ef04 3 11
...
0xbff9eef8 0xbff9eefc 0xbff9ef00 0xbff9ef04
q p b a
copie_a
...
3 11
q p
b a
copie_a
...
... ?
0x8048906 2 1
...
0xbff9eef8 0xbff9eefc 0xbff9ef00 0xbff9ef04
q p b a
copie_a
Introducere in ANSI C++
P
2
. Tipul indicat de un pointer
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.
P
3
. Pointerii void si modul lor de utilizare
- 168 -
#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;

}
Introducere in ANSI 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 -
#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;
}
Introducere in ANSI C++
P
4
. Pointeri la pointeri.
123 123
Situatia din problema anterioara este descrisa in Figura 12.4.
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 -
#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
i
p q t
Introducere in ANSI C++
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.
P
5
. Atribuirea pointerilor
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).
P
6
. Afisati locatia cea mai mica si locatia cea mai mare de memorie alocate in
- 171 -
123
pn
p1 p2
...
?
?
123
pn
p1 p2
...
#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);
}
Introducere in ANSI C++
program.
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 -
#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)

}
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
-=.
P
7
. Adunarea si scaderea dintre un pointer si un intreg
0xbfcb90ac 0xbfcb90a8
0xbfcb90b0 0xbfcb90d0
0xbfcb90ac 0xbfcb90a8
- 173 -
#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;

}
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++
P
8
. Alocarea dinamica a memoriei
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
P
9
. Folosirea pointerilor la structuri.
- 175 -
#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!";
}
Introducere in ANSI C++
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.
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 -
#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";
}
? ? ? ? ? ? ...
A
10 intregi
Introducere in ANSI C++
Figura 12.7
P
10
. Diferite modalitati de acces la elementele unui tablou
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:
O alta variantaimplica pozitionarea unui pointer pe pozitia imediat urmatoare
ultimului element din tablou si folosirea acestui pointer la verificarea sfarsitului de
vector:
P
11
. Impementati functiile de initializare random, de citire si de afisare a
vectorilor fara a folosi notatia indexata.
- 177 -
? ? ? ? ? ? ...
*A
10 intregi
A[1] *(A+2) *(3+A) 4[A]
#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 << " ";

}
for(p=A;p-A<n;p++)
foloseste(*p);
sf=A+n; // sau sf=&A[n];
for(p=A;p<sf;p++)
foloseste(*p);
Introducere in ANSI C++
n=3
10 20 30
3 6 7 5 3
10 20 30
- 178 -
#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;
}
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:
Accesul la elementele vectorului poate fi facut indexat sau folosind pointeri.
P
12
. 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 -
cin >> n;
A= new tip[n];
foloseste(A,n);
delete []A;
Introducere in ANSI C++
n=10
1 0 1 1 1 1 0 0 1 1
0 0 0 1 1 1 1 1 1 1
- 180 -
#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;
}
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.
Figura 12.8
P
13
. Fie o matrice patratica de intregi initializata random. Sortati crescator
fiecare linie a matricii.
- 181 -
A[0][0] A[0][1] A[0][2]
A[1][0] A[1][1] A[1][2]
. . .
. . .
A[0][9]
A[1][9]
A[9][0] A[9][1] A[9][2]
. . .
A[9][9]
.

.

.
.

.

.
.

.

.
.

.

.
A[0]
A[1]
A[9]
Introducere in ANSI C++
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 -
#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; }
}
Introducere in ANSI C++
Un caz in care folosirea vectorilor de pointeri se dovedeste utila este cazul in
care lucram cu matrici de caractere.
P
14
. Fie o matrice de caractere initializata cu zilele saptamanii. Afisati zilele in
ordine lexicografica.
luni marti miercuri joi vineri sambata duminica
duminica joi luni marti miercuri sambata vineri
- 183 -
#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]);
}
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*&, ...);
P
15
. Functie care realizeaza interschimarea a doua variabile de tip intreg,
folosind parametri pointeri.
- 184 -
Introducere in ANSI C++
1 2
2 1
Observam ca apelul trebuie facut cu adresele variabilelor de interschimbat!
P
16
. Functie care interschimba doi pointeri la int.
1 2
2 1
Daca nu am fi folosit referinte la pointeri interschimarea ar fi avut loc doar in
- 185 -
#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;
}
#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;
}
Introducere in ANSI C++
cadrul functiei. Urmatoarea varianta este echivalenta.
P
17
. Functie care interschimba doi pointeri la int (varianta 2).
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.
P
18
. Realizati o functie care, primind ca parametri doi vectori alocati static si
lungimile acestora, realizeaza interschimbarea lor (ca si continut).
- 186 -
#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;
}
Introducere in ANSI C++
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.
P
19
. Realizati o functie care, primind ca parametri doi vectori alocati dinamic si
lungimile acestora, realizeaza interschimbarea lor (ca si continut).
- 187 -
#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;
}
Introducere in ANSI C++
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 -
#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;
}
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.
P
20
. Functii de alocare/dealocare dinamica a vectorilor.
5
1 2 3 4 5
A:1 2 3 4 5
P
21
. Afisati prima linie dintr-o matrice patratica ce contine cel putin o valoare
nula (se stie ca matricea contine cel putin un zero).
- 189 -
#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;
}
Introducere in ANSI C++
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 -
#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];
}
Introducere in ANSI C++
P
22
. Apelul unei functii folosind un pointer la functie.
20 30
P
23
. Functie are primeste ca parametru alta functie.
sin(0)=0
- 191 -
#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;}
#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);
}
Introducere in ANSI C++
pow(2,3)=8
functia mea(2,3)=13
P
24
. Folosirea unui vector de pointeri la functii.
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 -
#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;
}
}
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:
Figura 12.9
Conform observatiilor anterioare, situatie memorie este:
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.
P
25
. Functie cu numar variabil de parametri care calculaeza o expresie de
forma: c
1
op
1
c
2
op
2
c
3
... op
n
c
n+1
, unde c
i
sunt intregi si op
i
este + sau -.
- 193 -
p1
p2
pn
...
...
parametri
cunoscuti
...
...
...
parametri
necunoscuti
Stiva
p1 p2 pn ... ...
parametri
cunoscuti
parametri
necunoscuti
Introducere in ANSI C++
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 -
#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;
}
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:
In acest caz, parametri sunt dati practic de elementele vectorului p: p[1],
p[2], ...,p[nr].
P
26
. Functie cu numar necunoscut de parametri care realizeaza suma valorilor
(primul parametru da numarul de parametri necunoscuti).
10
-3
- 195 -
tip_returnat nume(int nr, ...){
tip *p=&nr;
for(int i=1;i<=nr;i++)
foloseste(p[i]);
}
#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;
}
Introducere in ANSI C++
12.7 Probleme propuse
Pp
1
. Rescrieti functiile de la problemele rezolvate din capitolele cu vectori si cu
siruri de caractere folosind pointeri (fara acces indexat).
Pp
2
. Realizati o functie cu numar variabil de parametri care calculeaza cmmdc-
ul parametrilor.
Pp
3
. 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
incorrectly
';' dupa main(), inainte de '{'
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
module c0.ASM
s-a gresit numele functiei main (de
exemplu s-a scris mein)
Undefines symbol 'cout'
s-a uitat #include <iostream.h>
Illegal structure operation
schimbati '<<' cu '>>' sau invers
Function 'cutarescu' should
have a prototype
lipseste o directiva #include sau am
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
1 :: scope
Left-to-
right
2
() [] . -> ++ --
dynamic_cast static_cast
reinterpret_cast
const_cast typeid
postfix
Left-to-
right
3
++ -- ~ ! sizeof new
delete
unary (prefix)
* &
indirection and
reference (pointers)
+ - unary sign operator
Right-
to-left
4 (type) type casting
Right-
to-left
5 .* ->* pointer-to-member
Left-to-
right
6 * / % multiplicative
Left-to-
right
7 + - additive
Left-to-
right
8 << >> shift
Left-to-
right
- 208 -
Introducere in ANSI C++
9 < > <= >= relational
Left-to-
right
10 == != equality
Left-to-
right
11 & bitwise AND
Left-to-
right
12 ^ bitwise XOR
Left-to-
right
13 | bitwise OR
Left-to-
right
14 && logical AND
Left-to-
right
15 || logical OR
Left-to-
right
16 ?: conditional
Right-
to-left
17
= *= /= %= += -= >>= <<=
&= ^= !=
assignment
Right-
to-left
18 , comma
Left-to-
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 -

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