Sunteți pe pagina 1din 342

Executarea unui program in mod simplu se face cu combinatia de taste CTRL si F5

CONSTRUCTIA PROGRAMELOR IN Visual C++.Net


1)Intru in Visual studio.net
2)File/new project
3)Visual C++ si aleg Window Command Apas PE
4)dau numele proiectului OBJECT
5) BROWSER

APAS PE
ACEASTA
OPTIUNE

SCRIU PROGRAMUL SI O SA–


L RULEZ cu CTRL si F5
Il rulez
apasand
dublu clic

asa am vazut executia


INTRARE/IESIERE VISUAL c++.NET
Operaţii de intrare/ieşire în C++

C++ defineşte propriul său sistem de intrare/ieşire orientat pe obiecte. Ca şi sistemul


de I/E din C, cel din C++ este complet integrat. Aceasta înseamnă că diferitele aspecte ale
intrărilor sau ieşirilor din C++, cum ar fi operaţiile cu consola sau cu discul, sînt doar
perspective diferite ale aceluiaşi mecanism.
Sistemul de I/E din C este foarte bogat, flexibil şi puternic. Întrebarea care se pune pe
bună dreptate este de ce este necesară introducerea unui mecanism nou în C++. Răspunsul este
acela că sistemul de I/E din C nu cunoaşte obiectele, iar pentru a asigura un suprot complet
pentru programarea orientată pe obiecte, a fost necesară crearea unui sistem astfel orientat.
Acesta trebuie să poată opera cu obiectele create de utilizator. Mai există însă şi alte avantaje
ale utilizării sistemului de I/E definit în C++, care pot ieşi în evidenţă chiar în aplicaţii care nu
sînt scrise orientate pe obiecte.

Stream-uri în C++

Ca şi sistemul de I/E dinj C, cel din C++ operează pe fluxuri de informaţie - stream-
uri. Un stream este o entitate logică care produce sau primeşte informaţie. Un stream este legat
de un echipament fizic prin intermediul sistemului de I/E din C++. Toate stream-urile se
comportă la fel, chiar dacă echipamentele fizice la care sînt conectate efectiv pot să fie foarte
diferite. Aceleaşi funcţii de I/E pot opera, teoretic, asupra oricărui tip de echipament fizic. De
exemplu, aceeaşi funcţie care scrie într-un fişier poate fi folosită şi pentru a scrie la imprimantă
sau pe ecran. Avantajul acestei abordări este că interfaţa este astfel standardizată, unificată şi
deci trebuie cunoscută doar această modalitate universală de acces.

Ierarhia de clase pentru stream-uri

C++ asigură suportul pentru sistemul său de I/E în fişierul antet IOSTREAM.H. Aici
sînt definite două ierarhii de clase care admit operaţii de I/E. Clasa cu nivelul cel mai scăzut se
numeşte streambuf şi asigură operaţiile de bază de intrare şi de ieşire. Această clasă nu va fi
folosită direct decît dacă se doreşte derivarea propriilor clase de I/E. A doua ierarhie porneşte
cu clasa ios, care acceptă I/E formatate. Ierarhia completă este prezentată în fig. 8.1. Din
ierarhie fac parte clasele istream, ostream şi iostream Aceste clase sînt folosite pentru a crea
stream-uri capabile să introducă, să obţină şi respectiv să facă ambele operaţii. Dar se observă
că din ios mai sînt derivate multe alte clase pentru utilizarea fişierelor de pe disc şi formatarea
în memorie. Clasa ios conţine şi ea multe funcţii şi variabile membre care controlează sau
urmăresc operaţiile fundamentale asociate stream-ului. Dacă sistemul de I/E din C++ este
folosit în manieră normală, membrii clasei ios vor fi capabili să lucreze cu orice stream.

Clasa streambuf oferă o zonă de memorie tampon (buffer) şi metodele de lucru


asociate pentru operaţii cu caracter general, cu formatare minimă (sau fără formatare). Din
streambuf sînt derivate clasele :

- filebuf, specializată pe operaţii cu fişiere


- strstreambuf, pentru operaţii de formatare a datelor în memorie (similare celor
efectuate de sscanf() şi sprintf() din C)
Fig.. Clasele de intrare/ieşire din C++

Obiecte aparţinînd celor trei clase sînt utilizate de a doua ierarhie, avînd ca bază clasa
ios.
Clasa ios conţine adresa unui obiect streambuf, variabila de stare (care conţine
erorile înregistrate la ultimul transfer), variabile de control al formatării datelor şi un set de
funcţii. Acestea permit efectuarea aunor operaţii de intrare/ieşire de bază, cu sau fără formatare
şi control al erorilor folosind un obiect streambuf. Clasa ios este baza unei ierarhii mai
complexe, în care se foloseşte şi moştenirea multiplă. Toate clasele derivate sînt capabile de
operaţii cu sau fără formatare şi control al erorilor, datorită calităţilor moştenite de la ios, dar
sînt dedicate unor tipuri de operaţii diferite.
Se disting 3 direcţii de specializare, cărora le corespund următoarele categorii de clase :

1. Operaţii cu caracter general, folosind un streambuf :


- clasa istream, derivată din ios, pentru transferuri de la un obiect streambuf.
Obiectele
clasei reprezintă dispozitive de intrare.
- clasa ostream, derivată din ios, pentru transferuri către un obiect streambuf
(dispozitive de ieşire).
- clasa iostream, derivată din istream şi ostream pentru operaţii bidirecţionale
(dispozitive de intrare/ieşire).

2. Operaţiuni cu fişiere, utilizînd un filebuf :


- clasa fstreambase este derivată din ios şi constituie un nivel intermediar, care are
rolul de a adăuga aspectele specifice operaţiilor cu fişiere disc. Din fstreambase şi
clasele din categoria precedentă sînt derivate următoarele clase.
- clasa ifstream, derivată din istream şi fstreambase, pentru operaţii de intrare.
- clasa ofstream, derivată din ostream şi fstreambase, pentru operaţii de ieşire.
clasa fstream, derivată din iostream şi fstreambase, pentru operaţii de
intrare/ieşire.

3. Operaţii de formatare în memorie, folosind un obiect strstreambuf :


- clasa strstreambase este derivată din ios şi reprezintă nivelul intermediar, care
adaugă aspectele specifice fomării în memorie. Din strstreambase şi clasele din
categoria 1 sînt derivate dublu următoarele clase.
- clasa istrstream este derivată din istream şi strstreambase, pentru operaţii de citire.
- clasa ostrstream, derivată din ostream şi strstreambase, pentru operaţii de scriere.
- clasa strstream, derivată din iostream şi strstreambase, pentru operaţii de
citire/scriere.

Un stream C++ este deci un obiect aparţinînd uneia din clasele din cele 3 categorii
enumerate mai sus.

Stream-uri predefinite în C++

Cînd îşi începe execuţia un program scris în C++, se deschid automat patru stream-uri
încorporate. Acestea sînt :

Stream Semnificaţie Clasa din care face Dispozitiv Echivalent în C


parte implicit
cin intrare standard istream_withassign tastatură stdin
cout ieşire standard ostream_withassign ecran stdout
cerr ieşire standard pentru ostream_withassign ecran stderr
eroare (fără memorare)
clog versiune cu memorie ostream_withassign ecran fără echivalent
tampon pentru cerr

Implicit, stream-urile standard sînt folosite pentru a comunica cu consola. Însă, în


mediile care admit redirecţionarea I/E (DOS, Unix, Windows, OS/2), stream-urile standard pot
fi redirecţionate spre alte echipamente sau fişiere.
Standardul ANSI C++ mai defineşte patru stream-uri : win, wout, werr şi wlog, care
sînt folosite pentru seturile lărgite de caractere necesare anumitor limbi.

Clasele istream, ostream şi iostream

Clasele istream şi ostream (şi implicit toate derivatele lor, inclusiv iostream) dispun
de seturi de funcţii de intrare/ieşire şi supradefinesc cei doi operatori de deplasare (shift) pentru
a efectua transferul de informaţie cu un stream şi formatarea pentru tipurile de bază :
 operatorul << pentru operaţii de ieşire
 operatorul >> pentru operaţii de intrare

a. Clasa ostream
În clasa ostream, operatorul << este supradefinit sub forma :
ostream& operator <<(tip_de_baza);
şi se mai numeşte şi operator de inserare (într-un stream). Operatorul admite ca operanzi o
expresie de un tip fundamental oarecare şi (implicit) adresa obiectului din clasa ostream
specificat la apelare (un dispozitiv de ieşire). Rolul său este de a transfera valoarea expresiei, cu
un format adecvat, către acel stream. În plus, întoarce ca rezultat adresa dispozitivului pentru a
permite operaţii de ieşire multiple, înlănţuite. Exemplu (cunoscut de altfel din capitolele
precedente) :

float r=4.4, i=6.74;


cout <<”Numar complex, re = ”<< r <<”, im = ” << i << “\n”;

O secvenţă prea lungă se poate continua pe rîndul următor, ca în exemplul de mai jos
(o reluare a exemplului anterior):

cout <<”Numar complex, re = ”<< r


<<”, im = ” << i << “\n”;

Aşa cum ne aşteptăm, secvenţa va determina afişarea textului :

Numar complex, re = 5.5, im = 6.74

Operatorul este supradefinit astfel încît să admită toate tipurile fundamentale şi este
prevăzut pentru fiecare un format implicit (de aceea nu este obligatorie specificarea unui
format). Pentru tipurile pointer se afişează adresa completă în hexazecimal, cu segment şi
deplasament. În particular, pentru tipul (char*) se afişează şirul de caractere şi nu adresa. Pentru
afişarea adresei pentru acest tip de pointer se face o conversie explicită la tipul (void*). Mai jos
e prezentat un exemplu simplu pentru aceasta :

char str[]=”Exemplificare”;
int i, *p=&i;

cout << str << “\n”;


cout << (void*)str << “\n”;
cout << &i << “=” << p;

Se va afişa :

Exemplificare
0x8f55ffe6
0x8f55fff0=0x8f55fff0

Clasa dispune de o serie de funcţii membre, care asigură transferul informaţiei fără
formatare şi operaţii de poziţionare :

ostream& put(char c) - transferă caracterul c către dispozitivul apelant


Exemplu :
char c;
cout.put( c ); // echivalent cu cout << c;
ostream& write(const char *tab, int n) - transferă blocul de octeţi tab, de lungime n, fără nici
o modificare, către dispozitivul apelant
Exemplu :
char text[]=”Mesaj”;
cout.write(text, strlen(text));

ostream& seekp(long n) - efectuează poziţionarea absolută în stream, pe octetul n


(numerotarea se face de la zero).

ostream& seekp(long n, seek_dir ref) - poziţionare relativă în stream, cu referinţa la tipul


enumerare seek_dir, declarat împreună cu ios (funcţie supradefinită). Valorile din
enumerare sînt {beg, cur, end} şi semnifică începutul, poziţia curentă şi sfîrşitul
stream-
ului.

long tellp() - întoarce poziţia absolută în stream

ostream& flush() - goleşte tamponul, transferînd datele către dispozitivul fizic asociat.

b. Clasa istream

În clasa istream operatorul >> este supradefinit sub forma :

istream & operator >>(&tip_de_baza);

şi se mai numeşte operator de extragere (dintr-un stream).


Operatorul primeşte ca argumente adresa unei variabile de un tip fundamental oarecare
(în afară de tipul pointer) şi adresa unui obiect din clasa istream (implicit). Citeşte din
dispozitivul de intrare o valoare pe care o înscrie în variabilă, după efectuarea operaţiei de
conversie la reprezentarea internă a datelor. Pentru operanzi de tip (char*) se citeşte şi
memorează un şir de caractere, iar celelalte tipuri pointer nu sînt admise.
Deoarece întoarce adresa dispozitivului, poate fi utilizat pentru operaţii de intrare
multiple, de exemplu :

cin >> x >> y;

Ca delimitatori ai valorilor citite se utilizează “spaţiile albe”, adică oricare dintre


caracterele blanc, tab orizontal (\t), tab vertical (\v), linie nouă (\n), retur (\r), pagină nouă (\f).
Delimitarea se aplică şi pentru şirurile de caractere şi din acest motiv şirurile care conţin spaţii
albe nu vor fi citite corect.
O serie de funcţii disponibile pentru această clasă asigură transferuri fără formatare şi
operaţii de poziţionare :

istream& get(char &) - extrage din dispozitivul de intrare un caracter (inclusiv spaţii
albe) şi îl
înscrie în variabila de tip char primită ca parametru
Exemplu :

// copiaza cin la cout


while(cin.get( c)) cout.put( c);
Funcţia este supradefinită de două ori, prin versiunile :

int get() - citeşte din stream şi întoarce ca rezultat un caracter (EOF la sfîrşitul
fişierului).

Exemplu :

while(c=cin(get)!=EOF) cout.put( c); // echivalent cu exemplul


// precedent

istream& get(char *str, int n, char delim=”\n”); - citeşte caractere din stream
în şirul
str pînă la întîlnirea delimitatorului specificat (implicit linie nouă) sau pînă la
completarea a (n-1) caractere sau pînă la sfîrşit de fişier. Delimitatorul poate
fi
orice valoare char şi nu este extras din stream. Şirul str este completat cu
terminatorul “\0”

istream& getline(char *str, int n, char delim=”\n”); - este similară cu funcţia precedentă
get() dar extrage şi delimitatorul fără a-l înscrie însă în şirul str. Funcţia substituie cu
succes operatorul de extragere >> pentru şiruri de caractere care includ spaţii albe. În
particular, valoarea implicită “\n” este adecvată citirii unei linii de text.

istream& read(char* tab, int n); - citeşte n octeţi din stream în tabloul tab. Spre deosebire
de
funcţiile precedente, nici un caracter de delimitare nu întrerupe citirea (nu se face nici o
interpretare a şirului de octeţi citit).

int gcount(); - întoarce numărul de caractere citite la ultima operaţie.

int peek(); - întoarce caracterul următor fără să-l extragă din stream.

istream& putback(char); - reinserează un caracter în stream.

Funcţiile
long tellg();
ostream& seekg(long n);
ostream& seekg(long n, seek_dir);

sînt similare cu tellp() şi seekp(), membre ale clasei ostream.

// Sa se scrie un mesaj pe o linie


#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
cout << "Hello World!\n";
return 0;
}
// sa se scrie trei fraze pe verticala.

#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {
cout << "I am Blaxxon," << endl;
cout << "the godlike computer." << endl;
cout << "Fear me!" << endl;

return 0;
}
// sa se scrie trei fraze pe orizontala.

#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {
cout << "I am Blaxxon, ";
cout << "the godlike computer. ";
cout << "Fear me!" << endl;

return 0;
}
// sa se scrie trei fraze pe verticala cu distanta de un rand intre
ele.

#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {
cout << "I am Blaxxon," << endl << endl;
cout << "the godlike computer." << endl << endl;
cout << "Fear me!" << endl;

return 0;
}
// sa se scrie transformarea din grade Celsius in grade Fahrenheit

#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {
double ctemp, ftemp;

cout << "Input a Celsius temp and press ENTER: ";


cin >> ctemp;
ftemp = (ctemp * 1.8) + 32;
cout << "Fahrenheit temp is: " << ftemp;

return 0;
}

// Sa se scrie evaluarea unei expresii pe coloane cu operatorul


//CAST (fortez tipul rezultatului)
#include "stdafx.h"
#include<iostream>
using namespace std;

int main()
{
cout << "Hello there.\n";
cout << "Here is 5: " << 5 << "\n";
cout << "The manipulator ." << endl;

cout << "Here is a very big number:\t" << 70000 << endl;
cout << "Here is the sum of 8 and 5:\t" << 8+5 << endl;
cout << "Here's a fraction:\t\t" << (float) 5/8 << endl;
cout << "And a very very big number:\t" << (double) 7000 *
7000 <<endl;

cout << "Don't forget to replace Jesse Liberty with your


name...\n";
cout << "Jesse Liberty is a C++ programmer!\n";
return 0;
}
// sa se scrie transformarea din grade Celsius in grade Fahrenheit
//evaluarea facandu-se direct cu formula

#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {

// Declare ctemp as a floating-pt variable.

double ctemp;

// Prompt and input value of ctemp (Celsius Temp).

cout << "Input a Celsius temp and press ENTER: ";


cin >> ctemp;

// Convert ctemp and output results.

cout << "Fahrenheit temp is: " << (ctemp * 1.8) + 32;

return 0;
}
// sa se scrie transformarea din grade Celsius in grade Fahrenheit
//evaluarea facandu-se direct cu formula

#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {

// Declare n as a floating-pt variable.

double n;

// Prompt and input value of n.


cout << "Input a number and press ENTER: ";
cin >> n;

// Calculate and output the square.

cout << "The square is: " << n * n;

return 0;
}
// sa se scrie transformarea din grade Fahrenheit in grade Celsius

#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {
double ctemp, ftemp;

cout << "Input a Fahrenheit temp and press ENTER: ";


cin >> ftemp;
ctemp = (ftemp - 32) / 1.8;
cout << "Celsius temp is: " << ctemp;

return 0;
}
// sa se scrie transformarea din grade Fahrenheit in grade Celsius
//direct ca expresie

#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {
double ftemp;

cout << "Input a Fahrenheit temp and press ENTER: ";


cin >> ftemp;
cout << "Celsius temp is: " << (ftemp - 32) / 1.8;

return 0;
}
// sa se scrie n la puterea 3

#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {

// Declare n as a floating-pt variable.

double n;

// Prompt and input value of n.

cout << "Input a number and press ENTER: ";


cin >> n;

// Calculate and output the square.


cout << "The cube is: " << n * n * n;

return 0;
}

//sa se scrie pe doua linii un mesaj si sa se dea exemplu de folosire


//a comentariilor
#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
/* this is a comment
and it extends until the closing
star-slash comment mark */
cout << "Hello World!\n";
// this comment ends at the end of the line
cout << "That comment ended!\n";

// double slash comments can be alone on a line


/* as can slash-star comments */
return 0;
}
//sa se demonstreze nr de octeti ocupat de tipurile de date
cunoscute
#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
cout << "The size of an int is:\t\t" << sizeof(int) << "
bytes.\n";
cout << "The size of a short int is:\t" << sizeof(short) << "
bytes.\n";
cout << "The size of a long int is:\t" << sizeof(long) << "
bytes.\n";
cout << "The size of a char is:\t\t" << sizeof(char) << "
bytes.\n";
cout << "The size of a float is:\t\t" << sizeof(float) << "
bytes.\n";
cout << "The size of a double is:\t" << sizeof(double) << "
bytes.\n";

return 0;
}

//sa se initializeze doua variabile in forma diferite


#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
unsigned short int Width = 5, Length;
Length = 10;

// create an unsigned short and initialize with result


// of multiplying Width by Length
unsigned short int Area = Width * Length;
cout << "Width:" << Width << "\n";
cout << "Length: " << Length << endl;
cout << "Area: " << Area << endl;
return 0;
}
TIPURI DE DATE ,OPERATORI,INSTRUCTIUNI
DECIZIONALE

TIPURI INTREGI

Tipurile intregi sunt:


 unsigned char→caracter fara semn, ocupa 8 biti si ia valori intre 0 si 255;
 char→caracter, ocupa 8 biti si ia valori intre -128 si 127;
 unsigned int→intreg fara semn,ocupa 16 biti si ia valori intre 0 si 65535;
 short int→intreg scurt, ocupa 16 biti si ia valori intre -32768 si 32767;
 int→intreg, ocupa de regula 16 biti si ia valori intre -32768 si 32767;
 unsigned long→intreg lung fara semn, ocupa 32 de biti si ia valori intre 0 si
4.294.967.295;
 long→intreg lung cu semn, ocupa 32 de biti si ia valori intre -2.147.483.648 si
2.147.483.647.
Variabilele de tip intreg folosesc pentru memorarea datelor codul
complementar.Caracterele se memoreaza prin codul ASCII.

TIPURI REALE

Variabilele de tip real retin numere cu zecimale.Tipurile reale sunt:


 float→ocupa 32 de biti si ia valori intre 3.4x10-38 si 3.4x1038;
 double→ocupa 64 de biti si ia valori intre 1.7x10-308 si 1.7x10308;
 long double→ocupa 80 de biti si ia valori intre 3.4x10-4932 si 1.1x104932.
pentru memorare datelor se foloseste reprezentarea in virgula mobila.
Operatorii aritmetici:
 + adunare, - scadere, * produs, / impartire, % - restul impartirii intregi
 ++, -- incrementare si decrementare
Operatori relationali:
 <,>
 = = egal
                    <= mai mic sau egal
                           >= mai mare sau egal
                            != diferit
Operatori logici:
 && - si logic
 || -sau logic
 ! - negatie logica
Instructiunea IF
 if (expresie) instructiune1 ;
else
instructiune2;
// sa se implemeteze un program care determina media aritmetica a
trei numere
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;
void main(void)
{
int a,b,c;
float s;
cin>>a;
cin>>b;
c=a/2+b/2;
s=(a+b+c)/3;
cout<<"Media aritmetica este="<<s;

Obs: Cand apar expresii de tipul :


++variabila
sau
--variabila;
spunem ca se realizeaza o preincrementare, respectiv predecrementare. In cazul preincrementarii, variabila
va primi ca valoare 1+valoarea initiala. Daca preincrementarea apare intr-o expresie se realizeaza intai
aceasta operatie si abia apoi celelalte operatii care mai apar in expresie (preincrementarea are prioritate
mai mare).La fel la predecrementare.La postincrementare intai se face oparatia cu variavila nemarita,apoi
dupa efectuarea expresiei se marestre variabila cu 1.La fel la postdecrementare.
}
// sa se implemeteze un program care determina
//functionarea operatorilor de incrementare.post
incrementare,decrementare
//postdecerementare
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

void main(void)
{
int a,b,i=3;
a=++i; //preincrementare a lui i
cout<<a;
b=a--; //postdecrementare
cout<<"a="<<a<<"\n";
cout<<"b="<<b<<"\n";
a+=++b; //atribuire compusa
cout<<"a="<<a<<"\n";
cout<<"b="<<b<<"\n";
}

//sa se creeze un tip de date utilizator care sa se numeasca USHORT


#include "stdafx.h"
#include<iostream>
using namespace std;
typedef unsigned short int USHORT; //typedef defined

void main()
{
USHORT Width = 5;
USHORT Length;
Length = 10;
USHORT Area = Width * Length;
cout << "Width:" << Width << "\n";
cout << "Length: " << Length << endl;
cout << "Area: " << Area <<endl;
}
//sa se determine limitele unui tip de data
#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
unsigned short int smallNumber;
smallNumber = 65535;
cout << "small number:" << smallNumber << endl;
smallNumber++;
cout << "small number:" << smallNumber << endl;
smallNumber++;
cout << "small number:" << smallNumber << endl;
return 0;
}
//prin fortarea tipului de date in CHAR se afiseaza caracterele
//care au codul ascii numarul convertit
#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
for (int i = 32; i<128; i++)
cout << (char) i;
return 0;
}
//sa se creeze un tip de date enumerare
//componentele sale se numara de la zero
#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
enum Days { Sunday, Monday, Tuesday, Wednesday, Thursday,
Friday,Saturday };

Days DayOff;
int x;

cout << "What day would you like off (0-6)? ";
cin >> x;
DayOff = Days(x);

if (DayOff == Sunday || DayOff == Saturday)


cout << "\nYou're already off on weekends!\n";
else
cout << "\nOkay, I'll put in the vacation day.\n";
return 0;
}
//sa se dea valori diferite aceleasi variabile
//o sa se retina ultima valoare si sa se puna in acelasi timp
//in doua variabile rezultatul unei expresii
#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
int a=0, b=0, x=0, y=35;
cout << "a: " << a << " b: " << b;
cout << " x: " << x << " y: " << y << endl;
a = 9;
b = 7;
y = x = a+b;
cout << "a: " << a << " b: " << b;
cout << " x: " << x << " y: " << y << endl;
return 0;
}
#include "stdafx.h"
//sa se demonstreze ce face prefixarea si postfixarea incrementarii
#include<iostream>
using namespace std;
int main()
{
int myAge = 39; // initialize two integers
int yourAge = 39;
cout << "I am: " << myAge << " years old.\n";
cout << "You are: " << yourAge << " years old\n";
myAge++; // postfix increment
++yourAge; // prefix increment
cout << "One year passes...\n";
cout << "I am: " << myAge << " years old.\n";
cout << "You are: " << yourAge << " years old\n";
cout << "Another year passes\n";
cout << "I am: " << myAge++ << " years old.\n";
cout << "You are: " << ++yourAge << " years old\n";
cout << "Let's print it again.\n";
cout << "I am: " << myAge << " years old.\n";
cout << "You are: " << yourAge << " years old\n";
return 0;
}
//sa se testeze operatorii relationali
#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
int RedSoxScore, YankeesScore;
cout << "Enter the score for the Red Sox: ";
cin >> RedSoxScore;

cout << "\nEnter the score for the Yankees: ";


cin >> YankeesScore;

cout << "\n";

if (RedSoxScore > YankeesScore)


cout << "Go Sox!\n";

if (RedSoxScore < YankeesScore)


{
cout << "Go Yankees!\n";
cout << "Happy days in New York!\n";
}
if (RedSoxScore == YankeesScore)
{
cout << "A tie? Naah, can't be.\n";
cout << "Give me the real score for the Yanks: ";
cin >> YankeesScore;

if (RedSoxScore > YankeesScore)


cout << "Knew it! Go Sox!";

if (YankeesScore > RedSoxScore)


cout << "Knew it! Go Yanks!";

if (YankeesScore == RedSoxScore)
cout << "Wow, it really was a tie!";
}

cout << "\nThanks for telling me.\n";


return 0;
}
// Programul care urmeaza calculeaza maximul dintre doua numere
citite este:

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

main ( )
{
int a,b,max;
cout<<"a="; cin>>a;
cout<<"b="; cin>>b;
if (a>b) max=a;
else max=b;
cout<<"maximul este"<<max;
}

//verificarea tipului unui triunghi


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >

void main()
{
int a,b,c;
cout<<"test de triunghi"<<endl;
cout<<"introduceti numerele intregi a,b,c"<<endl;
cin>>a>>b>>c;
if (a==b && a==c)
cout<<"triunghi echilateral"<<endl;
else if ((a*a+b*b==c*c) || (a*a+c*c==b*b) || (b*b+c*c==a*a) )
cout<<"triunghi dreptunghic"<<endl;
else if ( ( (a+b>c) && (a+c>b)&& (b+c>a)
)
)
cout<<"numerele nu pot alcatui un
triunghi"<<endl;
else if(a==b || b==c || a==c)
cout<<"triunghi
isoscel"<<endl;
else
cout<<"triunghi oarecare"<<endl;
}

//verificarea tipului unei progresii


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >

void main()
{
int a,b,c;
cout<<"introduceti a"<<endl;
cin>>a;
cout<<"introduceti b"<<endl;
cin>>b;
cout<<"introduceti c"<<endl;
cin>>c;
if (((float)(a+b)/2==c )||((float)(a+c)/2==b) ||((float)(b+c)/2==a ))
cout<<"aritmetica";
if ( (a*c==b*b) || (a*b==c*c) ||(b*c==a*a)) cout<<"geometrica";
else cout<<"neverificata";
}

Se citesc trei variabile reale a, b si c.Sa se calculeze


a+b, c>0
e= a*b, c=0
a-b, c<0

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

main ( )
{
double a,b,c,e;
cout<<"a="; cin>>a;
cout<<"b="; cin>>b;
cout<<"c="; cin>>c;
if (c>0) e=a+b;
else
if (c==0) e=a*b;
else e=a-b;
cout<<e;
}

// sa se determine paritatea lui n

#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {
int n, remainder;

// Get a number from the keyboard.

cout << "Enter a number and press ENTER: ";


cin >> n;

// Get remainder after dividing by 2.

remainder = n % 2;

// If remainder is 0, the number input is even.

if (remainder == 0)
cout << "The number is even.";
else
cout << "The number is odd.";

return 0;
}
// sa se determine paritatea lui n
// dar in loc de conditie avem de evaluat o expresie

#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {
int n;

// Get a number from the keyboard.

cout << "Enter a number and press ENTER: ";


cin >> n;

// Get remainder after dividing by 2.


// If remainder is 0, the number input is even.

if (n % 2 == 0)
cout << "The number is even.";
else
cout << "The number is odd.";

return 0;
}
//sa se verifice utilitatea comenzii Else
#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
int firstNumber, secondNumber;
cout << "Please enter a big number: ";
cin >> firstNumber;
cout << "\nPlease enter a smaller number: "; cin >>
secondNumber;
if (firstNumber > secondNumber)
cout << "\nThanks!\n";
else
cout << "\nOops. The second is bigger!";

return 0;
}
//sa se dea un exemplu prin care sa se arate ca in cazul a doua IF-
uri imbricate
//Else apartine primului IF
#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
int x;
cout << "Enter a number less than 10 or greater than 100: ";
cin >> x;
cout << "\n";

if (x > 10)
{
if (x > 100)
cout << "More than 100, Thanks!\n";
}
else // not the else intended!
cout << "Less than 10, Thanks!\n";
return 0;
}
//sa se explice folosirea operatorului conditional
#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
int x, y, z;
cout << "Enter two numbers.\n";
cout << "First: ";
cin >> x;
cout << "\nSecond: ";
cin >> y;
cout << "\n";

if (x > y)
z = x;
else
z = y;

cout << "z: " << z;


cout << "\n";

z = (x > y) ? x : y;

cout << "z: " << z;


cout << "\n";
return 0;
}
// Exercitiul 2.2.2.txt
// Acest program testeaza operatorul && logic
#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {
int n;

cout << "Enter an age and press ENTER: ";


cin >> n;

if (n > 12 && n < 20)


cout << "Subject is a teenager.";
else
cout << "Subject is not a teenager.";

return 0;
}
// Exercitiul 2.2.2.txt
// Acest program testeaza operatorul && logic
#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {
int n;

cout << "Enter a number and press ENTER: ";


cin >> n;

if (n >= 0 && n <= 100)


cout << "Number is in range.";
else
cout << "Number is not in range.";

return 0;
}
// Exercitiul 2.2.2.txt
// Acest program testeaza operatorul "sau" || logic
#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {
int n;

cout << "Enter a number and press ENTER: ";


cin >> n;
if (n < 0 || n >= 100)
cout << "Number is in range.";
else
cout << "Number is not in range.";

return 0;
}

Instructiunea expresie

In C++ exista instructiunea expresie si este de forma:


expresie;
Se observa ca instructiunea expresie se termina cu “ ; ”.Daca expresia este vida, obtinem asa-numita
instructiune vida.
// . Programul urmator interschimba continutul a doua variabile
care //au fost citite.La sfarsit, se afiseaza noul continut al
//variabilelor.
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int a,b,c;
cout<<"a="; cin>>a;
cout<<"b="; cin>>b;
c=a; a=b; b=c;
cout<<"a="<<a<<endl;
cout<<"b="<<b<<endl;
}
// Se citesc doua valori intregi a si b.Se cere sa se afiseze media
lor aritmetica.
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int a,b;
float medie;
cout<<"a="; cin>>a;
cout<<"b="; cin>>b;
medie=float (a+b)/2;
cout<<"media este "<<medie;
}
Instructiunea compusa

Pentru a putea scrie mai multe instructiuni care sa fie interpretate de compilator ca una
singura se foloseste instructiunea compusa.Aceasta are forma urmatoare:

{
i1;
i2;
:
:
In ;
}

// Programul care urmeaza calculeaza radacinii ecuatiei de gradul 1

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

main ( )
{
float a,b,x;
cout<<"a="; cin>>a;
cout<<"b="; cin>>b;
if (a)
{
x= -b/a;
cout<<x;
}
else
if (b==0) cout<<"infinitate de solutii";
else cout<<"nu are solutie";

Instructiunea switch

Instructiunea switch are forma generala:


switch (expresie)
{
case exp1:secventa instructiuni1;break;
case exp 2:secventa instructiuni2;break;
……………………..
case expn:secventa instructiunin;break;
[default :secventa instructiunin+1];
}
}
// Programul care urmeaza testeaza comanta switch

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

main ( )
{
int i;
cin>>i;
switch(i)
{
case 1 : cout<<"am citit 1"; break;
case 2 : cout<<"am citit 2"; break;
default : cout<<"am citit altceva";
}
}

INSTRUCTIUNI REPETITIVE
Instructiunea while

Forma generala a acestei instructiuni este:


while (expresie) instructiune
Instructiunea DO WHILE

Aceasta instructiune este asemanatoare cu structura REPEAT UNTIL.Forma ei este


urmatoarea:
do
instructiune
while(expresie);

Instructiunea FOR

Instructiunea for are forma generala:


for (expresieinitializare;expresietest;expresieincrementare) instructiune
 Expresieinitializare se foloseste, de regula, pentru initializarea variabilei de ciclare.Este de remarcat
faptul ca in cadrul acestei expresii este posibil chiar sa declaram variabila de ciclare (cu valoare
initiala).
 Expresietest se foloseste pentru a testa daca se executa instructiunea subordonata – daca expresia
produce la evaluare o valoare diferita de 0, instructiunea subordonata for se executa.
 Expresieincrementare se foloseste pentru incrementarea variabilei de ciclare.

// sa se afiseze 1 2 3 ...n cu while

#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {
int i, n;

// Get a number from the keyboard and initialize i.

cout << "Enter a number and press ENTER: ";


cin >> n;
i = 1;

while (i <= n) { // While i less than or equal to n,


cout << i << " "; // Print i,
i = i + 1; // Add 1 to i.
}

return 0;
}
// 1 Suma a n numere introduse de utilizator cu WHILE
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

void main()
{
float a;
int i,n;
float suma=0;
i=1;
cout<<"\nNumarul de elemente=";
cin>>n;
while(i<=n)
{
cout<<"Elementul "<<i<<"este: ";
cin>>a;
suma=suma+a; //se mai poate scrie suma+=a
i++;
}
cout<<"Suma este= "<<suma;
}
// Suma primelor n numere naturale. cu WHILE
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

void main()
{
int n;
int i;
int suma=0;
cout<<"n=";
cin>>n;
i=1;
while(i<=n)
{
suma=suma+i;
i++;
}
cout<<"Suma este: "<<suma;
}

// Acest program testeaza daca un nr e prim sau nu


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

int main() {
int n; // Number to test for prime-ness
int i; // Loop counter
int is_prime; // Boolean flag

// Assume that a number is prime until proven otherwise

is_prime = true;

// Get a number from the keyboard.

cout << "Enter a number and press ENTER: ";


cin >> n;

// Test for prime-ness by checking for divisibility


// by all whole numbers from 2 to sqrt(n).
i = 2;
while (i <= sqrt(static_cast<double>(n))) {
// While i is <= sqrt(n),
if (n % i == 0) // If i divides evenly into n,
is_prime = false; // n is not prime.
i++; // Add 1 to i.
}

// Print results

if (is_prime)
cout << "Number is prime.";
else
cout << "Number is not prime.";

return 0;
}
// . Se citeste n, numar natural.Sa se calculeze suma cifrelor sale
(pentru n=213, se va tipari 6)cu WHILE
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int n,s=0;
cout<<"n="; cin>>n;
while (n)
{
s=s+n%10;
n=n/10;
}
cout<<s;
}
// . Se citeste n, numar natural.Sa se afiseze numarul obtinut
prin //inversarea cifrelor sale (pentru n=412,se va tipari214).
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int n,ninv=0;
cout<<"n="; cin>>n;
while (n)
{
ninv=ninv*10+n%10;
n=n/10;
}
cout<<"numarul inversat "<<ninv;
}
// . Se citeste n, numar natural.Sa se afiseze numarul obtinut prin
inversarea cifrelor sale (pentru n=412,se va tipari214).
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int n,ninv=0;
cout<<"n="; cin>>n;
while (ninv=ninv*10+n%10,n/=10);
cout<<ninv;
}
// . Se citeste n, numar natural.Sa se afiseze numarul obtinut
prin //inversarea cifrelor sale (pentru n=412,se va tipari214).
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int n,ninv=0;
cout<<"n="; cin>>n;
while (ninv*=10,ninv+=n%10,n/=10);
cout<<ninv;
}
// Exercitiul 2.2.2.txt
// Acest program testeaza daca un nr e prim sau nu folosind si
comanda break
#include "stdafx.h"
#include <iostream>
#include<math.h>
using namespace std;

int main() {
int n; // Number to test for prime-ness
int i; // Loop counter
int is_prime; // Boolean flag

// Assume that a number is prime until proven otherwise

is_prime = true;

// Get a number from the keyboard.

cout << "Enter a number and press ENTER: ";


cin >> n;

// Test for prime-ness by checking for divisibility


// by all whole numbers from 2 to sqrt(n).

i = 2;
double sqrt_n = sqrt(static_cast<double>(n));
while (i <= sqrt_n) { // While i is <= sqrt(n),
if (n % i == 0) { // If i divides evenly into n,
is_prime = false; // n is not prime.
break;
}
i++; // Add 1 to i.
}
// Print results

if (is_prime)
cout << "Number is prime.";
else
cout << "Number is not prime.";

return 0;
}

// sa se afiseze N1+1 N2+2 N3+3 ...n2 cu while

#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {
int i, n1, n2;

// Get a numbers n1 and n2 from the keyboard.

cout << "Enter first number and press ENTER: ";


cin >> n1;
cout << "Enter second number and press ENTER: ";
cin >> n2;

i = n1;

while (i <= n2) { // While i less than or equal to n2,


cout << i << " "; // Print i,
i = i + 1; // Add 1 to i.
}

return 0;
}
// Exercitiul 2.2.2.txt
// Acest program afseaza numerele de la n la 1, in ordine inversa CU
WHILE.
#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {
int i, n;

// Get a number from the keyboard and initialize i to n.

cout << "Enter a number and press ENTER: ";


cin >> n;
i = n;

while (i > 0) { // While i greater than 0,


cout << i << " "; // Print i,
i = i - 1; // Add 1 to i.
}

return 0;
}
// Exercitiul 2.2.2.txt
// Acest program afseaza numerele de la n la 1, in ordine inversa CU
DO ..WHILE.
#include "stdafx.h"
#include <iostream>
using namespace std;

int main() {
int i, n;

// Get a number from the keyboard and initialize i to n.

cout << "Enter a number and press ENTER: ";


cin >> n;
i = n;

do { // While i greater than 0,


cout << i << " "; // Print i,
i = i - 1; // Add 1 to i.
}while (i > 0);

return 0;
}
// Sa se calculeze suma primelor n numere naturale.
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int n,s=0,i=1;
cout<<"n="; cin>>n;
do
{ s=s+i;
i=i+1;
} while (i<=n);
cout<<s;
}
// Sa se calculeze suma primelor n numere naturale.
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int n,s=0,i=1;
cout<<"n="; cin>>n;
do s+=i++; while (i<=n);
cout<<s;
}
// . Se citeste n, numar natural.Sa se descompuna in factori primi.
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;
main ( )
{
int n,i=2,fm;
cout<<"n="; cin>>n;
do
{
fm=0;
while (n%i==0)
{
fm++; // sau fm=fm+1;
n/=i; // sau n=n/i;
}
if (fm) cout<<i<<"la puterea "<<fm<<endl;
i++;
} while (n!=1);
}
// . Programul urmator listeaza numerele 5, 4, 3, 2, 1.
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int i;
for (i=5;i>=1;i--) cout<<i<<" ";
}
// . Se citeste n (numar natural).Se cere sa se efectueze suma
primelor n numere naturale.Exemplu: n=3, s=1+2+3=6.

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

main( )
{
int i,n,s=0;
cout<<"n="; cin>>n;
for (i=1;i<=n;i++) s+=i; // sau s=s+i;
cout<<"suma primelor n numere naturale este "<<s;
}
// . Se citeste n (numar natural).Se cere sa se efectueze suma
primelor n numere naturale.Exemplu: n=3, s=1+2+3=6.

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

main( )
{
int i,n,s=0;
cout<<"n="; cin>>n;
for (i=1;i<=n;s+=i++);
cout<<"suma primelor n numere naturale este "<<s;
}
// Sa se calculeze suma: s=0,1+0,2+…+0,9.

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

main( )
{
int i;
float s=0.0;
for (i=1;i<=9;i++) s+=(float)i/10;
cout<<s;
}
// . Se citeste n un numar natural.Sa se calculeze suma
S=1+1*2+1*2*3+…+1*2*…*n.

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

main( )
{
int i,s=0,p=1,n;
cout<<"n="; cin>>n;
for (i=1;i<=n;i++)
{
p*=i; // p=p*i;
s+=p; // s=s+p;
}
cout<<s;
}
// Se citesc n numere intregi.Se cere sa se afiseze cel mai mare
numar citit.Exemplu: daca avem n=4, iar numerele sunt –7, 9, 2, 3, se
va afisa 9.

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

main( )
{
int i,max,n,nr;
cout<<"n="; cin>>n;
cout<<"nr="; cin>>nr;
max=nr;
for (i=2;i<=n;i++)
{
cout<<"nr="; cin>>nr;
if (nr>max) max=nr;
}
cout<<"maximul este "<<max;
}
// Se citeste un numar natural.Sa se afiseze numarul obtinut prin
inversarea cifrelor sale."

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

main ( )
{
int i,s,n,ninv;
cout<<"n="; cin>>n;
for (ninv=0;n>0;)
{
ninv=ninv*10+n%10;
n=n/10;
}
cout<<ninv;
}
// Se citeste un numar natural.Sa se afiseze numarul obtinut prin
inversarea cifrelor sale."

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

main ( )
{
int i,s,n,ninv;
cout<<"n="; cin>>n;
for (ninv=0;n>0;n/=10) ninv=ninv*10+n%10;
cout<<ninv;
}

// sa se calculeze exponentiala,logaritmul,radicalul si puterea


standard

#include "stdafx.h"
#include <iostream>
using namespace std;
#include<math.h>
main()
{
double h,x_inf,x_sup,x;
cout<<"introduceti X_inf:"<<endl;
cin>>x_inf;
cout<<"introduceti X_sup:"<<endl;
cin>>x_sup;
cout<<"introduceti H :"<<endl;
cin>>h;
if (x<=0) h=0.1;
if (x_inf<=0 ||x_sup<=0||x_inf>=x_sup)
{
x_inf=1;
x_sup=2;
}
for (x*=x_inf ;x<=x_sup; x+=h)
cout<<x<<exp(x)<<sqrt(x)<<log(x)<<pow(x,2)<<endl;
}

// afisarea lui 1 2 3 ..n cu For


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

int main() {
int i, n;

// Get a number from the keyboard and initialize i.

cout << "Enter a number and press ENTER: ";


cin >> n;

for (i = 1; i <= n; i++) // For i = 1 to n,


cout << i << " "; // Print i.

return 0;
}
// afisarea lui n1+1 n1+2 n1+3 ..n2 cu For
#include "stdafx.h"
#include <iostream>
#include<math.h>
using namespace std;

int main() {
int i, n1, n2;

// Get n1 and n2 from the keyboard.

cout << "Enter first number and press ENTER: ";


cin >> n1;
cout << "Enter second number and press ENTEr: ";
cin >> n2;

for (i = n1; i <= n2; i++) // For i = n1 to n2,


cout << i << " "; // Print i.

return 0;
}
// Exercitiul 3.1.2.txt
// Acest program afiseaza numerele de la n la 1 cu FOR

#include "stdafx.h"

#include <iostream>
using namespace std;

int main() {
int i, n;

// Get a number from the keyboard and initialize i.

cout << "Enter a number and press ENTER: ";


cin >> n;

for (i = n; i >= 1; i--) // For i = n down to 1


cout << i << " "; // Print i.

return 0;
}
// Exercitiul 3.1.2.txt
// Acest program determina DACA UN NUMAR E PRIM SAU NU cu FOR

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

int main() {
int n; // Number to test for prime-ness
int i; // Loop counter
int is_prime; // Boolean flag

// Assume that a number is prime until proven otherwise

is_prime = true;

// Get a number from the keyboard.

cout << "Enter a number and press ENTER: ";


cin >> n;

// Test for prime-ness by checking for divisibility


// by all whole numbers from 2 to sqrt(n).

for (i = 2; i <= sqrt((double) n); i++) {


if (n % i == 0)
is_prime = false;
}

// Print results

if (is_prime)
cout << "Number is prime.";
else
cout << "Number is not prime.";

return 0;
}
// Acest program determina daca un numar este prim,
// folosind o instructiune for si cod optimizat.
//

#include "stdafx.h"

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

int main() {
int n; // Number to test for prime-ness
int i; // Loop counter
int is_prime; // Boolean flag

// Assume that a number is prime until proven otherwise

is_prime = true;

// Get a number from the keyboard.

cout << "Enter a number and press ENTER: ";


cin >> n;

// Test for prime-ness by checking for divisibility


// by all whole numbers from 2 to sqrt(n).

double sqrt_n = sqrt(static_cast<double>(n));

for (i = 2; i <= sqrt_n; i++) {


if (n % i == 0) {
is_prime = false;
break;
}
}

// Print results

if (is_prime)
cout << "Number is prime.";
else
cout << "Number is not prime.";

return 0;
}
Functii matematice

Fiecare dintre functiile prezentate mai jos are prototipul in math.h :

 Functia abs are forma generala: int abs(int x); Aceasta inseamna ca are un parametru de tip int, iar rezultatul
este tot de tip int. Inaintea numelui se gaseste tipul rezultatului.Rolul ei este de a intoarce |x| (modulul lui x).
Iata cum arata un program care o foloseste (tipareste 1234):

#include <iostream.h>

#include <math.h>

main ( )
{

int n= -1234;

cout<<abs(n);

 Functia fabs are forma generala double fabs(double x);


are acelasi rol cu abs, numai ca intoarce valoarea unui numar real (chiar double).

 Functia labs are forma generala long int labs(long int x);
are acelasi rol cu abs, numai ca intoarce valoarea unui intreg

lung.

 Functia acos are forma generala double acos(double x); si calculeaza valoarea functiei arccos(x): [-
1,1][0,π].
 Functia asin are forma generala double asin(double x); si calculeaza valoarea functiei arcsin(x): [-
1,1][-π/2,π/2].
 Functia atan are forma generala double atan(double x); si
calculeaza valoarea functiei arctg(x):R(-π/2,π/2).

 Functia atan2 are forma generala


double atan2(double y,double x)

si calculeaza arctg(y/x).Rezultatul este in intervalul (-π,π).

 Functia ceil are forma generala double ceil(double x); si calculeaza |x| a lui x (rotunjirea se face in minus).
 Functia floor are forma generala double floor(double x); si
calculeaza valoarea rotunjita a lui x (rotunjirea se face in plus).

 Functia cos are forma genarala double cos(double x); si calculeaza valoarea functiei cos(x):R[-1,1].
 Functia sin are forma generala double sin(double x); si
calculeaza valoarea functiei sin(x):R[-1,1].

 Functia tan are forma generala double tan(double x); si calculeaza valoarea functiei tg(x):R—{k*π+π/2|k din
Z}R.
 Functia exp are forma generala double exp(double x); si calculeaza functia e x:RR*+.
 Functia log are forma generala double log(double x); si
calculeaza functia ln(x): R*+R, unde ln(x)=loge(x).

 Functia log10 are forma generala double log10(double x); si calculeaza functia lg(x): R*+R, unde
lg(x)=log10(x).
 Functia pow are forma generala double pow(double x, double y); si calculeaza xy.
Observatie: Este sarcina programatorului, ca pentru o astfel de functie, valoarea argumentului

sa fie in domeniul de definitie al functiei respective.

VECTORI SI MATRICE
Tablouri in C++

In C++ tipul tablou se declara astfel:

tip nume[numar natural1] [numar natural2]…[numar naturaln]

Adresarea unei componente se face prin indice, care se trece intre paranteze drepte, iar

componentele au indici intre 0 si 99.

//suma elementelor unui vector


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >

void main()
{
static int x[10]={1,2,3,4,5,6,7,8,9,10};
int i,s=0,n=10;
for(i=0;i<n;i++) s+=x[i];
cout<<" s="<<s<<endl;
}

// // Exercitiul 5.1.2.txt
// Acest program afiseaza sase intregi impreuna cu totalul lor.

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

int main() {
int i, sum = 0;
int scores[6] = {10, 22, 13, 99, 4, 5};

for(i = 0; i < 6; i++) {


cout << scores[i] << " ";
sum = sum + scores[i];
}
cout << endl << "The sum is " << sum << endl;

return 0;
}
// Se citeste un numar natural.Sa se afiseze un vector

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int v[100],n,i;
cout<<"numar de componente"; cin>>n;
for (i=0;i<n;i++)
{
cout<<"v["<<i+1<<"]=";
cin>>v[i];
}
for (i=0;i<n;i++) cout<<v[i]<<endl;
}

// sa se initializeze un vector

#include "stdafx.h"

#include <iostream>
#include <math.h>
using namespace std;
int main() {
int i;
double V[5] = {0.5, 1.5, 2.5, 3.5, 4.5};

for(i = 0; i < 5; i++) {


cout << V[i] << " ";
}

return 0;
}
// Se citeste un numar natural.Sa se afiseze un vector
//obtinut prin copierea de componente

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int n,i;
float a[50], b[50];
cout<<"numar de componente"; cin>>n;
for (i=0;i<n;i++)
{
cout<<"a["<<i+1<<"]=";
cin>>a[i];
}
for (i=0;i<n;i++) b[i]=a[i];
for (i=0;i<n;i++) cout<<b[i]<<endl;
}

// sa se initializeze un vector DE INTREGI


//INDICII PLEACA DE LA VALOAREA ZERO

#include "stdafx.h"

#include <iostream>
#include <math.h>
using namespace std;
int main() {
int i;
int scores[8] = {5, 15, 25, 35, 45, 55, 65, 75};

for(i = 0; i < 8; i++) {


cout << scores[i] << " ";
}

return 0;
}
// Se citeste un numar natural.Sa se afiseze maximul dintr-un vector

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

int v[9],n,i,max;
main ( )
{
cout<<"n ="; cin>>n;
for (i=0;i<n;i++)
{
cout<<"v["<<i+1<<"]=";
cin>>v[i];
};
int max=v[0];
for (i=0;i<n;i++)
if (v[i]>max) max=v[i];
cout<<"valoarea maxima citita este "<<max;
}
// Se citeste un numar natural.Sa se determine daca sunt elemente
distincete intr-un vector si nu avem deloc identice
//dintr-un vector

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;
int v[9],n,i,j,gasit;
main ( )
{
cout<<"n ="; cin>>n;
for (i=0;i<n;i++)
{
cout<<"v["<<i+1<<"]=";
cin>>v[i];
}
gasit=0;
for(i=0;i<n && !gasit;i++)
for(j=0;j<n && !gasit;j++)
if (v[i]==v[j]) gasit=1;
if (gasit) cout<<"numerele nu sunt distincte";
else cout<<"numerele sunt distincte";
}
// Se citeste un numar natural.Sa se determine apartenenta unui
element la un vector

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

int mult[9], n,e,i,gasit;


main ( )
{
cout<<"numarul de elemente ale multimii "; cin>>n;
for (i=0;i<n;i++)
{
cout<<"mult["<<i+1<<"]="; cin>>mult[i];
}
cout<<"elementul considerat "; cin>>e;
gasit=0;
for(i=0;i<n && !gasit;i++)
if (mult[i]==e) gasit=1;
if (gasit) cout<<"elementul apartine multimii";
else cout<<"elementul nu apartine multimii";
}
// Se citeste un numar natural.Sa se determine
//diferenta a doua multimi

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

int multa[9], multb[9],multc[9],n,m,i,j,k,gasit;


main ( )
{
cout<<"numarul de elemente al multimii A "; cin>>n;
for (i=0;i<n;i++)
{
cout<<"mult["<<i+1<<"]="; cin>>multa[i];
}
cout<<"numarul de elemente al multimii B "; cin>>m;
for (i=0;i<m;i++)
{
cout<<"mult["<<i+1<<"]="; cin>>multb[i];
}
k=0;
for (i=0;i<n;i++)
{
gasit=0;
for (j=0;j<=m && !gasit;j++)
if (multa[i]==multb[j]) gasit=1;
if (!gasit) multc[k++]=multa[i];
}
cout<<"A-B"<<endl;
for (i=0;i<k;i++) cout<<multc[i]<<endl;
}
// Se citeste un numar natural.Sa se determine
//reuniunea a doua multimi

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

int multa[9], multb[9],multc[9],n,m,i,j,k,gasit;


main ( )
{
cout<<"numarul de elemente al multimii A "; cin>>n;
for (i=0;i<n;i++)
{
cout<<"mult["<<i+1<<"]="; cin>>multa[i];
}
cout<<"numarul de elemente al multimii B "; cin>>m;
for (i=0;i<m;i++)
{
cout<<"mult["<<i+1<<"]="; cin>>multb[i];
}
k=0;
for (i=0;i<n;i++)
{
gasit=0;
for (j=0;j<=m && !gasit;j++)
if (multa[i]==multb[j]) gasit=1;
if (!gasit) multc[k++]=multa[i];
}
cout<<"A reunit cu B"<<endl;
for (i=0;i<m;i++) cout<<multb[i]<<endl;
for (i=0;i<k;i++) cout<<multc[i]<<endl;
}
// Se citeste un numar natural.Sa se determine
//intersectia a doua multimi

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;
int multa[9], multb[9],multc[9],n,m,i,j,k,gasit;
main ( )
{
cout<<"numarul de elemente al multimii A "; cin>>n;
for (i=0;i<n;i++)
{
cout<<"mult["<<i+1<<"]="; cin>>multa[i];
}
cout<<"numarul de elemente al multimii B "; cin>>m;
for (i=0;i<m;i++)
{
cout<<"mult["<<i+1<<"]="; cin>>multb[i];
}

k=0;
for (i=0;i<n;i++)
{
gasit=0;
for (j=0;j<=m && !gasit;j++)
if (multa[i]==multb[j]) gasit=1;
if (gasit) multc[k++]=multa[i];
}
cout<<"A intersectat cu B"<<endl;
for (i=0;i<k;i++) cout<<multc[i]<<endl;
}
// Se citeste un numar natural.Sa se determine
//produsul cartezian a doua multimi identice

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int n,m,i,j;
cout<<"numarul de elemente al multimii A "; cin>>n;
cout<<"numarul de elemente al multimii B "; cin>>m;
for (i=1;i<=n;i++)
for (j=1;j<=m;j++)
cout<<i<<" "<<j<<endl;
}
// Se citeste un numar natural.Sa se determine
//produsul cartezian a doua multimi diferite

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

char multa[9],multb[9];
int n,m,i,j;
main ( )
{
cout<<"numarul de elemente al multimii A "; cin>>n;
for (i=0;i<n;i++)
{
cout<<"mult["<<i+1<<"]="; cin>>multa[i];
}
cout<<"numarul de elemente al multimii B "; cin>>m;
for (i=0;i<m;i++)
{
cout<<"mult["<<i+1<<"]="; cin>>multb[i];
}
for (i=0;i<=n;i++)
for (j=0;j<=m;j++)
cout<<multa[i]<<" "<<multb[j]<<endl;
}
// Se citeste un numar natural.Sa se determine
//submultimile unei multimi

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

int multa[9],n,i,s;
main ( )
{
cout<<"numarul de elemente al multimii A "; cin>>n;
for (i=0;i<n;i++)
multa[i++]=0;
do
{
multa[n-1]++;
for (i=n-1;i>=1;i--)
if (multa[i]>1)
{
multa[i]-=2;
multa[i-1]+=1;
}
s=0;
for (i=0;i<n;i++) s+=multa[i];
for (i=0;i<n;i++)
if (multa[i]) cout<<i+1<<" ";
cout<<endl;
} while (s<n) ;
cout<<"multimea vida ";
}
// Sortarea prin selectarea minimului (maximului)

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

int a[9],n,i,j,k,man,min;
main ( )
{
cout<<"n="; cin>>n;
for (i=0;i<n;i++)
{
cout<<"a["<<i+1<<"]="; cin>>a[i];
} ;
for (i=0;i<n-1;i++)
{
int min=a[i];k=i;
for (j=i+1;j<n;j++)
if (a[j]<min)
{
min=a[j];
k=j;
}
man=a[k];
a[k]=a[i];
a[i]=man;
}
for (i=0;i<n;i++) cout<<a[i]<<endl;
}
// Se citeste un numar natural.Sa se determine
//sortarea prin interschimbare

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

int a[9],n,i,j,k,man,gasit;
main ( )
{
cout<<"n="; cin>>n;
for (i=0;i<n;i++)
{
cout<<"a["<<i+1<<"]="; cin>>a[i];
} ;
do
{
gasit=0;
for (i=0;i<n-1;i++)
if (a[i]>a[i+1])
{
int man=a[i];
a[i]=a[i+1];
a[i+1]=man;
gasit=1;
}
} while (gasit);
for (i=0;i<n;i++) cout<<a[i]<<endl;
}

// Se citeste un numar natural.Sa se determine


//sortarea prin selectie

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

int a[9], b[9], n,i,j,k,gasit;


main ( )
{
cout<<"n="; cin>>n;
for (i=0;i<n;i++)
{
cout<<"a["<<i+1<<"]="; cin>>a[i];
} ;
b[0]=a[0];
for (i=1;i<n;i++)
{
j=i-1;
while (j>=0 && a[i]<b[j]) j--;
for (k=i-1;k>=j+1;k--) b[k+1]=b[k];
b[j+1]=a[i];
}
for (i=0;i<n;i++) cout<<b[i]<<endl;
}
// Se citeste un numar natural.Sa se determine
//sortarea prin interclasare

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int a[100],b[100],c[200],m,n,i,j,k;
cout<<"m="; cin>>m;
for (i=0;i<m;i++)
{
cout<<"a["<<i+1<<"]="; cin>>a[i];
} ;
cout<<"n="; cin>>n;
for (i=0;i<n;i++)
{
cout<<"b["<<i+1<<"]="; cin>>b[i];
} ;
i=j=k=0;
while (i<m && j<n)
if (a[i]<b[j]) c[k++]=a[i++];
else c[k++]=b[j++];
if (i<m)
for (j=i;j<m;j++) c[k++]=a[j];
else
for (i=j;i<n;i++) c[k++]=b[i];
for (i=0;i<k;i++) cout<<c[i]<<endl;
}

// Se citeste un numar natural.Sa se determine


//cautarea binara

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int a[100],n,i,li,ls,k,nr,gasit;
cout<<"n="; cin>>n;
for (i=0;i<n;i++)
{
cout<<"a["<<i+1<<"]="; cin>>a[i];
} ;
cout<"nr="; cin>>nr;
li=0;ls=n-1;gasit=0;
do
{
k=(li+ls)/2;
if (a[k]==nr)
{
cout<<"gasit pe pozitia "<<k+1;
gasit=1;
}
else
if (a[k]<nr) li=k+1;
else ls=k-1;
} while (li<=ls && !gasit);
if (li>ls) cout<<"negasit";
}

// Se citeste un numar natural.Sa se afiseze o matrice

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int m,n,i,j,a[9][9];
cout<<"m ="; cin>>m;
cout<<"n ="; cin>>n;
for (i=0;i<m;i++)
for (j=0;j<n;j++)
{
cout<<"a["<<i+1<<","<<j+1<<"]=";
cin>>a[i][j];
}
for (i=0;i<m;i++)
{
for (j=0;j<n;j++) cout<<a[i] [j]<<" ";
cout<<endl;
}
}
// Se citeste m si n natural.Sa se determine
//schimbarea a doua linii intre ele

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int mat[10][10],m,n,i,j,x,y,man;
cout<<"m="; cin>>m;
cout<<"n="; cin>>n;
for (i=0;i<m;i++)
for (j=0;j<n;j++)
{
cout<<"mat["<<i+1<<","<<j+1<<"]=";
cin>>mat[i][j];
};
cout<<"x="; cin>>x;
cout<<"y="; cin>>y;
cout<<endl;
for (i=0;i<m;i++)
{
for (j=0;j<n;j++) cout<<mat[i][j]<<" ";
cout<<endl;
}
for (j=0;j<n;j++)
{
man=mat[x-1][j];
mat[x-1][j]=mat[y-1][j];
mat[y-1][j]=man;
}
cout<<endl;
for (i=0;i<m;i++)
{
for (j=0;j<n;j++) cout<<mat[i][j]<<" ";
cout<<endl;
}
}
// Se citeste m si n natural.Sa se determine
//parcurgerea pe spirala a unei matrice

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
int mat[10][10],n,i,j,k;
cout<<"n="; cin>>n;
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
{
cout<<"mat["<<i<<","<<j<<"]=";
cin>>mat[i][j];
}
for (k=1;k<=n/2;k++)
{
for (i=k;i<=n-k+1;i++) cout<<mat[k][i]<<endl;
for (i=k+1;i<=n-k+1;i++) cout<<mat[i][n-
k+1]<<endl;
for (i=n-k;i>=k;i--) cout<<mat[n-k+1][i]<<endl;
for (i=n-k;i>=k+1;i--) cout<<mat[i][k]<<endl;
}
}
TIPUL DE DATE SIR DE CARACTERE

Memorarea si declararea vectorilor de caractere


In memoria interna, o constanta de tip sir este retinuta sub forma unui vector de caractere.Conventia este ca

ultimul octet sa retina 0 (caracterul nul).Pentru fiecare caracter este retinut codul ASCII.

Vectorii de caractere pot fi initializati la declarare, caracterul nul fiind memorat automat.

// // Exercitiul 5.1.2.txt
// Acest program afiseaza copierea si concaternarea unor fraze
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
using namespace std;

int main() {
char str[600];
char name[100];
char addr[200];
char work[200];

// Get three strings from the user.

cout << "Enter name and press ENTER: ";


cin.getline(name, 99);
cout << "Enter address and press ENTER: ";
cin.getline(addr, 199);
cout << "Enter workplace and press ENTER: ",
cin.getline(work, 199);

// Build the output string, and then print it.

strcpy(str, "\nMy name is ");


strcat(str, name);
strcat(str, ", I live at ");
strcat(str, addr);
strcat(str, ",\nand I work at ");
strcat(str, work);
strcat(str, ".");

cout << str;

return 0;
}

/
// Exercitiul 7.1.1.txt
// Aceasta versiune de program utilizeaza varianta "n" a functiilor
strcpy si
// strcat, pentru a evita depasirea limitelor de lungime a sirului.

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
using namespace std;

int main() {
char str[600];
char name[100];
char addr[200];
char work[200];

// Get three strings from the user.

cout << "Enter name and press ENTER: ";


cin.getline(name, 99);
cout << "Enter address and press ENTER: ";
cin.getline(addr, 199);
cout << "Enter workplace and press ENTER: ",
cin.getline(work, 199);

// Build the output string, and then print it.

strncpy(str, "\nMy name is ", 599);


strncat(str, name, 599 - strlen(str));
strncat(str, ", I live at ", 599 - strlen(str));
strncat(str, addr, 599 - strlen(str));
strncat(str, ",\nand I work at ", 599 - strlen(str));
strncat(str, work, 599 - strlen(str));
strncat(str, ".", 599 - strlen(str));

cout << str;

return 0;
}

// Exercitiul 7.1.2.txt
// Aceasta versiune de program utilizeaza varianta "n" a functiilor
strcpy si
// strcat, pentru a evita depasirea limitelor de lungime a sirului.
// De asemenea, aceasta versiune utilizeaza si directiva #define,
astfel incat sa o puteti
// testa cu diferite valori ale lui STRMAX, prin modificarea unei
linii, dupa care
// trebuie sa recompilati.
//rcat, pentru a evita depasirea limitelor de lungime a sirului.

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
using namespace std;

#define STRMAX 599

int main() {
char str[STRMAX + 1];
char name[100];
char addr[200];
char work[200];

// Get three strings from the user.

cout << "Enter name and press ENTER: ";


cin.getline(name, 99);
cout << "Enter address and press ENTER: ";
cin.getline(addr, 199);
cout << "Enter workplace and press ENTER: ",
cin.getline(work, 199);

// Build the output string, and then print it.

strncpy(str, "\nMy name is ", STRMAX);


strncat(str, name, STRMAX - strlen(str));
strncat(str, ", I live at ", STRMAX - strlen(str));
strncat(str, addr, STRMAX - strlen(str));
strncat(str, ",\nand I work at ", STRMAX - strlen(str));
strncat(str, work, STRMAX - strlen(str));
strncat(str, ".", STRMAX - strlen(str));

cout << str;

return 0;
}

// sa se transforme in majuscule un sir

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
using namespace std;
#include <ctype.h>

int main() {
char s[100];
int i;
int length = strlen(s);

cout << "Enter string to convert and press ENTER: ";


cin.getline(s, 99);

cout << "The converted string is:" << endl;

for (i = 0; i < length; i++)


s[i] = toupper(s[i]);
for (i = 0; i < length; i++)
cout<<s[i];

return 0;
}

//SA SE TRANSFORME IN MINUSCULE

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
using namespace std;
#include <ctype.h>

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

cout << "Enter string to convert and press ENTER: ";


cin.getline(s, 99);
int length = strlen(s);
cout << "The converted string is:" << endl;

for (i = 0; i < length; i++)


s[i] = tolower(s[i]);
for (i = 0; i < length; i++)
cout<<s[i];

return 0;
}

// Se memoreze un vector de caractere

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
char a[20];
int i;
for (i=0;i<10;i++) cin>>a[i];
a[10]=0;
for (i=0;i<10;i++) cout<<a[i];
}

Functia cin.get(vector_de_caractere, int nr, char=’\n’) , care citeste un sir de caractere, memorat sub forma

unui vector cu nr-1 componente, pana la intalnirea caracterului dat.Al treilea parametru este optional.Daca nu

este trecut, se presupune ca este ‘\n’.

// Se memoreze maxim trei caractere

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

main ( )
{
char a[10];
cin.get(a,3);
cout<<a;

}
// Se memoreze doua fraze

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{
char sir1[1000], sir2[25];
cout<<"sir 1 "; cin.get(sir1,1000);
cin.get ( );
cout<<"sir 2 "; cin.get(sir2,25);
}

Tipul char*

Limbajul C++ permite ca un vector de caractere sa fie adresat incepand de la un anumit octet al sau.
 Octetii memoriei interne sunt numerotati incepand cu 0.
 Numarul de ordine al unui octet in memoria interna se numeste adresa octetului respectiv.
 Prin definitie, adresa unui vector de caractere este ardesa primului sau octet.
 O variabila de tipul char* poate retine adresa unui vector de caractere.
 In C++ numele unui vector de caractere este o adresa constanta de vector si poate fi atribuit unei variabile de
tip char*.

// Se piarda cate o litera incepand de la stanga la dreapta


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{
char a[ ]="masa";
cout<<a+1<<" "<<a+2<<" "<<a+3;
}
// Se piarda cate o litera incepand de la stanga la dreapta

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{ char a[ ]="Exemplu", *p;
p=a; cout<<p<<endl;
p++; cout<<p<<endl; // { ne deplasam pe urmatorul octet}
p++; cout<<p<<endl;
cout<<p[1]<<endl; //{ se tipareste numai acest octet}
cout<<p-a;
}
FUNCTII CARE OPEREAZA CU SIRURI DE CARACTERE
Functia strlen are rolul de a returna lungimea efectiva a unui sir (in calculul lungimii nu intra caracterul
nul).Forma generala este:
size_t strlen (char*);
 size_t este un tip intreg, utilizat in adresarea memoriei (il putem privi ca pe tipul unsigned int)
 argumentul este de tip char* - un vector de caractere
 Functia strcpy are forma generala:
char *strcpy (char* dest,char* sursa);
si are rolul de a copia sirul de adresa sursa la adresa dest.
 Functia standard strcat are forma generala:
char *strcat (char* dest, char* sursa);
si rolul de a adauga sirului de adresa dest sirul de adresa sursa.Sirul de adresa sursa ramane
nemodificat.Aceasta operatie se numeste concatenare si nu este comutativa
 Functia strncat are forma generala:
char *strncat (char *dest, const char *sursa, size_t nr);
si acelasi rol ca strcat cu deosebirea ca adauga sirului destinatie primii nr octeti ai sirului
sursa.Adaugarea se face inaintea caracterului nul.
 Functia strchr are forma generala:
char *strchr (char *s, int c);
si rolul de a cauta caracterul c in sirul s.Cautarea se face de la stanga la dreapta.In cazul in care caracterul
este gasit, functia
intoarce adresa subsirului care incepe cu prima aparitie a caracterului citit si se termina cu caracterul nul al
sirului in care se face cautarea.
 Functia strrchr are forma generala:
char *strrchr (const char *s, int c);
si are acelasi rol cu strchr , deosebirea fiind data de faptul ca returneaza adresa ultimei aparitii a
caracterului – cautarea se
face de la dreapta catre stanga.
 Functia strcmp are forma generala:
int strcmp (const char *s1, const char *s2);
si rolul de a compara doua siruri de caractere.Valoarea returnata este:
 <0, daca s1<s2;
 =0, daca s1=s2;
 >0, daca s1>s2;
Mecanismul prin care se compara doua siruri de caractere este urmatorul:
Fie m numarul de caractere ale sirului s1 si n numarul de caractere ale sirului s2.Sa presupunem ca
primele i caractere ale lui s1 coincid cu primele i ale lui s2.
 In cazul in care codul caracterului i+1 al sirului s1 este mai mare decat codul caracterului corespunzator al
sirului s2, avem s1>s2.
 In cazul in care codul corespunzator i+1 al sirului s1 este mai mic decat codul caracterului corespunzator al
sirului s2, avem s1<s2.In cazul in care avem egalitate, avem patru posibilitati:
 Ambele siruri au un numar strict mai mare de caracatere decat i+1, caz in care se compara ca inainte
caracterele de pe pozitia i+2;
 s1 are i+1 caractere, iar s2 are un numar de caractere mai mare decat i+1, in acest caz s1<s2;
 s2 are i+1 caractere, iar s1 are un numar de caractere mai mare decat i+1, in acest caz s1>s2;
 atat s1 cat si s2 au i+1 caractere, caz in care s1=s2.

Functia strstr are forma generala:


char *strstr (const char *s1, const char *s2);
si rolul de a identifica daca sirul s2 este subsir al sirului s1.
Daca acesta este identificat, functia returneaza adresa de inceput in cadrul sirului s1, altfel returneaza
adresa 0.Cautarea se face de la stanga la dreapta.
 Functia stricmp are forma generala:
int strcmp(char *s1,char *s2);
si are acelasi rol ca strcmp, cu deosebirea ca nu face distinctie intre literele mari si mici.
 Functia strtok are forma generala:
char *strtok(char *s1, const char *s2);
 Functia strcspn are forma generala:
size_t strcspn(const char *s1, const char *s2);
si rolul de a returna numarul de caractere ale sirului s1 (caractere consecutive care incep obligatoriu
cu primul caracter) care nu se gasesc in sirul s2.
 Functia standard strspn are forma generala:
size_t strspn(char *s1, char *s2);
si rolul de a returna numarul de caractere ale sirului s1 (caractere consecutive care incep obligatoriu
cu primul caracter) care se gasesc in sirul s2.
 Functia strlwr are forma generala:
char *strlwr(char *s);
si converteste toate literele mari in litere mici.Restul literelor raman neschimbate, iar functia
intoarce adresa s.
 Functia strupr are forma generala:
char *strupr(char *s);
si converteste toate literele mici in litere mari.Restul literelor raman neschimbate, iar functia
intoarce adresa s.
 Functia strpbrk are forma generala:
char *strpbrk(char *s1, char *s2);
si actioneaza astfel:
 Cauta primul caracter al sirului s1 in s2.Daca este gasit,
returneaza adresa sa din cadrul sirului s1 si executia se termina, altfel trece la pasul urmator.
 Cauta al doilea caracter al sirului s1 in s2.Daca este gasit,
returneaza adresa sa din cadrul sirului s1 si executia se termina, altfel trece la pasul urmator.
 …
 Daca nici un caracter al sirului s1 nu apartine sirului s2, functia returneaza adresa nula.
Urmatoarele functii au prototipul in stdlib.h si folosesc pentru conversia valorilor
numerice in sir si invers.
 Functia atof converteste un sir catre tipul double si are forma generala:
double atof (const char *s);
Daca conversia esueaza (se intalneste un caracter nenumeric), valoarea intoarsa este 0.Daca primele
caractere ale sirului sunt albe, acestea sunt ignorate.
Aceste observatii sunt valabile si pentru urmatoarele 3 functii.
 Functia _atold converteste un sir catre tipul long double:
long double _atold(const char *s);
 Functia atoi converteste un sir catre tipul int:
int atoi(const char *s);
 Functia atol converteste un sir catre tipul int:
long atol(const char *s);

// sa se determine lungimea unui sir de caractere

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{ char a[100];
cin.get(a,100);
cout<<"Sirul citit are "<<strlen (a)<<"caractere";
}
// Se se copieze un sir in alt sir

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{ char a[100]="un sir",b[100]="alt sir";
strcpy (a,b);
cout<<a;
}

// Sa se concaterneze doua siruri


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{
char a[20]="mama",b[100]="merge";
strcat (a,b);
cout<<a;
}

// Sa se spuna pozitia unde e gasit un caracter


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{
char a[100], *t,c;
cout<<"Introduceti sirul "; cin.get(a,100);
cout<<"caracterul cautat "; cin>>c;
t=strchr(a,c);
if (t) cout<<"Indicele este "<<t-a;
else cout<<"Sirul nu contine acest caracter ";
}

// Sa se spuna pozitia unde e gasit un caracter si de cate ori e


gasit si pe ce pozitii
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{
char a[100], *t,c;
cout<<"Introduceti sirul "; cin.get(a,100);
cout<<"caracterul cautat "; cin>>c;
t=a-1;
do
{
t++;
t=strchr(t,c);
if (t) cout<<"Indicele este "<<t-a<<endl;
} while (t);
}

// Sa se spuna care din doua siruri e mai mare ca valoare


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{
char a[100],b[100];
int semnal;
cout<<"Introduceti sirul a "; cin>>a;
cout<<"Introduceti sirul b "; cin>>b;
semnal=strcmp(a,b);
if (semnal<0) cout<<"a<b";
else
if (semnal>0) cout<<"a>b";
else cout<<"a=b";
}

// Sa se se sorteze alfabetic n cuvinte


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{ char cuvinte[10][25], man[25];
int i,n,gasit;
cout<<"n="; cin>>n;
for (i=0;i<n;i++)
{
cout<<"cuvant ";
cin>>cuvinte[i];
}
do
{ gasit=0;
for (i=0;i<n-1;i++)
if (strcmp(cuvinte[i], cuvinte[i+1])>0)
{
strcpy(man,cuvinte[i]);
strcpy(cuvinte[i],cuvinte[i+1]);
strcpy(cuvinte[i+1],man);
gasit=1;
}
}
while (gasit);
for (i=0;i<n;i++) cout<<cuvinte[i]<<endl;
}

// Sa se determine daca al doilea cuvant e subsir al primului


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{ char sir[1000], subsir[25], *t;
cout<<"Introduceti textul "; cin.get(sir,1000);
cin.get( );
cout<<"Introduceti subsirul cautat "; cin.get(subsir,25);
t=strstr(sir,subsir);
if (t) cout<<"este subsir si are indicele "<<t-sir;
else cout<<"nu este subsir";
}

// Sa se stearga toate aparitiile unui sir intr-un subsir


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{
char sir[1000], subsir[25], *p;
int lung_subsir;
cout<<"introduceti textul"; cin.get(sir,1000);
cin.get( );
cout<<"introduceti subsirul"; cin.get(subsir,25);
lung_subsir=strlen(subsir);
p=strstr(sir,subsir);
while (p)
{
strcpy(p,p+lung_subsir);
p=strstr(p,subsir);
}
cout<<sir;
}

// Sa se inlociuasca toate aparitiile unui sir intr-un sir cu alt


sir
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{
char sir[100],man[100],sterg[25],adaug[25],*p;
int lung_sterg,lung_adaug;
cout<<"introduceti textul"; cin.get(sir,100);
cin.get( );
cout<<"inlocuim subsirul"; cin.get(sterg,25);
cin.get( );
cout<<"cu subsirul "; cin.get(adaug,25);
lung_sterg=strlen(sterg);
lung_adaug=strlen(adaug);
p=strstr(sir,sterg);
while (p)
{
man[0]=0; // subsir vid;
strncat(man,sir,p-sir);
strcat(man,adaug);
strcat(man,p+lung_sterg);
strcpy(sir,man);
p=strstr(p+lung_adaug,sterg);
}
cout<<sir;
}

// Sa se afiseze cuvintele dintr-o fraza pe vericala


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{
char sir[1000],separator[ ]=", ", *p;
cin.get(sir,1000);
p=strtok(sir,separator);
while (p)
{
cout<<p<<endl;
p=strtok(NULL, separator);
}
}

// Sa se eleimine blancurile si virgulele dintr-un sir


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{
char sir[1000],separator[ ]=", ", *p;
cin.get(sir,1000);
p=strtok(sir,separator);
while (p)
{
cout<<p;
p=strtok(NULL, separator);
}
}

// Sa se determine daca un sir e numare sau alceva


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{ char cuvant[100],cifre[ ]="0123456789";
cout<<"Introduceti cuvantul "; cin>>cuvant;
if (strspn(cuvant,cifre)==strlen(cuvant))
cout<<"numeric";
else cout<<"nenumeric";
}

// Sa se determine daca un sir nu are numere deloc


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{ char cuvant[100],cifre[ ]="0123456789";
cout<<"Introduceti cuvantul "; cin>>cuvant;
if (strcspn(cifre,cuvant)==10) cout<<"corect";
else cout<<"incorect";
}

// Sa se transforme un sir in majuscule


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{
char a[20];
cout<<"Introduceti cuvantul"; cin>>a;
cout<<strupr(a);
}

// Sa se afisesze toate caracterele dintr-un sir care sunt in alt


sir
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{
char cuvant1[10],cuvant2[10],*p;
cout<<"Introduceti primul cuvant "; cin>>cuvant1;
cout<<"Introduceti al doilea cuvant "; cin>>cuvant2;
p=strpbrk(cuvant1,cuvant2);
while (p)
{
cout<<p[0]<<endl;
p++;
p=strpbrk(p,cuvant2);
}
}

// Sa se sumeze numerele dintr-o fraza cu numere separate prin


separatori
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{
char sir[1000],separator[ ]=" ", cifre[ ]="0123456789.+-",
*p;
double s=0;
cin.get(sir,1000);
p=strtok(sir,separator);
while (p)
{
if (strspn(p,cifre)==strlen(p))
s+=atof(p);
p=strtok(NULL, separator);
}
cout<<"suma numerelor intalnite in sir este "<<s;
}

// Sa se transforme un numar real in sir si sa se aproximeze


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main ( )
{
double numar;
int zec,semn;
char numar_sir[20]=" ",numar_prel[20]=" ";
cout<<"n="; cin>>numar;
strcpy(numar_sir,ecvt(numar,19,&zec, &semn));
cout<<"Sirul este "<<numar_sir<<" "<<zec<<" "<<semn<<endl;
if (semn) strcat(numar_prel,"-");
strncat(numar_prel,numar_sir,zec);
strcat(numar_prel,".");
strncat(numar_prel,numar_sir+zec,3);
cout<<numar_prel;
}

// Sa se determine daca un numar e intr-un interval si daca e numar


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

main (void)
{
char numar[20], *adresa;
long v;
cin>>numar;
v=strtol(numar,&adresa,10);
if (adresa-numar!=strlen(numar))
cout<<"Data contine caractere nenumerice";
else
if (v<10 || v>20)
cout<<"Data numerica in afara limitei ";
else cout<<v<<endl;
}
FISIERE
Notiunea de fisier
Definitie: Se numeste fisier o colectie de date omogene (adica de acelasi tip), stocate pe
suport extern si accesata printr-un nume, care reprezinta numele fisierului.
Exemple:
1.Programele sub forma executabila sunt memorate pe suport sub forma de fisiere.Acestea se
recunosc dupa extensia numelui, care este .exe sau .com.
2.Programele in format sursa (adica textul introdus de programator) sunt stocate si ele sub
forma de fisiere.Acestea pot fi recunoscute dupa extensia lor .pas pentru surse Pascal si .cpp pentru
surse C++.
3.Informatiile de natura economica sunt memorate, de asemenea, sub forma de
fisier.Informatiile referitoare la un material constituie o inregistrare, iar ansamblul inregistrarilor constituie
fisierul propriu-zis.
In C++ se lucreaza cu doua tipuri de fisiere:
a) Fisiere text;
b) Fisiere binare.
Notiunea de fisier text
Fisierele text se caracterizeaza prin urmatoarele:

 Datele sunt memorate sub forma unei succesiuni de caractere.


 Fiecare caracter este memorat prin utilizarea codului ASCII.
 Un fisier text se termina intotdeauna cu caracterul EOF, care permite ca la prelucrare sa poata
fi identificat sfarsitul fisierului.Daca dorim sa-l introducem de la tastatura, se tasteaza CTRL+Z.
 Fisierul text se considera alcatuit din una sau mai multe linii.O linie, mai putin ultima, se
termina prin caracterul newline (\ n).
 O variabila speciala, numita pointer, retine intotdeauna un octet al fisierului.

Schema unui fisier text este urmatoarea:

M a r iii n \n 1 H EOF

pointer

Orice editor de texte lucreaza cu fisiere text.


Cin si cout sunt doua tipuri speciale de fisiere text, care nu sunt memorate pe suport extern, ci
corespund dispozitivelor standard de intrare, respectiv de iesire.
Fisierul cin este privit ca fiind de intrare, adica fluxul de date este de la el catre memoria
interna.El este asimilat tastaturii, iar programul citeste datele din acest fisier.
Fisierul cout este privit ca unul de iesire, adica fluxul de date este de la memoria interna catre
el.El este asimilat monitorului, iar programul scrie astfel in acest fisier.
Toate scrierile / citirile efectuate in / din aceste fisiere sunt identice cu cele efectuate in / din
fisierele memorate pe suport magnetic.
In fisierele text putem scrie sau citi cu sau fara format.Chiar daca scriem fara format, exista
anumite reguli implicite care trebuie respectate.
Citiri / scrieri cu format
Citirile / scrierile cu format sunt caracterizate de urmatoarele notiuni:
1. Latimea –width- se utilizeaza la scriere si are rolul de a stabili numarul de caractere utilizate
pentru afisarea unei date.
2. Precizia –precision- se utilizeaza la scriere si se foloseste pentru a stabili numarul de
zecimale care vor fi afisate pentru o valoare reala.
3. Caracterul de umplere –fill- se utilizeaza la scriere, in cazul in care data propriu-zisa ocupa
mai putini octeti decat latimea, si precizeaza caracterul care se afiseaza in spatiile neocupate de data.
4. Alinierea se utilizeaza in cazul in care data propriu-zisa ocupa mai putin decat latimea si
precizeaza unde anume sa fie afisata data, la stanga –left- sau la dreapta –right-.
5. Salt sau nu peste caracterele albe.

In limbajul C++ exista biblioteca iostream.h in care sunt definite cateva variabile si constante
cu rol important in efectuarea de citiri / scrieri cu format.Variabilele sunt:
int x_precision;
int x_width;
int x_fill;
long x_flags;

 x_precision retine numarul de zecimale ce vor fi afisate pentru un numar real;


 x_width retine numarul de pozitii pe care se efectueaza afisarea (latimea).Valoarea este
retinuta pana cand se efectueaza prima afisare,dupa care variabila este initializata cu 0;
 x_fill retine caracterul care va fi afisat in cazul in care numarul pozitiilor pe care se face
afisarea este mai mare decat cel al pozitiilor efectiv ocupate de date;
 x_flags retine anumiti parametri pentru formatarea intrarilor / iesirilor, care sunt memorati la
nivel de bit si vor fi analizati in amanunt.Pentru a usura accesul la bit s-au definit constantele:
 skipws=0x0001 - caracterele albe care preced valoarea care trebuie citita sunt sarite;
 left=0x0002 - datele se tiparesc aliniate la stanga;
 right=0x0004 - datele se tiparesc aliniate la dreapta;
 internal=0x0008 - se foloseste la tiparirea semnului unui
numar sau a specificatorului de baza;
 dec=0x0010 - conversie in zecimal;
 oct=0x0020 - conversie in octal;
 hex=0x0040 - conversie in hexazecimal;
 showbase=0x0080 - afisarea indicatorului de baza;
 showpoint=0x0100 -forteaza afisarea punctului zecimal;
 uppercase=0x0200 - in cazul afisarii in hexa, se vor utiliza litere mari;
 showpos=0x0400 - valorile numerice sunt afisate precedate de semn;
 scientific=0x0800 - afisarea valorilor reale se face prin utilizarea formei stiintifice (1e -
8);
 fixed=0x1000 - afisarea valorilor reale se face prin utilizarea formei normale (-
12.45).

Accesul propriu-zis la variabilele respective se face cu ajutorul unor functii speciale, numite
manipulatori.Pentru utilizarea acestora se include fisierul antet iomanip.h.
Exemple de manipulatori:

 setw(int) – stabileste latimea;


 setprecision(int) – stabileste precizia (numarul de zecimale)
 setfill(char) – stabileste caracterul de umplere
 setiosflags(masca) – seteaza bitii din masca
 resetiosflags(masca) – reseteaza bitii din masca

Observatii:

1. De regula, utilizarea manipulatorilor are efect numai asupra primei citiri / scrieri, chiar daca operatia
recpectiva este scrisa in cadrul aceleiasi expresii.Una dintre exceptiile de la aceasta regula este saltul
peste caracterele albe.
2. In cazul in care latimea nu este suficienta, ea este ignorata.
3. Daca numarul de zecimale nu este precizat prin manipulator, atunci se tiparesc cel mult 6 zecimale
(daca valoarea respectiva are 6 zecimale).
4. In cazul in care nu a fost specificat caracterul de umplere, acesta este
blank-ul.
5. Conversia bazelor 8, 10, 16 se poate realiza simplificat prin utilizarea manipulatorilor oct dec hex.
Fisiere text memorate pe suport magnetic

Toate operatiile de citire / scriere efectuate asupra fisierelor cu numele logic cin / cout pot fi
efectuate si asupra fisierelor text memorate pe suport magnetic.
Pentru a putea fi prelucrat, orice fisiere are doua nume:
- un nume logic, folosit in program pentru referirea fisierului;
- un nume fizic, sub care fisierul se afla memorat pe suportul extern
In C++, pentru a putea lucra usor asupra fisierelor sunt definite anumite constante, dupa cum
urmeaza:
 in =0x01 – fisierul se deschide pentru citire;
 out =0x02 – fisierul se deschide pentru scriere;
 ate =0x04 – dupa deschidere, salt la sfarsitul fisierului;
 app =0x08 – deschidere pentru a scrie la sfarsitul fisierului;
 trunc =0x10 – daca fisierul care se deschide exista, in locul sau se creeaza
altul
 nocreate =0x20 – deschide fisierul doar daca acesta exista (nu este permisa crearea lui)
 noreplace =0x40 – daca fisierul exista, el poate fi deschis doar pentru consultare
 binary =0x80 – fisier binar – se utilizeaza constructorul ofstream(), apoi se utilizeaza metoda
open, in forma generala.

Orice program care lucreaza cu fisiere pe suport magnetic trebuie sa includa fisierul antet
fstream
Declararea fisierelor text memorate pe suport
magnetic

Forma generala a unei declaratii de fisier text memorat pe suport magnetic este:
fstream nume_logic(char*nume_fizic,int mod_de_deschidere);
Modul de deschidere (pentru citire, scriere etc) se descrie cu ajutorul constantelor prezentate
anterior si operator.

Observatii:

1. Calea se declara cu doua caractere backslash (\\).Caracterul respectiv este folosit pentru a scrie
secvente escape si, din acest motiv, pentru a fi inclus
intr-un sir de caractere este necesar sa fie scris de doua ori.
2. In anumite cazuri, numele fizic al fisierului trebuie citit de la tastatura.Astfel, avem posibilitatea ca
programul sa prelucreze fisiere cu orice nume fizic.In acest caz, declaratia fisierului trebuie sa contina
adresa vectorului de numere si sa fie plasata dupa citirea sirului respectiv.
Prelucrarea fisierelor text

In general, prelucrarea unui fisier se face dupa urmatoarea schema:

while (daca nu este sfarsit de fisier)


{
citeste
prelucreaza
}

Pentru detectarea sfarsitului de fisier, C++ contine o functie specializata, numita eof( ).Pentru a
preciza fisierul al carui sfarsit se testeaza, functia trebuie precedata de numele logic al fisierului si
punct.In cazul detectarii sfarsitului de fisier, functia returneaza o valoare diferita de 0, altfel returneaza 0.
Exista mai multe functii cu ajutorul carora programatorul poate actiona asupra pointerului dintr-un fisier
de intrare:
 Functia long tellp( ) returneaza pozitia pointerului la un moment dat.Pozitia este relativa la
inceputul fisierului.
 Functia seekp(long, seek_dir) pozitioneaza pointerul.Primul parametru reprezinta pozitia, iar al
doilea reperul in raport de care este calculata pozitia.
In acest sens, au fost definite 3 constante.Pentru accesul la ele se foloseste si de aceasta data ios:
 beg – inceput de fisier;
 cur – pozitia curenta in fisier;
 end – sfarsit de fisier.
Cand stabilim o pozitie aflata in stanga reperului, primul parametru este negativ, iar in dreapta
reperului, parametrul este pozitiv.

Variabila de stare. Controlul erorilor


Orice obiect stream moşteneşte din clasa ios un cuvînt de stare care descrie modul în
care a decurs operaţia precedentă. Aceasta este o variabilă de tip întreg (numită state - stare), ]n
care fiecare bit reprezintă un indicator de eroare. Pentru a facilita accesul la aceşti indicatori, în
clasa ios este declarat tipul enumerare io_state, sub forma :

public:
enum io_state {
goodbit = 0x00, // operatie corecta
eofbit=0x01, // s-a ajuns la sfirsitul fisierului
failbit=0x02, // operatie esuata
badbit=0x04, // operatia a fost nevalida
hardfail=0x80 // eroare irecuperabila
};

Valoarea 1 a unui bit semnifică apariţia erorii respective. Trebuie reţinut că nu mai pot
fi executate operaţii cu un stream pînă cînd condiţia de eroare care eventual a intervenit nu a
fost eliminată şi bitul respectiv de eroare a fost resetat.
Clasa ios şi (firesc!) derivatele sale dispun de funcţii membre care pot citi şi modifica
indicatorii de stare :

int eof() - este nenulă dacă eofbit este 1


int bad() - este nenulă dacă badbit este 1
int fail() - este nenulă dacă failbit este 1
int good() - este nenulă dacă operaţia s-a încheiat fără erori
int rdstate() - întoarce valoarea cuvîntului de stare
void clear(int i=0) - înscrie valoarea parametrului în cuvîntul de stare; valoarea implicită
determină ştergerea indicatorilor de eroare

Exemplu (pentru un stream numit fis) :

fis.clear(); // anuleaza toti indicatorii de eroare



fis.clear(ios::badbit); // pune badbit pe 1 si restul pe 0

fis.clear(ios::failbit | fis.rdstate()); // pune pe 1 failbit
iar
// ceilalti ramin neschimbati

Operatorii () şi ! sînt astfel supradefiniţi încît un stream să poată fi testat ca o variabilă


logică, folosind :
expresia (fis) - are valoarea zero dacă s-au înregistrat erori la operaţia precedentă şi
nenulă dacă
nu a fost eroare
expresia !(fis) - are valoarea !(fis) - invers decît mai sus

Exemplu (reluare) :

while(cin.get( c)) cout.put( c); // copiaza cin la cout , (cin)=0


// la sfirsitul fisierului

Formatarea datelor

De multe ori, programatorul doreşte să formateze datele de intrare/ieşire în modul dorit


de el, fie că o face pentru a prezenta sau introduce datele într-un anumit mod, fie pentru a
structura datele în modul dorit, atunci cînd lucrează cu fişiere. C++ pune la dispoziţia
programatorului un set foarte flexibil şi diversificat de instrumente în acest scop, prin accesul la
variabile pentru controlul formatului, prin manipulatori şi prin funcţii membre.

Variabile pentru controlul formatului

Formatul datelor de intrare/ieşire este controlat de următoarele variabile declarate în


clasa ios :

- cuvîntul de format : long int x_flags


- variabile întregi care determină, pentru operaţiile de ieşire :
- dimensiunea cîmpului de format : int x_width
- caracterul de completare a cîmpului de format : int x_fill (implicit este spaţiu)
- precizia pentru valori în virgulă mobilă (adică numărul de zecimale) : int
x_precision

Cuvîntul de format conţine un număr de indicatori care sînt biţi individuali. Ei pot fi
referiţi folosind un set de indicatori declaraţi în clasa ios, cu valori corespunzătoare poziţiei
bitului în cuvînt :

public:
enum {
skipws =0x0001, // sare peste spatii (intrare)
left =0x0002, // aliniere stinga (iesire)
right =0x0004, // aliniere dreapta (iesire)
internal =0x0008, // completare interna cu spatii,pornind de
la
// un semn sau de la caracterul
bazei(iesire)
dec =0x0010, // conversie zecimala
oct =0x0020, // conversie octala
hex =0x0040, // conversie hexa
showbase =0x0080, // afisarea bazei in care este convertit
// numarul (iesire)
showpoint =0x0100, // afisarea punctului zecimal si a
zerourilor
// finale - chiar fara semnificatie (iesire)
uppercase =0x0200, // afisare hexa cu litere mari (iesire)
showpos =0x0400, // determina afisarea “+” pentru numere
// pozitive (altfel nu se afiseaza nimic)
scientific =0x0800, // afisarea numerelor reale in format cu
// exponent - format stiintific (iesire)
fixed =0x1000, // numere reale in format cu punct fix,
// implicit cu 6 zecimale
unitbuf =0x2000, // bufferul este golit dupa fiecare iesire
stdio =0x4000 // la fel dupa scriere in stdout sau stderr
};

Se pot de asemenea indica trei cîmpuri de biţi :

adjustfield - conţine biţii left, right şi internal, care specifică modul de aliniere în spaţiul
alocat afişării
basefield - conţine biţii dec, oct şi hex care precizează baza de reprezentare a unei valori
întregi
floatfield - conţine biţii scientific şi fixed care specifică modul de reprezentare a valorilor în
virgulă mobilă.

În cîmpurile de biţi enumerate mai sus, doar cîte un bit poate fi activ (adică =1).
Indicatorii prezentaţi au valori implicite pentru afişări în formatele cele mai uzuale
(de exemplu numărul de spaţii alocat este cel minim necesar, alinierea se face la stînga, valorile
întregi se afişează în zecimal, fără indicarea bazei iar cele în virgulă mobilă sînt în format cu
punct zecimal).
Modificarea indicatorilor de format se realizează cu ajutorul unor funcţii membre ale
claselor stream sau a unor operatori numiţi manipulatori.

Manipulatori

Orice manipulator primeşte ca parametru şi întoarce ca rezultat adresa stream-ului


asupra căruia acţionează, astfel încît pot fi inseraţi în cadrul expresiilor de intrare/ieşire. În
funcţie de prezenţa sau lipsa unui parametru suplimentar cu rol de control al formatării, se
disting două categorii :

1. Manipulatorii fără parametri - sînt operatori care pot fi folosiţi în expresii de


intrare/ieşire cu sintaxa :
out << manipulator
sau
in >> manipulator
unde in şi out sînt fluxuri de intrare sau de ieşire, oarecare. În continuare este dată
lista de manipulatori fără parametri :

dec - activeaza bitul dec (intrare/iesire)


hex - activeaza bitul hex (intrare/iesire)
oct - activeaza bitul oct (intrare/iesire)
ws - activeaza bitul skipws (intrare)
endl - insereaza caracterul “\n” si goleste bufferul (iesire)
ends - insereaza caracterul “\0” (iesire)
flush - goleste tamponul (iesire)

Exemplu :

int i=127, j=1023;


cout << i << “=”<<hex << i << endl;
cout <<dec << j << “=” << hex << j << endl;
cout << i << endl;

Programul va afişa :

127=7f
1023=7ff
7f

Reţinem din exemplul prezentat că iniţial indicatorul de bază implicit a fost dec=1
(deci reprezentarea zecimală) iar după o modificare, se menţine pînă la următoarea operată
de programator (spre exemplu, în ultima linie, i este afişat în hex, ca şi la precedenta operaţie de
afişare).
Programatorul poate defini şi alţi manipulatori fără parametri, folosind declaraţii de
tipul:
istream& nume_manipulator(istream&);
ostream& nume_manipulator(ostream&);

Astfel, în exemplul următor, este definit un manipulator pentru operaţii de intrare care
afişează un mesaj “prompter” - de invitaţie :

istream& prompt(istream& in)


{
in >> hex;
cout << “Introduceti valoarea adresei (hexa) : “;
return in;
}

main()
{

cin >> prompt >> adr; // utilizarea manipulatorului definit mai sus
}

2. Manipulatorii cu parametri - sînt declaraţi în fişierul antet iomanip.h şi pot fi


utilizaţi în expresii de intrare/ieşire cu sintaxa :

out << manipulator(parametru);


in >> manipulator(parametru);

Aceşti manipulatori sînt funcţii cu prototipul de forma :

istream& nume_manip(parametru)
ostream& nume_manip(parametru)

Iată în continuare lista de manipulatori parametrici :

- setbase(int n) - stabileşte baza de numeraţie la n= 8, 10 sau 16


- resetioflags(long ) - pune pe 0 în biţii specificaţi în argument
- setioflags(long ) - pune pe 1 biţii specificaţi în argument
- setfill(int ) - defineşte caracterul de umplere
- setprecision(int ) - stabileşte precizia pentru numerele reale
- setw(int ) - stabileşte dimensiunea cîmpului de format pentru operaţia
următoare
Crearea unor manipulatori cu parametri de către programator este posibilă, dar printr-o
procedură mai complicată.
Controlul formatului folosind funcţii membre

Există un set de funcţii membre în ios care oferă alternative pentru controlul
formatului:

long setf(long ) - activează indicatorii de format specificaţi de argument (fără a modifica alţi
biţi) şi întoarce valoarea anterioară a cuvîntului de control al formatului. Exemplu :

stare = in.setf(ios::showbase | ios::hex) ;

Funcţia este supradefinită cu o variantă cu prototipul :

long setf(long, long) - care activează indicatorul specificat de primul argument în cadrul
cîmpului selectat de al doilea argument. Ceilalţi biţi ai cîmpului sînt dezactivaţi, iar
restul
cuvîntului de format nu se modifică. Funcţia întoarce valoarea anterioară a cîmpului.
Exemplu :

stare_baza=out.setf(ios::hex, ios::basefield); // schimbarea bazei


// (dar se retine baza precedenta in stare_baza)

out.setf(stare_baza, ios::basefield); // revenire la baza veche

long unsetf(long ) - dezactivează (anulează) indicatorii specificaţi de argument şi întoarce


valoarea anterioară a cuvîntului de format

char fill() - întoarce caracterul de umplere curent; este supradefinită cu varianta :

char fill(char ) - care modifică valoarea caracterului de umplere cu valoarea parametrului şi


întoarce valoarea anterioară

int precision() - întoarce valoarea curentă a preciziei; este supradefinită cu varianta:

int precision(int ) - care modifică valoarea curentă a preciziei şi întoarce valoarea sa


precedentă

int width() - întoarce valoarea actuală a dimensiunii cîmpului de afişare; este supradefinită
cu:

int width(int ) - care modifică dimensiunea cîmpului conform argumentului şi întoarce


valoarea anterioară.

//SA SE scrie trei fraze pe verticala intr-un fisier

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
using namespace std;

int main() {
char filename[81];

cout << "Enter a file name and press ENTER: ";


cin.getline(filename, 80);
ofstream f(filename);
if (! f) {
cout << "File " << filename << " could not be opened.";
return -1;
}
cout << "File " << filename << " was opened.";
f << "I am Blaxxon," << endl;
f << "the cosmic computer." << endl;
f << "Fear me.";
f.close();
return 0;
}

//SA SE scrie trei fraze pe verticala intr-un fisier


// acei cale se da de la tastatura

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
using namespace std;

int main() {
char filename[81];
char path[81];

cout << "Enter directory path: "; // Prompt for path


cin.getline(path, 80);

cout << "Enter a file name and press ENTER: ";


cin.getline(filename, 80);

strncat(path, filename, strlen(path) - 80); // concatenate

ofstream file_out(path); // Use path string to open


if (! file_out) {
cout << "File " << filename << " could not be opened.";
return -1;
}
cout << "File " << filename << " was opened.";
file_out << "I am Blaxxon," << endl;
file_out << "the cosmic computer." << endl;
file_out << "Fear me.";
file_out.close();
return 0;
}

//SA SE scrie intr-un fisier fraze pana cand la un moment dat se dau
trei caractere adica @@@

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
using namespace std;

int main() {
char filename[81];
char input_line[81]; // Input line for text entry

cout << "Enter a file name and press ENTER: ";


cin.getline(filename, 80);

ofstream file_out(filename);
if (! file_out) {
cout << "File " << filename << " could not be opened.";
return -1;
}
cout << "File " << filename << " was opened." << endl;
while (1) {
cout << "Enter line (@@@ to quit)>>";
cin.getline(input_line, 80);
if (strcmp(input_line, "@@@") == 0)
break;
file_out << input_line << endl;
}
file_out.close();
return 0;
}

//SA SE citeasca dintr-un fisier fraze pana cand la un moment dat se


da Q sau q

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
using namespace std;

int main() {
int c; // input character
int i; // loop counter
char filename[81];
char input_line[81];

cout << "Enter a file name and press ENTER: ";


cin.getline(filename, 80);

ifstream file_in(filename);

if (! file_in) {
cout << "File " << filename << " could not be opened.";
return -1;
}

while (1) {
for (i = 1; i <= 24 && ! file_in.eof(); i++) {
file_in.getline(input_line, 80);
cout << input_line << endl;
}
if (file_in.eof())
break;
cout << "More? (Press 'Q' and ENTER to quit.)";
cin.getline(input_line, 80);
c = input_line[0];
if (c == 'Q' || c == 'q')
break;
}
return 0;
}

// Exercitiul 8.2.1.txt
// Acest program afiseaza N linii din fisierul de text la un anumit
moment de timp ales;
// utilizatorul poate renunta sau poate specifica o noua valoare
pentru N.

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
using namespace std;

int main() {
int c; // input character
int i; // loop counter
char filename[81];
char input_line[81];

cout << "Enter a file name and press ENTER: ";


cin.getline(filename, 80);

ifstream file_in(filename);

if (! file_in) {
cout << "File " << filename << " could not be opened.";
return -1;
}

int lines_to_read = 20; // Number of lines to read; default =


20

while (1) {
for (i = 1; i <= lines_to_read && ! file_in.eof(); i++) {
file_in.getline(input_line, 80);
cout << input_line << endl;
}
if (file_in.eof())
break;
cout << "More? (Press 'Q' and ENTER to quit, or # lines to
print.)>";
cin.getline(input_line, 80);
c = input_line[0];
if (c == 'Q' || c == 'q')
break;
else if (strlen(input_line) > 0) // If user input
something
lines_to_read = atoi(input_line); // set new value of
lines_to_read
}
return 0;
}

// Exercitiul 8.2.1.txt
//listarea unui fisier

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
using namespace std;

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

int main(int argc, char *argv[]) {


int c; // input character
int i; // loop counter
char filename[81];
char input_line[81];

if (argc > 1)
strncpy(filename, argv[1], 80);
else {
cout << "Enter a file name and press ENTER: ";
cin.getline(filename, 80);
}

ifstream file_in(filename);
if (! file_in) {
cout << "File " << filename << " could not be opened.";
return -1;
}

while (1) {
for (i = 1; i <= 24 && ! file_in.eof(); i++) {
file_in.getline(input_line, 80);
cout << input_line;
}
if (file_in.eof())
break;
cout << endl << "More? (Press 'Q' and ENTER to quit.)";
cin.getline(input_line, 80);
c = input_line[0];
if (c == 'Q' || c == 'q')
break;
}
return 0;
}
// nu sunt sarite caracterele albe citite de la tastatura.
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;

main ( )
{
fstream f("c:\\fis.txt",ios::out);
char ch;
while (cin>>resetiosflags(ios::skipws)>>ch) f<<ch;
f.close( );
}

// Exercitiul 8.2.1.txt
//scrierea intr-un fisier dar fara spatii in fraza

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;

main ( )
{
fstream f("c:\\fis.txt",ios::out);
char ch;
while (cin>>ch) f<<ch;
f.close( );
}

//listarea unui fisier fara spatiile dintre cuvinte

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;

main ( )
{
fstream f("c:\\fis.txt",ios::in);
char ch;
while (f>>ch) cout<<ch;
f.close( );
}

//listarea unui fisier fara spatii dintre cuvinate

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;

main ( )
{
fstream f("c:\\fis.txt",ios::in);
char ch;
while (f>>resetiosflags(ios::skipws)>>ch) cout<<ch;
f.close( );

//copierea dintr-un fisier in altul

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;

main ( )
{
fstream f("c:\\fis.txt",ios::in),g("c:\\fis1.txt",ios::out);
char ch;
while (f>>resetiosflags(ios::skipws)>>ch) g<<ch;
f.close( );
}

//scrierea intr-un fisier a numerelor in baza 16 dar care nu depasesc


5 cifre

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;

main ( )
{
fstream f("c:\\fis2.txt",ios::out);
int i;
for (i=1;i<=100;i++)
f<<setw(5)<<hex<<i<<endl;
f.close( );
}

//scrierea dintr-un fisier a numerelor in baza 16 dar care se


afisesaza sunt in baza 10

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;

main ( )
{
fstream f("c:\\fis2.txt",ios::in);
int i;
while (f>>hex>>i)cout<<dec<<i<<endl;
f.close( );
}
//scrierea intr-un fisier a a primelor 4 caractere

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;

main ( )
{
fstream f("c:\\fis.txt",ios::in | ios::out);
char cuvant[10];
f>>cuvant;
cout<<cuvant;
f.seekp(0,ios::beg);//ma plasez fata de inceputul fisierului
la pozitia zero
strcpy(cuvant, "tata");
f<<cuvant;
f.close( );
}

//afisarea dintr-un fisier

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;

main ( )
{
fstream f("c:\\fis.txt",ios::in);
char linie [100];
while (f.get(linie,100))
{
cout<<linie<<endl;
f.get( );
}
}

//crearea unui buffer si listarea lui


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >

int main()
{
char fileName[80];
char buffer[255]; // for user input
cout << "File name: ";
cin >> fileName;

ofstream fout(fileName); // open for writing


fout << "This line written directly to the file...\n";
cout << "Enter text for the file: ";
cin.ignore(1,'\n'); // eat the newline after the file name
cin.getline(buffer,255); // get the user's input
fout << buffer << "\n"; // and write it to the file
fout.close(); // close the file, ready for reopen

ifstream fin(fileName); // reopen for reading


cout << "Here's the contents of the file:\n";
char ch;
while (fin.get(ch))
cout << ch;

cout << "\n***End of file contents.***\n";

fin.close(); // always pays to be tidy


return 0;
}
//adaugarea intr-un buffer si listarea lui
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >

int main() // returns 1 on error


{
char fileName[80];
char buffer[255];
cout << "Please re-enter the file name: ";
cin >> fileName;

ifstream fin(fileName);
if (fin) // already exists?
{
cout << "Current file contents:\n";
char ch;
while (fin.get(ch))
cout << ch;
cout << "\n***End of file contents.***\n";
}
fin.close();

cout << "\nOpening " << fileName << " in append mode...\n";

ofstream fout(fileName,ios::app);
if (!fout)
{
cout << "Unable to open " << fileName << " for appending.\
n";
return(1);
}

cout << "\nEnter text for the file: ";


cin.ignore(1,'\n');
cin.getline(buffer,255);
fout << buffer << "\n";
fout.close();

fin.open(fileName); // reassign existing fin object!


if (!fin)
{
cout << "Unable to open " << fileName << " for reading.\n";
return(1);
}
cout << "\nHere's the contents of the file:\n";
char ch;
while (fin.get(ch))
cout << ch;
cout << "\n***End of file contents.***\n";
fin.close();
return 0;
}

//afisarea dintr-un fisier a numerelor dintr-un interval dat

#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;

main ( )
{
fstream f("c:\\fis2.txt",ios::in);
int i,j;
char ch;
cout<<"i=";cin>>i;
cout<<"j=";cin>>j;
// pozitionez pointerul direct pe octetul i
f.seekp(i,ios::beg);
// atat timp cat pointerul este mai mic sau egal cu j
while (f.tellp( )<=j)
{
f>>ch;
cout<<ch;
}
f.close( );
}

Fisiere binare
Caracteristicile fisierelor binare sunt:

 Fisierele binare sunt alcatuite din mai multe inregistrari de acelasi tip.
Din acest motiv, aceste fisiere se mai numesc si cu tip.
Exemple:
 inregistrarile sunt de tip int;
 inregistrarile sunt de un tip descris cu struct.
 Datele sunt memorate in format intern.De exemplu, daca inregistrarea este de tip int, datele sunt
memorate in cod complementar.
 Fisierele binare se termina cu EOF, ca si cele text.

Observatie:Tot ce s-a studiat la fisierele text ramane valabil si pentru fisierele binare!
Observatii:

 Intrucat lucram cu un fisier binar, il deschidem cu parametrul respectiv, binary.


 Dupa citirea variabilei p urmeaza scrierea acesteia in fisier.Pentru aceasta, se foloseste functia
write, care scrie n caractere ale unui sir si nu insereaza caracterul nul.Ea are forma:
write (char*nume,int n);
 “Pacalim” calculatorul sa scrie, de fapt, continutul varabilei p.Adresa de inceput a variabilei p o
convertim catre un sir de caractere prin utilizarea operatorului de conversie explicita.Numarul de
caractere care trebuie scrise este dat de lungimea variabilei p.In acest moment, calculatorul “crede”
ca scrie un sir de caractere.Daca e sir de caractere, nu este cazul sa faca conversiile necesare, dar
el preia informatia in format intern si o scrie asa!
In prelucrarea fisierelor binare se folosesc urmatorii termeni:

 Creare – initial fisierul nu exista, dar dupa executia programului, acesta se va gasi pe
suport.Intrarile sunt de la tastatura sau din alte fisiere.
 Exploatare – utilizarea fisierului pentru a extrage informatii din el.In urma exploatarii, fisierul
ramane nemodificat.
 Actualizare – aducerea la zi a fisierului.Aceasta se face in trei feluri:

1) stergere – se sterg anumite inregistrari ale sale.In C++ nu exisat functii care permit ca
aceasta operatiune sa se faca direct.Din acest motiv, in practica sunt folosite doua
metode:

a)
stergere fizica – se creeaza alt fisier cu inregistrarile din primul fisier care nu se
sterg.Apoi primul fisier se sterge, iar cel proaspat creat este “rebotezat” cu
numele celui care a fost sters.
b) stergere logica – fiecare inregistrare are un camp care precizeaza daca ea a
fost stearsa logic sau nu.Toate programele de prelucrare tin cont de ea, in sensul
ca daca a fost stearsa logic, inregistrarea nu mai intra in prelucrare.Pentru a nu
retine date inutile, din cand in cand, inregistrarile sterse logic sunt sterse fizic.
2) modificare – in urma prelucrarii unei inregistrari (sau mai multor inregistrari), se modifica
anumite campuri.
3) adaugare – se adauga la sfarsitul fisierului alte inregistrari.
//Sa se creeze si listeze un fisier binary care ia date dintr-o clasa
//adaugarea intr-un buffer si listarea lui
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >

class Animal
{
public:
Animal(int weight, long
days):itsWeight(weight),itsNumberDaysAlive(days){}
~Animal(){}

int GetWeight()const { return itsWeight; }


void SetWeight(int weight) { itsWeight = weight; }

long GetDaysAlive()const { return itsNumberDaysAlive; }


void SetDaysAlive(long days) { itsNumberDaysAlive = days; }

private:
int itsWeight;
long itsNumberDaysAlive;
};

int main() // returns 1 on error


{
char fileName[80];
char buffer[255];

cout << "Please enter the file name: ";


cin >> fileName;
ofstream fout(fileName,ios::binary);
if (!fout)
{
cout << "Unable to open " << fileName << " for writing.\n";
return(1);
}

Animal Bear(50,100);
fout.write((char*) &Bear,sizeof Bear);

fout.close();

ifstream fin(fileName,ios::binary);
if (!fin)
{
cout << "Unable to open " << fileName << " for reading.\n";
return(1);
}

Animal BearTwo(1,1);

cout << "BearTwo weight: " << BearTwo.GetWeight() << endl;


cout << "BearTwo days: " << BearTwo.GetDaysAlive() << endl;

fin.read((char*) &BearTwo, sizeof BearTwo);

cout << "BearTwo weight: " << BearTwo.GetWeight() << endl;


cout << "BearTwo days: " << BearTwo.GetDaysAlive() << endl;
fin.close();
return 0;

//punerea datelor dintr-o structura intr-un fisier binar


#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >

struct persoana
{
char nume[30];
int varsta;
};
main( )
{
fstream f("pers.dat",ios::out | ios::binary);
persoana p,*adr_p=&p;
char x;
int n,i;
cout<<"Care este numarul de persoane ";cin>>n;
cin.get( );
for(i=0;i<n;i++)
{
cout<<"Numele ";cin.get(p.nume,30);cin.get(x);
cout<<"Varsta ";cin>>p.varsta;cin.get(x);
f.write((char*)adr_p,sizeof p);
}
f.close( );
}
//citirea datelor dintr-un fisier binar
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >

struct persoana
{
char nume[30];
int varsta;
};
main( )
{
persoana p, *adr_p=&p;
fstream g("pers.dat",ios::in | ios::binary);
while (g.read((char*)adr_p,sizeof(p)))
cout<<p.nume<<" "<<p.varsta<<endl;
g.close( );
}
//adaugari intr-un fisier binary
//citirea datelor dintr-un fisier binar
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >

struct persoana
{
char nume[30];
int varsta;
};
main( )
{
fstream f("pers.dat",ios::app | ios::binary);
persoana p,*adr_p=&p;
char x;
int n,i;
cout<<"Care este numarul de persoane ";cin>>n;
cin.get( );
for(i=0;i<n;i++)
{
cout<<"Numele ";cin.get(p.nume,30);cin.get(x);
cout<<"Varsta ";cin>>p.varsta;cin.get(x);
f.write((char*)adr_p,sizeof p);
}
f.close( );
}
//modidficarea datelor dintr-un fisier binar
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >

struct persoana
{
char nume[30];
int varsta;
};
main( )
{
int i;
cout<<"care inregistrare o modific (1..n) ?";cin>>i;
persoana p,*adr_p=&p;
fstream g("pers.dat",ios::in | ios::out | ios::binary);
g.seekp((i-1)*sizeof(p),ios::beg);
g.read((char*)adr_p,sizeof(p));
cout<<"varsta ";cin>>p.varsta;
g.seekp((i-1)*sizeof(p),ios::beg);
g.write((char*)adr_p,sizeof(p));
g.close( );
}

FUNCTII SI PROCEDURI
O functie este alcatuita din:
-antet_tip nume(lista parametrii formali);
-o instructiune compusa_aceasta cuprinde declaratiile variabilelor locale,
si instructiunile propriu zise.
 Parametrii care se găsesc în antetul funcţiei se numesc parametrii formali.
Atunci când scriem o funcţie nu cunoaştem valoarea propriu-zisă a parametrilor. Funcţia
trebuie să întoarcă rezultatul corect, oricare ar fi valoarea lor. Din acest punct de vedere
ei se numesc formali.

 Parametrii care se utilizează la apel se numesc parametrii efectivi.

La apel, lucrurile stau altfel: valorile acestora sunt cunoscute. Prin urmare aceştia se
cunosc parametrii efectivi.
 Vizibilitatea – precizează liniile textului sursă din care variabila respectivă poate
fi accesată. Astfel avem:

a. Vizibilitate la nivel de bloc (instrucţiune compusă);


b. Vizibilitatea la nivel de fişier – în cazul în care programul ocupă un singur
fişier sursă, singurul caz pe care îl tratăm acum.
c. Vizibilitatea la nivel de clasă – este în legătură cu programarea pe obiecte.
 Durata de viaţă – reprezintă timpul în care variabila respectivă are alocat spaţiu
în memoria internă. Astfel avem:

a. Durata statică – variabila are alocat spaţiu în tot timpul execuţiei


programului.
b. Durata locală - variabila are alocat spaţiu în timpul în care se execută
instrucţiunile blocului respectiv.
c. Durata dinamică – alocarea şi dezalocarea spaţiului necesar variabilei
respective se face de către programator prin operatori sau funcţii speciale.
Variabile globale se declară în afara corpului oricărei funcţii.
La declarare, variabilele globale sunt iniţializate cu 0.
Variabile locale sunt declarate în corpul funcţiilor. Mai precis, pot fi declarate în orice
bloc (instrucţiune compusă) al acestora.

// Se citeste n ,nr natural.sa se scrie programele care


//tiparesc valoarea calculata a expresiilor:
//E1=1+1/2+1/3+…+1/n;

#include "stdafx.h"
#include<iostream>
using namespace std;
double subp(int n)
{
double s=0.0;int I;
for (I=1;I<=n;I++) s+=1.0/I;
return s;
}
main()
{
int n;
cout<<"n=";cin>>n;
cout<<subp(n);
}
// sa se creeze un cap de tabel cu o procedura

#include "stdafx.h"
#include <iostream>
using namespace std;

main()
{
void cap_tabel(void);
cap_tabel();
}
void cap_tabel(void)
{
cout<<"Nr,Cod,Denumire,UM,Cantitate";
}

// Se citeste n ,nr natural.sa se scrie programele care


//tiparesc valoarea calculata a expresiilor:
//E1=1+1/2+1/3+…+1/n;

// Se citeste n ,nr natural.sa se scrie programele


//care tiparesc valoarea calculata a expresiilor:
//E1=1+1/2+1/3+…+1/n si
// E2=(1+1/2+1/3+…+1/n) la puterea n

#include "stdafx.h"
#include<iostream>
using namespace std;

double subp(int n)
{
double s=0.0;
int I;
for (I=1;I<=n;I++) s+=1.0/I;// sau s=s+1/I
return s;
}
main()
{
int n,I;
double rez,prod=1;
cout<<"n=";cin>>n;
rez=subp(n);
for (I=1;I<=n;I++) prod*=rez;
cout<<prod;
}
// sa se creeze doua functii care calculeaza suma si suma
patratelor //componentelor unui vector

#include "stdafx.h"
#include <iostream>
using namespace std;

int suma1(int x[],int n)


{
int s=0,i;
for(i=0;i<n;i++) s+=x[i];
return s;
}
int suma2(int x[],int n)
{
int s,i;
for(s=0,i=0;i<n;i++)
x[i]*=x[i];
s+=x[i] ;
return s;
}

main()
{
static int x[10]={2,13,14,15,16,7,8,9,11,22};
int n=10,i;
for (i=0;i<=n;i++) cout<<x[i];
cout<<suma1(x,n);
cout<<"suma patratelor este:"<<suma2(x,n);
for(i=0;i<n;i++) cout<<x[i];
}
// Sa se scrie o functie care primind pointeri la doua valori flotante, calculeaza suma lor si
returneaza // pointer la rezultat.
#include "stdafx.h"
#include <iostream>
using namespace std;
#include<math.h>
float *suma(float *pa,float *pb)
{
static float sum,*psum;
psum=&sum;
sum=*pa+*pb;
return psum;
}

main ( )
{
float a=6,b=8, *ps;
ps=suma(&a,&b);
cout<<*ps;
}
// sa se determine minimul a trei numere dar fara sa apara valoarea 3

#include "stdafx.h"
#include <iostream>
using namespace std;
#include<math.h>
#include <stdio.h>
main()
{
int val,minim();
if (minim()==val)
cout<<"a fost gasit";
else cout<<"datele sunt eronate";
}
int minim()
{
int a,b,c,val;
cout<<"introduceti a:";
cin>>a;
val=a;
cout<<"introduceti b:";
cin>>b;

cout<<"introduceti c";
cin>>c;
val+=c;
if(val== 3)
{
cout<<"a fost gasita";
if ((a>b)&&(b>c))
cout<<c;
else
cout<<b;
if (a>c)
cout<<c;
else
cout<<a;
return val;
}
else return c ;
}

// sa se creeze o functie care sumeaza doua valori

#include "stdafx.h"
#include <iostream>
using namespace std;
#include<math.h>
#include <stdio.h>
int f(int x,int y)

{
return x+y;
}
main( )
{
int val;

val=f(3,5);
cout<< val;
}

// sa se rotunjeasca valoarea unor numere reale cu o functie

#include "stdafx.h"
#include <iostream>
using namespace std;
int rotunjire ( double x)
{
int y ; y=(int) x;
if (x-y >=0.5 )
++ y;
else y ;
return y;
}
main ( )
{
double a=4.30 ,b=3.49 ,c=7.7 ,d=0.5;
cout <<rotunjire(a) ;
cout <<rotunjire (b);
cout << rotunjire ( c );
cout << rotunjire (d);
}

// sa se calculeze radacina unei ecuatii prin metoda bisectiei

#include "stdafx.h"
#include <iostream>
using namespace std;

double f( double x)
{
return(x*x*x+3*x+7);
}

double bisect(double a,double b,double aprox)


{

double m=(a+b)/2;

if( f(m)<aprox ) return m;


if (f(a)* f(m)<0 )
bisect(a,m,aprox);
else bisect (m,b,aprox);
}
main()
{
double x=5.0;
double a=1;
double b=10;
double aprox=0.1;
cout<<"\n insert in bisect cu a,b";

cin>>a;cin>>b;
if (f(x)*f(b)>0)
{
cout<<"\n ";
exit(1);
}
cout<<"\n radacina este %f"<< bisect (a,b,aprox ) ;
}

// sa se suma si diferenta a doua numere cu functii

#include "stdafx.h"
#include <iostream>
using namespace std;
#include<math.h>
#include <stdio.h>
int suma(int a,int b)
{
cout<<"s-a intrat in functia suma";
return a+b;
}
int diferenta(int a,int b)
{
cout<<"s-a intrat in functia diferenta";
return a-b;
}

main ( )
{
int a,b;
char *text[2] ={"suma","diferenta"};
cout <<"introduceti a";cin>>a;
cout<<"introduceti b";cin>>b;

cout<<"suma este:",text[0],suma(a,b);
cout<<"suma este:",text[1],diferenta(a,b);
}

//sa se sorteze un vector

#include "stdafx.h"
#include<iostream>
using namespace std;

void citesc(int vt[10],int n)


{
int I;
for(I=0;I<n;I++)
{
cout<<"vt["<<I+1<<"]=";cin>>vt[I];
}
}
void sortez(int vt[10],int n)
{
int gasit,I,man;
do
{
gasit=0;
for (I=0;I<=n-1;I++)
if (vt[I]>vt[I+1])
{
man=vt[I];vt[I]=vt[I+1];
vt[I+1]=man;
gasit=1;
}
} while(gasit);
}
void scriu(int vt[10],int n)
{
int I;
for (I=0;I<n;I++)
cout<<vt[I]<<endl;
}
main()
{
int vt[10],n;
cout<<"n=";cin>>n;
citesc(vt,n);
sortez(vt,n);
scriu(vt,n);
}
//sa se INTRODUCA CU AJUTORUL UNOR STRUCTURI O MATRICE CU FUNCTII

#include "stdafx.h"
#include<iostream>
using namespace std;

struct mat
{
float matrice[6][8];
};
mat cit(int m,int n)
{
mat a;
int I,j;
for (I=0;I<m;I++)
for (j=0;j<n;j++) cin>>a.matrice[I][j];
return a;
};
main()
{
int I,j;
mat mtr=cit(3,2);
for (I=0;I<3;I++)
for (j=0;j<2;j++) cout<<mtr.matrice[I][j]<<" ";

Nu este obligatoriu ca numele parametriilor formali sa coincida cu


numele parametriilor efectivi.
Exista doua mecanisme de transmitere a parametrilor: prin valoare si
prin referinta.
Se pot transmite prin valoare:
1)valorile retinute de variabile
2)expresii
3)Parametri efectivi trebuie sa fie numele variabilelor
}
//sa se dea un exemplu prin care sa se transmita
//parametrii prin valoare si ca in cazul in care
//parametrii actuali sunt reali si ei erau intregi ca
//parametrii formali se ia partea intreaga a lor

#include "stdafx.h"
#include<iostream>
using namespace std;
int suma(int a,int b)
{ return a+b;
}
main()
{ int c=4,d=3;
cout<<suma(2,3)<<endl;
cout<<suma(2+7,3-1*2)<<endl;
cout<<suma(c,d)<<endl;
cout<<suma(1.9,3.3)<<endl;
}
// sa se interschimbe doua valori prin referinta se face transmitrea
datelor

#include "stdafx.h"
#include <iostream>
using namespace std;
void comuta2 ( int *a ,int *b )
{
int temp ;
temp = *a , *a = *b , *b = temp ;
}
main ( )
{
int a = 7, b = 3 ;
cout << "a = "<<a<<"b = " <<b ;
comuta2 ( &a ,&b ) ;
cout << "a ="<<a<<"b = "<<b ;
}

// sa se interschimbe doua valori dintr un vector

#include "stdafx.h"
#include <iostream>
using namespace std;
void comuta2 ( int *a ,int *b )
{
int temp ;
temp = *a , *a = *b , *b = temp ;
}
void comuta3 (int a [10], int i,int j )

{
int temp ;
temp = a[i] , a[i] = a[j] , a[j] = temp ;
}

main ( )
{
int a [10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
comuta2( &a[6], &a[2]) ;
comuta3(a,1,3);
for (int i=0;i<10;i++)
cout<<a[i]<<endl;
}

//sa se dea un exemplu prin care sa se transmita


//parametrii prin valoare adica in programul principal
//variabila nu a fost schimbata

#include "stdafx.h"
#include<iostream>
using namespace std;

void test(int n)
{ n+=1;
cout<<n<<endl;
}
main()
{ int n=1;
test(n);
cout<<n<<endl;
}
//parametrii actuali pot fi expresii care mai intai se evalueaza

#include "stdafx.h"
#include<iostream>
using namespace std;

void test( int n)


{ cout<<n<<endl;
}
main()
{ test(3);
test(3+4*5);
}

A defini un subprogram inseamna a-l scrie efectiv,problema fiind locul unde se defineste
subprogramul.
A declara un subprogram inseamna a-l anunta.Definitia unui subprogram tine loc si de
declaratie.

//sa se scrie o functie care aduna doua numere


#include "stdafx.h"
#include<iostream>
using namespace std;
int Add (int x, int y)
{

cout << "In Add(), received " << x << " and " << y << "\n";
return (x+y);
} int main()
{
cout << "I'm in main()!\n";
int a, b, c;
cout << "Enter two numbers: ";
cin >> a;
cin >> b;
cout << "\nCalling Add()\n";
c=Add(a,b);
cout << "\nBack in main().\n";
cout << "c was set to " << c;
cout << "\nExiting...\n\n";
return 0;
}
// sa se creeze o functie optimizata care ridica la o putere un numar

#include "stdafx.h"
#include <iostream>
using namespace std;
int optpow(int x, int n)
{
int r=1;
while(n)
if (n&1) r*=x,n--;
else x*=x, n/=2;
return r;
}
main()
{
cout<<optpow(3,4);
}

// Folosind dezvoltarea in scris Taylor pentru sin(x) , elaborati o functie care determina valoarea lui
sin(x) // intr-un ponct dat cu aproximatie inpusa.
#include "stdafx.h"
#include <iostream>
using namespace std;
#include<math.h>
#define PI 3.141592

double sinus(double x,double aprox)


{
double termen, suma;
int k=1;
x=x*PI/180;
suma=termen=x;
while(fabs(termen) > aprox)
{
k+=2;
termen*=-(x*2)/k/(k-1);
suma+=termen;
}
return suma ;
}
main()
{
double x;
for (x=30;x<=45;++x)
cout<<x<<sinus(x,0.04)<<sinus(90-x,0.04);
}

//imbricarea subprogramelor unul in altul

#include "stdafx.h"
#include<iostream>
using namespace std;

void s1()
{ cout<<"eu sunt s1"<<endl;
}
void s2()
{ s1();
cout<<"eu sunt s2"<<endl;
}
main()
{ s1();s2();
}
//imbricarea subprogramelor unul in altul dar primul
//sa fie declarat in prealabil

#include "stdafx.h"
#include<iostream>
using namespace std;
void s2();
void s1()
{
s2();
cout<<"eu sunt s1"<<endl;
}
void s2()
{ cout<<"eu sunt s2"<<endl;
}
main()
{ s1();
}
//sa se determine cel mai mare divizor comun si cel
//mai mic multiplu comun

#include "stdafx.h"
#include<iostream>
using namespace std;
int cmmdc(int m,int n)
{ while( m!=n)
if (m>n) m-=n;
else n-=m;
return m;
}
main()
{ int cm,m,n;
cout<<"m=";cin>>m;
cout<"n=";cin>>n;
cm=cmmdc(m,n);
cout<<cm<<"cel mai mare multiplu comun este "<<m*n/cm;
}
//sa se determine cel mai mare divizor comun a n numere

#include "stdafx.h"
#include<iostream>
using namespace std;
int v[9],n;
int cmmdc(int m,int n)
{ while (m!=n)
if (m>n) m-=n;
else n-=m;
return m;
}
main()
{ int I,cm;
cout<<"n=";cin>>n;
for (I=0;I<=n;I++) cin>>v[I];
cm=cmmdc(v[0],v[1]);
for (I=2;I<n;I++) cm=cmmdc(cm,v[I]);
cout<<cm;
}
//sa se determine toate polindroamele dintr-un interval

#include "stdafx.h"
#include<iostream>
using namespace std;
int palin( int I)
{int isalv=I,iinv=0;
while(I)
{iinv=iinv*10+I%10;
I=I/10;
}
return isalv==iinv;
}
main()
{ int m,n,I;
cout<<"m=";cin>>m;
cout<<"n=";cin>>n;
for (I=m;I<n;I++)
if (palin(I)) cout<<I<<endl;
}
// cu functii sa se determine diferite operatii cu elemnetele unui
vector

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

main( )
{
char *nume[6]={"sum","min","max","sump","sumc","sabs"};
int sum( ), min ( ),max( ),sumc( ),sump( ),sabs( );
static int (*pf[6])( )={sum,min,max,sump,sumc,sabs};
static int x[10]={1,2,3,4,5,6,7,8,9,10};
int n=10;

cout<<sum()<<endl;
cout<<sump()<<endl;
cout<<sumc()<<endl;
cout<<sabs()<<endl;
cout<<min()<<endl;
cout<<max()<<endl;

cout<<"program terminat";
}
int sum()
{static int x[10]={1,2,3,4,5,6,7,8,9,10};
int n=10;
int s=0,i;
for (i=0;i<n;i++) s+=x[i] ;
return s;
}
int min()

{static int x[10]={1,2,3,4,5,6,7,8,9,10};


int n=10;
int minx=x[0],i;
for (i=0;i<n;i++)
if (minx>x[i] )
minx=x[i];
return minx;
}
int max()
{static int x[10]={1,2,3,4,5,6,7,8,9,10};
int n=10;
int maxc=x[0],i;
for (i=0;i<n;i++)
if (maxc<x[i] )
maxc=x[i];
return maxc;
}
int sump()

{static int x[10]={1,2,3,4,5,6,7,8,9,10};


int n=10;
int s2=0,i;
for (i=0;i<n;i++)
s2+=x[i]*x[i] ;
return s2;
}
int sumc()
{static int x[10]={1,2,3,4,5,6,7,8,9,10};
int n=10;
int s3=0,i;
for (i=0;i<n;i++)
s3+=x[i]*x[i] ;
return s3;
}
int sabs()
{static int x[10]={1,2,3,4,5,6,7,8,9,10};
int n=10;
int sa=0,i;
for (i=0;i<n;i++)
if (x[i]<0)
sa-=x[i];
else
sa+=x[i] ;
return sa;
}
// sa se cu functii minimul si maximul a trei numere

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

main ( )
{
int x,a,b,c;
int min ( ),max( );
cout<<"intoduceti a,b,c,x";
cin>>a>>b>>c>>x;
if (x>0) cout <<"valoarea functiei este:",min();
else
cout<<" valoarea functeiei este:",max();
}
int min ()
{int x,a,b,c;
if (a>b)
if(b>c) return c;
else return b;
else
if (a>c) return c;
else return a;
}

max ()
{int x,a,b,c;
if (a<b)
if (b<c) return c;
else return b;
else
if (a<c) return c;
}

//sa se determine toate polindroamele dintr-un interval


//care au si patratele tot polindromice

#include "stdafx.h"
#include<iostream>
using namespace std;

long palin( long I)


{ long isalv=I,iinv=0;
while(I)
{ iinv=iinv*10+I%10;
I=I/10;
}
return isalv==iinv;
}
main()
{ long m,n,I;
cout<<"m=";cin>>m;
cout<<"n=";cin>>n ;
for (I=m;I<n;I++)
if (palin(I)) cout<<I<<" "<<I*I<<endl;
}

//Suma cuburilor cifrelor.

#include "stdafx.h"
#include<iostream>
using namespace std;

int seria[1000],n,ind,I,gasit;
int suma(int n)
{ int s=0,c;
while (n)
{ c=n%10;
s+=c*c*c;
n/=10;
}
return s;
}
main()
{
cout<<"n=";cin>>n;
ind=1;seria[ind]=n;
do
{ seria[++ind]=suma(seria[ind-1]);
for (I=1;I<ind;I++)
if (seria[I]==seria[ind]) gasit=1;
}
while (!gasit);
cout<<"lungimea este "<<ind<<endl;
for (I=1;I<=ind;I++) cout<<seria[I]<<endl;
}
//sa se afiseze
// 1
// 23
// 456

#include "stdafx.h"
#include<iostream>
using namespace std;

int succ(int k)
{ if (k==9) return 1;
else return k+1;
}
void tipar(int m,int n)
{int I,j,s=n;
for(I=1;I<=m;I++)
{for (j=1;j<=I;j++)
{cout<<s;
s=succ(s);
}
cout<<endl;
}
}
main()
{int m,n;
cout <<"m=";cin>>m;
cout <<"n=";cin>>n;
tipar (m,n);
}

//sa se afiseze numerele care au numar egal de zerouri cu unu-ri in


// baza 2

#include "stdafx.h"
#include<iostream>
using namespace std;

int valabil (int nr)


{int zero=0,unu=1;
while(nr)
{if (nr%2)unu ++;
else zero++;
nr=nr/2;
}
return zero==unu;
}
main()
{int n,I,s=0;
cout<<"n=";cin>>n;
for (I=1;I<=n;I++)
if(valabil(I)) s++;
cout<<s;
}
//sa se supraincarce o functie
#include "stdafx.h"
#include<iostream>
using namespace std;

void functia(int n)
{ cout<<"eu sunt functia cu un parametru de tip int"<<endl;
}
void functia(int n,int m)
{cout<<"eu sunt functia cu doi parametrii de tip int"<<endl;
}
void functia (int * n)
{cout <<"eu sunt functia cu un parametru de tip int*"<<endl;
}
main()
{functia(2);functia(3,5);
int n;
functia(&n);
}
//SA SE DETERMINE O FUNCTIE CARE RETURNEAZA PRODUSUL A DOUA NUMERE
#include "stdafx.h"
#include<iostream>
using namespace std;
typedef unsigned short USHORT;

USHORT FindArea(USHORT length, USHORT width); //function prototype

int main()
{
USHORT lengthOfYard;
USHORT widthOfYard;
USHORT areaOfYard;

cout << "\nHow wide is your yard? ";


cin >> widthOfYard;
cout << "\nHow long is your yard? ";
cin >> lengthOfYard;

areaOfYard= FindArea(lengthOfYard,widthOfYard);

cout << "\nYour yard is ";


cout << areaOfYard;
cout << " square feet\n\n";
return 0;
}

USHORT FindArea(USHORT l, USHORT w)


{
return l * w;
}
//SA SE DETERMINE O FUNCTIE CARE RETURNEAZA CONVERSIA DIN GRADE
CELSIUS IN Fahrenheit
#include "stdafx.h"
#include<iostream>
using namespace std;
float Convert(float);
int main()
{
float TempFer;
float TempCel;

cout << "Please enter the temperature in Fahrenheit: ";


cin >> TempFer;
TempCel = Convert(TempFer);
cout << "\nHere's the temperature in Celsius: ";
cout << TempCel << endl;
return 0;
}

float Convert(float TempFer)


{
float TempCel;
TempCel = ((TempFer - 32) * 5) / 9;
return TempCel;
}

//SA SE DETERMINE O FUNCTIE CARE RETURNEAZA CONVERSIA DIN GRADE


CELSIUS IN Fahrenheit
#include "stdafx.h"
#include<iostream>
using namespace std;
float Convert(float);
int main()
{
float TempFer;
float TempCel;

cout << "Please enter the temperature in Fahrenheit: ";


cin >> TempFer;
TempCel = Convert(TempFer);
cout << "\nHere's the temperature in Celsius: ";
cout << TempCel << endl;
}

float Convert(float Fer)


{
float Cel;
Cel = ((Fer - 32) * 5) / 9;
return Cel;
}

//SA SE DETERMINE O procedura prin care se pun in evidenta


variabilele locale si globale
#include "stdafx.h"
#include<iostream>
using namespace std;
void myFunction(); // prototype

int x = 5, y = 7; // global variables


int main()
{

cout << "x from main: " << x << "\n";


cout << "y from main: " << y << "\n\n";
myFunction();
cout << "Back from myFunction!\n\n";
cout << "x from main: " << x << "\n";
cout << "y from main: " << y << "\n";
return 0;
}

void myFunction()
{
int y = 10;
//Y VARIABILA LOCALA
cout << "x from myFunction: " << x << "\n";
cout << "y from myFunction: " << y << "\n\n";
}

//SA SE DETERMINE O procedura prin care se pun in evidenta


variabilele locale si globale
#include "stdafx.h"
#include<iostream>
using namespace std;
void myFunc();

int main()
{
int x = 5;
cout << "\nIn main x is: " << x;

myFunc();

cout << "\nBack in main, x is: " << x;


return 0;
}

void myFunc()
{

int x = 8;
cout << "\nIn myFunc, local x: " << x << endl;

{
cout << "\nIn block in myFunc, x is: " << x;

int x = 9;

cout << "\nVery local x: " << x;


}

cout << "\nOut of block, in myFunc, x: " << x << endl;


}

//SA SE DETERMINE O procedura prin care se pun in evidenta


transmiterea prin valoare
#include "stdafx.h"
#include<iostream>
using namespace std;
void swap(int x, int y);

int main()
{
int x = 5, y = 10;

cout << "Main. Before swap, x: " << x << " y: " << y << "\n";
swap(x,y);
cout << "Main. After swap, x: " << x << " y: " << y << "\n";
return 0;
}

void swap (int x, int y)


{
int temp;

cout << "Swap. Before swap, x: " << x << " y: " << y << "\n";

temp = x;
x = y;
y = temp;

cout << "Swap. After swap, x: " << x << " y: " << y << "\n";

//SA SE DETERMINE O functie prin care se pun in evidenta


//returnarea a doua rezultate in functie de datele de intrare
#include "stdafx.h"
#include<iostream>
using namespace std;
int Doubler(int AmountToDouble);

int main()
{

int result = 0;
int input;

cout << "Enter a number between 0 and 10,000 to double: ";


cin >> input;

cout << "\nBefore doubler is called... ";


cout << "\ninput: " << input << " doubled: " << result << "\
n";

result = Doubler(input);

cout << "\nBack from Doubler...\n";


cout << "\ninput: " << input << " doubled: " << result <<
"\n";

return 0;
}

int Doubler(int original)


{
if (original <= 10000)
return original * 2;
else
return -1;
cout << "You can't get here!\n";
}
//SA SE DETERMINE O functie prin care se pun in evidenta
//faptul ca desi se fac intializari in atetul functiei se preiau
//valorile din programul principal al parametrilor
//si nu conteaza numarul de parametrii la apel al functiei
#include "stdafx.h"
#include<iostream>
using namespace std;
int AreaCube(int length, int width = 25, int height = 1);

int main()
{
int length = 100;
int width = 50;
int height = 2;
int area;

area = AreaCube(length, width, height);


cout << "First area equals: " << area << "\n";

area = AreaCube(length, width);


cout << "Second time area equals: " << area << "\n";

area = AreaCube(length);
cout << "Third time area equals: " << area << "\n";
return 0;
}

AreaCube(int length, int width, int height)


{

return (length * width * height);


}
//SA SE DETERMINE O functie prin care se pun in evidenta
//faptul ca functia poate avea parametrii de tipuri diferite la
intrare
#include "stdafx.h"
#include<iostream>
using namespace std;
int Double(int);
long Double(long);
float Double(float);
double Double(double);

int main()
{
int myInt = 6500;
long myLong = 65000;
float myFloat = 6.5F;
double myDouble = 6.5e20;

int doubledInt;
long doubledLong;
float doubledFloat;
double doubledDouble;

cout << "myInt: " << myInt << "\n";


cout << "myLong: " << myLong << "\n";
cout << "myFloat: " << myFloat << "\n";
cout << "myDouble: " << myDouble << "\n";

doubledInt = Double(myInt);
doubledLong = Double(myLong);
doubledFloat = Double(myFloat);
doubledDouble = Double(myDouble);

cout << "doubledInt: " << doubledInt << "\n";


cout << "doubledLong: " << doubledLong << "\n";
cout << "doubledFloat: " << doubledFloat << "\n";
cout << "doubledDouble: " << doubledDouble << "\n";

return 0;
}

int Double(int original)


{
cout << "In Double(int)\n";
return 2 * original;
}

long Double(long original)


{
cout << "In Double(long)\n";
return 2 * original;
}

float Double(float original)


{
cout << "In Double(float)\n";
return 2 * original;
}

double Double(double original)


{
cout << "In Double(double)\n";
return 2 * original;
}
//SA SE DETERMINE O functie prin care se pun in evidenta
//faptul ca functia INLINE poate fi flosita oriunde in program
//si oricand
#include "stdafx.h"
#include<iostream>
using namespace std;
inline int Double(int);

int main()
{
int target;

cout << "Enter a number to work with: ";


cin >> target;
cout << "\n";

target = Double(target);
cout << "Target: " << target << endl;

target = Double(target);
cout << "Target: " << target << endl;

target = Double(target);
cout << "Target: " << target << endl;
return 0;
}

int Double(int target)


{
return 2*target;
}
RECURSIVITATE
.

Recursivitatea este un mecanism general de elaborare a programelor.


Ea consta in posibilitatea ca un subprogram sa se autoapeleze
//SA SE DETERMINE O functie prin care se pun in evidenta
//faptul ca functia FIBONACCI ne da rezultate recursive in fiecare
etapa
#include "stdafx.h"
#include<iostream>
using namespace std;
int fib(int n);

int main()
{

int n, answer;
cout << "Enter number to find: ";
cin >> n;

cout << "\n\n";

answer = fib(n);

cout << answer << " is the " << n << "th Fibonacci number\n";
return 0;
}

int fib (int n)


{
cout << "Processing fib(" << n << ")... ";

if (n < 3 )
{
cout << "Return 1!\n";
return (1);
}
else
{
cout << "Call fib(" << n-2 << ") and fib(" << n-1 << ").\n";
return( fib(n-2) + fib(n-1));
}
}

//sa se determine factorialul cu functii


#include "stdafx.h"
#include<iostream>
using namespace std;

int fact (int n)


{if(!n) return 1;
else return n*fact(n-1);
}
main()
{ int n;
cout<<"n=";cin>>n;
cout<<fact(n);
}
//sa se determine factorialul cu proceduri
#include "stdafx.h"
#include<iostream>
using namespace std;

void fact(int val,int n,int& prod)


{
if(val<=n)
{prod*=val;
fact(val+1,n,prod);
}
}
main()
{
int val,n,p=1;

cout<<"n=";cin>>n;
fact(1,n,p);
cout<<p;
}
//sa se determine functia lui Manna Pnueli

#include "stdafx.h"
#include<iostream>
using namespace std;

int x;
int manna(int x)
{
if(x>=12) return x-1;
else return manna(manna(x+2));
}
main()
{
cout<<"x=";cin>>x;
cout<<manna(x);
}
//sa se determine divizor comun a doua numere prin scaderi succesive
#include "stdafx.h"
#include<iostream>
using namespace std;

int a,b;
int cmmdc(int a,int b)
{if (a==b) return a;
else if (a>b) return cmmdc (a-b,b);
else return cmmdc(a,b-a);
}
main()
{
cout<<"a=";cin>>a;
cout<<"b=";cin>>b;
cout<<cmmdc(a,b);
}
//sa se determine suma cifrelor unui numar
#include "stdafx.h"
#include<iostream>
using namespace std;

int n;
int s(int n)
{
if(!n) return 0;
else return n%10 +s(n/10);
}
main()
{
cout <<"n=";cin>>n;
cout<<s(n);
}
//sa se determine un numar intr-o baza recursiv
#include "stdafx.h"
#include<iostream>
using namespace std;

int n,b;
void transform(int n, int b)
{ int rest=n%b;
if(n>=b) transform(n/b,b );
cout <<rest;
}
main()
{ cout <<"n=";cin>>n;
cout<<"baza=";
cin>>b;
transform(n,b);
}
//sa se determine recursiv An si Bn
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

double a,b;
int n;
double bn(int n);
double an(int n)
{
if (!n) return a;
else return (an(n-1)+bn(n-1))/2;
}
double bn(int n)
{
if (!n) return b;
else return sqrt(an(n-1)*bn(n-1));
}
main()
{ cout <<"a=";cin>>a;
cout<<"b="; cin>>b;
cout<<"n="; cin>>n;
cout<<an(n)<<" "<<bn(n);
}
POINTARI SI ADRESE
Memoria internă poate fi privită ca o succesiune de octeţi. Pentru a-i distinge,
aceştia sunt numerotaţi. Numărul de ordine al unui octet se numeşte adresa lui.

Orice variabilă ocupă un număr succesiv de octeţi. De exemplu, o variabilă de tip


int ocupă doi octeţi (în varianta VISUAL C++ .NET). Adresa primului octet al variabilei se
numeşte adresa variabilei.
Variabilele de tip pointer se caracterizează prin faptul că valorile pe care le pot memora
sunt adresa ale unor variabile.

Limbajul VISUAL C++.NET face distincţie între natura adreselor care pot fi
memorate. Astfel, există adrese ale variabilelor de tip int, adrese ale variabilelor de tip
float, adrese ale variabilelor de tip char, etc
 O astfel de variabilă - capabilă să reţină adrese – se declară astfel:
Tip *nume
 Adresa unei variabile se obţine cu ajutorul operatorului de referinţe “&”,
care trebuie să preceadă numele variabilei:
&Nume_variabilă;
Fie o variabilă a, de tip pointer către tipul x şi n un număr natural. Atunci
au sens operaţiile a+n şi a-n.
 a+n reprezintă adresa care se obţine ca diferenţă între adresa lui
a şi n înmulţit cu numărul de octeţi care sunt ocupaţi de o
variabilă de tipul x.
 a-n reprezintă adresa care se obţine ca diferenţă între adresa lui
a şi n înmulţit cu numărul de octeţi care sunt ocupaţi de variabila
de tipul x.
În VISUAL C++.NET numele unui masiv (tablou) este pointer. Vom
analiza în amănunt acest fapt mai întâi pentru vectori şi apoi pentru
tablouri p-dimensionale.
 Numele vectorului este un pointer constant (nu poate fi modificat) către
tipul de bază al vectorului.
a[n]=*(a+n)=*(n+a)=n[a]
În C++ există un tip special care permite ca o variabilă să fie “botezată” cu
mai multe nume, numit tip referinţă. Aparent, programul lucrează cu mai
multe variabile, dar în fapt se lucrează cu una singură. O astfel de
declaraţie se face ca mai jos:

tip& nume variabilă = valoare de iniţializare

//SA SE DETERMINE un exemplu prin care se pun in evidenta


//faptul ca variabile de tipuri diferite se memoreaza la adrese
diferite
#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
unsigned short shortVar=5;
unsigned long longVar=65535;
long sVar = -65535;

cout << "shortVar:\t" << shortVar;


cout << " Address of shortVar:\t";
cout << &shortVar << endl;

cout << "longVar:\t" << longVar;


cout << " Address of longVar:\t" ;
cout << &longVar << endl;

cout << "sVar:\t" << sVar;


cout << " Address of sVar:\t" ;
cout << &sVar << endl;

return 0;
}
//SA SE DETERMINE un exemplu prin care se pun in evidenta
//faptul ca o variabila data rin numele ei si valoarea sa
//dar si pointerul *la numele ei e tot una
#include "stdafx.h"
#include<iostream>
using namespace std;
typedef unsigned short int USHORT;
int main()
{
USHORT myAge; // a variable
USHORT * pAge = 0; // a pointer
myAge = 5;
cout << "myAge: " << myAge << "\n";

pAge = &myAge; // assign address of myAge to pAge

cout << "*pAge: " << *pAge << "\n\n";

cout << "*pAge = 7\n";

*pAge = 7; // sets myAge to 7

cout << "*pAge: " << *pAge << "\n";


cout << "myAge: " << myAge << "\n\n";

cout << "myAge = 9\n";

myAge = 9;

cout << "myAge: " << myAge << "\n";


cout << "*pAge: " << *pAge << "\n";

return 0;
}
//transmiterea prin referinta

#include "stdafx.h"
#include<iostream>
using namespace std;
void intersc(int*x,int*y)
{ int man;
man=*x;*x=*y;*y=man;
}
main()
{ int a=2,b=3;
intersc(&a,&b);
cout<<a<<" "<<b;
}

//SA SE DETERMINE un exemplu prin care se pun in evidenta


//faptul ca o adresa e diferita de valoarea unei variabile
//data pprin pointerul variabilei respective
#include "stdafx.h"
#include<iostream>
typedef unsigned short int USHORT;
int main()
{
unsigned short int myAge = 5, yourAge = 10;
unsigned short int * pAge = &myAge; // a pointer

cout << "myAge:\t" << myAge << "\tyourAge:\t" << yourAge <<
"\n";
cout << "&myAge:\t" << &myAge << "\t&yourAge:\t" << &yourAge
<<"\n";

cout << "pAge:\t" << pAge << "\n";


cout << "*pAge:\t" << *pAge << "\n";

pAge = &yourAge; // reassign the pointer

cout << "myAge:\t" << myAge << "\tyourAge:\t" << yourAge <<
"\n";
cout << "&myAge:\t" << &myAge << "\t&yourAge:\t" << &yourAge
<<"\n";

cout << "pAge:\t" << pAge << "\n";


cout << "*pAge:\t" << *pAge << "\n";

cout << "&pAge:\t" << &pAge << "\n";


return 0;
}

//SA SE DETERMINE un exemplu prin care se pun in evidenta


//faptul ca pot pune valoarea unei variabile la o anumita adresa
//daca accesez variabila de la acea adresa am aceiasi valoare ca la
destinatie
#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
int intOne;
int &rSomeRef = intOne;

intOne = 5;
cout << "intOne: " << intOne << endl;
cout << "rSomeRef: " << rSomeRef << endl;

rSomeRef = 7;
cout << "intOne: " << intOne << endl;
cout << "rSomeRef: " << rSomeRef << endl;
return 0;
}
//SA SE DETERMINE un exemplu prin care se pun in evidenta
//faptul ca pot pune valoarea unei variabile la o anumita adresa
//daca accesez variabila de la acea adresa am aceiasi valoare ca la
destinatie
//adresele sursa si destinatie ale variabilelor o sa coincida
#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
int intOne;
int &rSomeRef = intOne;

intOne = 5;
cout << "intOne: " << intOne << endl;
cout << "rSomeRef: " << rSomeRef << endl;

cout << "&intOne: " << &intOne << endl;


cout << "&rSomeRef: " << &rSomeRef << endl;

return 0;
}

//SA SE DETERMINE un exemplu prin care se pun in evidenta


//faptul ca pot pune valoarea unei variabile la o anumita adresa
//daca accesez variabila de la acea adresa am aceiasi valoare ca la
destinatie
//adresele sursa si destinatie ale variabilelor o sa coincida
//cand fac initializarea variabilei sursa adresa acesteia se schimba
//dar variabila destinatie ramane la aceiasi adresa
#include "stdafx.h"
#include<iostream>
using namespace std;
int main()
{
int intOne;
int &rSomeRef = intOne;

intOne = 5;
cout << "intOne:\t" << intOne << endl;
cout << "rSomeRef:\t" << rSomeRef << endl;
cout << "&intOne:\t" << &intOne << endl;
cout << "&rSomeRef:\t" << &rSomeRef << endl;

int intTwo = 8;
rSomeRef = intTwo; // not what you think!
cout << "\nintOne:\t" << intOne << endl;
cout << "intTwo:\t" << intTwo << endl;
cout << "rSomeRef:\t" << rSomeRef << endl;
cout << "&intOne:\t" << &intOne << endl;
cout << "&intTwo:\t" << &intTwo << endl;
cout << "&rSomeRef:\t" << &rSomeRef << endl;
return 0;
}
//SA SE DETERMINE un exemplu prin care se pun in evidenta
//faptul ca interschimbarea prin poiteri se face prin referinta
//si la apel procedura sau functia foloseste adresele variabilelor
chiar
//daca in antet avem pointeri
#include "stdafx.h"
#include<iostream>
using namespace std;
void swap(int *x, int *y);

int main()
{
int x = 5, y = 10;

cout << "Main. Before swap, x: " << x << " y: " << y << "\n";
swap(&x,&y);
cout << "Main. After swap, x: " << x << " y: " << y << "\n";
return 0;
}

void swap (int *px, int *py)


{
int temp;

cout << "Swap. Before swap, *px: " << *px << " *py: " << *py
<< "\n";

temp = *px;
*px = *py;
*py = temp;

cout << "Swap. After swap, *px: " << *px << " *py: " << *py <<
"\n";

}
//SA SE DETERMINE un exemplu prin care se pun in evidenta
//faptul ca interschimbarea prin adresa se face prin referinta
//si la apel procedura sau functia foloseste doar numele variabilelor
chiar
//daca in antet avem adrese
#include "stdafx.h"
#include<iostream>
using namespace std;
void swap(int &x, int &y);

int main()
{
int x = 5, y = 10;

cout << "Main. Before swap, x: " << x << " y: " << y <<
"\n";
swap(x,y);
cout << "Main. After swap, x: " << x << " y: " << y <<
"\n";
return 0;
}

void swap (int &rx, int &ry)


{
int temp;

cout << "Swap. Before swap, rx: " << rx << " ry: " <<
ry << "\n";

temp = rx;
rx = ry;
ry = temp;

cout << "Swap. After swap, rx: " << rx << " ry: " <<
ry << "\n";

}
//SA SE DETERMINE un exemplu prin care se pun in evidenta
//faptul ca o functie poate returna mai multe rezultate
//parametrii pot fi unii poiteri dar se apaelaza prin adresa lor
//la afisare parametrii care au in fata semnul adresa sunt de iesire
//si ei pot fi afisati doar prin numele lor
#include "stdafx.h"
#include<iostream>
using namespace std;
typedef unsigned short USHORT;

short Factor(USHORT, USHORT*, USHORT*);

int main()
{
USHORT number, squared, cubed;
short error;

cout << "Enter a number (0 - 20): ";


cin >> number;

error = Factor(number, &squared, &cubed);

if (!error)
{
cout << "number: " << number << "\n";
cout << "square: " << squared << "\n";
cout << "cubed: " << cubed << "\n";
}
else
cout << "Error encountered!!\n";
return 0;
}

short Factor(USHORT n, USHORT *pSquared, USHORT *pCubed)


{
short Value = 0;
if (n > 20)
Value = 1;
else
{
*pSquared = n*n;
*pCubed = n*n*n;
Value = 0;
}
return Value;
}
//SA SE DETERMINE un exemplu prin care se pun in evidenta
//faptul ca o functie poate returna mai multe rezultate
//parametrii pot fi unii poiteri dar se apaelaza prin adresa lor
//la afisare parametrii care au in fata semnul adresa sunt de iesire
//si ei pot fi afisati doar prin numele lor
//transmiterea datelor se face prin referinta
#include "stdafx.h"
#include<iostream>
using namespace std;
typedef unsigned short USHORT;
enum ERR_CODE { SUCCESS, ERROR };

ERR_CODE Factor(USHORT, USHORT&, USHORT&);

int main()
{
USHORT number, squared, cubed;
ERR_CODE result;

cout << "Enter a number (0 - 20): ";


cin >> number;

result = Factor(number, squared, cubed);

if (result == SUCCESS)
{
cout << "number: " << number << "\n";
cout << "square: " << squared << "\n";
cout << "cubed: " << cubed << "\n";
}
else
cout << "Error encountered!!\n";
return 0;
}

ERR_CODE Factor(USHORT n, USHORT &rSquared, USHORT &rCubed)


{
if (n > 20)
return ERROR; // simple error code
else
{
rSquared = n*n;
rCubed = n*n*n;
return SUCCESS;
}
}
//SA SE DETERMINE un exemplu prin care se pun in evidenta
//faptul ca o functie poate returna mai multe rezultate
//parametrii pot fi unii poiteri dar se apaelaza prin adresa lor
//la afisare parametrii care au in fata semnul adresa sunt de iesire
//si ei pot fi afisati doar prin numele lor
//transmiterea datelor se face prin referinta
#include "stdafx.h"
#include<iostream>
using namespace std;
#include <iostream>
using namespace std;

void double_it(int *p);

int main() {
int a = 5, b = 6;

cout << "Value of a before doubling is " << a << endl;


cout << "Value of b before doubling is " << b << endl;

double_it(&a); // Pass address of a.


double_it(&b); // Pass address of b.
cout << "Value of a after doubling is " << a << endl;
cout << "Value of b after doubling is " << b << endl;

return 0;
}

void double_it(int *p) {


*p = *p * 2;
}

// Exercitiul 6.1.1.txt
// Acest program transmite adresa unei variable la o functie,
// care tripleaza valoarea indicata.

#include "stdafx.h"
#include <iostream>
using namespace std;

#include <iostream>
using namespace std;

void triple_it(int *n);

int main() {
int n = 15;

cout << "Value of n before tripling: " << n << endl;

triple_it(&n); // Pass address of temp.

cout << "Value after tripling: " << n << endl;

return 0;
}

void triple_it(int *n) {


*n = *n * 3;
}

// Exercitiul 6.1.2.txt
// Acest program transmite adresa unei variable la o functie,
// care realizeaza o conversie din grade Celsius in grade
Fahrenheit.

#include "stdafx.h"

#include <iostream>
using namespace std;

void convert_temp(double *p);

int main() {
double temp = 10.0;

cout << "Value (Celsius) before conversion: " << temp << endl;
convert_temp(&temp); // Pass address of temp.

cout << "Value after conversion to Fahrenheit: " << temp << endl;

return 0;
}

void convert_temp(double *p) {


*p = (*p * 1.8) + 32;
}

// Exercitiul 6.1.3.txt
// Acest program realizeaza sortarea unui vector prin intermediul
poiterilor

#include "stdafx.h"

#include <iostream>
using namespace std;

void sort(int n);


void swap(int *p1, int *p2);

int a[10];

int main () {
int i;

for (i = 0; i < 10; i++) {


cout << "Enter array element #" << i << ": ";
cin >> a[i];
}
sort(10);

cout << "Here are all the array elements, sorted:" << endl;
for (i = 0; i < 10; i++)
cout << a[i] << " ";

return 0;
}

// Sort array function: sort array named a, having n elements.


//
void sort (int n) {
int i, j, low;

for(i = 0; i < n - 1; i++) {

// This part of the loop finds the lowest


// element in the range i to n-1; the index
// is set to the variable named low.

low = i;
for (j = i + 1; j < n; j++)
if (a[j] < a[low])
low = j;

// This part of the loop performs a swap if


// needed.
if (i != low)
swap(&a[i], &a[low]);
}
}

// Swap function.
// Swap the values pointed to by p1 and p2.
//
void swap(int *p1, int *p2) {
int temp = *p1;
*p1 = *p2;
*p2 = temp;
}

// Exercitiul 6.3.1.txt
// Acest program initializeaza cu zero un vector cu pointeri
#include "stdafx.h"
#include <iostream>
using namespace std;
void zero_out_array(int *arr, int n);

int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

int main() {
int i;

zero_out_array(a, 10);

// Print out all the elements of the array.

for (i = 0; i < 10; i++)


cout << a[i] << " ";

return 0;
}

// Zero-out-array function.
// Assign 0 to all elements of an int array of size n.
//
void zero_out_array(int *p, int n) {
while (n-- > 0) { // Do n times:
*p = 0; // Assign 0 to element pointed
// to by p.
p++; // Point to next element.
}
}

// Exercitiul 6.3.3.txt
// Acest program este similar cu cel din scriptul zero_out.cpp,
// cu diferenta ca utilizeaza o referire directa la un pointer
// de afisare a elementelor.

#include "stdafx.h"

#include <iostream>
using namespace std;

void zero_out_array(int *arr, int n);


int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

int main() {
int *p;

zero_out_array(a, 10);

// Print out all the elements of the array.

for (p = a; p < a + 10; p++)


cout << *p << " ";

return 0;
}

// Zero-out-array function.
// Assign 0 to all elements of an int array of size n.
//
void zero_out_array(int *p, int n) {
while (n-- > 0) { // Do n times:
*p = 0; // Assign 0 to element pointed
// to by p.
p++; // Point to next element.
}
}

// Exercitiul 6.3.2.txt
// Acest program introduce si testeaza o functie care copiaza
// intreg continutul unei matrice in alta.

#include "stdafx.h"

#include <iostream>
using namespace std;

void copy_array(int *arr1, int *arr2, int n);

int a[10];
int b[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

int main() {
int *p;

copy_array(a, b, 10); // Copy a[] <- b[]

// Print out all the elements of the array a.

for (p = a; p < a + 10; p++)


cout << *p << " ";

return 0;
}

// Zero-out-array function.
// Copy contents of second array into first array.
//
void copy_array(int *p1, int *p2, int n) {
while (n-- > 0) { // Do n times:
*p1 = *p2;
p1++;
p2++;
}
}

STIVA
 Stiva este o listă pentru care singurele operaţii permise sunt:
● Adăugarea unui element în stivă;
● Eliminarea, consultarea, sau modificarea ultimului element introdus în stivă.
Stiva funcţionează pe principiul LIFO (Last In First Out) – “ultimul
intrat, primul ieşit”.
Pentru a înţelege modul de lucru cu stiva, ne imaginăm un număr n de farfurii
identice, aşezate una peste alta (o “stivă” de farfurii). Adăugarea sau scoaterea unei
farfurii se face, cu uşurinţă, numai în vârful stivei.

Oricât ar părea de simplu principiul stivei, el are consecinţe uriaşe în programare.

Stivele se pot aloca secvenţial (ca vectori). Fie ST[i] un vector. ST[1], ST[2], … , ST[n] pot reţine numai
litere sau numai cifre. O variabilă k indică în permanenţă vârful stivei, adică ultimul element introdus.

În stivă iniţial vidă se introduce litera A, vârful stivei va fi la nivelul 1,


(k=1);
A
B
A
Introducem în stivă litera B, deci k va lua valoarea 2.

Scoatem din stivă pe B (A nu poate fi scos deocamdată); k=1

Scoatem din stivă pe A; stiva rămâne vidă k=0

Observaţii:

În mod practic, la scoaterea unei variabile din stivă, valoarea variabilei ce indică vârful stivei scade cu 1, iar atunci
când scriem ceva în stivă, o eventuală valoare reziduală se pierde.

Pe un anumit nivel se reţine, de regulă, o singură informaţie (literă sau cifră), însă este posibil, aşa cum va rezulta
din exemplele prezentate în lucrare, să avem mai multe informaţii, caz în care avem stive duble, triple, etc.

În cazul stivei, alocarea secvenţială nu prezintă mari dezavantaje, ca în cazul mai general, al listelor, pentru că nu
se fac operaţii de inserare sau ştergere în interiorul stivei. Singurul dezavantaj, în comparaţie cu alocarea dinamică
înlănţuită este dat de faptul că numărul de noduri care pot fi memorate la un moment dat este mai mic – depinde de
gradul de ocupare al segmentului de date.
În literatura de specialitate veţi întâlni termenul PUSH pentru operaţia de adăugare în stivă a unei înregistrări şi
POP, pentru extragere.

Exemple:

□ Funcţia Manna-Pnueli. Se citeşte xЄZ. Se cere programul pentru calculul funcţiei:

F(x)= x-1, x≥12


F(F(x+2)), x<12

Vom începe prin a studia modul de calcul al funcţiei pentru x=15 şi x=8.

f(15)=14;
f(8)=f(f(10))=f(f(f(12)))=f(f(11))=f(f(f(13)))=f(f(12))=f(11)=f(f(13))= f(12)=11.
Algoritmul va folosi o stivă ST şi o variabilă k, ce indică în permanenţă vârful stivei. Algoritmul se
bazează pe următoarele considerente:
■ la o nouă autoapelare a funcţiei f, se urcă în stivă (k se incrementează cu 1) şi se pune noua valoare.

■ în situaţia în care pentru valoarea aflată pe nivelul k se poate calcula funcţia, se coboară în stivă, punându-se pe
acest nivel noua valoare.

■ algoritmul se încheie când se ajunge în stivă la nivelul 0.

Pentru exemplul dat, prezentăm schematic funcţionarea sa:

12 13

10 10 11
11
8
8 8 8 8

12 13

8 11 11 12
f=11

//sa se determine FUNCTIA MANNA PNUELI CU STIVA


F(x)= x-1, x≥12
F(F(x+2)), x<12
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;
int st[100], n, k;
main( )
{ cout<<"n="; cin>>n;
k=1; st[1]=n;
while (k>0)
if (st[k]<12)
{ k++;
st[k]=st[k-1]+2;
}
else
{ k--;
if (k>0) st[k]=st[k+1]-1;
}
cout<<"n="<<st[1]-1;
}
Funcţia lui Ackermann. Se dă funcţia următoare, definită pe produsul cartezian NXN.. Se citesc
m şi n. Să se calculeze Ack(m, n).

n+1, m=0
Ack(m,n)= Ack(m-1, 1), n=0
Ack(m-1, Ack(m, n-1)), altfel

Pentru a elabora algoritmul, studiem un exemplu numeric:

ack(2,1)=ack(1,ack(2,0))=ack(1, ack(1,1))=ack(1, ack(0, ack(1,0))= ack(1, ack(0, ack(0,1))=ack(1,


ack(0,2))=ack(1,3)=ack(0, ack(1,2))= ack(0, ack(0, ack(1,1))=ack(0, ack(0, ack(0, ack(1,0))))=
ack(0, ack(0, ack(0, ack(0,1))))=ack(0, ack(0, ack(0,2)))=ack(0,,ack(0,3))= ack(0,4)=5.

Pentru calculul acestei funcţii, folosim o stivă dublă, ST. Iniţial, valorile m şi n se reţin la nivelul
1. Pe nivelul k al stivei se reţin valorile curente m şi n. În funcţie de valorile acestora se
procedează astfel:

■ pentru m şi n diferite de 0, este necesar un nou calcul de funcţie, caz în care se urcă în stivă şi
pe noul nivel se pun argumente m şi n-1.

■ pentru cazul n=0, se rămâne pe acelaşi nivel în stivă, punând în locul lui m valoarea m-1, iar în
locul lui n valoarea 1.

■ în situaţia în care m=0, funcţia se poate calcula; se coboară în stivă şi se înlocuieşte valoarea lui
m cu m-1, valoarea lui n cu valoarea calculată anterior.

În continuare, prezentăm grafic modul de funcţionare a algoritmului pentru exemplul ack(2,1):

10 01
20 11 11 11
21 21 21 21 21
10
01 11 11
11
02 02 13 12 12
12
21 12
13 03
12 13 13
13 13 13 04

//sa se determine FUNCTIA lui Ackerman


n+1, m=0
Ack(m,n)= Ack(m-1, 1), n=0
Ack(m-1, Ack(m, n-1)), altfel

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

int st[10000][2];
main( )
{ int m, n, k;
cout<<"m="; cin>>m;
cout<<"n="; cin>>n;
k=1; st[k][0] =m; st[k][1] =n;
while (k>0)
if (st[k][0] && st[k][1])
{
k++;
st[k][0] =st[k-1][0];
--st[k-1][1];
st[k][1] =st[k-1][1];
}
else
if (!st[k][1])
{
--st[k][0];
st[k][1] = 1;
}

else
{
k--;
if (k>0)
{ --st[k][0] ;
st[k][1] =st[k+1][1] +1;
}
}
cout<<"ac("<<m<<", "<<n<<") = "<<st[1][1] +1;
}

//sa se determine dinamic notiunea de stiva cu operatiile


corespunzatoare
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;
struct Nod
{
int info;
Nod* adr_inap;
};

Nod* v;
int n;

void Push( Nod*& v, int n)


{
Nod* c;
if (!v)
{
v= new Nod; v->info=n; v->adr_inap=0;
}
else
{c= new Nod; c->info=n; c->adr_inap=v;
v=c;
}
}

void Pop(Nod*& v)
{
Nod* c;
if (!v) cout<<"stiva este vida";
else
{
c=v;
cout<<"am scos"<< c->info<<endl;
v=v->adr_inap;
delete c;
}
}

main( )
{ Push(v,1); Push(v,2); Push(v,3);
Pop(v); Pop(v); Pop(v); Pop(v);
}
//sa se determine dinamic cu notiunea de stiva functia Manna Pnueli
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

struct Nod
{ int info;
Nod* adr_inap;
};
Nod* v;
int n;
void Push(Nod*& v, int n)
{ Nod* c;
if (!v)
{ v= new Nod; v->info=n; v->adr_inap=0;}
else
{ c= new Nod; c->info=n; c->adr_inap=v;
v=c;
}
}
void Pop (Nod*& v)
{ Nod* c;
if (!v) cout<< "stiva este vida";
else
{ c=v;
cout<<" am scos"<<c->info<<endl;
v=v->adr_inap;
delete c;
}
}
main( )
{ int Man;
cout<<"n="; cin>>n;
Push(v,n);
while (v)
if (v->info<12)
{
Push(v,v->info+2);
}
else
{ Man=v->info;
Pop(v);
if (v) v->info=Man-1;
}
cout<<"f="<<Man-1;
}
COADA

 O coadă este o listă pentru care toate inserările sunt făcute la unul din capete,
toate ştergerile (consultările, modificările) la celălalt capăt.

Coada funcţionează pe principiul FIFO (First In First Out) – “primul


intrat, primul ieşit”.

Este cu totul nerecomandabilă alocarea secvenţială a cozii, deoarece în această situaţie, are loc
un fenomen de migraţie a datelor către ultimele componente ale vectorului (cele de indice mare).

Să presupunem că simulăm o coadă cu ajutorul unui vector cu zece componente, care reţin
numere întregi. Introducem în coadă, pe rând, numerele 1, 2, 3, 4.

1 2 3 4

Dacă scoatem din coadă pe 1 şi introducem în coadă pe 5, coada va arăta astfel:

2 3 4 5

Scoatem din coadă pe 2 şi introducem pe 6:

3 4 5 6

Se observă acest fenomen de “migraţie”.

Alocarea dinamică înlănţuită a cozii. O variabilă v va reţine adresa elementului care urmează a
fi scos (servit). O alta, numită sf, va reţine adresa elementului introdus în coadă. Figura următoare
prezintă o coadă în care primul element care urmează a fi scos are adresa în v, iar ultimul introdus are
adresa sf.
v sf

7 3 5 2

//sa se determine dinamic cu notiunea de coada


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

struct Nod
{
int info;
Nod* adr_urm;
};

Nod* v, *sf;
int n;

void Pune( Nod*& v, Nod*& sf, int n)


{
Nod* c;
if (!v)
{ v= new Nod; v->info=n; v->adr_urm=0;
sf=v;
}
else
{ c= new Nod;
sf->adr_urm=c;
c->info=n;
c->adr_urm=0;
sf=c;
}
}

void Scoate(Nod*& v)
{ Nod* c;
if (!v) cout<<"coada este vida"<<endl;
else
{ cout<<"Am scos"<<v->info<<endl;
c=v; v=v->adr_urm;
delete c;
}
}

void Listare(Nod* v)
{ Nod* c=v;
while ( c )
{ cout<<c->info<<" ";
c=c->adr_urm;
}
cout<<endl;
}
main( )
{ Pune(v, sf, 1); Pune(v, sf, 2); Pune(v, sf, 3); Listare(v);
Scoate(v); Listare(v);
Scoate(v); Listare(v);
Scoate(v); Listare(v);
Scoate(v); Listare(v);
}
DIVIDE ET IMPERA

Descrierea metodei

Dându-se o funcţie care lucrează asupra a n date de intrare, tehnica


“DIVIDE ET IMPERA” (Desparte şi stăpâneşte) presupune desfacerea (divizarea)
intrărilor în K submulţimi distincte, , care produc k subprobleme.
Aceste probleme trebuie rezolvate şi apoi trebuie gasită o metodă de combinare
a subsoluţiilor pentru a da soluţia întregii probleme.
Dacă subproblemele sunt încă mari tehnica poate fi reaplicată, dacă ele
sunt de acelaşi tip cu problema generală şi acesta este cazul cel mai frecvent.
Reaplicarea metodei conduce la o procedură recursivă. În acest fel se generează
subprobleme din ce în ce mai mici care în cazurile cele mai simple, se rezolvă
fără a fi redivizate. De obicei problema se împarte în două subprobleme de
acelaşi gen.
Această metodă e una din cele mai larg folosite.
Fie n intrări memorate în tabloul A (1:n) . Procedura generală de tip funcţie, cu
numele DETI este apelată iniţial prin DETI (1,n). Funcţia DETI (p,q), rezolvă o
problemă cu intrările A(p,q).
Descrierea funcţiei este următoarea:

procedure DETI(p,q)
global n,A(1:n);integer p,q,m // //
if MIC(p,q) then return(G(p,q))
else
m:=DIVIDE(p,q);
return(combină (DETI(p,m),DETI(m+1,q)))
endif
end DETI

//sa determine prin divide et impera maximul dintr-un vector


#include "stdafx.h"
#include<iostream>
using namespace std;
int v[10],n;

int max(int i,int j)


{ int a,b;
if (i==j) return v[i];
else
{ a=max(i,(i+j)/2);
b=max((i+j)/2+1,j);
if (a>b) return a;
else return b;
}
}
main ( )
{ cout<<"n=";cin>>n;
for (int i=1;i<=n;i++)
{cout<<"v["<<i<<"]=";cin>>v[i];}
cout<<"max="<<max(1,n);
}
//sa determine prin divide et impera GASIREA UNUI ELEMENT
//dintr-un vector prin cautare binara
#include "stdafx.h"
#include<iostream>
using namespace std;

int v[100],n,nr;

void caut(int i,int j)


{ if (nr==v[(i+j)/2])
cout<<"gasit"<<" "<<"indice"<<(i+j)/2;
else
if(i<j)
if (nr<v[(i+j)/2])
caut(i,(i+j)/2-1);
else caut ((i+j)/2+1,j);
};
main( )
{ cout<<"n=";cin>>n;
for (int i=1;i<=n;i++)
{ cout<<"v["<<i<<"]=";cin>>v[i];}
cout<<"nr=";cin>>nr;
caut(1,n);
}
//sa determine prin divide et impera sortarea elementelor
//dintr-un vector prin interclasare
#include "stdafx.h"
#include<iostream>
using namespace std;

int a[10],n;

void sort(int p,int q,int a[10])


{
int m;
if (a[p]>a[q])
{
m=a[p];
a[p]=a[q];
a[q]=m;}
}
void interc(int p,int q,int m,int a[10])
{
int b[10],i,j,k;
i=p;j=m+1;k=1;
while (i<=m && j<=q)
if (a[i]<=a[j])
{
b[k]=a[i];
i=i+1;
k=k+1;
}
else
{
b[k]=a[j];
j=j+1;
k=k+1;
}
if (i<=m)
for (j=i;j<=m;j++)
{
b[k]=a[j];
k=k+1;
}
else
for (i=j;j<=q;j++)
{
b[k]=a[i];
k=k+1;
}
k=1;
for (i=p;i<=q;i++)
{
a[i]=b[k];
k=k+1;
}
}
void divimp (int p,int q,int a[10])
{
int m;
if ((q-p)<=1) sort(p,q,a);
else
{ m=(p+q)/2;
divimp(p,m,a);
divimp(m+1,q,a);
interc(p,q,m,a);
}
}
main( )
{ int i;
cout<<"n=";cin>>n;
for (i=1;i<=n;i++)
{
cout<<"a["<<i<<"]=";cin>>a[i];}
divimp(1,n,a);
for (i=1;i<=n;i++)
cout<<a[i]<<" ";
}
//sa determine prin divide et impera sortarea elementelor
//dintr-un vector prin sortare rapida
#include "stdafx.h"
#include<iostream>
using namespace std;

int a[100],n,k;

void poz(int li,int ls,int& k,int a[100])


{
int i=li,j=ls,c,i1=0,j1=-1;
while (i<j)
{ if (a[i]>a[j])
{
c=a[j];
a[j]=a[i];
a[i]=c;
c=i1;
i1=-j1;
j1=-c;
}
i=i+i1;
j=j+j1;
k=i;
}
}

void quick (int li,int ls)


{ if (li<ls)
{ poz (li,ls,k,a);
quick(li,k-1);
quick(k+1,ls);
}
}
main( )
{ int i;
cout<<"n=";cin>>n;
for (i=1;i<=n;i++)
{ cout<<"a["<<i<<"]=";cin>>a[i];}
quick(1,n);
for (i=1;i<=n;i++) cout <<a[i]<<endl;
}
//sa determine prin divide et impera mutarea turnurilor din Hanoi
#include "stdafx.h"
#include<iostream>
using namespace std;

char a,b,c;
int n;

void han(int n,char a,char b,char c)


{
if (n==1) cout<<a<<b<<endl;
else
{
han(n-1,a,c,b);
cout<<a<<b<<endl;
han(n-1,c,b,a);
}
}
main ( )
{
cout<<"N=";cin>>n;
a='a';
b='b';
c='c';
han(n,a,b,c);
}
Tehnica backtracking

Aspecte teoretice
Aceasta tehnica se foloseste in reezolvarea problemelor care indeplinesc simultan urmatoarele
conditii:
 solutia lor poate fi pusa sub forma unui vector S=x1,x2,..,xn,cu x1 apartine de de A1,x2
apartine de A2,…,xn apartine de An;
 multimile A1,A2,…,An sunt multimi finite,iar elementele lor se considera ca se afla
intr-o relatie de ordine bine stabilita;
 nu se dispune de o alta metoda de rezolvare,mai rapida.
Observatii:
 nu pentru toate problemele n este cunoscut de la inceput;
 x1,x2,…,xn pot fi la randul lor vectori;
 in multe probleme,multimile A1,A2,…,An coincide.
Observatie: tehnica Backtracking are ca rezultat obtinerea tuturor solutiilor problemei.In cazul
in care se cere o singura solutie,se poate forta oprirea,atunci cand a fost gasita.
 Pentru usurarea intelegerii metodei,vom prezenta o rutina unica(aplicabila oricarei
probleme),rutina care este elaborate folosind structura de stiva.Rutina va apela functii
care au intotdeauna acelasi nume si care,din punct de vedere al metodei,realizeaza
acelasi lucru.Sarcina rezolvitorului este sa scrie explicit,pentru fiecare problema in
parte,functiile apelate de rutina backtracking.
 Evident o astfel de abordare conduce la programe lungi.Nimeni nun e opreste ca,dupa
intelegerea metodei,sa scriem programe scurte,specifice fiecarei probleme in parte(de
exemplu,scurtam substantial textul doar daca renuntam utilizarea unor functii,scriind
instructiunile lor chiar in corpul rutinei).
De exemplu,pentru generarea permutarilor multimii {1,2,3…,n},orice nivel al stivei va lua
valori de la 1 la n.Initializarea unui nivel(oarecare) se face cu valoarea 0.Functia de initializare
se va numi init( ).
→ Gasirea urmatorului element al multimii Ak+1,element netestat,se face cu ajutorul functiei
int Am_Succesor( ).Daca exista successor,acesta este pus in stiva si functia returneaza 1,altfel
functia returneaza 0.
→ Testul daca s-a ajuns sau nu la solutia finala se face cu ajutorul functiei int Solutie( )
→ Solutia se tipareste cu ajutorul functiei Tipar( ).
→Testarea conditiilor de continuare(adica daca avem sansa sau nu ca prin valoarea aflata pe
nivelul k+1 sa ajungem la solutie) se face cu functia int E_Vakid( ) careintoarce 1 daca
conditiile sunt indeplinite,sau 0 in caz contrar.

//sa determine prin backtracking permutarile numerelor de la 1 la n


#include "stdafx.h"
#include<iostream>
using namespace std;

int st[10],n,k;

void Init( )
{ st[k]=0;}

int Am_Succesor( )
{ if (st[k]<n)
{ st[k]++;
return 1;
}
else return 0;
}
int E_Valid( )
{ for (int i=1;i<k;i++)
if (st[i]==st[k]) return 0;
return 1;
}

int Solutie ( )
{ return k==n;}

void Tipar( )
{
for (int i=1;i<=n;i++) cout<<st[i];
cout<<endl;
}

void back( )
{int AS;
k=1; Init( );
while (k>0)
{ do { } while ((AS=Am_Succesor( )) && !E_Valid( ));
if (AS)
{
if (Solutie( )) Tipar( );
else
{
k++; Init( );
}
}
else k--;
}
}

main ( )
{ cout<<"n=";cin>>n;
back( );
}
//Prin Bactracking sa se rezolve problema damelor
//ex:n=4
D

//Adica:2413

#include "stdafx.h"
#include<iostream>
using namespace std;
#include<stdio.h>
#include <math.h>
int st[100],n,k;
void Init( )
{ st[k]=0; }

int Am_Succesor ( )
{ if (st[k]<n)
{ st[k]++;
return 1;
}
else return 0;
}
int E_Valid ( )
{ for (int i=1; i<k; i++)
if (st[k]==st[i]) return 0;
else
if (abs(st[k]-st[i])==abs(k-i) ) return 0;
return 1;
}

int Solutie( )
{ return k==n;}

void Tipar( )
{ for (int i=1; i<=n; i++) cout<<st[i];
cout<<endl;
}

void back( )
{int AS;
k=1; Init( );
while (k>0)
{ do { } while ((AS=Am_Succesor( )) && !E_Valid( ));
if (AS)
{
if (Solutie( )) Tipar( );
else
{
k++; Init( );
}
}
else k--;
}
}

main ( )
{ cout<<"n=";cin>>n;
back( );
}
//sa determine prin backtracking aranjamente de n elemente luate cate
// k ,conteaza ordinea adica (1 2) nu e tot una cu (2 1)
#include "stdafx.h"
#include<iostream>
using namespace std;
#include<stdio.h>
#include <math.h>

int st[10],n,k,p;

void Init ( )
{ st[k]=0; }

int Am_Succesor( )
{ if (st[k]<n)
{ st[k]++;
return 1;
}
else return 0;
}
int E_Valid( )
{
for (int i=1; i<k; i++)
if (st[k]==st[i]) return 0;
return 1;
}
int Solutie( )
{
return (k==p);}

void Tipar( )
{
for (int i=1; i<=p;i++) cout<<st[i];
cout<<endl;
}

void back( )
{int AS;
k=1; Init( );
while (k>0)
{ do { } while ((AS=Am_Succesor( )) && !E_Valid( ));
if (AS)
{
if (Solutie( )) Tipar( );
else
{
k++; Init( );
}
}
else k--;
}
}

main ( )
{ cout<<"n=";cin>>n;
cout<<"p="; cin>>p;
back( );
}
//sa determine prin backtracking combinari de n elemente luate cate k
//NU conteaza ordinea adica {1 2} e tot una cu {2 1} ca multimi de
elemente
#include "stdafx.h"
#include<iostream>
using namespace std;
#include<stdio.h>
#include <math.h>

int st[10],n,k,p;
void Init ( )
{ if (k>1) st[k]=st[k-1];
else st[k]=0;
}

int Am_Succesor ( )
{ if (st[k]<n-p+k)
{ st[k]++;
return 1;
}
else return 0;
}
int E_Valid( )
{
for (int i=1; i<k; i++)
if (st[k]==st[i]) return 0;
return 1;
}

int Solutie ( )
{ return k==p;}

void Tipar ( )
{ for ( int i=1; i<=p;i++) cout <<st[i];
cout<<endl;
}

void back( )
{int AS;
k=1; Init( );
while (k>0)
{ do { } while ((AS=Am_Succesor( )) && !E_Valid( ));
if (AS)
{
if (Solutie( )) Tipar( );
else
{
k++; Init( );
}
}
else k--;
}
}

main ( )
{ cout<<"n=";cin>>n;
cout<<"p="; cin>>p;
back( );
}
//sa determine prin backtracking produsul cartezian a N multimi
#include "stdafx.h"
#include<iostream>
using namespace std;
#include<stdio.h>
#include <math.h>

int st[10],a[10],n,k;

void Init( )
{ st[k]=0; }
int Am_Succesor ( )
{ if (st[k]<a[k])
{ st[k]++; return 1;}
else return 0;
}
int E_Valid ( )
{ return 1;}

int Solutie( )
{ return k==n;}

void Tipar( )
{ for (int i=1; i<=n;i++) cout<<st[i];
cout<<endl;
}

void back( )
{int AS;
k=1; Init( );
while (k>0)
{ do { } while ((AS=Am_Succesor( )) && !E_Valid( ));
if (AS)
{
if (Solutie( )) Tipar( );
else
{
k++; Init( );
}
}
else k--;
}
}

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

back( );
}
//sa determine prin backtracking problema colorarii hartilor
#include "stdafx.h"
#include<iostream>
using namespace std;
#include<stdio.h>
#include <math.h>

int st[10],a[20][20],n,k;

void Init( )
{ st[k]=0; }

int Am_Succesor ( )
{ if (st[k]<4)
{st[k]++;
return 11;
}
else return 0;
}

int E_Valid( )
{
for (int i=1; i<=k-1; i++)
if ( st[i]==st[k] && a[i][k]==1) return 0;
return 1;
}
int Solutie( )
{ return k==n;}

void Tipar( )
{ cout<<"varianta"<<endl;
for (int i=1;i<n; i++)
cout<<"tara"<<i<<"culoarea"<<st[i]<<endl;
cout<<endl;
}
void back( )
{int AS;
k=1; Init( );
while (k>0)
{ do { } while ((AS=Am_Succesor( )) && !E_Valid( ));
if (AS)
{
if (Solutie( )) Tipar( );
else
{
k++; Init( );
}
}
else k--;
}
}

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

back( );
}

BACKTRAKING RECURSIV
//sa determine prin backtracking recursiv problema damelor
#include "stdafx.h"
#include<iostream>
using namespace std;
#include<stdio.h>
#include <math.h>

#include <math.h>
int t[20],n;
void tipar ( )
{
for (int i=1;i<=n;i++) cout<<t[i];
cout<<endl;
}
void dame(int k)
{int i,j,corect;
if (k==n+1) tipar( );
else
{
for (i=t[k]+1;i<=n;i++)
{
t[k]=i;
corect=1;

for (j=1;j<=k-1;j++)
if (t[j]==t[k]) corect=0;
else
if (abs (t[k]-t[j])==abs(k-j))
corect=0;
if (corect) dame (k+1);
}
}
t[k]=0;
}
main( )
{
cout<<"n=";cin>>n;
dame(1);
}
//sa determine prin backtracking recursiv partitiile unui numar
#include "stdafx.h"
#include<iostream>
using namespace std;
#include<stdio.h>
#include <math.h>

int s[20],n;
void tipar (int k)
{ for (int i=1;i<=k;i++) cout<<s[i];
cout<<endl;}
void part (int k,int v)
{int i;
s[k]=v;
tipar(k);
for (i=1;i<=s[k]-1;i++)
{
s[k]=s[k]-i;
part(k+1,i);
s[k]=s[k]+1;
}
}
main( )
{cout<<"n=";cin>>n;
part(1,n);}
//sa determine prin backtracking recursiv problema platii unei
sume //cu
// anumite tipuri de bancnote
#include "stdafx.h"
#include<iostream>
using namespace std;
#include<stdio.h>
#include <math.h>
int sol[10],a[10],b[10],n,i,s;

void tipar (int k)


{
cout<<"Solutie"<<endl;
for (i=1;i<=k;i++)
if (sol[i])
cout<<sol[i]<<" bancnote de "<<a[i]<<endl;
}
void plata (int k,int s0)
{
while(sol[k]<b[k]&& s0+a[k]<=s)
{sol[k]=sol[k]+1;
if (sol[k]>0)
s0+=a[k];
if (s0==s) tipar(k);
else if (k<n) plata (k+1,s0);}
sol[k]=-1;
}

void main( )
{
cout<<"cate tipuri de bacnote avem?";cin>>n;
cout<<"suma=";
cin>>s;
for (i=1;i<=n;i++)
{
cout<<"valoarea monedei de tipul"<<i<<" ";
cin>>a[i];
b[i]=s/a[i];
sol[i]=-1;
}
plata (1,0);
}
//sa determine prin algoritmul de umplere a unei suprafete inchise

#include "stdafx.h"
#include<iostream>
using namespace std;
#include<stdio.h>
#include <math.h>
int a[10] [10],i,j,m,n,x,y;
void scriu (int x,int y,int a[10][10])
{
if (a[x][y]==0)
{
a[x][y]=1;
scriu(x+1,y,a);
scriu(x,y+1,a);
scriu(x-1,y,a);
scriu(x,y-1,a);
}
}
void main( )
{
cout <<"M=";cin>>m;
cout<<"N=";cin>>n;
for (i=1;i<=m;i++)
for (j=1;j<=n;j++)
{
cout<<"a["<<i<<"."<<j<<"]=";
cin>>a[i][j];
}
for (i=1;i<=n;i++)
{
a[0][i]=1;
a[m+1][i]=1;
}
for (i=1;i<=m;i++);
{
a[i][0]=1;a[i][n+1]=1;
}
cout<<"X=";
cin>>x;
cout<<"Y=";
cin>>y;
for (i=1;i<=m;i++)
{
for (j=1;j<=n;j++)
cout<<a[i][j];
cout<< endl;
}
scriu(x,y,a);
cout<<endl<<endl;
for (i=1;i<=m;i++)
{
for (j=1;j<=n;j++)
cout<<a[i][j];
cout<<endl;
}
}
//sa se determine problema fotografiei recusiv
//ex:n=4
//m=4
1 1 0 0
0 0 0 1
A= 1 1 1 1
1 1 1 1

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

int a[10][10],i,j,m,n,x,y,gasit;
void compact (int x,int y, int a[10][10])
{
if (a[x][y])
{
a[x][y]=0;
compact (x-1,y,a);
compact (x-1,y+1,a);
compact (x,y+1,a);
compact (x+1,y+1,a);
compact(x+1,y,a);
compact(x+1,y-1,a);
compact(x,y-1,a);
compact(x-1,y-1,a);
}
}
main( )
{
cout <<"M=";cin>>m;
cout<<"N=";cin>>n;
for (i=1;i<=m ;i++)
for(j=1;j<=n;j++)
{
cout<<"a["<<i<<","<<j<<"]=";
cin>>a[i][j];
}
for (i=1;i<n;i++)
{
a[0][i]=0;
a[m+1][i]=0;
}
for (i=1;i<=m;i++)
{
a[i][0]=0;a[i][n+1]=0;
}
x=0;
do
{
x++;
y=0;
do
{
y++;
}
while (y!=n && a[x][y]!=1);
}
while((x!=m)&& a[x][y]!=1);
compact(x,y,a);
gasit=0;
for (i=1;i<=m;i++)
for(j=1;j<=n;j++)
if (a[i][j]==1) gasit=1;
if(gasit) cout<<"mai multe obiecte";else cout<<"un obiect";
}
GREEDY

Descrierea metodei
Metoda Greedy este o metodă generală de elaborare a algoritmilor;
provenienţa numelui o vom explica mai jos. În esenţă, ea se aplică problemelor în
care se dă o mulţime A conţinând n date de intrare cerându-se să se determine o
submulţime B a sa care să îndeplinească anumite condiţii pentru a fi acceptată;
cum în general există mai multe astfel de mulţimi se mai dă şi un criteriu
conform căruia dintre submulţimile acceptabile (numite soluţii posibile) să
alegem una singură (numită soluţie optimă) ca rezultat final. Soluţiile posibile au
următoarea proprietate: dacă B este o soluţie posibilă şi CB, atunci şi C este o
soluţie posibilă; vom presupune că Ø este totdeauna soluţie posibilă.
Metoda Greedy tratează acest tip de probleme în următoarele două
moduri, care urmează aceeşi idee, dar diferă doar prin ordinea de efectuare a
unor operaţii.
Se pleacă de la soluţia vidă. Se alege pe rând într-un anumit fel un
element din A neales la paşii precedenţi. Dacă adăugarea lui la soluţia parţială
anterior construită conduce la o soluţie posibilă, construim noua soluţie posibilă
prin adăugarea elementului ales (vezi procedura GREEDY1).

FORMA 1:

Procedure GREEDY1(A,n,B);
BØ
For i=1,n
Call ALEGE(A,i,x)
Call POSIBIL(B,x,v)
If v=1 then call ADAUG(B,x)
Endif
Repeat
Return
End

FORMA 2:

Procedure GREEDY2(A,n,B);
Call PREL(A); BØ
For i=1,n
Call POSIBIL(B,ai,v)
If v=1 then call ADAUG(B,ai)
Endif
Repeat
End

//sa se determine ordinea de planificare a spectacolelor stiind cand


//incepe si cat dureaza
//ex:2
//n=2
//2
//20
//2
//40
//3
//10
//3
//20
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

int s[2][10],o[10],n,i,h1,m1,h2,m2,ora;
void sortare( )
{
int gata,m,i;
do
{ gata=1;
for (i=1;i<=n-1;i++)
if (s[i][o[i]] >s[1][o[i+1]])
{
m=o[i];
o[i]=o[i+1];
o[i+1]=m;
gata=0;
}
}
while (!gata);
}
main( )
{ cout<<"n=";cin>>n;
for (i=1;i<=n;i++)
{o[i]=i;
cout<<"ora de inceput pentru spectacolul"<<i<<"( h h) m m )=";
cin >>h1>>m1;
s[0][i]=h1*60+m1;
cout <<"oradesfarsit pentru spectacolul "<<i<<"(hh mm)=";
cin>>h2>>m2;
s[1][i]=h2*60+m2;
}
sortare( );
cout<<"ordinea spectacolelor este"<<endl<<o[1]<<endl;
ora=s[1][o[1]];
for (i=2;i<=n;i++)
{ if (s[0][o[i]]>=ora)
{cout<<o[i]<<endl;
ora=s[1][o[i]];}
}
}
//sa se determine alegerea de obiecte pentru umplerea
//unui rucsac cunoscand capacitatea lui,greutatea
obiectelor ,valoarea lor
//Ne intreseaza sa ducem maxim cantitativ si cu valoare maxima
ex:3
// 3
// 2
// 2
// 4
// 1
// 6
// 3
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

double c[9],g[9],ef[9],gv,man,castig;
int n,i,man1,inv,ordine[9];
main( )
{cout<<"Greutatea ce poate fi transportata=";cin>>gv;
cout<<"Numar de obiecte=";cin>>n;
for(i=1;i<=n;i++)
{
cout<<"c["<<i<<"]=";cin>>c[i];
cout<<"g["<<i<<"]";cin>>g[i];
ordine[i]=i; ef[i]=c[i] /g[i];
}
do
{
inv=0;
for(i=1;i<=n-1;i++)
if(ef[i]<ef[i+1])
{
man=ef[i];ef[i]=ef[i+1];ef[i+1]=man;
man=c[i]; c[i]=c[i+1]; c[i+1]=man;
man=g[i];g[i]=g[i+1]=man;
inv=1;
man1=ordine[i];ordine[i]=ordine[i+1];ordine[i+1]=man1;
}
}
while (inv);
i=1;
while(gv>0 && i<=n)
{
if (gv>g[i])
{ cout <<"Obiectul "<<ordine[i]<< " "<<1<<endl;
gv-=g[i];castig+=c[i];
}
else
{cout<<"Obiectul "<<ordine[i]<<" " <<gv /g[i]<<endl;
castig+c[i]*gv /g[i];
gv=0;
}
i++;
}
cout<<"Castig total="<<castig;
}
PROGRAMARE DINAMICA

Alaturi de Greedy,programarea dinamica este o tehnica ce conduce, de cele mai


multe ori, la un timp de calcul polinomial.Mai mult, ea furnizeaza in totdeauna solutia
optima .Din nefericire, programarea dinamica nu se poate aplica tuturor problemelor, ci
numai care indeplinesc anumite conditii.
Se considera o problema in care rezultatul se obtine ca urmare a unui sir de decizii D1,
D2,......Dn. In urma decizei D1 sistemul evolueaza din starea S0 in starea S1,in urma
decizei D2 sistemul evolueaza din starea S1 in starea S2,....,in urma decizei Dn sistemul
evolueaza din starea Sn-1 in stareaSn.
Daca D1, D2,....Dn este un sir de decizii care comduce sistemul in mod optim din S0 in
Sn,atunci trebuie indeplinita una din conditiile urmatoare (principiul de optimalitate):
1)Dk...Dn este un sir de decizii ce conduce optim sistemul din starea Sk-1 in
stareaSn,Ak,1<=k<=n;
2)D1....Dk este un sir de decizii ce conduce optim sistemul din starea S0 in
stareaDk,Ak,1<=K<=;
3)Dk+1...Dn,D1...Dk sunt siruri de decizii care conduc optim sistemul starea Sk in starea
Sn, respectiv din starea D0 in starea Sk,Ak,1<=k<=n.
=>Daca principiulde optimalitate se verifica in forma 1,spunem ca se aplica programarea
dinamica metoda inainte.
=>Daca principul de oplimalitate se verifica in forma 2, spunem ca se aplica programarea
dinamica inapoi.
=>Daca primcipiul de optimalitate se verifica in forma 3, spunem ca se aplica
programarea dinamica metoda mixta.
Programarea dinamica se poate aplica problemelor la care optimul general implica
optimul partial.
Faptulca optimul general determina optimul partial, nu inseamna ca optimul partial
determina optimul general.
cu toate acestea, faptul ca potimul general impune optimul partial ne este de mare
ajutor:cautam optimul general,intre optimele partiale, pe care le retinem la fiecare
pas.Oricum,cautarea se reduce considerabil.

//sa se determine prin programare dinamica suma maxima


//in parcurgerea si sumarea elemntelor
//din matricea triunghiulara ,stiind ca ma pot deplasa numai o
pozitie jos sau dreapta-jos
//ex:2
// 2
// 3
// 5

Exemplu:n=4;
2
3 5
6 3 4
5 6 1 4
Se pot forma mai multe sume:
S1=2+3+6+5=16;
S2=2+5+4+1=12;
Sk=2+3+6+6=17
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

int t[50][50],c[50][50],drum[50][50],n,i,j;
main()
{

cout<<"n=";cin>>n;
for (i=1;i<=n;i++)
for (j=1;j<=i;j++)
{ cout <<"t["<<i<<","<<j<<"]=";
cin>>t[i][j];
}
for (j=1;j<=n;j++) c[n][j]=t[n][j];
for (i=n-1;i>=1;i--)
{
for (j=1;j<=i;j++)
if (c[i+1][j]<c[i+1][j+1])
{
c[i][j]=t[i][j]+c[i+1][j+1];drum[i][j]=j+1;
}
else
{
c[i][j]=t[i][j]+c[i+1][j];
drum[i][j]=j;
}
};

cout<<"suma maxima="<<c[1][1]<<endl;
i=1;
j=1;
while (i<=n)
{
cout<<t[i][j]<<endl;
j=drum[i][j];
i++;
};
}
//sa se determine prin programare dinamica
//un subsir crecator care are maxim de componente dar sa fie
crescator
// ex:5
// 4
// 1
// 7
// 6
// 7
L=(3,3,2,2,1).
Componentele vectorului L au fost calculate astfel:
-cel mai lung subsir care se poate forma cu elementul 7,aflat pe ultima pozitie,are lungimea 1;
-cel mai lung subsir care se poate forma cu elementul 6 aflat pe pozitia 4 are lungimea
(1+L(5)), pentru ca pe pozitia 5se gaseste elementul 7 care este mai mare decat 6;
-cel mai lung subsir care se poate forma cu elementul aflat pe pozitia 3 are lungimea2(1+L(5))
pentru ca 7 este egal cu 7;
-algoritmul continua in acest mod pana se completeazaL(1).

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

int v[20],l[20],n,i,k,max,t;
main()
{
cout<<"n="; cin>>n;
for(i=1;i<=n;i++)
{cout<<"v["<<i<<"]=";cin>>v[i];
}
l[n]=1;
for(k=n-1;k>=1;k--)
{
int max=0;
for(i=k+1;i<=n;i++)
if ( v[i]>=v[k] && l[i]>max)
max=l[i];
l[k]=1+max;
}
int max=l[1]; t=1;
for(k=1; k<=n;k++)
if (l[k]>max)
{max=l[k]; t=k;}
cout<<"lungimea maxima:"<<max<<endl<<v[t]<<endl;
for(i=t+1;i<=n;i++)
if (v[i]>v[t]&& l[i] ==max-1)
{cout<<v[i] << endl;
max--;
}
}
//sa se determine prin programare dinamica
//imultirea otima a unui sir de matrice
// ex:4
// 10
// 1
// 10
// 1
// 10
Sa consideram produsul de matrice A1xA2x....xAn (A1(d1,d2),A2(d2,d3)...,An(dn,dn+1)).Se
cunoaste ca legea de compozitie produs de matrice nu este comutativa in schimb este
asociativa.De exemplu ,daca avem de inmultit trei m atrice A,B,C produsul se poate face in
doua moduri:(AxB) xC; Ax(BxC).Este interesant de observat ca nu este indiferent modul de
inmultire a celor n matrice.Sa considera ca avem de inmultit patru matrice
A1(10,1),A2(1,10),A3(10,1),A4(1,10).
Pentru inmultirea lui A1 cu A2 se fac 100 de inmultiri si se obtine o matrice cu 10 lini si 10
coloane.Prin inmul
tirea acesteia cu A3 se fac 100 de inmultiri si se obtine o matrice cu 10 linii si o coloana.daca
aceasta matrice se inmulteste cu A4 se fac 100 inmultiri. In concluzie, daca acest produs se
efectueaza in ordine naturala,se efectueaza 300 inmultiri.
SAefectuam acelas produs in ordinea care rezulta din expresia A1x((A2XA3) x A4).Efectuand
produsul A2 cu A3 se efectueaza 10 inmultiri si se obtine o matrice cu o linie si cu o
coloana.aceasta matrice se inmulteste cu A4 se fac 10 inmultiri si se obtine o matrice cu 1 linie
si 10 coloane.Daca o inmultim pe aceasta cu prima, efectuam 100 inmtltiri , obtinand rezultatul
final cu numai 120 de inmultiri.

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

int i,n,dim[10];
int a[10][10];

void costopt(int n,int dim[10],int a[10][10])


{int k,i,j,l;
long m;
for (i=1;i<=n;i++) a[i][i]=0;
for (k=1;k<=n-1;k++)
for (i=1;i<=n-k;i++)
{ j=i+k;
a[i] [j]=100000;
for(l=i;l<=j;l++)
{m=a[i] [l] +a[l+1] [j]+dim[i]*dim[l+1]*dim[j+1];
if (a[i] [j]>m)
{
a[i] [j]=m;;
a[j] [i]=l;
}
}
}
cout<<"cost optim:"<<a[1][n]<<endl;

}
main()
{cout<<"n=";cin>>n;
for (i=1;i<=n+1;i++)
{ cout<<"d=";cin>>dim[i];}
costopt(n,dim,a);
}
Alocarea dinamica a memoriei

Variabile de tip pointer


Memoria interna poate fi privita ca o succesiune de octeti.Numarul de ordine al unui octet
se numeste adresa lui.Adresa unei variabile nu trebuie confundata cu valoarea pe care
aceasta o memoreaza.
Definitie: Adresa primului octet al variabilei se numeste adresa variabilei.
Adresele variabilelor se memoreaza cu ajutorul variabilelor de tip pointer.
Tipul unei variabile de tip pointer se declara astfel:
tip *nume
Adresa unei variabile se obtine cu ajutorul operatorului ‘ & ‘, care trebuie sa preceada numele
variabilei:
&Nume_variabila;

//sa se puna in evidenta notiunea de pointer si adresa

#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;
void main()
{
int a=7, *adr=&a;
cout<<*adr;
}
//sa se puna in evidenta notiunea de pointer si adresa
//la structuri de date
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

struct elev
{
char nume[20], prenume[20];
};

void main()
{
elev a, *adra=&a;
strcpy(a.nume, "Bojian");
strcpy(a.prenume, "Andronache");
cout<<(*adra).nume<<" "<<(*adra).prenume<<endl;

}
Alocarea dinamica a memoriei

Spatiul necesar memorarii este rezervat in HEAP, in timpul executiei


programului, iar atunci cand variabila nu mai este utila, spatiul din
memorie este eliberat.
In C++, pentru alocarea dinamica se utilizeaza urmatorii operatori:
 Operatorul new aloca spatiu in HEAP pentru o variabila
dinamica.Dupa alocare, adesa variabilei se atribuie lui p, care este o
variabila de tip pointer catre tip:
p=new tip
 Operatorul delete elibereaza spatiul rezervat pentru variabila a
carei adresa este retinuta in p.Dupa eliberare, continutul variabilei p
este nedefinit.
delete p
//sa se puna in evidenta notiunea de alocare dinamica si eliberarea
spatiului
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

void main()
{
int *adr1;
adr1=new int;
*adr1=7;
cout<<*adr1;
delete adr1;

}
//sa se puna in evidenta notiunea de alocare dinamica si eliberarea
spatiului
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

void main()
{
float* adresa;
adresa=new float;
*adresa=7.65;
cout<<adresa<<endl;
cout<<*adresa;
delete adresa;
}
//sa se puna in evidenta notiunea de alocare dinamica si
//eliberarea spatiului la structuri
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;
struct inreg
{ char nume[20], prenume[20];
int varsta;
};

void main()
{ inreg* adr;
adr=new inreg;
cin>>adr->nume>>adr->prenume>>adr->varsta;
cout<<adr->nume<<adr->prenume<<adr->varsta;
delete adr;
}
Alocarea dinamica a masivelor
 Un tablou p-dimensional se declara astfel:
tip nume[n1] [n2] … [np]
 Numele tabloului de tip p-dimensional de mai sus este pointer constant catre un
tablou p-1 dimensional de forma [n2] … [np], care are componentele de baza de
acelasi tip cu cele ale tabloului.
 Un pointer catre un tablou k dimensional cu [l1] [l2] …[lk] componente de un
anumit tip
se declara astfel:
tip (*nume) [l1] [l2] …[lk];
 Intrucat numele unui masiv p dimensional este pointer catre un masiv p-1
dimensional, pentru a aloca dinamic un masiv se va utiliza un pointer catre masive
p-1 dimensionale (ultimele p-1 dimensiuni).

//sa se puna in evidenta notiunea de alocare dinamica si


//eliberarea spatiului la tablouri
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

void main()
{ int *a=new int[4];
a[3]=2;
cout<<a[3];
delete a;
}
//sa se puna in evidenta notiunea de alocare dinamica si
//eliberarea spatiului la tablouri
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

void main()
{ double (*a)[5]=new double [3] [5];
a[1][2]=7.8;
cout<<a[1][2];
delete a;
}
//sa se puna in evidenta notiunea de alocare dinamica si
//eliberarea spatiului la tablouri bidimensionale

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

main ( )
{
int m,n,i,j,(*adr)[10];
adr=new int[10] [10];
cout<<"m="; cin>>m;
cout<<"n="; cin>>n;
for(i=0;i<m;i++)
for(j=0;j<n;j++)
cin>>adr[i][j];
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
cout<<adr[i][j]<<" ";
cout<<endl;
}
delete adr;
}
//sa se puna in evidenta notiunea de alocare dinamica si
//eliberarea spatiului la tablouri bidimensionale
//sa se sumeze doua maatrice si sa se returneze un pointer catre un
VOID
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

void* Cit_Mat(int m, int n)


{
int i,j,(*adr1)[10]=new int [10] [10];
for(i=0;i<m;i++)
for(j=0;j<n;j++) cin>>adr1[i][j];
return adr1;
}
void Tip_Mat(int m, int n, int(*adr1)[10])
{ int i,j;
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
cout<<adr1[i][j]<<" ";
cout<<endl;
}
}
void* Suma_Mat(int m, int n, int(*adr1)[10],int (*adr2)[10])
{ int i,j,(*adr)[10]=new int[10][10];
for(i=0;i<m;i++)
for(j=0;j<n;j++) adr[i][j]=adr1[i][j]+adr2[i][j];
return adr;
}
main ( )
{ int m,n,i,j,(*adr)[10],(*adr1)[10],(*adr2)[10];
cout<<"m="; cin>>m;
cout<<"n="; cin>>n;
adr1=(int(*)[10]) Cit_Mat(m,n);
adr2=(int(*)[10]) Cit_Mat(m,n);
adr=(int(*)[10]) Suma_Mat(m,n,adr1,adr2);
Tip_Mat(m,n,adr);
}
//• Pentru fiecare dintre cele n materiale aflate intr-o magazie se
cunoaste: denumirea materialului, unitatea de masura si cantitatea
care se gaseste in magazie.Programul de mai jos citeste informatiile
si le organizeaza astfel:
//-segmentul de date contine un vector cu n componente, unde
fiecare componenta
//retine un pointer catre inregistrarea cu datele citite pentru
fiecare material;
//-datele citite pentru fiecare material se organizeaza ca
struct, alocat in HEAP.

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

struct material
{ char denumire[20], unit_mas[5];
float cantitate;
};
void Cit_Material(int i,material* v[100])
{
v[i]=new material;
cout<<"Denumire "; cin>>v[i]->denumire;
cout<<"Unitate de masura "; cin>>v[i]->unit_mas;
cout<<"Cantitate "; cin>>v[i]->cantitate;
}
void Tip_Material(int i,material* v[100])
{
cout<<v[i]->denumire<<endl<<v[i]->unit_mas<<endl<<v[i]->cantitate;
}
main ( )
{ int n,i;
material* v[100];
cout<<"n="; cin>>n;
for(i=0;i<n;i++) Cit_Material(i,v);
for(i=0;i<n;i++) Tip_Material(i,v);
}
Liste liniare
Definitia listelor

Def.:O lista liniara este o colectie de n>=0 noduri, X1,X2,…,Xn, aflate intr-o relatie de
ordine.Astfel, X1 este primul nod al listei, X2 este al doilea nod al listei,…, Xn este ultimul
nod.Operatiile permise sunt:
 Accesul la oricare nod al listei in scopul citirii sau modificarii informatiei continute de
acesta.
 Adaugarea unui nod, indiferent de pozitia pe care o ocupa in lista.
 Stergerea unui nod,indiferent de pozitia pe care o ocupa in lista.
 Schimbarea pozitiei unui nod in cadrul listei.

Liste liniare alocate simplu inlantuit

Prezentare generala

O lista liniara simplu inlantuita este o structura de forma:


in1 adr1 in2 adr2 inn 0

adr1 adr2 adrn

Dupa cum se observa, fiecare nod, cu exceptia ultimului, retine adresa nodului
urmator.
1. Accesul la un nod al listei se face parcurgand nodurile care il preced.
2. Informatiile ocupa memorie, fiind prezente in cadrul fiecarui nod.
3. Avantajele alocarii inlantuite sunt date de rapiditatea operatiilor de adaugare si
eliminare.
//sa se puna in evidenta notiunea de lista simplu inlantuita
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

struct Nod
{
int info;
Nod* adr_urm;
};

Nod*v;
int nr;

void Adaug(Nod*& v, int nr)


{
Nod* c=new Nod;
c->info=nr;
c->adr_urm=v;
v=c;
}

void Tip(Nod* v)
{
Nod*c=v;
while(c)
{
cout<<c->info<<endl;
c=c->adr_urm;
}
}

main( )
{
cout<<"numar="; cin>>nr;
while(nr)
{
Adaug(v,nr);
cout<<"numar="; cin>>nr;
};
Tip(v);
}
//sa se puna in evidenta notiunea de lista simplu inlantuita
// si operatii cu liste simple
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

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

struct Nod
{
int info;
Nod* adr_urm;
};

Nod* v,*sf;
int i;

void Adaugare(Nod*& v, Nod*& sf, int val)


{
Nod* c;
if(v==0)
{
v=new(Nod); v->info=val; v->adr_urm=0;
sf=v;
}
else
{
c=new(Nod); sf->adr_urm=c;
c->info=val; c->adr_urm=0;
sf=c;
}
}

void Inserare_dupa(Nod* v, Nod*& sf, int val, int val1)


{
Nod* c=v, *d;
while(c->info!=val) c=c->adr_urm;
d=new Nod; d->info=val1;
d->adr_urm=c->adr_urm; c->adr_urm=d;
if(d->adr_urm==0) sf=d;
}
void Inserare_inainte(Nod*& v, int val, int val1)
{
Nod* c,*d;
if(v->info==val)
{
d=new Nod; d->info=val1; d->adr_urm=v; v=d;
}
else
{
c=v;
while(c->adr_urm->info!=val) c=c->adr_urm;
d=new Nod; d->info=val1; d->adr_urm=c->adr_urm; c->adr_urm=d;
}
}

void Sterg(Nod*& v, Nod*& sf, int val)


{
Nod* c,*man;
if(v->info==val)
{
man=v; v=v->adr_urm;
}
else
{
c=v;
while(c->adr_urm->info!=val) c=c->adr_urm;
man=c->adr_urm; c->adr_urm=man->adr_urm;
if(man==sf) sf=c;
}
delete man;
}

void Tip(Nod* v)
{
Nod*c=v;
while(c)
{
cout<<c->info<<endl;
c=c->adr_urm;
}
}

main( )
{
for (i=1;i<=10;i++)
Adaugare(v,sf,i);
Tip(v);
Inserare_dupa(v,sf,7,11);
Inserare_dupa(v,sf,10,12);
Inserare_dupa(v,sf,1,13);
Tip(v);
Inserare_inainte(v,13,14);
Inserare_inainte(v,1,15);
Tip(v);
Sterg(v,sf,15);
Sterg(v,sf,13);
Sterg(v,sf,12);
Tip(v);
}
//sa se puna in evidenta notiunea de lista simplu inlantuita
// si sortarea prin insertie a acesteia
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

const MaxInt=32000;
struct Nod
{
int info;
Nod* adr_urm;
};
int n,i;
Nod *v,*adr,*c,*c1;
main ( )
{
cout<<"n="; cin>>n;
v=new Nod; v->info=MaxInt; v->adr_urm=0;
for(i=1;i<=n;i++)
{
adr=new Nod;
cout<<"numar="; cin>>adr->info;
if(adr->info<=v->info)
{
adr->adr_urm=v;
v=adr;
}
else
{
c=v;
c1=v->adr_urm;
while(c1->info<adr->info)
{
c=c->adr_urm;
c1=c1->adr_urm;
}
c->adr_urm=adr;
adr->adr_urm=c1;
}
}
c=v;
while(c->info!=MaxInt)
{
cout<<c->info<<endl;
c=c->adr_urm;
}
}
Liste alocate dublu inlantuit

O lista alocata dublu inlantuit este o structura de date de forma:

0 in1 adr2 adr1 in2 adr3 adrn-1 inn 0 0


0000adr3
adr1 adr2
adrn

Operatiile posibile asupra unei liste dublu inlantuite sunt:

1) creare;
2) adaugare la dreapta;
3) adaugare la stanga;
4) adaugare in interiorul listei;
5) stergere din interiorul listei;
6) stergere la stanga listei;
7) stergere la dreapta listei;
8) listare de la stanga la dreapta;
9) listare de la dreapta la stanga.

1) Creare

O lista dublu inlantuita se creeaza cu o singura inregistrare.Pentru a ajunge la


numarul de inregistrari dorit, utilizam functii de adaugare la stanga si la
dreapta.Functia creare realizeaza citirea informatiei numerice, alocarea de
spatiu pentru inregistrare, completarea inregistrarii cu informatia si
completarea adreselor la dreapta si la stanga cu 0.

2) Adaugare la dreapta

Functia add citeste informatia numerica, aloca spatiu pentru inregistrare,


completeaza adresele, modifica adresa la dreapta a inregistrarii din s cu adresa
noii inregistrari si ii atribuie
lui s valoarea noii inregistrari.

3) Adaugare la stanga

4) Adaugare in interiorul listei

Functia includ parcurge lista pentru a gasi inregistrarea cu informatia m, in


dreapta careia urmeaza sa introducem noua inregistrare, citeste informatia,
aloca spatiu, completeaza informatia, completeaza adresa stanga a noii
inregistrari cu valoarea adresei inregistrarii de informatie m, si completeaza
adresa dreapta a noii inregistrari cu valoarea adresei dreapta a inregistrarii cu
informatia utila m.
5) Stergere in interiorul listei

Functia Sterg parcurge lista pentru a gasi informatia care va fi stearsa, atribuie
inregistrarii precedente campul de adresa dreapta al inregistrarii care va fi
stearsa, iar inregistrarii care urmeaza celei care va fi stearsa i se atribuie campul
de adresa stanga al inregistrarii pe care o stergem, dupa care se elibereaza
spatiul de memorie rezervat inregistrarii care se sterge.

6)-7) Stergere la stanga si la dreapta listei

8) Listare de la stanga la dreapta

Functia listare porneste din stanga listei si tipareste informatia numerica a


fiecarei inregistrari, atata timp cat nu s-a ajuns la capatul listei.

9) Listare de la dreapta la stanga

//sa se puna in evidenta notiunea de lista dublu inlantuita


// si operatii cu aceasta
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;

struct Nod
{ Nod *as,*ad;
int nr;
};

Nod *b,*s,*c;
int n,m,i;

void Creare(Nod*& b, Nod*& s)


{ cout<<"n="; cin>>n;
b=new Nod; b->nr=n;
b->as=b->ad=0;
s=b;
}
void Addr(Nod*& s)
{ cout<<"n="; cin>>n;
Nod* d=new Nod;
d->nr=n;
d->as=s; d->ad=0;
s->ad=d; s=d;
}

void Listare(Nod*& b)
{ Nod* d=b;
while(d)
{ cout<<d->nr<<endl;
d=d->ad;
}
}

void Includ(int m,Nod* b)


{
Nod *d=b, *e;
while(d->nr!=m) d=d->ad;
cout<<"n="; cin>>n;
e=new Nod;
e->nr=n;
e->as=d;
d->ad->as=e;
e->ad=d->ad;
d->ad=e;
}

void Sterg(int m, Nod *b)


{ Nod* d=b;
while(d->nr!=m) d=d->ad;
d->as->ad=d->ad;
d->ad->as=d->as;
delete d;
}

main ( )
{ cout<<"Creare lista cu o singura inregistrare "<<endl;
Creare(b,s);
cout<<"Cate inregistrari se adauga ?"; cin>>m;
for(i=1;i<=m;i++) Addr(s);
cout<<"Acum listez de la stanga la dreapta"<<endl;
Listare(b);
cout<<"Includem la dreapta o inregistrare"<<endl;
cout<<"Dupa care inregistrare se face includerea?"; cin>>m;
Includ(m,b);
cout<<"Acum listez de la stanga la dreapta"<<endl;
Listare(b);
cout<<"Acum stergem o inregistrare din interior"<<endl;
cout<<"Ce inregistrare se sterge?";
cin>>m;
Sterg(m,b);
cout<<"Acum listez de la stanga la dreapta"<<endl;
Listare(b);
}
Grafuri orientate
Grafuri orientate –notiuni de baza

Grafuri orientate – noţiuni de bază

Noţiunea de graf orientat.


Un exemplu de graf orientat este: reţeaua de străzi a unui oraş. Străzile sunt muchii în graf, iar
intersecţiile reprezintă vârfurile grafului. Întrucât mergând pe jos ne putem deplasa pe orice stradă în
ambele sensuri, vom spune că din punctul de vedere al pietonilor, „graful unui oraş” este neorientat.
Cu totul altfel stau lucrurile în ceea ce priveşte conducătorii auto, pentru că în orice oraş există străzi cu
sens unic. Pentru un şofer străzile trebuie să primească în graf o anumită orientare. Desigur că acele
străzi pe care se poate circula în ambele sensuri vor primi orientare dublă. Am ajuns astfel la noţiunea
de graf orientat.
Numim graf orientat, o pereche ordonată de mulţimi G=(X,U), unde:
X este o mulţime finită şi nevidă numită mulţimea nodurilor (vârfurilor);
U este o mulţime formată din perechi ordonate de elemente ale lui X, numită mulţimea arcelor
(muchiilor)
observaţii:
Prin noţiunea de perechi ordonate nu trebuie să
înţelegem că o muchie este mai mare decât alta, ci pur
U1
şi simplu că facem deosebire între o muchie de forma
(x,z) şi o alta de forma (y,x). Cu alte cuvinte muchiile
1
sunt diferenţiate prin ordinea de scriere a simbolurilor.
Arcul (x,y) nu este tot una cu arcul (y,x).
Exemplu: U2
Pentru graful G=(X,U) din figura 1. avem: X={1, 2, 3, 4}
2
şi U={u1, u2, u3, u4, u5, u6, u7,}= {(1,1), (2,1), (3,2),
(2,3), (2,4), (3,4), (3,4)} U3
arc va fi de forma u= (x,y), unde x se numeşte U5
extremitate iniţială, iar y se numeşte extremitate finală a U4
arcului. Cu alte cuvinte, “arcul iese din nodul x şi intră în
nodul y”. La fel ca la grafurile neorientate, vom spune că 3
nodurile x şi y sunt adiacente, iar arcul u şi nodul x sunt U6
incidente (la fel arcul x şi nodul y). Nodul y se numeşte 4
succesor al lui x, iar nodul x se numeşte predecesor al
U7
lui y. Un arc de forma (x,x), care iese din nodul x şi intră
tot x, se numeşte buclă.
Exemplu: Figura1
În graful din figura 1, avem bucla (1,1).
Într-un graf putem avea două sau mai multe arce identice.
Exemplu:
În graful din figura 1, există două arce identice, u6 = u7 = (3,4)
Definiţie
Se numeşte p-graf, un graf orientat în care numărul arcelor identice este mai mic sau egal cu o valoare
dată p.
În cele ce urmează vom analiza numai 1-grafuri fără bucle.
Graful unui vârf. Mulţimile Γ şi ω
Gradul exterior al unui vârf x, notat d*(x), reprezintă numărul arcelor care ies din nodul x, adică numărul
arcelor de forma (x,z) ε U.
Analog, se defineşte gradul interior al unui vârf x, notat d-(x), ca fiind numărul arcelor care intră în nodul
x (de forma (y,x) ε U).
Exemplu:
În graful reprezentat în figura 1, pentru nodul x=2, avem:
d*(2) =3 → există trei arce care ies din nodul 2, şi anume : u2=(2,1), u4=(2,3) şi u5 = (2,4).
d-(2) =1 → în nodul 2 intră un singur arc, în speţă arcul u3=(3,2).
Se mai definesc următoarele mulţimi:
  x   y  X x, y  U 
→ mulţimea nodurilor ce constituie extremităţi finale ale arcelor care
pleacă din nodul x. Pe scurt, mulţimea succesorilor lui x;
  x   y  X  y, x  U 
→ mulţimea nodurilor ce constituie extremităţi iniţiale ale arcelor care
pleacă din nodul x. Pe scurt, mulţimea predecesorilor lui x;
Exemplu:
În graful din figura 1, pentru nodul x=2, avem:
- Γ+(2) = {1,3,4} → urmare a faptului că muchiile care pleacă din nodul 2 sunt (2,1), (2,3) şi (2,4), putem
spune că mulţimea succesorilor nodului 2 este {1,3,4}.
- Γ-(2) = {3} → în nodul 2 intră doar muchia (3,2), deci mulţimea predecesorilor lui 2 conţine doar nodul
3.
ω+(x) = {u = (x,y)| u ε U} → mulţimea arcelor care ies din nodul x;
ω-(x) = {u = (y,x)| u ε U} → mulţimea arcelor care intră în nodul x;
Exemplu:
În graful din figura 1, pentru nodul 2, avem:
ω+(x) = {(2,1), (2,3), (2,4)}, ω-(x) = {(3,2)}
Graf parţial şi subgraf
Fie graful G = (X,U). Un graf parţial al lui G, este un graf G 1= (X,V), cu V  U . Altfel spus, un graf
parţial G1 al lui G, este chiar G, sau se obţine din G păstrând toate vârfurile şi suprimând nişte muchii.
Fie graful G = (X,U). Un graf parţial al lui G, este un graf G 1= (Y,T), unde V  X şi T  U , iar T va
conţine numai muchiile care au ambele extremităţi în Y. Altfel spus, un graf parţial G 1 al lui G, se obţine
din G eliminând nişte vârfuri şi păstrând doar acele muchii care au ambele extremităţi în mulţimea
vârfurilor rămase.
Exemplu:
Se consideră graful G = (X,U) din figura 2, în care X = {1,2,3,4,5,6} şi U={u1, u2, u3, u4, u5, u6, u7}.
- Construim graful parţial G1 = (X,V), unde X = {1,2,3,4,5,6} şi V = { u2, u3, u4, u6, u7} (figura 3)
din graful G au fost eliminate arcele u1 şi u5.
- Construim subgraful G2 = (Y,T), unde Y = {3,4,5,6} şi T = {u4, u5, u6, u7} (figura 4) din graful G
au fost eliminate nodurile 1 şi 2 precum şi arcele u1, u2 şi u3 care au o extremitate în afara
mulţimii nodurilor rămase.
Reprezentarea grafurilor orientate
Considerăm un graf orientat G= (X,U) cu m arce şi n noduri.
Cele mai cunoscute forme de reprezentare sunt: matricea de adiacenţă, matricea vârfuri – arce,
matricea drumurilor şi listele vecinilor.
Matricea de adiacenţă

u2 u2
1 2 1 2
u1
u3 u3
u4 u5 u4 u4
3 3 3 u5
4 4 4
5 5 5
u7 u6 u7 u7
u6 u6

6 6 6
Figura 2 Figura 3 Figura 4

Are aceeaşi semnificaţie ca în cazul grafurilor neorientate: fiecare element a[i,j], cu i,j ε {1,2,...,n}, este: 1
dacă există arcul (i,j), respectiv 0 în caz contrar.
Datorită orientării, aşa cum am mai spus, arcul (i,j) nu este totuna cu arcul (j,i). Prin urmare, a[i,j] ≠ a[j,i].
Aşadar matricea de adiacenţă nu mai este simetrică faţă de diagonala principală, aşa cum se întâmpla
în cazul grafurilor neorientate.
Exemplu:
Pentru graful G=(X,U) din figura 5, matricea de adiacenţă este:
coloana 1 2 3 4

0 0 0 0 1

1 0 1 1 2
A=
0 0 0 1 3

0 1 0 0 4

2
3

Continuăm cu câteva 1 aplicaţii.


Aplicaţie:
Citirea de la tastatură şi 4 afişarea matricei
de adiacenţă
Figura 5

Prin citirea matricei de adiacenţă de la tastatură, putem memora arcele existente între nodurile
unui graf. În cazul grafurilor neorientate, citeam doar “porţiunea” de deasupra diagonalei
principale în matrice, deoarece matricea este simetrică. Acum trebuie să citim toate elementele
matricei. Avem de-a face cu algoritmii banali de citire şi afişare a unei matrice cu n linii şi n
coloane (unde n este numărul de noduri) în două cicluri for, deci nu considerăm că mai sunt
necesare alte explicaţii.
Matricea vârfuri – arce
Este o matrice b cu n linii şi m coloane, în care fiecare element b[i,j] este:
- 1, dacă nodul i este o extremitate iniţială a arcului u j;
- -1, dacă nodul i este o extremitate finală a arcului u j;
- 0, dacă nodul i nu este o extremitate a arcului uj.
Exemplu:
Pentru graful de mai jos cu n=4 noduri şi m=5 arce, matricea vârfuri – arce este:
1 0 0 0 0

-1 -1 -1 0 0

0 1 0 1 -1

0 0 1 -1 1
2

u1 u3
u2
1
u4
3 4

u5
Figura 6

Pentru a exemplifica construcţia matricei, vom deduce elementele liniei 3:


- a[3,1]= 0 pentru că nodul 3 nu este o extremitate a arcului u1. Analog, a[3,3]= 0 deoarece
nodul 3 nu este extremitate a arcului u3.
- a[3,5]= -1 pentru că nodul 3 este o extremitate finală a arcului u5.
- a[3,2]= 1 şi a[3,4]= 1 întrucât nodul 3 este o extremitate iniţială a arcului u2 respectiv u4.
Observaţii:
Pe fiecare coloană j (aferentă arcului uj), avem exact două elemente nenule: un 1 (linia i pe care se află
reprezintă extremitatea iniţială a arcului uj) şi un -1 (linia i pe care se află reprezintă extremitatea finală a
arcului uj)
Numărul valorilor de 1 de pe linia i, reprezintă gradul exterior al nodului i (numărul arcelor ce au ca
extremitate iniţială pe i), iar numărul valorilor de -1 de pe linia i reprezintă gradul interior al nodului i
(numărul arcelor care au ca extremitate finală pe i).
Listele vecinilor
Pentru fiecare nod x se construiesc două liste ale vecinilor săi:
- L*(x) → lista vecinilor succesori; conţine nodurile ce sunt extremităţi finale ale arcelor care ies
din nodul x.
- L-(x) → lista vecinilor predecesori; conţine nodurile ce sunt extremităţi iniţiale ale arcelor care
intră în nodul x.
Exemplu:
În graful din figura 6 de mai sus, pentru nodul x=4 avem:
- arcele care ies din nodul 4 sunt (4,2) şi (4,3). În consecinţă, lista vecinilor succesori L*(4)
conţine nodurile 2 şi 3;
- în nodul 4 intră un singur arc, şi anume (3,4), motiv pentru care lista vecinilor predecesori L-(4)
conţine doar nodul 3.
Prezentăm în continuare aceste liste ale vecinilor pentru graful din figura 6.

Nodul x L*(x) L-(x)


1 2 vidă
2 vidă 1,3,4
3 2,4 4
4 2,3 3

Matricea drumurilor
Această matrice va fi reprezentată în cadrul capitolului “Drumuri şi circuite în grafuri orientate”.
Reprezentarea grafului ca un vector de muchii
Fiecare arc al grafului poate fi privit ca o înregistrare cu două componente, în speţă cele două noduri
care constituie extremităţile arcului:
- nod_in -> nodul din care iese arcul (“nodul de început” al arcului);
- nod_sf -> nodul în care intră arcul (“nodul de sfârşit” al arcului);
Putem defini tipul de date ARC, astfel:
Drumuri si circuite in grafuri orientate
Se numeşte lanţ intr-un graf orientat, o mulţime de arce L={u 1,u2,...,uk}, cu proprietatea ca oricare doua
arce vecine in mulţime au o extremitate comuna.
Un lanţ este de fapt un traseu care uneşte prin arce doua noduri numite extremităţile lanţului, fără a tine
cont de orientarea arcelor componente.
Se numeşte drum în graful G, un şir de noduri D={z 1, z2, z3, …, zk}, unde z1, z2, z3, …, zk aparţin lui x, cu
proprietatea că oricare două noduri consecutive sunt adiacente, adică există arcele [z 1, z2], [z2, z3], …,
[zk-1,zk] aparţin lui U.
Practic, un drum poate fi privit ca un traseu în care toate arcele au aceeaşi orientare, dată de sensul de
deplasare de la z1 la zk.
Dacă nodurile z1, z2, z3, …, zk sunt distincte două câte două, drumul se numeşte elementar. În caz
contrar, drumul este ne-elementar.
Asemenea uni lanţ într-un graf neorientat, un drum într-un graf orientat este de fapt un traseu pe care l-
am parcurge între două noduri deplasându-ne de-a lungul unor arce şi trecând prin nişte noduri
intermediare. Deosebirea unui drum faţă de un lanţ constă în faptul că de-a lungul unui arc ne putem
deplasa numai în sensul dat de orientarea arcului.
Se numeşte circuit într-un graf, un lanţ L={z 1, z2, z3, …, zk} cu proprietatea că z1=zk şi arcele [z1, z2], [z2,
z3], …, [zk-1,zk] sunt distincte două câte două.
Dacă într-un circuit, toate nodurile cu excepţia primului şi ultimului sunt distincte două câte două, atunci
circuitul se numeşte elementar. În caz contrar, el este ne-elementar.

u2
1 2

u1
u3
u4 u5
3
4
5
u7 u6

6
Figura 8

Matricea drumurilor.
Este o matrice d cu n linii şi n coloane, în care fiecare element d[i,j] este :
- 1, dacă există drum de la nodul i la nodul j în graf;
- 0, în caz contrar.
Algoritmul Roy-Warshall de determinare a matricei drumurilor
Matricea drumurilor se obţine aplicând matricei de adiacenţă transformări succesive. Vom spune că
există drum de la nodul i la nodul j, dacă găsim un nod k (diferit de i, j) cu proprietatea că există drum de
la i la k şi drum de la j la k. Astfel:
 un element a[i, j] care este 0, devine 1, dacă există un nod k astfel încât a[i, k]=1 şi a[k, j]=1.
Pentru a găsi arcele nodului k, trebuie parcurse pe rând în varianta k toate nodurile 1, 2, …, n.

Metode de reprezentare in memorie


a unui graf

Exista mai multe metode de reprezentare in memorie a unui graf orientat:


1-metoda matricei adiacente:
1, pentru[I,j] apartin de g
a[I,j]=

0, pentru[I,j]nu apartinde g
fisierul graf.txt este in calea: C:\Documents and Settings\ticatica\My Documents\Visual Studio
Projects\p2
//sa se puna in evidenta notiunea de matrice de adiacenta si
//sa se listeze dintr-un fisier
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;
#include<fstream>

int A[50][50],n,I,j;
void Citire(char Nume_fis[20],int a[50][50],int& n)
{
fstream f(Nume_fis,ios::in);
int I,j;
f>>n;
while (f>>I>>j) A[I][j]=1;
f.close();
}

main()
{
Citire("Graf.txt",A,n);
for (I=1;I<=n;I++)
{ for (j=1;j<=n;j++) cout <<A[I][j]<<" ";
cout<<endl;
}
}
Parcurgerea grafurilor orientate

Parcurgerea in latime(BF-breadth first)


-parcurgerea in latime se face incepand de la un nod I, pe care il consideram parcurs;
-parcurgem apoi toti descendentii sai – multimea nodurilor j pentru care exista
[I,j]apartin de g;
-parcurgem apoi toti descendentii nodurilor parcurse la pasul anterior.
Parcurgerea BF se efectueaza prin utilizarea structurii numita coada, avand grija ca un
nod sa fie vizitat o singura data. Coada va fi alocata prin utilizarea unui vector.
Fie graf.txt ce contine:
7
1 2
1 6
1 3
3 6
2 5
2 4
3 7
=>1 3 2 6 4 5 7
//sa se puna in evidenta parcurgerea in latime la grafuri
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;
#include<fstream>

int coada[50],s[50],A[50][50],I_c,sf_c,I,j,n;
void bf_r1()
{ int k;
if (I_c<=sf_c)
{ for (k=1;k<=n;k++)
if ( (A[coada[I_c]][k]==1) && (s[k]==0) )
{ sf_c++;
coada[sf_c]=k;
s[k]=1;
}
I_c++;
bf_r1();
}
}
void Citire(char Nume_fis[20],int a[50][50],int& n)
{
fstream f(Nume_fis,ios::in);
int I,j;
f>>n;
while (f>>I>>j) A[I][j]=1;
f.close();
}
main()
{
Citire("Graf.txt",A,n);
for (I=1;I<=n;I++)
{ for (j=1;j<=n;j++) cout <<A[I][j]<<" ";
cout<<endl;
}
I_c=sf_c=1;
coada[I_c]=s[1]=1;
bf_r1();
for(I=1;I<=sf_c;I++)cout<<coada[I]<<" ";
}

Parcurgerea in adancime(DF-depth first)

-se face incapand de la un nod I


-dupa parcurgerea unui nod se parcurge primul dintre descendntii sai
neparcursii inca.

Parcurgerea in latime(BF-breadth first)


-parcurgerea in latime se face incepand de la un nod I, pe care il consideram parcurs;
-parcurgem apoi toti descendentii sai – multimea nodurilor j pentru care exista
[I,j]apartin de g;
-parcurgem apoi toti descendentii nodurilor parcurse la pasul anterior.
Parcurgerea BF se efectueaza prin utilizarea structurii numita coada, avand grija ca un
nod sa fie vizitat o singura data. Coada va fi alocata prin utilizarea unui vector.
Fie graf.txt ce contine:
7
1 2
1 6
1 3
3 6
2 5
2 4
3 7
=>1 2 4 5 3 6 7
//sa se puna in evidenta parcurgerea in adancime la grafuri
#include "stdafx.h"
#include<iostream>
#include<math.h>
using namespace std;
#include<fstream>

int s[50],A[50][50],I,j,n;
void df_r(int nod)
{
int k;
cout<<nod<<" ";
s[nod]=1;
for (k=1;k<=n;k++)
if ((A[nod][k]==1) && (s[k]==0))
df_r(k);
}

void Citire(char Nume_fis[20],int a[50][50],int& n)


{
fstream f(Nume_fis,ios::in);
int I,j;
f>>n;
while (f>>I>>j) A[I][j]=1;
f.close();
}
main()
{
Citire("Graf.txt",A,n);
for (I=1;I<=n;I++)
{ for (j=1;j<=n;j++) cout <<A[I][j]<<" ";
cout<<endl;
}
df_r(1);
}

// cu liste de adiacenta sa se implemeteze


//parcurgerea in adancime
// 7
// 1 2
// 1 6
// 1 3
// 3 6
// 2 5
// 2 4
// 3 7
//=>1 3 7 6 2 5 4

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

struct Nod
{
int nd;
Nod* adr_urm;
};

int s[50],n;
Nod *L[50];
void df_r1(int nod)
{
Nod* p;
cout<<nod<<" ";p=L[nod];
s[nod]=1;
while (p)
{
if (s[p->nd]==0)
df_r1(p->nd);
p=p->adr_urm;
}
}

void Citire_1( Nod* L[50], int& n)


{
Nod* p;
int I,j;
fstream f("graf.txt",ios::in);
f>>n;
for (I=1;I<=n;I++) L[I]=0;
while (f>>I>>j)
{ p=new Nod;
p->adr_urm=L[I]; p->nd=j;
L[I]=p;
}
f.close();
}
main()
{
Citire_1(L,n);
df_r1(1);
}
// cu liste de adiacenta sa se implemeteze
//parcurgerea in latime recursiv
// 7
// 1 2
// 1 6
// 1 3
// 3 6
// 2 5
// 2 4
// 3 7
//=>1 3 6 2 7 4 5

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

struct Nod
{
int nd;
Nod* adr_urm;
};
Nod* L[50],*p;
int coada[50],s[50],I_c,sf_c,I,n;
void bf_r1()
{
Nod*p;
if (I_c<=sf_c)
{
p=L[coada[I_c]];
while (p)
{
if (s[p->nd]==0)
{
sf_c++;
coada[sf_c]=p->nd;
s[p->nd]=1;
}
p=p->adr_urm;
}
I_c++;
bf_r1();
}
}

void Citire_1( Nod* L[50], int& n)


{
Nod* p;
int I,j;
fstream f("graf.txt",ios::in);
f>>n;
for (I=1;I<=n;I++) L[I]=0;
while (f>>I>>j)
{ p=new Nod;
p->adr_urm=L[I]; p->nd=j;
L[I]=p;
}
f.close();
}

main()
{ Citire_1(L,n);
I_c=1; sf_c=1; coada[I_c]=1; s[1]=1;
bf_r1();
for (I=1;I<=sf_c;I++) cout<<coada[I]<<" ";
}
// cu liste de adiacenta sa se implemeteze
//parcurgerea in latime iterativ
// 7
// 1 2
// 1 6
// 1 3
// 3 6
// 2 5
// 2 4
// 3 7
//=>1 3 6 2 7 4 5

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

struct Nod
{
int nd;
Nod* adr_urm;
};

Nod* L[50],*p;
int coada[50],s[50],I_c,sf_c,I,n;

void bf_r1()
{
Nod*p;
while (I_c<=sf_c)
{
p=L[coada[I_c]];
while (p)
{
if (s[p->nd]==0)
{
sf_c++;
coada[sf_c]=p->nd;
s[p->nd]=1;
}
p=p->adr_urm;
}
I_c++;
//bf_r1();
}
}

void Citire_1( Nod* L[50], int& n)


{
Nod* p;
int I,j;
fstream f("graf.txt",ios::in);
f>>n;
for (I=1;I<=n;I++) L[I]=0;
while (f>>I>>j)
{ p=new Nod;
p->adr_urm=L[I]; p->nd=j;
L[I]=p;
}
f.close();
}

main()
{ Citire_1(L,n);
I_c=1; sf_c=1; coada[I_c]=1; s[1]=1;
bf_r1();
for (I=1;I<=sf_c;I++) cout<<coada[I]<<" ";
}

MATRICEA DRUMURILOR
m[I,j]= 1, daca exista drum de la I la j,
0, daca nu exista drum de la I la j, sau I=j.
// cu liste de adiacenta sa se implemeteze
//obtinerea matricei drumurilor
// 7
// 1 2
// 1 6
// 1 3
// 3 6
// 2 5
// 2 4
// 3 7
//=>
// 0 1 1 1 1 1 1
// 0 0 0 1 1 0 0
// 0 0 0 0 1 1 1
// 0 0 0 0 1 0 0
// 0 0 0 0 0 0 0
// 0 0 0 0 1 0 0

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

struct Nod
{
int nd;
Nod* adr_urm;
};

int s[50],n,I,j,M_dr[50][50];
Nod* L[50];
void df(int baza,int nod)
{
Nod* p;
if (baza!=nod) M_dr[baza][nod]=1;
p=L[nod]; s[nod]=1;
while(p)
{
if (s[p->nd]==0) df(baza,p->nd);
p=p->adr_urm;
}
}

void Citire_1( Nod* L[50], int& n)


{
Nod* p;
int I,j;
fstream f("graf.txt",ios::in);
f>>n;
for (I=1;I<=n;I++) L[I]=0;
while (f>>I>>j)
{ p=new Nod;
p->adr_urm=L[I]; p->nd=j;
L[I]=p;
}
f.close();
}

main()
{
Citire_1(L,n);
for (I=1;I<=n;I++)
{
for (j=1;j<=n;j++) s[j]=0;
df(I,I);
}
for (I=1;I<=n;I++)
{
for (j=1;j<=n;j++) cout<<M_dr[I][j]," ";
cout<<endl;
}
}
Componente tare conexe

Definitie.G1=(X1g1) este o componenta tare conexa daca:


1)Oricare ar fi x , y din multimea X1, exista drum de la x la y si drum de
la y la x.
2)Nu exista un alt subgraf al lui G care indeplineste conditia 1)
// sa se implemeteze componentele tare conexe
//ale unui graf ca intersectie intre predecesori si succesori la care
adaug nodul
5
1 2
2 3
3 1
1 4
4 5
5 4
=>copmomenta I
1 2 3
comonenta II
4 5

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

int suc[50],pred[50],A[50][50],n,nrc,I,j;

void Citire(char Nume_fis[20],int a[50][50],int& n)


{
fstream f(Nume_fis,ios::in);
int I,j;
f>>n;
while (f>>I>>j) A[I][j]=1;
f.close();
}

void df_r1(int nod)


{
int k;
suc[nod]=nrc;
for (k=1;k<=n;k++)
if ( (A[nod][k]==1)&&(suc[k]==0) )
df_r1(k);
}
void df_r2(int nod)
{
int k;
pred[nod]=nrc;
for (k=1;k<=n;k++)
if ( (A[k][nod]==1)&&(pred[k]==0))
df_r2(k);
}

main()
{
Citire("Graf.txt",A,n);
nrc=1;
for (I=1;I<=n;I++)
if (suc[I]==0)
{
suc[I]=nrc;
df_r1(I);df_r2(I);
for (j=1;j<=n;j++)
if (suc[j]!=pred[j]) suc[j]=pred[j]=0;
nrc++;
}
for (I=1;I<=n;I++)
{
cout<<"Componenta "<<I<<endl;
for (j=1;j<=n;j++)
if (suc[j]==I) cout<<j<<" ";
cout<<endl;
}
}
Drumuri in grafuri
Consideram un graf orientat G=(X,U) cu n noduri, in care fiecarui arc ii este asociat un numar intreg numit cost.
Semnificatia
acestui cost poate fi foarte variata , in functie de domeniul pe care il descrie graful .

Matricea costurilor

Pentru evidentierea costurilor tuturor arcelor unui graf cu n noduri se poate defini o matrice a, cu n linii * n
coloane.Exista doua forme ale acestei matrici:
Forma a): Fiecare element a[i,j] poate fi:
c , daca exista un arc de cost c>0 intre nodurile i si j;
0 , daca i=j;
+∞ ,daca nu exista arc intre nodurile i si j .
Forma b): Este absolut similara,cu singura deosebire ca in loc de +∞ avem -∞.
Forma a) se foloseste pentru determinarea drumurilor de cost minim intre doua noduri , iar forma b) este
utilizata in aflarea drumurilor de cost maxim.
Daca dorim sa citim matrice costurilor ,evident ca nu putem introduce de la tastatura “+”! In loc de +
vom da un numar intreg foarte mare.

Algoritmul lui Dijkstra

Se consideră un graf neorientat, conex cu N noduri. Graful este dat prin matricea costurilor A.

c, dacã existã un arc c între nodurile i si j



Aij  0, daca i  j
x, dac nu exista un arc intre nodurile i si j

Se consideră un nod iniţial R. Se cer lungimile drumurilor minime de la R la celelalte noduri ale grafului,
precum şi nodurile prin care trec aceste drumuri.
Problema are numeroase aplicaţii practice. Să presupunem că dispunem de o hartă cu oraşele unei ţări.
Acestea sunt unite prin şosele. Oraşele formează nodurile grafului, iar şoselele – arcele acestuia. Algoritmul
furnizează drumurile optime de la un oraş iniţial la celelalte oraşe. Este interesant de observat faptul că, spre
deosebire de alţi algoritmi, acesta furnizează şi nodurile prin care trec drumurile optime, nu numai
lungimile acestora.

Exemplu: Se consideră graful din figură:

Pentru acest graf matricea costurilor este:


0  13  16 8 
 
 0  6  10 
13  0 14  11 
 
 6 14 0 5 17 
16   5 0 7 

8 10 11 17 7 0 

Întrucât graful este neorientat, matricea este simetrică.


Algoritmul selectează nodurile grafului, unul câte unul, în ordinea crescătoare a costului drumului de la
nodul R la ele, într-o mulţime S, care iniţial conţine numai nodul R. În felul acesta ne încadrăm în strategia
generală GREEDY. În procesul de prelucrare se folosesc trei vectori: D,S şi T.
Vectorul D este vectorul costurilor de la nodul R la celelalte noduri ale grafului. Prin D(I), unde I{1..N},
se înţelege costul drumului găsit la un moment dat, între nodul R şi nodul I.
Vectorul T indică drumurile găsite între nodul R şi celelalte noduri ale grafului.
Vectorul S (vector caracteristic) indică mulţimea S a nodurilor selectate. S(I)=0 dacă nodul I este neselectat
şi S(I)=1 dacă nodul I este selectat.

Prezentarea algoritmului.
P1) Nodul R este adăugat mulţimii S iniţial vidă (S(R)=1);
- costurile drumurilor de la R la fiecare nod al grafului se preiau în vectorul D de pe linia R a matricii
A;
- pentru toate nodurile I având un cost al drumului de la R la ele finit, se pune T(I)=R.
P2) Se execută de n-1 ori secvenţa
- printre nodurile neselectate se caută cel aflat la distanţa minimă faţă de R şi se selectează adăugându-l
mulţimii S;
- pentru fiecare din nodurile neselectate se actualizează în D costul drumurilor de la R la el, utilizând
ca nod intermediar nodul selectat, procedând în felul următor: se compară distanţa existentă în vectorul D
cu suma dintre distanţa existentă în D pentru nodul selectat şi distanţa de la nodul selectat la nodul pentru
care se face actualizarea distanţei (preluată din A), iar în cazul în care suma este mai mică, elementul din D
corespunzător nodului pentru care se face actualizarea capătă ca valoare aceasă sumă şi elementul din T
corespuzător aceluiaşi nod ia valoarea nodului selectat (drumul trece prin acest nod). Presupunând că a
fost selectat nodul K, se actualizează distanţa pentru nodul L şi se compară D(K)+A(K,L) cu D(L).
P3) Pentru fiecare nod al grafului, cu excepţia lui R, se trasează drumul de la R la el.

Pentu acest exemplu se consideră R=1.


Linia 1 a matricei A aste încărcată în vectorul D, vectorii S şi T au iniţial valorile care se observă:
D 0   8
13 16

S 1 0 0 0 0 0

T 0 0 1 0 0
1

Se selectează nodul 6 (costul drumului minim).


Se actualizează conţinutul vectirilor D, S şi T.

D(6)+A(6,2)=8+10=18< D(2)=18 şi T(2)=6


D(6)+A(6,3)=8+11=19>13D(3)=13.
D(6)+A(6,4)=8+17=25< D(4)=25 şi T(4)=6.
D(6)+A(6,5)=8+7=15<16 D(5)=15 şi T(5)=6.

D 0 13 15 8
18 25

S 1 0 0 0 0 1

T 0 6 1 6 6 1

Se selectează nodul 3.
D(3)+A(3,2)=13+>18D(2)=18.
D(3)+A(3,4)=13+14=27>25D(3)=13.
D(3)+A(3,5)=13+>15D(5)=15.

D 0 8
18 13 25 15

S 1 0 1 0 0 1

T 0 6 1 6 6 1

Se selectează nodul 5.
D(5)+A(5,2)=15+>18D(2)=18.
D(5)+A(5,4)=15+5=20D(4)=20 şi T(4)=5.

D 0 8
18 13 20 15

S 1 0 1 0 1 1

T 0 6 1 5 6 1
Se selectează nodul 2.
D(2)+A(2,4)=18+6=24>20D(4)=20.

D 0 18 8
13 20 15

S 1 1 1 0 1 1

T 6 1 5 6 1
0

Se selectează nodul 4.
În continuare, pentru fiecare nod se trasează drumul de la nodul iniţial la el.
Vom considera, ca exemplu, nodul 4. Distanţa de la nodul 1 la el D(4) şi anume 20.
Avem T(4)=5; T(5)=6; T(6)=1; drumul trece prin nodurile 1,6,5.
Avem A(1,6)=8; A(6,5)=7; A(5,4)=5.Rezultă 8+5+7=20.
Întrucât drumul se trasează în ordine inversă faţă de cum este găsit, în program se foloseşte o procedură
recursivă.
În cele ce urmează vom nota nodurile cu Ni1,Ni2,…,Nin. Acestea sunt tot nodurile 1,2,…,R,…,N
cosiderate în altă ordine. Nodului R îi corespunde nodul Ni1.

Demonstrarea algoritmului.

Lema 1. Algoritmul selectează nodurile în ordinea costului drumului de la nodul iniţial la ele.

Demonstraţie:
Utilizăm metoda inducţiei matematice. Prima dată se selectează nodul Ni2 (are costul drumului minim faţă
de Ni1). Aceasta înseamnă că ipoteza de inducţie se verifică pentru prima selecţie. Presupunem că nu au
fost selectate nodurile Ni2,Ni3,…,Nip (p<n) în ordinea costului drumului de la Ni1 la ele. Se selectează
nodul Nip+1. Presupunem, prin absurd, că există un alt nod N1, neselectat, care are un cost al drumului de
la Ni1 la el mai scăzut decât al nodului Nip+1. Atunci, acesta poate fi plasat în şirul nodurilor deja selectate,
aşezate în ordinea distanţei faţă de Ni1, în următoarele două moduri:
1) Ni1,…,N1,…,Nip,Nip+1.
În acest caz, se contrazice ipoteza de inducţie (nodurile Ni1,…,Nip erau aşezate în ordine distanţei faţă de
Ni1).

2) Ni2,…, Nip,N1,Nip+1.
Aici este contrazisă alegerea lui Nip+1. Acesta a fost ales ca nod cu distanţă minimă faţă de Nil dintre toate
nodurile neselectate, iar N1 este un nod neselectat.

Lema 2. Orice drum optim de la nodul iniţial la oricare din nodurile selectate trece numai prin noduri
selectate.

Demonstraţie:
Presupunem prin absurd că există un drum de cost mai mic de la Ni1 la Nik (Nik este un nod deja selectat)
care nu trece numai prin noduri selectate. Fie Nz primul nod prin care trece acest drum şi care nu este
selectat. Aceasta înseamnă că nodul Nz are costul drumului de la Ni1 la el mai mic decât cel de la Ni1 la
Nik (nod care este selectat). Aceasta contrazice LEMA 1.

TEOREMĂ.
Odată selectat un nod, nu există un drum de cost mai mic între Ni1 şi el, decât drumul de cost indicat de
vectorul D.

Demonstraţie:
În demonstrarea acestui fapt utilizăm metoda inducţiei matematice.
Pentru selectarea lui Ni2 afirmaţia este evidentă, întrucât acesta este cel mai apropiat de Ni1.
Presupunem selectate nodurile Ni2,…,Nip. Selectăm Nip+1. Presupunem că de la Ni1 la el există un drum
de cost mai mic decât cel indicat de vectorul D.
Avem două posibilităţi:

1) Drumul de cost mai mic trece numai prin noduri selectate.


Analizăm modul de funcţionare a algoritmului până în acest moment.
La selecţia nodurilor Ni1,…,Nip s-au actualizat distanţele reţinute în vectorul D (pentru fiecare nod
neselectat s-a comparat vechea distanţă reţinută în D cu suma dintre distanţa de la Ni1 la nodul selectat şi
distanţa de la nodul selectat la nodul pentru care se face actualizarea, iar în cazul în care suma din urmă era
mai mică, aceasta era reţinută în vectorul D). În concluzie, nu există un drum mai scurt între Ni1 şi Nip+1
care trece numai prin noduri selectate.

2) Drumul de cost mai mic trece şi prin noduri neselectate.


În acest caz se contrazice LEMA 2.
// sa se implemeteze un program care aplica algoritmul DIJKSTRA
//pentru determinarea drumurilor de lungime minima
//nodul de plecare e 1
5
1 2 1
1 3 9
1 5 3
2 4 3
2 3 7
4 3 2
4 1 1
5 2 4
5 4 2
=>drumul minim de la 1 la 3 e 6 si trece prin nodurile 1 2 4 3
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;
const float Pinfinit=1.e20;
float A[50][50],D[50],min;
int S[50],T[50],n,I,j,r,poz;
void Citire_cost (char Nume_fis[20],float A[50][50],int& n)
{
int I,j;
float c;
fstream f("graf.txt",ios::in);
f>>n;
for (I=1;I<=n;I++)
for (j=1;j<=n;j++)
if (I==j) A[I][j]=0;
else A[I][j]=Pinfinit;
while (f>>I>>j>>c) A[I][j]=c;
f.close();
}

void drum(int I)
{
if (T[I]) drum(T[I]);
cout<<I<<" ";
}
main()
{ float min;
Citire_cost("Graf.txt",A,n);
cout<<"Introduceti nodul de pornire "<<endl;
cout<<"r=";cin>>r;S[r]=1;
for (I=1;I<=n;I++)
{
D[I]=A[r][I];
if (I!=r)
if (D[I]<Pinfinit) T[I]=r;}
for (I=1;I<=n;I++)
{
min=Pinfinit;
for(j=1;j<=n;j++)
if (S[j]==0)
if (D[j]<min)
{
min=D[j];
poz=j;
}
S[poz]=1;
for (j=1;j<=n;j++)
if (S[j]==0)
if (D[j]>D[poz]+A[poz][j])
{
D[j]=D[poz]+A[poz][j];
T[j]=poz;
}
}
for (I=1;I<=n;I++)
if (I!=r)
if(T[I])
{
cout<<"distanta de la "<<r<<" la "<<I<<" este "<<D[I]<<endl;
drum(I);
cout<<endl;
}
else
cout<<"nu exista drum de la "<<r<<" la "<<I<<endl;
}

Algoritmul Roy Floyd


Fiind dat un graf prin matricea ponderilor sa se calculeze drumul (lungimea lui adica
suma costurilor) minim de la orice doua noduri din graf.
matricea ponderilor este
0 1 9 ω 3
ω 0 7 3 ω
ω ω 0 ω ω
1 ω 2 0 ω
ω 4 ω 2 0

Etapa 1)Caut drumurile optime intre oricare doua noduri dar drumurile trec prin nodul
intermediar 1
a[4,2]= ω >a[4,1]+a[1,2]=1+1=2 deci a[4,2]=2
a[4,5]=ω>a[4,1]+a[1,5]=1+3=4 deci a[4,5]=4
matricea ponderilor este

0 1 9 ω 3
ω 0 7 3 ω
ω ω 0 ω ω
1 2 2 0 4
ω 4 ω 2 0
Etapa 2)Caut drumurile optime intre oricare doua noduri dar drumurile trec prin nodul
intermediar 2
a[1,3]=9>a[1,2]+a[2,3]=1+7=8 deci a[1,3]=8
a[1,4]=ω>a[1,2]+a[2,4]=1+3=4 deci a[1,4]=4
a[5,3]=ω>a[1,2]+a[2,3]=4+7=11 deci a[5,3]=11
a[5,4]=ω>a[5,2]+a[2,4]=4+3=7 deci neschimbat

matricea ponderilor este


0 1 8 4 3
ω 0 7 3 ω
ω ω 0 ω ω
1 2 2 0 4
ω 4 11 2 0

Etapa 3)Caut drumurile optime intre oricare doua noduri dar drumurile trec prin nodul
intermediar 3 dar nu avem nimic nou.
Etapa 4)Caut drumurile optime intre oricare doua noduri dar drumurile trec prin nodul
intermediar 4
a[1,3]=ω>a[1,4]+a[4,3]=4+2=6 deci a[1,3]=6
a[2,1]=ω>a[2,4]+a[4,1]=3+1=4 deci a[2,1]=4
a[2,3]=ω>a[2,4]+a[4,3]=3+2=5 deci a[2,3]=5
a[2,5]=ω>a[2,4]+a[4,5]=3+4=7 deci a[2,5]=7
a[5,1]=ω>a[5,4]+a[4,1]=2+1=3 deci a[5,1]=3
a[5,3]=ω>a[5,4]+a[4,3]=2+2=4 deci a[5,3]=4

01 6 4 3
4 0 5 3 7
ω ω 0 ω ω
1 2 2 0 4
3 4 4 2 0
// sa se implemeteze un program care aplica algoritmul Roy Floyd
5
1 2 1
1 3 9
1 5 3
2 4 3
2 3 7
4 3 2
4 1 1
5 2 4
5 4 2
=>5 4 1 2
are lungimea 4
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;
const float Pinfinit=1.e20;
float minfinit=-1.e20;
float A[50][50];
int n;
void Citire_cost (char Nume_fis[20],float A[50][50],int& n)
{
int I,j;
float c;
fstream f("graf.txt",ios::in);
f>>n;
for (I=1;I<=n;I++)
for (j=1;j<=n;j++)
if (I==j) A[I][j]=0;
else A[I][j]=Pinfinit;
while (f>>I>>j>>c) A[I][j]=c;
f.close();
}

void Drum(int I, int j)


{
int k=1,gasit=0;
while ( (k<=n) && (!gasit ))
{
if ( (I!=k) && (j!=k) && (A[I][j]==A[I][k]+A[k][j]) )
{
Drum(I,k);Drum(k,j);
gasit=1;
}
k++;
}
if (!gasit) cout<<j<<" ";
}

void Scriu_drum(int Nod_Initial, int Nod_Final)


{
if (A[Nod_Initial][Nod_Final]<Pinfinit)
{
cout<<"Drumul de la "<<Nod_Initial<<" la "<<Nod_Final<<" are
lungimea "<<A[Nod_Initial][Nod_Final]<<endl;
cout<<Nod_Initial<<" ";
Drum(Nod_Initial,Nod_Final);
}
else
cout<<"Nu exista drum de la "<<Nod_Initial<<" la "<<Nod_Final;
}
void Lungime_Drumuri()
{
int I,j,k;
for (k=1;k<=n;k++)
for(I=1;I<=n;I++)
for (j=1;j<=n;j++)
if (A[I][j]>A[I][k]+A[k][j])
A[I][j]=A[I][k]+A[k][j];
}
main()
{
Citire_cost("graf.txt",A,n);
Lungime_Drumuri();
Scriu_drum(5,2);
}
// sa se implemeteze un program care aplica algoritmul Roy Floyd
//pentru determinarea drumurilor de lungime maxima
//sa nu avem circuite
5
1 2 1
1 3 9
1 5 3
2 4 3
2 3 7
4 3 2
4 1 1
5 2 4
5 4 2

=>are lungimea 27
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;
const float Minfinit=-1.e20;
float A[50][50];
int n;

void Citire_cost1(char Nume_fis[20], float A[50][50], int& n)


{
int I,j;
float c;
fstream f(Nume_fis,ios::in);
f>>n;
for (I=1;I<=n;I++)
for (j=1;j<=n;j++)
if (I==j) A[I][j]=0;
else A[I][j]=Minfinit;
while (f>>I>>j>>c) A[I][j]=c;
f.close();
}

void Drum(int I, int j)


{
int k=1,gasit=0;
while ( (k<=n) && (!gasit ))
{
if ( (I!=k) && (j!=k) && (A[I][j]==A[I][k]+A[k][j]) )
{
Drum(I,k);Drum(k,j);
gasit=1;
}
k++;
}
if (!gasit) cout<<j<<" ";
}

void Scriu_drum(int Nod_Initial, int Nod_Final)


{
if (A[Nod_Initial][Nod_Final]>Minfinit)
{
cout<<"Drumul de la "<<Nod_Initial<<" la "<<Nod_Final<<" are
lungimea "<<A[Nod_Initial][Nod_Final]<<endl;
cout<<Nod_Initial<<" ";
Drum(Nod_Initial,Nod_Final);
}
else
cout<<"Nu exista drum de la "<<Nod_Initial<<" la "<<Nod_Final;
}
void Lungime_Drumuri()
{
int I,j,k;
for (k=1;k<=n;k++)
for(I=1;I<=n;I++)
for (j=1;j<=n;j++)
if (A[I][j]<A[I][k]+A[k][j])
A[I][j]=A[I][k]+A[k][j];
}
main()
{
Citire_cost1("graf.txt",A,n);
Lungime_Drumuri();
Scriu_drum(1,2);
}

Grafuri neorientate
Notiuni introductive
Grafuri neorientate
Definiţie. Se numeşte graf neorientat o pereche ordonată de mulţimi (X, U), X fiind o mulţime
finită şi nevidă de elemente numite noduri sau vârfuri, iar U o mulţime de perechi neordonate
( submulţimi cu două elemente) din X, numite muchii.
Ex.

2 6
1 +8
3
5

7
4
Fig.1

Pentru graful de mai sus avem:


X={1, 2, 3, 4, 5, 6, 7, 8}
U={[1,2], [1,4], [1,5], [2,3], [2,5], [3,4], [6,7]}
Dacă u1 şi u2 sunt două muchii care au o extremitate comună ele se vor numi adiacente.
Definiţie. Un graf parţial al grafului G=(X,U) este un graf G 1=(X,V) astfel încât VU, adică G1
are aceeaşi mulţime de vârfuri ca G iar mulţimea de muchii V este chiar U sau o submulţime a acesteia.
Ex. Mai jos avem un graf parţial al grafului de mai sus (Fig.1)
6
2 +8
1
3
5

7
4
Fig.2

Cu alte cuvinte, un graf parţial al unui graf se obţine păstrând aceeaşi mulţime de vârfuri şi
eliminând o parte din muchii.
Definiţie. Un subgraf al unui graf G=(X,U) este un graf H=(Y,V) astfel încât Y  X iar V conţine
toate muchiile din U care au ambele extremităţi în Y. Vom spune că subgraful H este indus sau generat
de mulţimea de vârfuri Y.
Ex. Mai jos avem un subgraf al grafului din Fig.1 obţinut prin eliminarea nodului 3

2 6
+8
1
5

7
4
Definiţie. Gradul unui vârf x este numărul muchiilor incidente cu x.
Gradul vârfului x se notează cu d(x).
Ex. în Fig.1 d(1)=3, d(4)=2, d(8)=0, d(6)=1
Un vârf care are gradul 0 se numeşte vârf izolat.
Un vârf care are gradul 1 se numeşte vârf terminal.
Propoziţia 1. Dacă un graf G=(X,U) are m muchii şi n vârfuri iar X={x 1,x2,..,xn}, atunci
d(x1)+d(x2)+...+d(xn)=2m.
Corolar. În orice graf G există un număr par de vârfuri de grad impar.
Definiţie. Se numeşte graf complet cu n vârfuri un graf care are proprietatea că orice două
noduri diferite sunt adiacente.
Propoziţia 2. Un graf complet Kn are n(n-1)/2 muchii.
Definiţie. Un graf G=(X,U) se numeşte bipartit dacă există două mulţimi nevide A, B astfel
încât X=A U B, A  B = şi orice muchie u a lui G are o extremitate în A iar cealaltă în B.
Definiţie. Un graf bipartit se numeşte complet dacă pentru orice x din A şi orice y din B, există
în G muchia [x,y].
Definitie.Un graf partial al unui graf neorientat dat G=(X,G) este un graf G1=(X,g1 unde G1 inclus
sau=cu G.
Definitie.Un subgraf al unui graf neorientat G=(X,g) este un graf H=(Y<G1), unde Y inclus in X, iar
muchiile din G1 sunt toate muchiile din G care au ambele extremitati in multimea Y.
Definitie.Lant.Pentru graful neorientat , un lant este o succesiune de varfuri cu proprietatea ca oricare
doua varfuri sunt adiacente.

Graf complet si bipartit

Se numeste graf complet cu n varfuri , notat Kn , un graf G=(X,U) cu proprietatea ca oricare doua
varfuri sunt adiacente adica :
() x,y є x → ca exista muchia [x,y] apartine de U
Teorema:
Un graf complet cu n varfuri , are n(n-1)/2 muchii.
Definitia :
Se numeste graf bipatrat ,un graf G=(X,U) cu propietate ca exista doua multimi A si B incluse in X,
astfel incat :
-A ∩ B=Ø ,A U B=X,
-toate muchiile grafului au o extremitate in A si cealalta in B .
Definitie :
Se numeste graf bipatrat complet, un graf bipatrat cu propietatea ca pentru orice varf x din A si orice
varf y din B,exista muchia (x,y) (unde A si B sunt cele doua submultimi care partitioneaza miltimea
varfurilor X).

Notiunea de lant si ciclu

Definitie :
Se numeste lant in graful G ,o succesiune de varfuri (z1, z2,z3 ,….zk),unde x1,x2,…,xk apartine de X ,
cu propietatea ca oricare doua varfuri consecutive sunt adiacente ,adica exista muchiile [z1, z2],[z2 ,z3],
….,[zk-1,zk] apartine de U.
Varfurile z1 si zk se numesc extremitatile lantului ,iar numarul de muchii care intra in componenta sa
reprezinta lungimea lantului .
Definitie :
Se numeste ciclu intr-un graf ,un lant L=(z1,z2,….zk) cu propietatea ca z1=zk si muchiile [z1,z2 ],
[z2,z3], ….,[zk-1,zk] sunt disticte doua cate doua.
Daca intr-un ciclu , toate varfurile cu exceptia primului si a ultimului sunt disticte doua cate
doua ,atunci
ciclul se numeste elementar .In contrar, el este neelementar.
CONEXITATE

Fie G=(X, U) un graf neorientat, X={x1, x2, ..., x2}.


Definiţie. Se numeşte lanţ în G succesiunea de vârfuri L={x i1, xi2,..., xik} cu proprietatea că orice două
noduri consecutive din L sunt adiacente, adică [xi1, xi2], [xi2, xi3],..., [xik-1, xik]  U.
Dacă vârfurile xi1, xi2,..., xik sunt diferite două câte două atunci lanţul se numeşte elementar. În caz
contrar, lanţul este neelementar.
1 2 5

8
7

3 4 6

Ex. L1=[1,2,4] – lanţ elementar


L2=[1,2,3,1,2,4] – lanţ neelementar
Definiţie. Se numeşte ciclu în G un lanţ L pentru care x i1=xik şi toate muchiile adică [x i1, xi2], [xi2, xi3],...,
[xik-1, xik] sunt diferite două câte două.
Ex. C=[1,2,3,1] este un ciclu.
Definiţie. Se numeşte ciclu elementar un ciclu care are proprietatea că oricare două vârfuri ale sale,
cu excepţia primului şi ultimului, sunt diferite două câte două.
Ex. C1=[1,2,3,1] este ciclu elementar.
C2=[3,1,2,4,8,2,3] este un ciclu neelementar.
Definiţie. Un graf G se numeşte conex dacă pentru orice două vârfuri x şi y diferite ale sale există un
lanţ care le leagă.
Definiţie. Se numeşte componentă conexă a grafului G=(X, U) un subgraf C=(X 1, U1), conex, a lui G
care are proprietatea că nu există nici un lanţ în G care să lege un vârf din X 1 cu un vârf din X-X1.

Un graf G este conex , daca oricare ar fi doua varfuri ale sale ,exista un lant care le leaga.
Definitie:

Se numeste componenta conexa a grafului G=(X,U),un subgraf G1=(X1,U1) a lui G ,conex ,


cu propietatea ca nu exista nici un lant care sa lege un nod din X1 cu un nod din X-X1(pentru orice nod ,
nu exista un lant intre acel nod si nodurile care nu fac parte din subgraf).
Definitie.Daca multimea G are proprietatea de simetrie, graful se numeste neorientat.
Definitie.Un graf partial al unui graf neorientat dat G=(X,g) este un graf G1=(X,g1
unde g1 submultime a lui g.
Definitie.Un subgraf al unui graf neorientat G=(X,g) este un graf H=(Y,g1), unde
Yinclus in X, iar muchiile din g1 sunt toate muchiile din g care au ambele extremitati
in multimea Y.
Definitie.Lant.Pentru graful neorientat , un lant este o succesiune de varfuri cu
proprieatea ca oricare doua varfuri sunt adiacente.

// sa se implemeteze un program care determina componentele conexe


// la un graf neorientat
5
1 2
1 3
4 5
=>componenta 1
1 2 3
coponenta 2
4 5

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

int S[50],A[50][50],n,I,k;

void CitireN (char Nume_fis[20],int A[50][50],int& n)


{
int I,j;
fstream f(Nume_fis,ios::in);
f>>n;
while (f>>I>>j)A[I][j]=A[j][I]=1;
f.close();
}

void df_r(int nod)


{
int k;
cout<<nod<<" "; S[nod]=1;
for (k=1;k<=n;k++)
if ( (A[nod][k]==1)&& (S[k]==0) ) df_r(k);
}
main()
{

CitireN("graf.txt",A,n);
k=1;
for (I=1;I<=n;I++)
if (S[I]==0)
{
cout<<"componenta "<<k<<endl;
df_r(I);

195
cout<<endl;
k++;
}
}
Grafuri hamiltoniene
Definitie:
Se numeste ciclu hamiltonian intr-un graf, un ciclu elementar care contine toate varfurile grafului .
Se numeste graf hamiltonian ,un graf care contine un ciclu hamiltonian.
Se numeste lant hamiltonian intr-un graf, un lant elementar care contine toate varfurile grafului.
Teorema:
Daca intr-un graf G=(X,U) cu n>=3 varfuri, gradul fiecarui varf x verifica conditia d(x)>=n/2, atuncigraful este
hamiltonian,

// sa se implemeteze un program care determina un ciclu hamiltonian


intr-un graf si care e
9
1 2
1 4
2 4
2 3
2 5
3 4
3 9
3 8
4 6
5 6
5 7
5 8
7 8
7 5
8 9
=>1 2 3 9 8 7 5 6 4 ca ciclu hamiltonian
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

int st[50],a[50][50],n,k;
void CitireN (char Nume_fis[20],int A[50][50],int& n)
{
int I,j;
fstream f(Nume_fis,ios::in);
f>>n;
while (f>>I>>j)A[I][j]=A[j][I]=1;
f.close();
}

void Init()
{ st[k]=1; }
int AmSuccesor ()
{ if (st[k]<n)
{ st[k]++;
return 1;
}
else return 0;

196
}
int E_Valid()
{ if (!a[st[k-1]][st[k]]) return 0;
else
for (int I=1;I<=k-1;I++)
if (st[I]==st[k]) return 0;
if (k==n && !a[1][st[k]]) return 0;
return 1;
}
int Solutie()
{ return k==n;}
void Tipar()
{ for (int I=1;I<=n;I++) cout<<"Nodul "<<st[I]<<endl;
k=0;
}
void back()
{ int AS;
k=2; Init();
while (k>1)
{ do {} while ((AS=AmSuccesor ()) && !E_Valid());
if (AS)
if (Solutie()) Tipar();
else {k++;Init();}
else k--;
}
}
main () { st[1]=1;k=2;st[k]=1;
CitireN("graf.txt",a,n);
back();
}

Grafuri euleriene
Definitie.Un graf care contine un ciclu eulerian se numeste eulerian.
Un lant L al unui graf G care contine fiecare muchie o data si numai o data se numeste lant
eulerian;
Daca x0=xp si lantul e eulerian atunci ciclul se numeste ciclu eulerian;

// sa se implemeteze un program care determina un ciclu eulerian


intr-un graf si care e
9
1 2
1 4
2 4
2 3
2 5
3 4
3 9
3 8
4 6

197
5 6
5 7
5 8
7 8
7 5
8 9
=>1 2 4 6 5 7 8 3 9 8 5 2 3 4 1 ca ciclu eulerian
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;
struct Nod
{
int nd;
Nod* adr_urm;
};

int A[50][50],S[50],n;
Nod* Alista, *Indice;

void CitireN (char Nume_fis[20],int A[50][50],int& n)


{
int I,j;
fstream f(Nume_fis,ios::in);
f>>n;
while (f>>I>>j)A[I][j]=A[j][I]=1;
f.close();
}
void ciclu(Nod* v)
{int Nodul;
Nod *ANod_baza,*ANod_gasit,*ANod_urm;
ANod_urm=v->adr_urm;
ANod_baza=v;
do
{
Nodul=1;
while (A[ANod_baza->nd][Nodul]==0) Nodul++;
A[ANod_baza->nd][Nodul]=0;A[Nodul][ANod_baza->nd]=0;
ANod_gasit=new Nod; ANod_gasit->nd=Nodul;
ANod_gasit->adr_urm=0;
ANod_baza->adr_urm=ANod_gasit;ANod_baza=ANod_gasit;
} while (ANod_gasit->nd!=v->nd);
ANod_baza->adr_urm=ANod_urm;
}
int adauga()
{
int I,gasit=0;
Indice=Alista;
while (Indice && !gasit)
{
for (I=1;I<=n;I++)
if (A[Indice->nd][I]==1) gasit=1;
if (!gasit) Indice=Indice->adr_urm;
}
if (Indice)
{
ciclu (Indice);
return 1;
}

198
else return 0;
}
int grade_pare()
{
int I=1,j,s,gasit=0;
while ( (I<=n) && ! gasit)
{
s=0;
for (j=1;j<=n;j++) s+=A[I][j];
if (s%2) gasit=1;
I++;
}
return !gasit;
}
void df(int nod)
{
int k;
S[nod]=1;
for (k=1;k<=n;k++)
if ( (A[nod][k]==1) && (S[k]==0)) df(k);
}
int conex()
{
int gasit=0,I;
df(1);
for (I=1;I<=n;I++)
if (S[I]==0) gasit=1;
return !gasit;
}
main()
{ CitireN("Graf.txt",A,n);
if (conex())
if (grade_pare())
{
Alista=new Nod;
Alista->nd=1;Alista->adr_urm=0;
while (adauga());
Indice=Alista;
while (Indice)
{ cout<<Indice->nd<<" ";
Indice=Indice->adr_urm;
}
}
else cout <<"Graful nu indeplineste conditiile de paritate";
else cout<<"Graful nu este conex";
}

199
Flux intr-o retea de transport

O retea de transport este un graf orientat G=(V,E) care satisface urmatoarele


conditii:
a) exista un unic varf s apartine V in care nu intra nici un
arc(gradul interior 0) numit sursa;
b) exista un unic varf d apartine V in care nu iese nici un
arc(gradul exterior 0);
c) pentru fiecare nod x apartine V-(s,d)exista cel putin un drum de
la sursa la destinatie;cu alte cuvinte graful G este conex;
d) pe multimea arcelor se defineste o functie c:E->R+,numita functie
de capacitate;
Algoritmul se executa intr-un nr finit de pasi.in cadrul surselor prezentate
in continuare determinare drumului de crestere din graful rezidual asociat se
realizeaza printr-o parcurgere BF a acestuia.

// sa se implemeteze un program care determina algoritmul lui


Ford //Furkerson
7
1 7
1 4 6
1 2 1
2 3 8
2 5 4
3 4 3
5 6 5
6 7 8
3 7 1
=>1 2 3 7 dat prin matricea de adiacenta ca fiind de cost minim
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
using namespace std;

200
struct Nod
{
int nd;
Nod* adr_urm;
};

void Citire_Cap(char Nume_fis[20],int A[50][50][2],int& n,int&


st,int& fin)
{
int I,j, cost;
fstream f(Nume_fis,ios::in);
f>>n>>st>>fin;
while (f>>I>>j>>cost)A[I][j][0]=cost;
f.close();
}
int A[50][50]
[2],n,st,fin,gasit,coada[50],s[50],f[50],I_c,sf_c,I,j,min;
void refac(int Nod)
{int min;
if (Nod!=st)
if (s[Nod]>0)
{
if (min>(A[s[Nod]][Nod][0]-A[s[Nod]][Nod][1]))
min=A[s[Nod]][Nod][0]-A[s[Nod]][Nod][1];
refac(s[Nod]);
A[s[Nod]][Nod][1]+=min;
}
else
{
if (min>A[Nod][s[abs(Nod)]][1])
min=A[Nod][abs(s[Nod])][1];
refac(abs(s[Nod]));
A[Nod][abs(s[Nod])][1]-=min;
}
}
void drum_in_crestere()
{
gasit=0;
I_c=sf_c=1;coada[I_c]=st;
while( (I_c<=sf_c) && (coada[sf_c]!=fin) )
{
I=1;
while ( (I<=n) && !gasit)
{
if ((A[coada[I_c]][I][0]-A[coada[I_c]][I][1]>0) && (s[I]==0))
{
s[I]=coada[I_c];coada[++sf_c]=I;
}
else
if ((A[I][coada[I_c]][1]>0) && (s[I]==0) && (I!=st) )
{
s[I]=-coada[I_c];coada[++sf_c]=I;
}
I++;
}
I_c++;
}
if (coada[sf_c]==fin) gasit=1;
}
void caut()
{int min;

201
do
{
for (I=1;I<=n;I++)s[I]=0;
drum_in_crestere();
if (s[fin])
{
min=32000;
refac(fin);
}
} while (gasit);
}
main()
{
Citire_Cap("Graf.txt",A,n,st,fin);
caut();
for (I=1;I<=n;I++)
{
for (j=1;j<=n;j++) cout <<A[I][j][1]<<" ";
cout<<endl;
}
}

Arbori
Noţiunea de arbore

Definiţie. Se numeşte arbore un graf orientat care este conex si nu conţine cicluri.

Problema. Se citeşte un graf sa se scrie un program care sa verifice daca este arbore.

1. Mai întâi trebuie văzut daca graful este conex. In cazul grafurilor orientate aceasta problema se rezolva printr-o
simpla parcurgere in adâncime (DF). Dar in cazul grafurilor neorientate? Aici apare o problema. De la nodul i la
nodul j exista doua arce, de la i la j si de la j la i. Aceasta conduce la semnalarea unui ciclu fals. Pentru rezolvarea,
după alegerea unei muchii ,de exemplu de la i la j se elimina muchia de la j la i. In final daca au fost atinse toate
nodurile(adică daca orice componenta a vectorului s retine numai 1) înseamnă ca graful este conex.

2. Trebuie analizat daca graful nu are cicluri. Aceasta problema se rezolva tot cu ajutorul parcurgerii in adâncime.
Parcurgerea asigura selecţia unei muchi o singura data. Daca graful are cel puţin un ciclu, atunci un nod este atins
de doua ori. Cum ne putem da seama ca aceasta are loc? simplu, daca a fost atins un nod i , după care s[i]=1.

//exemplu de determinare averificarii daca un graf este arbore

//4
//1 2
//1 4
//2 3
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >

202
int A[50][50],S[50],n,i,suma,gasit;

void CitireN (char Nume_fis[20],int A[50][50],int& n)


{
int I,j;
fstream f(Nume_fis,ios::in);
f>>n;
while (f>>I>>j)A[I][j]=A[j][I]=1;
f.close();
}
void df_r(int nod)
{
int k;
S[nod]=1;
for (k=1;k<=n;k++)
if (A[nod][k]==1)
{
A[k][nod]=0;
if (S[k]==0) df_r(k);
else gasit=1;
}
}
main()
{

CitireN("graf.txt",A,n);
df_r(1);
suma=0;
for (i=1;i<=n;i++)
suma+=S[i];
if (suma!=n) cout<<"e conex"<<endl;
else
if (gasit) cout<<"are un ciclu macar"<<endl;
else cout<<"este arbore";
}
Mai jos este reprezentat grafic acelasi arbore in mai multe feluri. Ultimele 3 reprezentări sunt făcute
considerând pe rând ca vârf al arborelui nodurile 1,3,2. de asemenea ultimele trei reprezentări justifica
si denumirea data grafurilor conexe si fara cicluri, cea de arbori.

203
Teorema. Fie G un graf neorientat cu n noduri. G este arbore daca si numai daca g are n-1 muchii si nu
contine cicluri.

Demonstraţie :

 Vom demonstra prin inducţie. Daca n=1,numarul muchiilor este 0(se verifica). Vom presupune
proprietatea adevărata pentru arbori cu n noduri(vom avea n-1 muchii). Fie un arbore cu n+1 noduri.
Exista cel putin un nod terminal(nod care are o singura muchie incident). Daca nu ar exista un astfel de
nod, arborele va contine cicluri(se contrazice definiţia). Eliminam nodul terminal si muchia care ii este
incident. Obţinem un arbore cu n noduri. Conform ipotezei făcute aceasta va avea n-1 muchii.
Înseamnă ca arborele cu n+1 noduri va avea n muchii(n- 1 +1).

 Fie un graf cu n-1 muchii care nu contine cicluri. Rămâne de dovedit ca G este conex. Vom
demonstra prin reducere la absurd. Presupunem ca G nu este conex. Fie G 1, G2, .. ,Gp componentele
conexe. Fiecare dintre ele indeplineste conditiile:

1) Este conexa(asa a fost aleasa);


2) Nu contine cicluri(pentru ca G nu contine cicluri).

Rezulta ca fiecare dintre ele este arbore. Fie mi numarul muchiilor si ni numarul nodurilor fiecarui arbore
Gi. Avem mi=ni-1. Dar m1+m2+….+mp=n-1. Rezulta: n1-1+n2-1+…..np-1=n-1, deci n1+n2+…..+np=n+p-1.
Dar G are n noduri. Rezulta :n+p-1=n,deci p=1. In concluzie exista o singura componenta conexa care
nu contine cicluri. Deci G este arbore.

 Din demonsratie s-a vazut ca un graf neorientat fara cicluri


dar neconex este alcătuit, din mai mulţi arbori. Din acest
motiv, un astfel de graf se numeşte pădure !
 Tot in aceasta demonstatie, a fost introdus termenul de nod terminal al unui arbore cu
o singura muchie incident.

 Ati reţinut, ca arborele poate fi privit ca avand un anumit varf ! Varf al arborelui poate
fi oricare nod al sau, deci si unul termial !

204
Algoritmul lui Prim

Fie G=(X,) un graf neorientat şi conex. Graful este dat prin matricea costurilor. Se cere să se
determine arborele de cost parţial minim (între oricare două noduri să existe un drum), iar în plus suma
muchiilor să fie minimă.
O problemă concretă, în care intervine problema enunţată, este cea a conectării oraşelor cu
cost minim.
Avem N oraşe precum şi costul conectării anumitor perechi de oraşe. Se cere să se genereze
muchii care asigură existenţa unui drum între oricare două oraşe astfel încât costul cuplării să fie
minim.
Pentru rezolvare se folosesc trei vectori:
-vectorul S, vector caracteristic. Avem S(I)=0 dacă nodul I nu aparţine arborelui construit şi
S(I)=1 în caz contrar;
-vectorul T reţine pentru fiecare nod care se adaugă arborelui nodul părinte al acestuia (cu
ajutorul acestui vector se poate reconstitui arborele);
-vectorul P reţine pentru fiecare nod C costul arcului de la părinte la el.

Prezentarea algoritmului.

P1) Se citeşte N (numărul nodurilor), matricea costurilor A şi nodul de pornire V (S(V)=1);

P2) Se alege muchia de cost minim (L,C) care are o extremitate într-unul din nodurile
arborelui deja construit (S(L)=1), iar cealălaltă într-un nod care nu aparţine arborelui (S(C)=0). Se pune
T(C)=L şi P(C)=A(L,C);

P3) Dacă nu au fost alese N-1 muchii, se reia pasul 2.

Exemplu. Fie graful din figura următoare: (s=(0 1 1 1 1) )

3 2

5 2

205
2 1 5

4 3

4
Se porneşte cu nodul 1(v=1).
Alegem muchia de cost minim (1,2).
S=(0 0 2 2 1)

Pentru nodurile 1 şi 2, ca puncte de plecare, se alege muchia de cost


minim (2,4) si s=(0 0 4 0 1)

1
4

Pentru nodurile 1,2 şi 4 se alege muchia de cost minim (1,5).


S=(0 0 4 0 0)

2 3
5

206

41
2 5
Pentru nodurile 1,2,4 şi 5 se alege muchia de cost minim (4,3) .

1
3
2

4
3

s=(0 0 0 0 0)
Am ales patru muchii şi s-a obţinut muchia de cost minim.
Configuraţiile finale ale vectorilor T şi P sunt:

1 2 3 4 5
T 0 1 4 2 1
P 0 2 4 1 3

Dacă pornim dintr-un alt nod, este posibil să obţinem un alt arbore dar şi el va avea costul
minim.

Demonstrarea algoritmului.

În urma aplicării algoritmului se obţine un arbore (vom avea N noduri şi N-1 muchii).
Rămâne de demonstrat că acest arbore este de cost minim. Notăm cu Gk=(Xk,k) arborele
obţinut după alegerea a k muchii, cu k{1,2,…,N-1}. Fie G1 un arbore de cost minim. Fie M1,M2,
…,Mk primele k muchii găsite în urma aplicării algoritmului pentru arborele Gk+1. Considerăm că
muchia Mk este prima muchie care nu aparţine lui G1. Fie P şi Q cele două noduri unite de muchia Mk.
Este evident că în G1, cele două nu sunt unite direct (în caz contrar muchia Mk ar face parte din arborele
G1). Aceasta înseamnă că în G1, nodurile P şi Q sunt unite printr-un lanţ. Acest lanţ nu aparţine lui G k+1,
pentru că el împreună cu Mk ar forma un ciclu. Înseamnă că acest lanţ uneşte în G1 două noduri, P1 şi
Q1 cu P1Xk şi Q1Xk. În caz contrar dacă ar uni numai noduri din Xk înseamnă că Gkm ar conţine un
lanţ (conţine muchia Mk, care uneşte pe P şi Q, conţine şi restul lanţului din G1 pentru că primele k
noduri în G1 şi Gk sunt legate identic). Presupunem nodurile P1 şi Q1 unite prin muchia M1. Înlocuim
în G1 pe M1 cu Mk. În urma acestei înlocuiri,G1 se transformă într-un alt arbore G2. Dar
A(P,Q)A(P1,Q1) pentru că în caz contrar, prin logica algoritmului, s-ar fi ales muchia M1. Aceasta
înseamnă că arborele parţial G2 rămâne tot de cost minim. În plus G1 şi Gk+1 au k+1 muchii care
coincid. Repetăm procedeul până obţinem coincidenţa a n-1 muchii. Rezultă de aici că l-am
transformat pe G1 în arborele generat de algoritm fără a-i modifica costul. În concluzie arborele generat
de algoritm este de cost minim.

207
//algoritmul lui Prim
5
122
153
142
255
241
237
344
327
454
412
421
434
531
544
525
513
=>cost 10
0 1 4 2 1 e traseul
//
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >
const float Pinfinit=1.e20;
float A[50][50],min,cost;
int s[50],t[50],n,i,j,k,v;

void Citire_cost (char Nume_fis[20],float A[50][50],int& n)


{
int I,j;
float c;
fstream f("graf.txt",ios::in);
f>>n;
for (I=1;I<=n;I++)
for (j=1;j<=n;j++)
if (I==j) A[I][j]=0;
else A[I][j]=Pinfinit;
while (f>>I>>j>>c) A[I][j]=c;
f.close();
}

void main( )
{
cost=0;
Citire_cost("graf.txt",A,n);
cout<<"nodul de pornire";
cin>>v;
for (i=1;i<=n;i++)

208
if (i==v) s[i]=0;
else s[i]=v;
for (k=1;k<=n-1;k++)
{
float min=Pinfinit;
for (i=1;i<=n;i++)
if (s[i])
if (A[s[i]][i]<min)
{
float min=A[s[i]][i];
j=i;
}
t[j]=s[j];
cost+=A[s[j]][j];
s[j]=0;
for (i=1;i<=n;i++)
if (s[i] && A[i][s[i]]>A[i][j]) s[i]=j;
}
cout<<"cost="<<cost<<endl;
for (i=1;i<=n;i++) cout<<t[i]<<" ";
}
Notiunea de arborescenta

Notiunea de arbore poate fii extinsa si pentru grafuri orientate.


Definitie. Fiind date doua noduri i si j ale unui graf orientat, se spune ca exista un lant de la i la j daca
exista o succesiune de arce, indiferent de sensul lor prin care cele doua noduri sunt unite.
 Daca exista un lant de de la i la j, exista si unul de la j la i.

Definitie. Un graf orientat G=(x,) exte conex daca  ijx


exista un lant de la i la j.

 Daca un graf orientat este tare conex, atunci el este conex, dar reciproca nu este
adevarata. Graful de mai sus este conex.
Definitie. Un graf orientat admite un ciclu daca exista un mod i, pentru care exista un lant de la i
la i.

Exemplu. In graful anterior nodurile 4 2 3 sunt unite printr-un ciclu.

Definitie. Un graf orientat este arbore daca nu este conex si nu admite cicluri.

Exemple:

209
1. Graful anterior nu este arbore pentru ca admite un ciclu.
2.

Definitie. Un graf orentat g=(x,) admite o radacina vx daca pentru orice xx-(v) exista un drum
(atnete, nu lant) de la v la x.

Exemple:

1. graful de mai sus nu admite o radacina. De exemplu nu exista drum de la 1 la 3


(1 nu este radacina), nu exista drum de la 3 la 4 (nici 3 nu este radacina) etc.

2. Graful alaturat are radacinile 1, 2, 3,4.

Definitie. Se numeste arborescenta un graf orientat care indeplineste simultant doua conditii :
1.Este arbore;
2.Admite radacina.

 Intr-o arborestenta radacina este unica. Daca de exemplu exista doua radacini v 1 si v2 atunci exista
drum de la v1 la v2 si de la v2 la v1. aceasta presupune existenta unui ciclu, deci nu este arbore.
 De regula, atunci cand se da o arborescenta se preciaza radacina sa.

Alaturat este prezentata o arborescenta de radacina 2.

210
 Se observa ca din radacina pleaca arce, nu intra. Daca ar si intra s-ar obtine un ciclu.

 de asemenea, orice nod are un singur predecesor. Daca, prin absurd, ar avea doi sau mai multi, s-ar
obtine un ciclu care include radacina.

Problema. Se citeste un graf orientat. Acesta este dat prin matricea de adiacenta.se cere ca programul
dv. sa decida daca graful este sau nu oarborescenta. In caz afirmativ, se va tipari radacina acesteia.

211
Rezolvare.

1. Tebuie decis mai intai daca graful orientat este arbore. Acesta se face printr-o singura
parcurgere in adancime,asemanator cu altgoriymul aplicat in cazul grafurilor orienta.
2. In cazul cand graful este arbore , trebuie vazut daca acesta are o radacina. Se testeaza, pe
rand, fiecare nod daca indeplineste conditia de radacina. Fiecare test se face printr-o
parcurgere in adancime pornind de la nodul respectiv.

//exemplu de determinare arborescenta

//4
//1 2
//1 4
//2 3
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >

int A[50][50],s[50],b[50][50],ok,radacina,n,i,j,r,suma,gasit;

void Citire(char Nume_fis[20],int a[50][50],int& n)


{
fstream f(Nume_fis,ios::in);
int I,j;
f>>n;
while (f>>I>>j) A[I][j]=1;
f.close();
}
void df_r(int nod)
{
int k;
cout<<nod<<" ";
s[nod]=1;
for (k=1;k<=n;k++)
if ((A[nod][k]==1) && (s[k]==0))
df_r(k);
}

main()
{
Citire("Graf.txt",A,n);
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
b[i][j]=A[i][j];
df_r(1);
for (i=1;i<=n;i++) suma+=s[i];
if (suma!=n) cout<<"NU e conex"<<endl;
else cout<<" e conex"<<endl;
if (gasit) cout<<"are un ciclu"<<endl;
else cout<<" nu are cicluri"<<endl;
if (suma==n && ! gasit)

212
{
cout<<"este arbore"<<endl;
ok=1;
}
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
b[i][j]=A[i][j];
if (ok)
{
r=1;
do
{
suma=0;
for (i=1;i<=n;i++) s[i]=0;
df_r(r);
for (i=1;i<=n;i++) suma+=s[i];
if (suma==n)
{
cout<<"radacina este "<<r<<endl<<"este arborescenta";
radacina=1;
}
else r++;
}
while (!radacina && r<=n);
if (!radacina) cout <<"nu are radacina";
}
}

Metode de memorare a arborilor

1. asa cum am aratat, un arbore este un graf neorientat, cu anumite proprietati.


Aceasta inseamna ca el poate fi reprezentat ca un graf. De aici rezulta ca pentru
reprezentarea unui arbore se pot utilza:

- matricea de adiacenta;
- liste de adiacente.
2. O a doua forma de reprezentare a arborilor este legatura de tip TATA . arborele se
reprezinta sub forma unui vector t cu n componente: daca t[i]=k, atunci nodul i
este descendent al nodului k. Daca nodul i este varf, t[i]=0.

5 3 5 5 0 3 4 1 7--------- k
1 2 3 4 5 6 7 8 9 --------- t[i]

 Legatura de tip TATA se mai numeste si legatura cu referinte ascendente.

213
 In mod evident, legatura de tip TATA este determinata si de nodul ales ca varf ! Daca, de exemplu
pentru acelasi arbor varful este 9, reprezentarea este alta. Este ca si cum „apucam” arborele de un nod
si celelalte cad !

 De fapt prin legatura de tip TATA se reprezinta o padure !

035003 417
123456789

 Aceasta reprezentare a mai fost intalnita. De exemplu, la altgoritmul lui Dijkstra !

3.Codul lui Puffer(facultativ). Pentru a reprezenta un arbore oarecare se pot utiliza doi vectori, pe care-i
vom numi t-de la nodul terminal – si pt – de la parinte nod terminal. Modul in care acestia retin datele
este explicat mai jos:

 Se cauta cel mai mic nod terminal, acesta este retinut in vectorul t iar parintele sau este
memorat in vectorul pt.
 Se obtine un nou arbore renuntand la nodul terminal si la muchia care-l uneste de parinte.
 Procedeul se rea pana cand ramane un arbore cu un singur nod.

Exemplu .

Pentru arborele alaturat cel mai mic nod terminal este doi,iar parintele trei.

In noul arbore ,cel mai mic nod terminal este 6, iar parintele lui 6 este 3.

214
Cel mai mic nod terminal este 3, iar parintele 5.

Cel mai mic nod terminal este 8, iar parintele sau este 1.

Cel mai mic nod terminal este 1, iar parintele sau este 5.

215
 Pana in acest moment am
memorat arborele prin utilizarea a 2 vectori t si pt. Fiecare dintre ei, are n-1 componente!

 Prin logica altgoritmului nodul care ramane este cel mai mare adica nodul n. Acesta este ultimul
memorat in vectorul pt.Prin urmare, daca se cunoaste n sunt suficiente n-2 componente pentru vectorul
pt.

 Foarte important! Vectorul t se poate reconstitui doar daca cunoastem vectorul pt. aceasta inseamna
ca un arbore cu n noduri a fost memorat doar printr-un vector cu n-2 componente!

Pentru reconstituirea vectorului t pornim de la pt,vom incepe prin a memora in pt, numarul n, pentru
componenta n-1. vectorul t se reconstituie prin formula:

i{1,2…n-1}
t[i]=min{kk{t[1]=t[2],…t[i-1],pt[i],pt[i+1]…pt[n-1]}}

Cum s-a dedus formula de mai sus?

- daca numarul se gaseste in pt[i],pt[i+1],…pt[n-1] inseamna ca nodul respectiv nu a fost eliminat pana
la pasul i, pentru ca este parinte.
- daca numarul se gaseste in t[1],t[2],…t[i-1] inseamna ca a fost extras la unul din pasii anteriori.
- dintre nodurile care nu se gasesc ca mai sus , la pasul i a fost extras nodul minim.

Exemplu. Plecam de la n=9,si pt={3 3 5 1 5 4 7 }


Pasul 1
T={}
Pt={3 3 5 1 5 4 7,9}
Cel mai mic numar care nu se gaseste in pt si este intre 1 si 9 este 2.

Pasul 2
T={2}
Pt={3 3 5 1 5 4 7,9}
Se alege 6.

Pasul 3.
T={2 6 }
Pt={3 3 5 1 5 4 7,9}
Se alege 8.

216
//exemplu la codul PUFFER
//n=9
//3 3 5 1 5 4 7 9
//=>2 6 3 8 1 5 4
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >

int t[50],pt[50],i,j,k,n,gasit;
main()
{
cout<<"n=";cin>>n;
for (i=1;i<=n-2;i++)
{
cout<<"PT["<<i<<"]";
cin>>pt[i];
}
pt[n-1]=n;k=1;
for (i=1;i<=n-1;i++)
{
k=1;
do
{
gasit=0;
for (j=0;j<=i-1;j++)
if (t[j]==k) gasit=1;
if (!gasit
)
for (j=i;j<=n-1;j++)
if (pt[j]==k) gasit=1;
if (gasit) k++;
} while (gasit);
t[i]=k;
}
for (i=1;i<=n-1;i++)
cout<<t[i]<<" ";
}

Arbori binari

Notiunea de arbore binar

217
Programatorii folosesc de multe ori prin abuz de limbaj, termenul de arbore, in loc de
arborescenta. In astfel de cazuri se specifica radacina care se mai numeste si varf si se considera
ca sensul arcelor este implicit,motiv pentru care nu se mai reprezinta grafic.

In cazul in care arborescenta are cel mult doi descendenti, unul stang si unul drept, spunem ca avem
un arbore binar.

Exemplu. Mai jos vedeti o arborescenta cu radacina 1 care este un arbore binar. Alaturat obs. Modul in
care se reprezinta grafic renuntand la sensurile arcelor, care sunt implicite.

218
 Se presupune ca nodurile sunt asezate pe mai multe niveluri. Radacina este pe
nivelul 0, descenndentii direci directi ai radacini sunt pe nivelul 1, descendentii directi
ai nodurilor de pe nivelul 1 sunt pe nivelul 2 etc.
 Numarul de niveluri mai putin cel al radacinii, ocupate de nodurile grafului,se numeste
adancimea arborelui binar.
 Vom face dinstinctie intre descendentul stang si cel drept. De exemplu, arborii de mai
jos sunt considerati dinstincti.

Modalitati de reprezentare a arborilor binari

Desigur, arborii binari pot fi reprezentati ca orice grf orientat, dar


aceasta forma este deosebit de greoaie in aplicatii. Din acest motiv sunt
cu mult mai convenabile reprezentarile pe care le urmarim in continuare.
1. reprezentarea cu ajutorul vectorilor ( clasica ).

219
Un arbore binar poate fi reprezentat cu ajutorul a doi vectori, pe care ii vom numi st (de la stanga ) si dr
(de la dreapta). Pentru fiecare nod i dintre cele n, st[i] retine nr. de ordine al nodului stang subordonat
de i, iar dr[i] retine nr de ordine al nodului drept subordonat de i. Daca nu exista nod subordonat retine
0.

Exemplu. Arborele binar cu 7 noduri si v=1 de pe pagina anterioara se reprezinta astfel:

st 2 4 5 0 0 0 0

1 2 3 4 5 6 7

dr 3 0 6 0 7 0 0

2. Reprezentarea in HEAP (actuala).

Programul va retine doar adresa radacinii (varfului). In aplicatii veti intalni numeroase exemple in acest
sens, motiv pentru care ne oprim aici cu aceasta reprezentare.

3. Reprezentarea cu ajutorul legaturii TATA.

Aceasta a mai fost prezentata in cazul arborilor neorientati. Mentionam doar faptul ca aceasta
reprezentare este neconvenabila in majoritatea aplicatiilor.

Modalitati de parcurgere a arborilor binari

In scopul prelucrarii,este necesar ca nodurile arborelui binar sa fie vizitate. Axista mai multe

modalitati de parcurgere a arborilor binari carer difera prin ordinea de vizitare a nodurilor.

220
 Putem considera ca fiecare nod al arborelui binar subordoneaza un subarbore
binar stang si unul drept. Pe baza acestei observatii putem scrie usor
subprograme recursive pentru diverse le modalitati de pacurgere.

Principalele modalitati de parcurgere ale unui arbore binar sunt:

A) Parcurgerea in inordine – SVD – se se patrcurge mai


intai subarborele stang, apoi varful apoi subarborele
drept.
B) Parcurgerea in preordine – VSD – se parcurge mai
intai subarborele stang, apoi subarborele drept.
C) Parcurgerea in postordine – SD – se parcurge mai
intai subarborele stang, apoi subarborele drept, apoi
varful.
D) Parcurgerea in adancime – a fost studiata pentru
grafuri, aici se aplica in particular. Se parcurge
radacina, apoi nodurile de pe nivelul 1,apoi cele de pe
nivelul 2 etc.

 De exemplu parcurgerea SDV se face pe urmatoarea idee: varful subordoneaza


doi subarbori: cel stang si cel drept. Se trece la subarborele stang, apoi la varf,
apoi la subarborele drept. Pentru fiecare subarbore se repeta rationamentul.

Ordinea de parcurgere pentru arborele alaturat este: inordine –SDV-:4 2 1 5 7 3 6

preordine –VSD-:1 2 4 3 5 7 6

postordine –SDV-:4 2 7 5 6 3 1

latime:1 2 3 4 5 6 7

221
Programul urmator citeste si parcurge in inordine,postordine si preordine
un arbore binar. Arborele este retinut in HEAP. Pentru a marca faptul ca
descendentul unui anumit nod lipseste se introduce 0.
//sa se testeze parcurgerile de arbori binari
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >

struct nod {
int nr ;
struct nod * st ;
struct nod * dr ;
} ;

nod * c;
nod* arb()
{
int n;
nod* c;
cout<<"n=";cin>>n;
if (n)
{
c=new nod;
c->nr=n;
c->st=arb();
c->dr=arb();
return c;
}
else
return 0;
}

void Preordine ( nod *a )


{
if ( a)
{
cout<< a -> nr ;
Preordine ( a -> st ) ;
Preordine ( a->dr ) ;
}
}
void Postordine ( nod *a )
{
if ( a )
{
Postordine (a -> st) ;
Postordine ( a -> dr ) ;
cout<< a -> nr ;

222
}
}
void Inordine ( nod *a )
{
if ( a)
{
Inordine (a -> st ) ;
cout<< a -> nr ;
Inordine ( a -> dr ) ;
}
}
void main( )
{
c=arb();
Inordine (c);cout<<endl;
Postordine (c); cout<<endl;
Preordine (c);cout<<endl;
}
Arbore binar de cautare
Definitie. Se numeste arbore de cautare un arbore binar ale carui noduri
au o cheie de identificare,iar pentru fiecare nod avem proprietatiile
urmatoare:
- orice cheie asociata unui nod al subbarborelui stang este mai mica decat cheia asociata
nodului;
- orice cheie asociata unui nod al subarborelui drept este mai mare decat cheia asociata
nodului.

Cheile de identificare sunt distincte !

Alaturat observati un arbore de cautare.

1. INSERAREA

Crearea arborilor de cautare se face aplicand de un nr de ori operatia de inserare. Regula de inserare
este urmatoarea:

 Se compara cheia asociata unui nod cu cheia inregistrarii care se insereaza. Avem trei posibilitati:

- cheia coincide cu nr – se renunta la inserarea acelui numar;


- cheia este mai mare decat numarul – se incearca inserarea in subarborele stang;
- cheia este mai mica decat numarul – se incearca inserarea in subarborele drept.

 Inserarea propriu-zisa se realizeaza atunci cand subarborele stang,respectiv


drept,este vid,astfel se reia.

Vezi procedura INSERARE.

223
2. CAUTAREA

Se face in mod asemanatorcu inserarea motiv pentru care nu o mai comentam.

3. LISTAREA

Informatia se poate lista utilizand oricare din metodele cunoscute pentru parcurgerea arborilor. Daca
dorim listarea informatiilor in ordinea strict crescatoare a cheilor,se utilizeaza metoda stang-varf-dreapta
(inordine), intrucat pentru orice nod avem urmatoarele:

 cheile nodurilor din subarborele stang sunt mai mici decat cheia asociata
nodului;
 cheile nodurilor din subarborele drept sunt mai mari decat cheia asociata
nodului.

Vezi procedura SVD.

4. STERGEREA

Dupa stergerea unui nod care are o anumita cheie, arborele ramas trebuie sa fie de cautare.

Se disting 4 situatii posibile:

a) nodul care urmeaza sa fie sters este nod terminal – in acest caz se face stergerea
avand grija ca la parintele lui sa inlocuim adresa catre el cu nil;
b) nodul care urmeaza a fi sters subordoneaza un singur subarbor – cel drept – caz in
care parintelui se va inlocui adresa catre el cu adresa subarborelui drept,iar nodul
respectiv se sterge;
c) nodul care urmeaza a fi sters subordoneaza un singur subarbore – cel stang – caz in
care parintelui i se va inlocui adresa catre el cu adresa subarborelui stang, iar nodul
respectiv se sterge;
d) nodul care urmeaza a fi sters( dupa cum vom vedea, acesta se va sterge numai logic)
subordoneaza doi subarbori, caz in care se fac operatiile:

- se indentifica cel mai din dreapta nod al subarborelui stang coorespunzator nodului care
urmeaza a fi sters (acesta va fi sters in mod efectiv, nu inainte de a muta informatiile sale la
nodul care se sterge logic);
- cheia acestuia si alte informatii utile continute de el se muta la nodul care urmeaza a fi sters
- subarborele stang al nodului care se va sterge fizic se leaga:
- in stanga nodului care se sterge logic (daca nodul indentificat ca cel mai din dreapta din
subarborele stang este descendent direct al nodului care se sterge logic)
- in dreapta tatalui nodului care se sterge fizic( in caz contrar);

Exemple de stergere:

1. Arborelui din stanga i se sterge nodul 8. acesta nu subordoneaza nici un alt arbore.

224
2. Arborelui din stanga i se sterge nodul 9. acesta subordoneaza un singur subarbore, cel
drept.

3. Arborelui din stanga i se sterge nodul 3. Cel mai din dreapta nod al subarborelui stang este 1.
se obtine:

4. Arborelui din stanga i se sterge nodul 7. cel mai din dreapta nod al subarborelui stang este 6.
tatal nodului care se sterge fizic este 3. in dreapta sa se leaga subarborele 5 4 . se obtine:

225
Vezi procedura STERG. In situatia in care nodul care urmeaza a fi sters subordoneaza doi arbori,se
apeleaza procedura CMMD.

 Intrebarea la care trebuie sa raspundem in continuare este urmatoarea:de ece daca


se sterge in acest mod un nod,arborele ramane de cautare? Stergerea unui nod se
face in mod dinstinct pentru fiecare din cele 4 cazuriaratate. Datorita simplitati
prelucrarii primele tri cazuri nu necesita comentarii. In cazul 4 se indentifica nodul cel
mai din dreaptadin arborele stang. Cheia acestuia trece in locul cheii nodului care se
sterge. Aceasta este mai mica decat cheia initiala,este in acelasi timp cea mai mare
din subarborele stang,deci este cea mai mare cheie mai mica decat cheia care se
sterge. Iata motivul pentru care aceasta trece in locul cheii sterse logic.
 Transmiterea parametrului c se face prin referinta. Adresa de alocare va fi trimisa
automat parintelui,caadresa de subarbore stang sau drept (duopa caz).
 Altgoritmul are complexitatea in cazul cel mai defavorabil 0(n 2). In cazul in care, de
exemplu cheile inserate sunt in ordine crescatoare, arborele va degenera intr-o lista
liniara –orice nod are numai un descendent drept,iar
 inserarea unui nod inseamna parcurgerea tuturor nodurilor deja inserate in pasul
anterior.

Teoria regasirii informatiei este deosebit de importanta pentru viata practica. Aceasta conduce la o
cautare rapida (putine comparatii).
//
#include <stdlib.h>
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <string.h>
#include <time.h>
#include <iomanip>
using namespace std;
#include <stdio.h >
# include <conio.h >

struct nod
{
int nr;
nod *as,*ad;
};
nod *v,*man;
char opt;
int k;

void inserare(nod*& c,int k)

226
{
if (c)
if (c->nr==k)
cout<<"este deja";
else
if (c->nr<k) inserare(c->ad,k);
else
inserare(c->as,k);
else
{
c=new nod;c->as=c->ad=0;
c->nr=k;
}
}

void cautare(nod*& c,nod*& adr,int k)

{
if (c)

if (c->nr<k) cautare(c->ad,adr,k);
else
if (c->nr>k)
cautare(c->as,adr,k);
else
adr=c;
else
adr=0;
}

void parcurg (nod* c)


{
if (c)
{
parcurg(c->as);
cout<<c->nr<<endl;
parcurg(c->ad);
}
}

void cmmd(nod*&c,nod*& f)
{
if (f->ad) cmmd(c,f->ad);
else
{
c->nr=f->nr;
man=f;
f-f->as;
delete man;
}
}
void sterg (nod*& c,int k)
{
nod* f;
if (c)
if (c->nr==k)
if (c->as==c && c->ad==0)
{
delete c;
c=0;
}

227
else

if (c->as==0)
{
f=c->ad;
delete c;
c=f;
}
else
if (c->ad==0)
{
f=c->as;
delete c;
c=f;
}
else
cmmd(c,c->as);
else
if (c->nr<k)
sterg (c->ad,k);
else
sterg(c->as,k);
else
cout<<"nu e numarul ";
}
main()
{char opt;
v=0;
do
{
cout<<"tastati t-terminare,i-inserare,l-listare,c-cautare,s-
stergere";cin>>opt;
switch (opt)
{
case 'i':
cout<<"k=";cin>>k;
inserare(v,k);
break;
case 'l':parcurg(v);
break;
case 'c':
cout<<"k=";cin>>k;
cautare(v,man,k);
if (man) cout<<k<<endl;
else
cout <<"nu exista acest nod"<<endl;
break;
case 's':
cout<<"pe cine stergi ";
cin>>k;
sterg(v,k);
break;
}
}while (opt!='t');
}

228
APLICATII
PROGRAMAREA PE OBIECTE
ASPECTE INTRODUCTIVE
Notiunea de structura
Abordarea orientată pe obiecte (AOO)

A. Un obiect poate fi considerat o entitate care încorporează atît structuri de date


(denumite atribute) cît şi comportament (operaţii). Un obiect trebuie să aibă precizate
mai multe caracteristici :

 identitate : obiectul are o identitate discretă, care se distinge dintre alte


entităţi.

Exemple de obiecte particulare :

 căciula studentului
 o fereastră deschisă pe un calculator
 un triunghi desenat pe hîrtie

Se observă că obiectele la care ne referim se referă la modelarea


realităţii imediate (v. fereastra)

 clasificare: obiectele cu aceleaşi atribute şi operaţii se grupează în clase.


Fiecare obiect poate fi considerat ca o instanţă a unei clase.

Exemple de clase :

 căciulă
 fereastră
 triunghi

229
 polimorfism: aceeaşi operaţie (cu acelaşi nume) poate să aibă
comportament diferit în clase diferite

Exemple: a muta

 o căciulă
 o fereastră
 un triunghi

Implementarea concretă a unei operaţii într-o anumită clasă se numeşte


metodă (method)

 moştenire: atributele şi operaţiile se transmit de-a lungul claselor bazate pe


o relaţie ierarhică

Exemple: se pot defini clasele Triunghi_Isoscel şi Triunghi_Echilateral ca


şi clase derivate din clasa Triunghi şi care moştenesc din această clasă poziţia pe
hîrtie, respectiv operaţia a muta.

În realitatea imediată să ne imaginăm că un fiu moşteneşte de la părinte o casă,


avînd aceasta anumite caracteristici. Fiul mai adaugă încăperi noi casei. Ca urmare,
casa dobîndeşte, pe lîngă caracteristicile existente, altele noi. Aşa şi în ierarhia de
clase: există, dependent de direcţia de parcurgere a ierarhiei, clase-părinte şi clase-fiu.
Clasele-fiu moştenesc trăsăturile claselor-părinte (deci toate structurile şi
comportamentele) la care pot fi adăugate altele noi.

B. Abordarea orientată spre obiecte foloseşte nişte concepte de bază:

 abstractizarea constă în focalizarea pe aspectele esenţiale ale unei entităţi.


Accentul, pentru un obiect, se pune pe ce este acesta şi pe ce trebuie să
facă, înainte de a stabili concret detaliile de implementare. De aceea, etapa
esenţială în crearea unei aplicaţii orientate spre obiecte este analiza şi nu
implementarea, care trebuie să devină aproape mecanică.

 încapsularea (ascunderea) informaţiei - constă în separarea aspectelor


externe ale unui obiect, care sunt accesibile altor obiecte, de aspectele de
implementare internă, care sunt ascunse celorlalte obiecte. Utilizatorul
poate accesa doar anumite atribute şi operaţii ale obiectului, numite publice,
în timp ce alte operaţii îi rămîn inaccesibile (numite private). Încapsularea
este foarte importantă atunci cînd se doreşte schimbarea implementării
pentru anumite operaţii, în scopul perfecţionării unui algoritm sau
eliminării unor erori. Încapsularea ne va împiedica să modificăm toate
caracteristicile obiectului, iar aplicaţiile nu vor avea de suferit

 "împachetarea" datelor şi a comportamentului în acelaşi obiect se referă la


faptul că un obiect conţine atît structuri de date cît şi operaţii şi este utilă
întrucît vom şti totdeauna cărei clase aparţine o metodă, chiar dacă există
mai multe operaţii cu aceaşi denumire, în clase diferite.

230
Existenţa unor operaţii (metode) diferite, cu acelaşi nume, dar cu
comportament diferit, se numeşte polimorfism. Utilizatorul nu trebuie
să se preocupe care anume operaţie este apelată, întrucît compilatorul
va face această identificare, în funcţie de argumentele metodei apelate.
Astfel, a muta o Căciulă este diferit de a muta o Fereastră pe ecran,
sau de a muta un Triunghi pe hîrtie, de aceea nu poate exista confuzie:
în funcţie de ce anume trebuie mutat, operaţia îşi va cunoaşte clasa,
deci şi implementarea.

 partajarea (sharing): aici înseamnă transmiterea aceloraşi structuri de date şi


respectiv operaţii, de-a lungul unor clase dintr-o ierarhie de clase, şi aceasta
are un efect benefic asupra economisirii de spaţiu (dacă o clasă moşteneşte
o altă clasă, atunci ea moşteneşte toate atributele şi operaţiile clasei de bază,
iar din punctul de vedere al codului, acestea sunt aceleaşi cu cele ale clasei
de bază şi nu copii ale lor).

Partajarea oferă posibilitatea reutilizării proiectării, în proiecte ulterioare.


Reutilizarea însă trebuie avută în vedere de la începutul proiectării, chiar
dacă implică un efort ceva mai mare. Beneficiile însă se recuperează din
plin, în timp.

 accentul pe structura de obiect, nu pe cea de procedură: în tehnicile


orientate spre obiecte, accentul cade pe înţelegerea sistemului din punctul
de vedere al descompunerii acestuia în entităţi (obiecte) şi al stabilirii
relaţilor dintre acestea, deci pe ce este un obiect (spre deosebire de analiza
funcţională - sau procedurală - care pune accentul pe ce trebuie să facă).
Mai important decît a stabili ce face sistemul, în acest caz trebuie precizat
cine face şi care sunt relaţiile între cei care fac.
Structuri şi clase

C++ a crescut rolul structurii standard din C la acela al unui mod mai subtil, de
specificare a unei clase. De fapt, diferenţa imediat vizibilă dintre o structură şi o clasă este
aceea că implicit toţi membrii unei structuri sînt publici pe cînd cei ai unei clase sînt implicit
privaţi. În celelalte privinţe, structurile şi clasele sînt similare. Aceasta înseamnă că în C++ o
structură defineşte de asemenea un tip special de clasă
Deoarece o structură (declarată cu cuvîntul cheie struct) în C++ defineşte un tip de clasă,
obiectele de acel tip pot fi declarate folosind doar numele generic al structurii, fără a mai folosi
cuvîntul cheie struct, aşa cum trebuie făcut în C (dar nu este o eroare dacă se precedă declaraţia
cu struct).
//Sa se defineasca o structura
#include "stdafx.h"
#include <iostream>
using namespace std;
#include <string.h>

// declararea structurii
struct sir_exemplu{
void face_sir(char *); // implicit va fi sectiune public
void arata_sir();
private: // iar sectiunea privata trebuie declarata explicit
char sir[80];
};

231
// urmeaza definirile functiilor
void sir_exemplu::face_sir(char *s)
{
if (! *s) *sir ='\n'; // initializare sir
else strcat(sir, s);
}

void sir_exemplu::arata_sir()
{
cout << sir << "\n";
}
Notiunea de uniune
Uniuni şi clase

Ca şi o structură, union poate fi folosită de asemenea pentru a defini o clasă.În C++,


uniunile pot conţine şi acestea, atît funcţii emmbre cît şi variabile membre. Ele pot să mai
includă şi funcţii constructor şi destructor. În C++ union păstrează toate capacităţile din C, cea
mai importantă fiind aceea că toate elementele de date împart aceeaşi locaţie de memorie. Ca şi
structura, membrii unei union sînt implicit publici.
La fel ca şi o structură, o declaraţie a unei union în C++ defineşte un tip special de clasă, deci
se păstrează principiul încapsulării. Iată acum cîteva restricţii asupra folosirii union în C++ :

 nu poate moşteni nici un alt tip de clasă


 nu poate fi clasă de bază
 nu poate avea funcţii virtuale membre (vom vedea mai departe ce înseamnă funcţii
virtuale)
 nu poate avea ca membre variabile de tip static
 nu poate avea ca membru nici un obiect care are supraîncărcat operatorul =
 nu poate avea ca membri obiecte care conţin funcţii constructor sau destructor

Uniuni anonime

În C++ există un tip special de union numit uniune anonimă. Aceasta nu conţine un nume de
tip şi nici o variabilă nu poate fi declarată ca fiind de acel tip de uniune. În schimb, ea comunică
compilatorului că variabilele membre ale uniunii vor împărţi aceeaşi locaţie. Dar variabilele în
sine pot if utilizate direct, fără sintaxa cu operator punct.
Mai mult, chiar dacă ele sînt definite într-o declaraţie union, ele sînt la acelaşi nivel al
domeniului de existenţă ca şi oricare alte variabile locale din acelaşi bloc. Membrii unei uniuni
anonime nu pot de altfel să aibă acelaşi nume cu al nici unui alt identificator cunoscut în
domeniul curent. Aceasta înseamnă că numele membrilor unei uniuni anonime nu trebuie să
intre în conflict cu alţi identificatori cunoscuţi din domeniul uniunii. Toate restricţiile pentru o
union se aplică şi celor anonime, cu următoarele completări :

 elementele care pot fi conţinute într-o uniune anonimă trebuie să fie de tip date (nu
sînt permise funcţii membre)
 uniunile anonime nu pot conţine elemente de tip private sau protected
 uniunile globale anonime trebuie să fie specificate ca fiind de tip static.

#include "stdafx.h"
#include <iostream>

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

main()
{
// urmeaza definirea uniunii anonime
union {
long l;
double d;
char s[10];
};
// accesul la membrii uniunii anonime este direct
l=150000;
cout << l << endl;
d=123.456;
cout << d <<endl;
strcpy(s, "abcdefghij");
cout << s << endl;

return 0;
}
//sa se creeze o uniune in care sa se puna in evidenta urmatoarele:
//• nu poate mosteni nici un alt tip de clasa
//• nu poate avea functii virtuale membre (vom vedea mai departe ce
înseamna functii virtuale)
//• nu poate avea ca membre variabile de tip static
//• nu poate avea ca membru nici un obiect care are supraîncarcat
operatorul =
//• nu poate avea ca membri obiecte care contin functii constructor
sau destructor

#include "stdafx.h"
#include <iostream>
using namespace std;
// declararea union
union schimbare_octeti {
void schimba();
void pune_octeti(unsigned );
void arata_cuvint();

unsigned u;
unsigned char c[2];
};

// definirile functiilor membre


void schimbare_octeti::schimba()
{
unsigned char tmp,t;
t=c[0];
c[0]=c[1];
c[1]=t;
}
void schimbare_octeti::pune_octeti(unsigned i)
{
u=i;
}
void schimbare_octeti::arata_cuvint()
{
cout << u;
}

233
main()
{
schimbare_octeti sch;
sch.pune_octeti(34567);
sch.schimba();
sch.arata_cuvint();

return 0;
}
Clasele

Clasele sînt create utilizîndu-se cuvîntul cheie class. O declarare a unei clase defineşte
un nou tip care uneşte cod şi date. Acest nou tip este apoi folosit pentru a declara obiecte din
acea clasă. De aceea, o clasă este o abstractizare logică, dar un obiect are o existenţă fizică.
Altfel spus, un obiect este un exemplar (o instanţă) al unei clase.
O declarare de classă este similară sintactic cu cea a unei structuri. În capitolul
precedent a fost prezentată (simplificat) această declarare. Iată forma generală completă
a unei declaraţii de clasă care nu este un descendent al vreunei alte clase :

class nume_clasa {
date si functii particulare (fara specificator de acces, implicit)
specificator_de_acces:
date si functii
specificator_de_acces:
date si functii
...
specificator_de_acces:
date si functii
} lista de obiecte;

Lista de obiecte este opţională şi ea declară obiecte din acea clasă.


Specificator_de_acces este unul din următoarele cuvinte-cheie din C++ : public, protected
sau private. Implicit, funcţiile şi datele declarate într-o clasă sînt proprii acelei clase şi doar
membrii săi pot să aibă acces la ele (sînt deci private). Totuşi, folosind specificatorul de acces
public, accesul la funcţiile şi datele din secţiunea respectivă devin accesibile altor secţiuni ale
programului. O dată utilizat un specificator de acces, efectul său durează pînă cînd se întîlneşte
alt specificator de acces sau se ajunge la sfîrşitul declaraţiei clasei. Pentru întoarcerea la
declararea particulară (deci acces numai pentru membrii clasei) se poate folosi specificatorul de
acces private. Specificatorul protected este folosit în cazul moştenirii (se va vedea mai
departe).
Există cîteva restricţii care se aplică membrilor clasei :

 O variabilă membru care nu este de tip static nu poate să aibă o iniţializare;


 Nici un membru nu poate fi obiect al clasei care se declară (deşi un membru poate
fi un pointer către clasa care este declarată);
 Nici un membru nu poate fi declarat auto, extern sau register.

În general, trebuie să faceţi variabilele membre ale unei clase să fie


particulari acelei clase (deci de tipul private). Aceasta este şi ea un aspect al
încapsulării. Totuşi, pot exista situaţii în care se simte nevoia accesului la unele
variabile membre (de exemplu, poate fi necesar ca o variabilă folosită intens să fie

234
accesibilă global, pentru a obţine timpi de rulare mai mici sau chiar economie de
memorie). Cînd o variabilă este public, ea poate fi accesată direct de oricare secţiune a
programului. Sintaxa pentru accesul la o variabilă membră de tipul public este aceeaşi
ca pentru apelarea unei funcţii.
În rezumat : în C++ class creează un nou tip de date care pot fi
folosite pentru a construi obiecte de acel tip. De aceea, un obiect este o
instanţiere (un exemplar) a unei clase exact în acelaşi fel în care altă
variabilă este de exemplu un exemplar al tipului de date int. Altfel spus, o
clasă este o abstractizare logică, iar un obiect este real, clasa constituie
modelul după care se generează obiecte concrete (care există în memoria
calculatorului).

Forma generală a declarării unei clase este :

class nume_clasa {
date si functii private
public:
date si functii publice
} lista de obiecte;

Desigur, lista de obiecte poate fi vidă.


:: este numit operatorul de specificare a domeniului (operator de rezoluţie). Mai
multe clase pot folosi acelaşi nume de funcţie, iar compilatorul ştie care funcţie
aparţine fiecărei clase datorită operatorului de rezoluţie
6) Atenţie ! Variabilele private ale unui obiect sînt accesibile doar funcţiilor membre
ale obiectului. Deşi nu există de fapt o regulă care să dicteze ordinea de definire a
diverselor module de program, cel mai uzual funcţiile membre ale claselor sînt
definite înainte de main() iar funcţiile uzuale (nemembre) sînt definite după main().
În aplicaţiile uzuale, se foloseşte includerea claselor asociate unui program în
fişiere antet.
Supraîncărcarea funcţiilor

Un mod în care C++ realizează polimorfismul este supraîncărcarea funcţiilor


(overloading). În C++, două sau mai multe funcţii pot să aibă acelaşi nume atît timp
cît declaraţiile lor de parametri sînt diferite. În această situaţie, se spune că funcţiile cu
acelaşi nume sînt supraîncărcate iar procesul este numit supraîncărcarea funcţiilor.

Functii prietene
Este posibil să permitem unei funcţii care nu este membru să aibă acces la membrii particulari
ai clasei folosind cuvîntul cheie friend (prieten). O funcţie friend are acces la membrii private
şi protected ai clasei căreia îi este prietenă. Pentru a declara o funcţie friend, trebuie inclus
prototipul ei în acea clasă, precedat de cuvîntul cheie friend, există condiţii cînd funcţiile
prietene îşi dovedesc din plin utilitatea :
 la supraîncărcarea anumitor tipuri de operatori (se va vedea mai încolo)
 la crearea anumitor tipuri de operatori de intrare/ieşire
 în unele cazuri, două sau mai multe clase pot conţine membri care sînt corelaţi cu
alte secţiuni ale programului.
Pentru funcţiile friend se aplică următoarele restricţii :

235
 O clasă derivată nu poate moşteni funcţii friend;
 o funcţie friend nu poate avea un specificator de clasă de memorare, adică nu
poate fi declarată static sau extern.
Clase prietene

Chiar şi clasele pot fi declarate friend una pentru alta. În această situaţie, clasa friend
are acces la numele private definite în cadrul celeilalte. Aceste nume pot cuprinde nume de
tipuri şi enumerări de date. Trebuie reţinut că o clasă friend are acces doar la numele definite în
interiorul celeilalte. Ea nu moşteneşte cealaltă clasă, deci membrii primei clase nu devin
membri ai clasei friend.

//sa permitem unei functii care nu este membru sa aiba acces la


membrii particulari ai clasei folosind
//cuvîntul cheie friend (prieten)
#include "stdafx.h"
#include <iostream>
using namespace std;
class clasa_exemplu{
int a,b;
public:
friend int suma(clasa_exemplu ); // iata o functie
// prietena
void furniz_ab(int, int );
};

void clasa_exemplu::furniz_ab(int i, int j)


{
a=i;
b=j;
}

// acum urmeaza definirea functiei prietene suma, dar aceasta


// nu e membra a vreunei clase
int suma(clasa_exemplu cl){
return cl.a + cl.b; // functia are acces la a si b
}

main(){
clasa_exemplu c;
c.furniz_ab(1,2);
cout << suma(c);
return 0;
}

//folosirea unei functii friend in cadrul unei clase


#include "stdafx.h"
#include <iostream>
using namespace std;
#define IDLE 0
#define IN_USE 1

// declarari de clase
class C2; // vezi mai jos
class C1 {
int stare; // valorile IN_USE daca este pe ecran,
// IDLE daca nu e
// …

236
public:
void setare_stare(int );
int idle(C2 ); // nu mai este friend ci pur si
// simplu membru al clasei C1 de aceea nu mai
// trebuie C1 in lista de parametri
};
class C2{
int stare; // IN_USE daca e pe ecran, IDLE daca nu e
// …
public:
void setare_stare(int );
friend int C1::idle(C2 ); //diferenta e ca apare C1::
// (deci se marcheaza apartenenta la C1)
};

// definiri de functii membre


void C1::setare_stare(int cond)
{
stare=cond;
}
void C2::setare_stare(int cond)
{
stare=cond;
}

// functie membra C1 si prietena pentru C2


int C1::idle(C2 b)
{
if(stare || b.stare) return 0; // nu mai trebuie a.stare
else return 1; // ci e suficient direct
// stare
}

// programul principal
main()
{
C1 x;
C2 y;

x.setare_stare(IDLE);
y.setare_stare(IDLE); // initial ambele sint IDLE

if(x.idle(y)) cout << "Ecranul poate fi folosit.\n";


// referirea e ca functie membra pentru x
else cout << "In curs de folosire.\n";

x.setare_stare(IN_USE); // acum setam un ecran pe


// "folosire"
if(x.idle(y)) cout << "Ecranul poate fi folosit.\n";// si
else cout << "In curs de folosire.\n"; // si iata
// rezultatul
return 0;
}

// In programul principal folosim clasa definita de structura


main()
{
sir_exemplu sir;

sir.face_sir(""); // initializare
sir.face_sir("Acesta"); // construim

237
sir.face_sir("este"); // un sir mai lung in etape
sir.face_sir("exemplu.");

sir.arata_sir(); // si il afisam

return 0;
}

//sa se scrie o clasa cu date publice ce se refera la salariul


//unui angajat
#include "stdafx.h"
#include <iostream>
using namespace std;
#include <string.h>
// declararea clasei angajat
class angajat{
char nume[80];
public:
void pune_nume(char *);
void scoate_nume(char *);
private: // iar sectiune private
double salar;
public: // iar sectiune public
void pune_salar(double );
double furnizeaza_salar();
};

// urmeaza definirile functiilor membre


void angajat::pune_nume(char *num)
{
strcpy(nume, num);
}
void angajat::scoate_nume(char *num)
{
strcpy(num, nume);
}
void angajat::pune_salar(double suma)
{
salar=suma;
}
double angajat::furnizeaza_salar()
{
return salar;
}

// urmeaza programul principal


main()
{
angajat gheorghe; // se generaza un obiect de tip angajat
char nume[80];

gheorghe.pune_nume("Gheorghe Popescu");
gheorghe.pune_salar(860000); // i se adauga salariul pe
// luna curenta
gheorghe.scoate_nume(nume); // in nume va fi transferat
// numele
cout << nume << " are atitia lei ";
cout << gheorghe.furnizeaza_salar() << "pe luna.\n";

238
return 0;
}
//accesul la date publice se face direct in orice sectiune a
programului
#include "stdafx.h"
#include <iostream>
using namespace std;
class clasa_exemplu{
public:
int i,j,k; //acestea vor fi accesibile intregului program
};

main()
{
clasa_exemplu a,b; // se definesc doua obiecte de tipul
// clasa_exemplu
a.i=100;
a.j=4; // se lucreaza la fel ca si cu oricare
a.k=a.i*a.j; // variabila

b.i=a.j;
b.k=11; // a.k si b.k sint evident diferite
cout << a.k << " " <<b.k;
return 0;
}

Functii inline
O importantă caracteristică în C++, posibilitatea de a utiliza funcţii inline, eset
adeseori asociată cu folosirea claselor. În C++ pot fi create funcţii scurte care nu sînt apelate
efectiv ci codul respectivelor funcţii este inserat la fiecare folosire a acestora. Aceasta seamănă
cu utilizarea macro-urilor. Pentru a determina această modalitate de lucru, definirea funcţiei
respective trebuie precedată de cuvîntul-cheie inline.
Funcţiile inline sînt utilizate din motive de eficienţă. Astfel, pentru clase este adeseori necesar
să se solicite executarea frecventă a funcţiilor de interfaţă, care asigură accesul la datele private.
Prin utilizarea funcţiilor inline, eficienţa creşte prin aceea că astfel este înlocuit mecanismul
relativ complex al apelului şi transmiterii parametrilor (prin folosirea stivei şi salvarea
regiştrilor), prin folosirea directă a codului executabil a funcţiilor, fără să se mai folosească acel
mecanism. Bineînţeles prin acest procedeu codul executabil creşte în dimensiuni, de aceea se
recomandă utilizarea funcţiilor inline doar pentru coduri foarte scurte (puţine linii-sursă). Mai
mult decît atît, se recomandă alegerea acelor funcţii care au un impact puternic asupra
îmbunătăţirii performanţelor programului.
Asemenea specificatorului register, inline este pentru compilator o solicitare, nu o
comandă. Acesta poate chiar să o ignore. De asemenea, unele compilatoare nu pot insera inline
orice funcţie. De exemplu nu poate fi inline o funcţie recursivă (uşor de înţeles de ce).
Funcţiile inline pot fi membre ale unei clase.
Este posibilă definirea funcţiilor inline şi direct într-o declarare de clasă. Cînd o funcţie este
definită într-o declarare a unei clase, ea este automat transformată într-o funcţie inline, dacă e
posibil (dacă permite compilatorul). Nu este necesară declararea cu cuvîntul cheie inline (dar
bineînţeles nu constituie o greşeală).
// Sa se foloseasca o functie inline(codul respectivelor funcţii este
inserat la fiecare folosire a acestora)

239
#include "stdafx.h"
#include <iostream>
using namespace std;

inline int max(int a, int b)


{
return a>b ? a: b;
}

main()
{
cout << max(100,200);
cout << " " << max (300, 299);
return 0;
}

//destructorii sunt invers ca ordine apelati fata de constructori


#include "stdafx.h"
#include <iostream>
using namespace std;

class ordine{
public:
int cine;
ordine(int );
~ordine();
} glob_ob1(10), glob_ob2(20); // doua obiecte globale

ordine::ordine(int valinit)
{
cout << "Initializare " << valinit << "\n";
cine=valinit;
}
ordine::~ordine()
{
cout << "Distrugere " << cine << "\n";
}

main()
{
ordine local_ob1(30); // obiect local

cout << "Vedeti ? Aceasta nu e prima linie afisata !\n";

ordine local_ob2(40); // alt obiect local

return 0;
}

//Un alt exemplu de utilizare a funcţiei constructor cu parametri se


referă la o clasă care
//păstrează informaţiile despre cărţile dintr-o bibliotecã :
#include "stdafx.h"
#include <iostream>
using namespace std;
#include <string.h>

#define IN_BIBLIO 1
#define IMPRUMUTAT 0

class carte{

240
char autor[40];
char titlu[40];
int stare;
public:
carte(char *, char *, int );
int furniz_stare() {return stare;}
void pozit_stare(int s) {stare=s;}
void arata();
};
// constructorul initializeaza autor, titlu, stare
// transmisi ca parametri
carte::carte(char *aut, char *tit, int s)
{
strcpy(autor, aut);
strcpy(titlu, tit);
stare=s;
}
void carte::arata()
{
cout << titlu << " de " << autor <<" este ";
if (stare== IN_BIBLIO) cout << "aici.\n";
else cout << "imprumutata.\n";
}

main()
{
carte carte1("Cartarescu","Orbitor",IMPRUMUTAT);
carte carte2("Dinescu", "Democratia naturii", IN_BIBLIO);

carte1.arata();
carte2.arata();

return 0;
}
Membrii de tip static ai claselor
Membrii de tip static ai claselor
Atît funcţiile membre cît şi datele membre ale unei clase pot fi declarate static. În
continuare, să vedem ce înseamnă aceasta pentru fiecare tip de membru.

Membri statici de tip date

O dată care este precedată de cuvîntul static va exista doar într-un singur exemplar (o
singură copie) şi va fi folosită de toate obiectele de acea clasă. Spre deosebire de variabilele
membre obişnuite, nu sînt create copii individuale ale variabilelor membre static, pentru fiecare
obiect. Nu are importanţă cîte obiecte de acea clasă sînt create, va exista doar o singură copie a
membrilor de tip static. Cînd este creat primul obiect de acel tip, toate variabilele de tip static
sînt automat iniţializate cu zero.
În cadrul unei clase, declararea unei variabile static nu alocă memorie pentru aceasta.
Din acest motiv, trebuie dată a definire globală pentru membrii de tip static, în afara clasei,
folosind specificatorul de domeniu, pentru a preciza clasa de apartenenţă. Doar astfel se asigură
existenţa fizică a variabilei, prin alocarea de memorie pentru aceasta (este şi normal, declararea
clasei nu este altceva decît definirea unei structuri abstracte, a unui model după care pot fi
create obiecte; din acest motiv, variabilele statice nu pot fi alocate prin simpla includere într-un
model abstract). O variabilă membră de tip static există înainte de a fi creat orice obiect din

241
acea clasă. Mai mult, dacă respectiva variabilă este public şi întrucît există înainte de crearea
unui obiect din clasa în a cărei declarare apare variabila ca membră, aceasta poate dobîndi
valoare (care nu va fi modificată de crearea vreunui obiect din acea clasă) şi poate fi utilizată în
domeniul său de valabilitate, oricînd. Trebuie reţinut modul de acces la variabilele statice,
atunci cînd sînt accesate independent de obiecte: prin folosirea numelui clasei, urmat de
operatorul de rezoluţie şi apoi numele vaiabilei statice.
Uzual, variabilele membre statice sînt folosite la controlul accesului la unele resurse
comune. Fiecare obiect va putea să controleze valoarea variabilei statice membre pentru a
verifica posibilitatea accesului, deoarece există un singur exemplar al acestei variabile, care
poate fi văzut de toate instanţele clasei şi care va juca rolul unui semafor.
Funcţii membre statice

Şi funcţiile membre pot fi declarate static. Există mai multe restricţii relativ la funcţiile
astfel declarate :

 pot să aibă acces doar la alţi membri de tip static ai clasei (şi bineînţeles la funcţiile
şi datele globale);
 nu pot avea un pointer de tip this (se va vedea mai departe ce înseamnă acesta);
 nu pot coexista versiuni statice şi ne-statice ale aceleiaşi funcţii
De fapt, funcţiile membre de tip static au o arie de aplicatibilitate destul de limitată. O
utilizare potrivită a acestora este iniţializarea datelor private de tip static, înainte de
crearea vreunui obiect al clasei respective.
Operatorul de specificare a domeniului

Operatorul :: este folosit la asocierea unui nume de clasă cu un nume de


membru pentru a transmite astfel compilatorului cărei clase aparţine acel membru. Dar
operatorul de specificare a domeniului (operator de rezoluţie) are şi o altă utilizare
asemănătoare : permite accesul la un nume dintr-un domeniu, dublat de un acelaşi
nume printr-o declarare locală.

//Cînd este creat primul obiect de acel tip, toate variabilele de tip
static sînt automat iniţializate cu zero.
//În cadrul unei clase, declararea unei variabile static nu
alocă memorie pentru aceasta. Din acest motiv, trebuie dată a
definire globală pentru membrii de tip static, în afara clasei,
folosind
//specificatorul de domeniu, pentru a preciza clasa de
apartenenţă.
#include "stdafx.h"
#using <mscorlib.dll>
#include <stdlib.h>
#include <iostream>
using namespace std;
class exemplu_static{
static int a; // aici e o variabila membra de tip static
int b; // aceasta nu e de tip static
public:
void seteaza(int i, int j) {a=i; b=j; }
void arata();
};

int exemplu_static::a; // iata si definirea globala


// pentru variabila de tip static
void exemplu_static::arata()

242
{
cout << "Acesta este a static: " << a;
cout << "\nAcesta este b ne-static: " << b;
cout << "\n";
}

main()
{
exemplu_static ob1, ob2; // doua obiecte de tipul clasei
// exemplu_static

ob1.seteaza(1,2); // a va fi 1, b va fi 2
ob1.arata(); // sa vedem daca e asa

ob2.seteaza(3,4); // acum setam in celalalt obiect, dar


// diferit
ob2.arata(); // si verificam

ob1.arata(); // dar vedem ca a s-a modificat si


// pentru ob1, firesc deoarece a este
// acelasi pentru ambele obiecte
return 0;
}
//Trebuie reţinut modul de acces la variabilele statice, atunci cînd
sînt accesate independent de obiecte: prin folosirea numelui clasei,
urmat de
//operatorul de rezoluţie şi apoi numele vaiabilei statice.
#include "stdafx.h"

#using <mscorlib.dll>

#include <stdlib.h>
#include <iostream>
using namespace std;
class comun{
public:
static int a; // static si public totodata
};

int comun::a; // iata si definirea variabilei statice

main()
{
// initializam variabila statica inainte de crearea
// vreunui obiect folosind operatorul ::
comun::a=789;
cout << "Valoarea initiala a lui a: " << comun::a <<"\n";
comun c1; // abia acum se creaza un obiect de tip comun
cout << "Valoarea lui a din c1: " << c1.a;

return 0;
}
//Exemplul următor ilustrează cum poate fi controlat accesul la o
astfel de resursă comună (care
//poate fi un fişier, un buffer partajat etc.):
#include "stdafx.h"
#using <mscorlib.dll>
#include <stdlib.h>
#include <iostream>
using namespace std;

243
class semafor{
static int resursa;
public:
int ocupa_resursa();
void elibereaza_resursa() {resursa=0; }
};

int semafor::resursa; // aceasta este variabila statica care


// marcheaza ocuparea
int semafor::ocupa_resursa()
{
if (resursa) return 0; // resursa ocupata
else {
resursa=1;
return 1; // resursa atribuita obiectului
// apelant
}
}

main()
{
semafor s1, s2; // doua obiecte de tip semafor
if(s1.ocupa_resursa())
cout << "Obiectul 1 a ocupat resursa.\n";
if(!s2.ocupa_resursa())
cout << "Obiectul 2 nu are acces la resursa.\n";
s1.elibereaza_resursa(); // eliberare resursa
if(s2.ocupa_resursa())
cout << "Obiectul 2 poate acum folosi resursa.\n";

return 0;
}
//Se observă că accesul la funcţia statică ocupa_resursa()
//este permis fie independent de vreun obiect, utilizînd numele
clasei şi operatorul de specificare
//a domeniului (operatorul de rezoluţie) fie în legătură
//cu un obiect (operatorul de apartenenţă cu punct).
#include "stdafx.h"
#using <mscorlib.dll>
#include <stdlib.h>
#include <iostream>
using namespace std;
class semafor{
static int resursa;
public:
static int ocupa_resursa();
void elibereaza_resursa() {resursa=0; }
};

int semafor::resursa; // aceasta este variabila statica


// care indica ocuparea
int semafor::ocupa_resursa()
{
if (resursa) return 0; // resursa ocupata
else {
resursa=1;
return 1; // resursa atribuita obiectului
// apelant
}
}

244
main()
{
semafor s1, s2; // doua obiecte de tip semafor
// in plus fata de programul precedent, ocupa_resursa()
// poate fi apelat independent de orice obiect
if(semafor::ocupa_resursa())
cout << "Obiectul 1 a ocupat resursa.\n";
if(!semafor::ocupa_resursa())
cout << "Obiectul 2 nu are acces la resursa.\n";
s1.elibereaza_resursa(); // eliberare resursa
if(s2.ocupa_resursa()) // se poate folosi si apelul
// cu obiect
cout << "Obiectul 2 poate acum folosi resursa.\n";

return 0;
}

Clase imbricate, clase locale


Se poate defini o clasă în interiorul altei clase. Procedînd astfel, se crează clase
imbricate. Deoarece o declarare a unei clase defineşte de fapt un domeniu de delimitare, ("de
influenţă", de valabilitate, potrivit principiului încapsulării), o clasă imbricată este validă doar
în interiorul clasei ce o conţine. Clasele imbricate sînt rareori folosite, deoarece moştenirea
oferă suficientă flexibilitate şi putere pentru a acoperi necesităţile care ar fi acoperite de
folosirea claselor imbricate.
Cînd declarăm o clasă în definirea unei funcţii, respectiva clasă este cunoscută doar acelei
funcţii. Nu putem să facem referiri la ea în afara funcţiei.
Există mai multe restricţii care se aplică acestui gen de clase :

 Toate funcţiile membre trebuie definite în interiorul declaraţiei clasei respective;


 Clasa locală nu poate să folosească sau să acceseze variabile locale ale funcţei în
care este declarată, cu excepţia variabilelor locale de tip static declarate în interiorul
funcţiei;
 În interiorul unei clase locale nu pot fi declarate variabile de tip static.

Din aceste motive, nu se folosesc prea des clase locale.


O clasă poate fi definită în interiorul unei funcţii, caz în care se numeşte clasă locală.
Transmiterea obiectelor către funcţii

Obiectele pot fi pasate către funcţii exact ca oricare alt tip de variabilă (de altfel,
această posibilitate a fost folosită la un exemplu anterior, care folosea o funcţie friend pentru
controlul accesului la o resursă comună). Obiectele sînt pasate funcţiilor prin utilizarea
mecanismului standard de apelare prin valoare, adică prin copiere. Aceasta ar implica de fapt
crearea unui alt obiect. În aceste circumstanţe, se pune întrebarea dacă la crearea acestei copii
mai este apelat constructorul, respectiv, dacă această copie este distrusă apoi cu destructorul
clasei. Răspunsul la această întrebare este interesant şi uşor de justificat : constructorul nu este
apelat la realizarea copiei pentru pasarea către funcţie, deoarece astfel valorile care dau
atributele obiectului (deci valorile variabilelor membre) ar fi iniţializate, iar noi dorim să
transmitem spre funcţia apelantă chiar starea curentă a obiectului. În schimb destructorul este
executat la încheierea funcţiei, întrucît copia folosită nu mai e necesară
Cînd un obiect este returnat de o funcţie, este creat automat un obiect temporar, care conţine
valoarea returnată. Acesta este de fapt obiectul returnat. După ce valoarea a fost returnată, acest
obiect temporar este distrus. Această distrugere poate avea uneori efecte secundare neaşteptate.

245
Astfel, dacă obiectul care este returnat are un destructor care eliberează memorie alocată
dinamic, acea memorie va fi eliberată chiar dacă obiectul care primeşte valoarea returnată încă
o mai foloseşte. Apariţia acestei probleme poate fi prevenită prin supraîncărcarea operatorului
de atribuire şi definirea constructorului de copii, amintit anterior.

Atribuirea obiectelor
Presupunînd că două obiecte sînt de acelaşi tip, se poate realiza operaţia de atribuire
între acestea. Aceasta determină copierea datelor obiectelor din membrul drept în datele
obiectului din membrul stîng al operaţiei de atribuire.

//O clasă poate fi definită în interiorul unei funcţii,


//caz în care se numeşte clasă locală.
#include "stdafx.h"
#using <mscorlib.dll>
#include <stdlib.h>
#include <iostream>
using namespace std;
void f();

main()
{
f();
// aici inca nu cunoastem clasa clas_local
return 0;
}
void f()
{
// aici definim clasa locala clas_local
class clas_local{
int i;
public:
void setare_i(int val) {i=val; }
int furniz_i() {return i; }
} ob; // si iata si un obiect de clasa respectiva
ob.setare_i(77);
cout << ob.furniz_i();
}
//Obiectele pot fi pasate către funcţii exact ca oricare
//alt tip de variabilă (de altfel, această posibilitate a
//fost folosită la un exemplu anterior, care folosea o
//funcţie friend pentru controlul accesului la o resursă
//comună). Obiectele sînt pasate funcţiilor prin utilizarea
mecanismului standard de apelare prin valoare, adică prin copiere.

#include "stdafx.h"
#using <mscorlib.dll>
#include <stdlib.h>
#include <iostream>
using namespace std;

class ex_apel{
int i;
public:
ex_apel(int );
~ex_apel();
void set_i(int val) {i=val;}
int ret_i() {return i;}
};

246
ex_apel::ex_apel(int init)
{
i=init;
cout << "Construirea pentru " << i << "\n";
}
ex_apel::~ex_apel()
{
cout << "Distrugerea pentru " << i << "\n";
}

void f(ex_apel );

main()
{
ex_apel ex1(1); // un obiect de tip ex_apel
f(ex1); // aici, apel de functie cu parametru obiect
cout << "Valoarea i din main : " << ex1.ret_i() << "\n";
return 0;
}

void f(ex_apel ex)


{
ex.set_i(2); // setam pe alta valoare
cout <<"Valoarea i din functie : " << ex.ret_i() << "\n";
}
//O funcţie poate returna un obiect
//în modulul de program apelant
#include "stdafx.h"
#using <mscorlib.dll>
#include <stdlib.h>
#include <iostream>
using namespace std;
class retur_ob{
int i;
public:
void set_i(int val) {i=val;}
int ret_i() {return i;}
};

retur_ob f(); //prototipul unei functii care returneaza un


// obiect

main()
{
retur_ob o; // se creaza un obiect

o=f(); // obiectul dobindeste valoarea returnata de


// functie
cout << o.ret_i() << "\n";
return 0;
}

retur_ob f()
{
retur_ob interior; // obiect din functie
interior.set_i(1); // setam ca sa ne convingem ca e
// transmis in afara
return interior; // si returnam un obiect
}
//Sa se prezinte atribuirea a doua obiecte

247
#include "stdafx.h"
#using <mscorlib.dll>
#include <stdlib.h>
#include <iostream>
using namespace std;
class atribuire{
int i;
public:
void set_i(int val) {i=val; }
int ret_i() {return i; }
};

main()
{
atribuire a1, a2; // cele doua obiecte

a1.set_i(33); // setam i pentru primul obiect


a2=a1; // atribuirea
cout << "Valoarea i din a2 : " << a2.ret_i() << "\n";
return 0;
}
//sa se defineasca o functie in 3 feluri
//adica se supraincarca
#include "stdafx.h"
#using <mscorlib.dll>
#include <stdlib.h>
#include <iostream>
using namespace std;
// aici definim functia noastra in trei feluri

int abs(int );
double abs(double );
long abs(long );

// acum vine programul principal

main()
{
cout << abs(-10) << "\n";
cout << abs(-22.5) << "\n";
cout << abs(-5L) << "\n";

return 0;
}

// iar aici definim cele trei functii (diferite)

int abs(int i)
{
cout << "ABS pentru intregi\n";
return i<0 ? -i : i ;
}

double abs(double d)
{
cout << "ABS pentru double\n";
return d<0 ? -d : d ;
}

long abs(long l)
{

248
cout << "ABS pentru intregi lungi\n";
return l<0 ? -l : l ;
}

//Cu ajutorul constructorilor si destructorilor


//sa se implementeze notiunea de stiva
#include "stdafx.h"
#using <mscorlib.dll>
#include <stdlib.h>
#include <iostream>
using namespace std;
#define SIZE 100

// intii definim clasa


class stiva {
int stiv[SIZE];
int virf_stiva;
public:
stiva(); // constructor
~stiva(); // destructor
void pune(int );
int scoate();
};

// urmeaza definitiile functiilor membre

// functia constructor
stiva::stiva(){
virf_stiva=0;
cout << "In regula, stiva este initializata\n";
}

// functia destructor
stiva::~stiva()
{
cout << "In regula, stiva e distrusa\n";
}

// celelalte functii membre


void stiva::pune(int i){
if(virf_stiva==SIZE) {
cout << "Stiva este plina\n";
return;
}
stiv[virf_stiva]=i;
virf_stiva++;
}

int stiva::scoate(){
if (virf_stiva==0) {
cout << "Depasire inferioara\n";
return 0;
}
virf_stiva--;
return stiv[virf_stiva];
}

// Programul principal
main()
{
stiva stiv1, stiv2; // crearea a doua obiecte de tip stiva

249
stiv1.pune(1); // punem ceva in stive
stiv2.pune(2);
stiv1.pune(3);
stiv2.pune(4);

cout << stiv1.scoate() << " "; // acum scoatem din stive
si
cout << stiv1.scoate() << " "; // afisam
cout << stiv2.scoate() << " ";
cout << stiv2.scoate() << "\n ";

return 0; // gata
}

// Exercitiul 11.3.1.txt
// Acest program testeaza clasa Fraction prin initializarea unei
serii de
// fractii si afisarea fiecarei valori.
//
// Nota: Desi eu sugerez sa folositi combinatia copy-si-paste pentru
a genera
// o parte a acestui cod, folosirea unor matrice este probabil cea
mai buna
// modalitate de a economisi timpul. Dar aceasta abordare este
lasata pentru
// dumneavoastra, ca un alt exercitiu.

#include "stdafx.h"

#using <mscorlib.dll>

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

class Fraction {
private:
int num, den;
public:
void set(int n, int d) {num = n; den = d; normalize();}
int get_num() {return num;}
int get_den() {return den;}
private:
void normalize();
int gcf(int a, int b);
int lcm(int a, int b);
};

int main() {

Fraction f1, f2, f3, f4, f5;

f1.set(2, 2); // 2/2


f2.set(4, 8); // 4/8
f3.set(-9, -9); // -9/-9
f4.set(10, 50); // 10/50

250
f5.set(100, 25); // 100/25

cout << f1.get_num() << "/" << f1.get_den() << endl;


cout << f2.get_num() << "/" << f2.get_den() << endl;
cout << f3.get_num() << "/" << f3.get_den() << endl;
cout << f4.get_num() << "/" << f4.get_den() << endl;
cout << f5.get_num() << "/" << f5.get_den() << endl;
}

void Fraction::normalize(){

if (den == 0 || num == 0) {
num = 0;
den = 1;
}

if (den < 0) {
num *= -1;
den *= -1;
}

int n = gcf(num, den);


num = num / n;
den = den / n;
}

int Fraction::gcf(int a, int b) {


if (a % b == 0)
return abs(b);
else
return gcf(b, a % b);
}

int Fraction::lcm(int a, int b){


return (a / gcf(a, b)) * b;
}

// Folosind POO sa se creze clasa punct GEOMETRIC si sa se afiseze

#include "stdafx.h"

#using <mscorlib.dll>

#include <iostream>
using namespace std;

class Point {
private:

251
int x, y;
public:
void set(int new_x, int new_y);
int get_x();
int get_y();
};

int main() {
Point pt1, pt2;

pt1.set(10, 20);
cout << "pt1 is " << pt1.get_x();
cout << ", " << pt1.get_y() << endl;
pt2.set(-5, -25);
cout << "pt2 is " << pt2.get_x();
cout << ", " << pt2.get_y() << endl;
return 0;
}

void Point::set(int new_x, int new_y) {


if (new_x < 0)
new_x *= -1;
if (new_y < 0)
new_y *= -1;
x = new_x;
y = new_y;
}

int Point::get_x() {
return x;
}

int Point::get_y() {
return y;
}

// Exercitiul 11.1.1.txt
// Acest program declara o clasa Point ca in scriptul din point1.cpp,
// dar, in aceasta versiune, este stabilita o limita superioara
pentru
// valorile din membrii x si y.

#include "stdafx.h"

#using <mscorlib.dll>

#include <iostream>
using namespace std;

class Point {
private: // Data members (private)
int x, y;
public: // Member functions
void set(int new_x, int new_y);
int get_x();
int get_y();
};

int main() {

252
Point pt1, pt2;

pt1.set(10, 20);
cout << "pt1 is " << pt1.get_x();
cout << ", " << pt1.get_y() << endl;
pt2.set(-5, -25);
cout << "pt2 is " << pt2.get_x();
cout << ", " << pt2.get_y() << endl;

pt1.set(200, 500);
cout << "pt1 is " << pt1.get_x();
cout << ", " << pt1.get_y() << endl;

return 0;
}

void Point::set(int new_x, int new_y) {


if (new_x < 0)
new_x *= -1;
if (new_y < 0)
new_y *= -1;
if (new_x > 100)
new_x = 100;
if (new_y > 100)
new_y = 100;
x = new_x;
y = new_y;
}

int Point::get_x() {
return x;
}

int Point::get_y() {
return y;
}
//sa se scrie doua functii care seteaza punctul X si Punctul Y
diferite
#include "stdafx.h"

#using <mscorlib.dll>

#include <iostream>
using namespace std;

class Point {
private:
int x, y;
public:
void set(int new_x, int new_y);
int get_x();
int get_y();
void set_x(int new_x);
void set_y(int new_y);
};

int main() {
Point pt1, pt2;

pt1.set(10, 20);
cout << "pt1 is " << pt1.get_x();

253
cout << ", " << pt1.get_y() << endl;
pt2.set(-5, -25);
cout << "pt2 is " << pt2.get_x();
cout << ", " << pt2.get_y() << endl;

pt1.set_x(-50);
pt1.set_y(-10);
cout << "pt1 is " << pt1.get_x();
cout << ", " << pt1.get_y() << endl;
return 0;
}

void Point::set_x(int new_x) {


if (new_x < 0)
new_x *= -1;
x = new_x;
}

void Point::set_y(int new_y) {


if (new_y < 0)
new_y *= -1;
y = new_y;
}

void Point::set(int new_x, int new_y) {


if (new_x < 0)
new_x *= -1;
if (new_y < 0)
new_y *= -1;
x = new_x;
y = new_y;
}

int Point::get_x() {
return x;
}

int Point::get_y() {
return y;
}
// Sa se adune doua fractii cu POO

#include "stdafx.h"

#using <mscorlib.dll>

#include <iostream>
using namespace std;

class Fraction {
private:
int num, den;
public:
void set(int n, int d)
{num = n; den = d; normalize();}

254
int get_num() {return num;}
int get_den() {return den;}
Fraction add(Fraction other);
Fraction mult(Fraction other);
private:
void normalize();
int gcf(int a, int b);
int lcm(int a, int b);
};

int main() {
Fraction fract1, fract2, fract3;

fract1.set(1, 2);
fract2.set(1, 3);
fract3 = fract1.add(fract2);
cout << "1/2 plus 1/3 = ";
cout << fract3.get_num() << "/" << fract3.get_den();
}

void Fraction::normalize(){

if (den == 0 || num == 0) {
num = 0;
den = 1;
}

if (den < 0) {
num *= -1;
den *= -1;
}

int n = gcf(num, den);


num = num / n;
den = den / n;
}

int Fraction::gcf(int a, int b) {


if (a % b == 0)
return abs(b);
else
return gcf(b, a % b);
}

int Fraction::lcm(int a, int b){


return (a / gcf(a, b)) * b;
}

Fraction Fraction::add(Fraction other) {


Fraction fract;
int lcd = lcm(den, other.den);
int quot1 = lcd/den;
int quot2 = lcd/other.den;

255
fract.set(num * quot1 + other.num * quot2, lcd);
return fract;
}

Fraction Fraction::mult(Fraction other) {


Fraction fract;
fract.set(num * other.num, den * other.den);
return fract;
}
// Exercitiul 11.4.1.txt
// Acest program aduna oricare doua fractii introduse si
// afiseaza rezultatele.
#include "stdafx.h"

#using <mscorlib.dll>

#include <iostream>
using namespace std;

class Fraction {
private:
int num, den;
public:
void set(int n, int d)
{num = n; den = d; normalize();}
int get_num() {return num;}
int get_den() {return den;}
Fraction add(Fraction other);
Fraction mult(Fraction other);
private:
void normalize();
int gcf(int a, int b);
int lcm(int a, int b);
};

int main() {
Fraction fract1, fract2, fract3;
int n, d;

cout << "Enter numerator for first fraction: ";


cin >> n;
cout << "Enter denominator for first fraction: ";
cin >> d;
fract1.set(n, d);
cout << "Enter numerator for second fraction: ";
cin >> n;
cout << "Enter denominator for second fraction: ";
cin >> d;
fract2.set(n, d);

fract3 = fract1.add(fract2);

cout << "The sum of the fraction is: ";


cout << fract3.get_num() << "/" << fract3.get_den() << endl;
}

void Fraction::normalize(){

256
if (den == 0 || num == 0) {
num = 0;
den = 1;
}

if (den < 0) {
num *= -1;
den *= -1;
}

int n = gcf(num, den);


num = num / n;
den = den / n;
}

int Fraction::gcf(int a, int b) {


if (a % b == 0)
return abs(b);
else
return gcf(b, a % b);
}

int Fraction::lcm(int a, int b){


return (a / gcf(a, b)) * b;
}

Fraction Fraction::add(Fraction other) {


Fraction fract;
int lcd = lcm(den, other.den);
int quot1 = lcd/den;
int quot2 = lcd/other.den;
fract.set(num * quot1 + other.num * quot2, lcd);
return fract;
}

Fraction Fraction::mult(Fraction other) {


Fraction fract;
fract.set(num * other.num, den * other.den);
return fract;
}
// Exercitiul 11.4.2.txt
// Acest program inmulteste oricare doua fractii introduse si
// afiseaza rezultatele.
#include "stdafx.h"

#using <mscorlib.dll>
#include <iostream>
using namespace std;

class Fraction {
private:
int num, den;
public:
void set(int n, int d)

257
{num = n; den = d; normalize();}
int get_num() {return num;}
int get_den() {return den;}
Fraction add(Fraction other);
Fraction mult(Fraction other);

private:
void normalize();
int gcf(int a, int b);
int lcm(int a, int b);
};

int main() {
Fraction fract1, fract2, fract3;
int n, d;

cout << "Enter numerator for first fraction: ";


cin >> n;
cout << "Enter denominator for first fraction: ";
cin >> d;
fract1.set(n, d);
cout << "Enter numerator for second fraction: ";
cin >> n;
cout << "Enter denominator for second fraction: ";
cin >> d;
fract2.set(n, d);

fract3 = fract1.mult(fract2);
cout << "fract1 * fract2 is: ";
cout << fract3.get_num() << "/" << fract3.get_den() << endl;

void Fraction::normalize(){

if (den == 0 || num == 0) {
num = 0;
den = 1;
}

if (den < 0) {
num *= -1;
den *= -1;
}

int n = gcf(num, den);


num = num / n;
den = den / n;
}

int Fraction::gcf(int a, int b) {


if (a % b == 0)
return abs(b);
else
return gcf(b, a % b);
}

258
//
int Fraction::lcm(int a, int b){
return (a / gcf(a, b)) * b;
}

Fraction Fraction::add(Fraction other) {


Fraction fract;
int lcd = lcm(den, other.den);
int quot1 = lcd/den;
int quot2 = lcd/other.den;
fract.set(num * quot1 + other.num * quot2, lcd);
return fract;
}

Fraction Fraction::mult(Fraction other) {


Fraction fract;
fract.set(num * other.num, den * other.den);
return fract;
}

// Exercitiul 11.4.3.txt
// Acest program extinde clasa Point prezentata in capitolul 11
// prin includerea unei functii noi, Point::add.

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

class Point {
private:
int x, y;
public:
void set(int new_x, int new_y);
int get_x();
int get_y();
Point add(Point other);
};

int main() {
Point pt1, pt2, pt3;

pt1.set(10, 20);
cout << "pt1 is " << pt1.get_x();
cout << ", " << pt1.get_y() << endl;
pt2.set(-5, -25);
cout << "pt2 is " << pt2.get_x();
cout << ", " << pt2.get_y() << endl;

pt3 = pt1.add(pt2);
pt2.set(-5, -25);
cout << "pt3 is " << pt3.get_x();
cout << ", " << pt3.get_y() << endl;

return 0;
}

void Point::set(int new_x, int new_y) {

259
if (new_x < 0)
new_x *= -1;
if (new_y < 0)
new_y *= -1;
x = new_x;
y = new_y;
}

int Point::get_x() {
return x;
}

int Point::get_y() {
return y;
}

Point Point::add(Point other) {


Point new_pt;
int new_x = x + other.get_x();
int new_y = y + other.get_y();
new_pt.set(new_x, new_y);
return new_pt;
}

#include "stdafx.h"

// Exercitiul 11.4.4.txt
// Acest program include functiile sub (scadere) si div (impartire)
// pentru clasa Fraction.

#include <iostream>
using namespace std;

class Fraction {
private:
int num, den;
public:
void set(int n, int d)
{num = n; den = d; normalize();}
int get_num() {return num;}
int get_den() {return den;}
Fraction add(Fraction other);
Fraction mult(Fraction other);
Fraction sub(Fraction other);
Fraction div(Fraction other);

private:
void normalize();
int gcf(int a, int b);
int lcm(int a, int b);
};

int main() {
Fraction fract1, fract2, fract3;
int n, d;

260
cout << "Enter numerator for first fraction: ";
cin >> n;
cout << "Enter denominator for first fraction: ";
cin >> d;
fract1.set(n, d);
cout << "Enter numerator for second fraction: ";
cin >> n;
cout << "Enter denominator for second fraction: ";
cin >> d;
fract2.set(n, d);

fract3 = fract1.sub(fract2); // TEST NEW SUB FUNCTION


cout << "fract1 - fract2 is: ";
cout << fract3.get_num() << "/" << fract3.get_den() << endl;

fract3 = fract1.div(fract2); // TEST NEW DIV FUNCTION


cout << "fract1 / fract2 is: ";
cout << fract3.get_num() << "/" << fract3.get_den() << endl;

void Fraction::normalize(){

// Handle cases involving 0

if (den == 0 || num == 0) {
num = 0;
den = 1;
}

if (den < 0) {
num *= -1;
den *= -1;
}

int n = gcf(num, den);


num = num / n;
den = den / n;
}

//
int Fraction::gcf(int a, int b) {
if (a % b == 0)
return abs(b);
else
return gcf(b, a % b);
}

int Fraction::lcm(int a, int b){


return (a / gcf(a, b)) * b;
}

Fraction Fraction::add(Fraction other) {


Fraction fract;

261
int lcd = lcm(den, other.den);
int quot1 = lcd/den;
int quot2 = lcd/other.den;
fract.set(num * quot1 + other.num * quot2, lcd);
return fract;
}

Fraction Fraction::mult(Fraction other) {


Fraction fract;
fract.set(num * other.num, den * other.den);
return fract;
}

Fraction Fraction::sub(Fraction other) {


Fraction fract;
fract.set(-1 * other.num, other.den);
return add(fract);
}

Fraction Fraction::div(Fraction other) {


Fraction fract;
fract.set(num * other.den, den * other.num);
return fract;
}

CONSTRUCTORI IN VISUAL C++.NET


Funcţii constructor cu parametri

Se pot transmite parametri către funcţiile constructor. Aceştia sînt folosiţi mai ales
pentru iniţializarea unui obiect la creare. Pentru aceasta, trebuie pur şi simplu adăugaţi
parametri în modul în care acest lucru se realizează pentru orice funcţie. Iar parametrii transmişi
vor fi folosiţi pentru iniţilizarea obiectului.
Funcţiile constructor cu parametri sînt utile deoarece permit evitarea unui aple suplimentar
pentru iniţializarea valorilor unor variabile din obiecte.
Un caz special al funcţiilor constructor cu parametri este constituit de funcţiile
constructor cu un parametru. În acest caz, există o altă cale de a-i pasa acestuia o valoare
iniţială. În cazul cînd constructorul are un singur argument, se poate folosi pur şi simplu forma
de iniţializare "naturală". Compilatorul va atribui automat valoarea din dreapta semnului "=",
parametrului constructorului.
Despre execuţia constructorilor şi destructorilor

Un constructor este de obicei apelat la declararea obiectului, iar un destructor este


apelat cînd este distrus obiectul. Însă momentele exacte ale acestor acţiuni trebuie puţin
comentate deoarece se întîlnesc situaţii diverse :

1. O funcţie constructor de obiecte este executată cînd este întîlnită instrucţiunea de


declarare a obiectului. Mai mult, cînd două sau mai multe obiecte sînt declarate în aceeaşi
instrucţiune, constructorii sînt apelaţi în ordinea în care sînt ele întîlnite, de la stînga la dreapta.
Funcţiile destructor pentru obiecte locale sînt executate în ordine inversă faţă de cele
constructor.

262
2. Funcţiile constructor pentru obiecte globale sînt executate înaintea lui main(). Constructorii
globali din acelaşi fişier sînt executaţi în rodinea în care au fost întîlniţi, de la stînga la dreapta
şi de sus în jos. E greu de depistat ordinea execuţiei constructorilor împrăştiaţi în mai multe
fişiere. Destructorii globali se execută în ordine inversă, după încheierea funcţiei main().

//sa se adauge niste contructori pentru clasa PUNCT

#include "stdafx.h"

#include <iostream>
using namespace std;

class Point {
private:
int x, y;
public: // Constructori
Point() {set(0,0);};
Point(int new_x, int new_y) {set(new_x, new_y);}

// functii membre

void set(int new_x, int new_y);


int get_x();
int get_y();
};

int main() {
Point pt1, pt2;
Point pt3(5, 10);

cout << "The value of pt1 is ";


cout << pt1.get_x() << ", ";
cout << pt1.get_y() << endl;

cout << "The value of pt3 is ";


cout << pt3.get_x() << ", ";
cout << pt3.get_y() << endl;
return 0;
}

void Point::set(int new_x, int new_y) {


if (new_x < 0)
new_x *= -1;
if (new_y < 0)
new_y *= -1;
x = new_x;
y = new_y;
}

int Point::get_x() {
return x;
}

int Point::get_y() {
return y;
}
// Exercitiul 12.1.1.txt
// Aceasta versiune a lui point2.cpp raporteaza ce constructori vor
fi utilizati.

263
//sa se defineasca doi constructori ,unul pentru un mesaj altul cu
parametrii pentru alt mesaj

#include "stdafx.h"

#include <iostream>
using namespace std;

class Point {
private: // Data members (private)
int x, y;
public: // Constructors
Point()
{set(0,0); cout << "Using default constructor" << endl; }

Point(int new_x, int new_y)


{set(new_x, new_y); cout << "Using (int, int) constructor" <<
endl;}

// Other member functions

void set(int new_x, int new_y);


int get_x();
int get_y();
};

int main() {
Point pt1, pt2;
Point pt3(5, 10);

cout << "The value of pt1 is ";


cout << pt1.get_x() << ", ";
cout << pt1.get_y() << endl;

cout << "The value of pt3 is ";


cout << pt3.get_x() << ", ";
cout << pt3.get_y() << endl;
return 0;
}

void Point::set(int new_x, int new_y) {


if (new_x < 0)
new_x *= -1;
if (new_y < 0)
new_y *= -1;
x = new_x;
y = new_y;
}

int Point::get_x() {
return x;
}

int Point::get_y() {
return y;
}

// Exercitiul 12.1.2.txt
// Aceasta versiune a programului Point2 adauga constructorul
Point(int)
// (un constructor care preia un singur argument intreg).

264
#include "stdafx.h"

#include <iostream>
using namespace std;

class Point {
private: // Data members (private)
int x, y;
public: // Constructors
Point() {set(0, 0);}
Point(int new_x, int new_y) {set(new_x, new_y);}

Point(int n) {set(n, 0);} // NEW CONSTRUCTOR

// Other member functions

void set(int new_x, int new_y);


int get_x();
int get_y();
};

int main() {
Point pt1(6); // THIS TESTS THE NEW CONSTRUCTOR
Point pt2;
Point pt3(5, 10);

cout << "The value of pt1 is ";


cout << pt1.get_x() << ", ";
cout << pt1.get_y() << endl;

cout << "The value of pt3 is ";


cout << pt3.get_x() << ", ";
cout << pt3.get_y() << endl;
return 0;
}

void Point::set(int new_x, int new_y) {


if (new_x < 0)
new_x *= -1;
if (new_y < 0)
new_y *= -1;
x = new_x;
y = new_y;
}

int Point::get_x() {
return x;
}

int Point::get_y() {
return y;
}
//sa se defineasca constructori pentru clasa Fractie

#include "stdafx.h"

#include <iostream>
using namespace std;

265
class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}

void set(int n, int d) {num = n; den = d; normalize();}


int get_num() {return num;}
int get_den() {return den;}
Fraction add(Fraction other);
Fraction mult(Fraction other);
private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};

int main() {
Fraction f1, f2;
Fraction f3(1, 2);

cout << "The value of f1 is ";


cout << f1.get_num() << "/";
cout << f1.get_den() << endl;

cout << "The value of f3 is ";


cout << f3.get_num() << "/";
cout << f3.get_den() << endl;
return 0;
}

void Fraction::normalize(){

// Handle cases involving 0

if (den == 0 || num == 0) {
num = 0;
den = 1;
}

// Put neg. sign in numerator only.

if (den < 0) {
num *= -1;
den *= -1;
}

// Factor out GCF from numerator and denominator.

int n = gcf(num, den);


num = num / n;
den = den / n;
}

// Greatest Common Factor


//
int Fraction::gcf(int a, int b) {
if (a % b == 0)
return abs(b);

266
else
return gcf(b, a % b);
}

// Lowest Common Multiple


//
int Fraction::lcm(int a, int b){
return (a / gcf(a, b)) * b;
}

Fraction Fraction::add(Fraction other) {


Fraction fract;
int lcd = lcm(den, other.den);
int quot1 = lcd/den;
int quot2 = lcd/other.den;
fract.set(num * quot1 + other.num * quot2, lcd);
fract.normalize();
return fract;
}

Fraction Fraction::mult(Fraction other) {


Fraction fract;
fract.set(num * other.num, den * other.den);
fract.normalize();
return fract;
}

// Exercitiul 12.2.1.txt
// Aceasta versiune a clasei Fraction revizuieste constructorul
prestabilit
// astfel incat sa stabileasca direct valoarea membrilor de date num
si den.
//
// Apelarea functiei normalize nu este strict necesara, dar este
putin mai precaut,
// in particular, daca functia normalize va fi rescrisa de subclase
// (cum se va explca mai tarziu in acest capitol).
//
// Setarea directa a functiilor num si den este putin mai eficienta,
deoarece ocoleste
// ap
#include "stdafx.h"
elarea unei functii; totusi, aceasta este un foarte mica
imbunatatire.

#include <iostream>
using namespace std;

class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {num = 0; den = 0; normalize();} // <-- NEW VERSION

Fraction(int n, int d) {set(n, d);}

void set(int n, int d) {num = n; den = d; normalize();}


int get_num() {return num;}
int get_den() {return den;}

267
Fraction add(Fraction other);
Fraction mult(Fraction other);
private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};

int main() {
Fraction f1, f2;
Fraction f3(1, 2);

cout << "The value of f1 is ";


cout << f1.get_num() << "/";
cout << f1.get_den() << endl;

cout << "The value of f3 is ";


cout << f3.get_num() << "/";
cout << f3.get_den() << endl;
return 0;
}

void Fraction::normalize(){

// Handle cases involving 0

if (den == 0 || num == 0) {
num = 0;
den = 1;
}

// Put neg. sign in numerator only.

if (den < 0) {
num *= -1;
den *= -1;
}

// Factor out GCF from numerator and denominator.

int n = gcf(num, den);


num = num / n;
den = den / n;
}

// Greatest Common Factor


//
int Fraction::gcf(int a, int b) {
if (a % b == 0)
return abs(b);
else
return gcf(b, a % b);
}

// Lowest Common Multiple


//
int Fraction::lcm(int a, int b){
return (a / gcf(a, b)) * b;
}

Fraction Fraction::add(Fraction other) {

268
Fraction fract;
int lcd = lcm(den, other.den);
int quot1 = lcd/den;
int quot2 = lcd/other.den;
fract.set(num * quot1 + other.num * quot2, lcd);
fract.normalize();
return fract;
}

Fraction Fraction::mult(Fraction other) {


Fraction fract;
fract.set(num * other.num, den * other.den);
fract.normalize();
return fract;
}

// Exercitiul 12.2.2.txt
// Aceasta versiune a clasei Fraction adauga un constructor
Fraction(int),
// care creeaza o fractie de forma n/1.

#include "stdafx.h"

#include <iostream>
using namespace std;

class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(int n) {set(n, 1);} // NEW CONSTRUCTOR ADDED

void set(int n, int d) {num = n; den = d; normalize();}


int get_num() {return num;}
int get_den() {return den;}
Fraction add(Fraction other);
Fraction mult(Fraction other);
private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};

int main() {
Fraction f1(6); // THIS TESTS THE NEW CONSTRUCTOR
Fraction f2;
Fraction f3(1, 2);

cout << "The value of f1 is ";


cout << f1.get_num() << "/";
cout << f1.get_den() << endl;

cout << "The value of f3 is ";


cout << f3.get_num() << "/";
cout << f3.get_den() << endl;
return 0;
}

269
void Fraction::normalize(){

// Handle cases involving 0

if (den == 0 || num == 0) {
num = 0;
den = 1;
}

// Put neg. sign in numerator only.

if (den < 0) {
num *= -1;
den *= -1;
}

// Factor out GCF from numerator and denominator.

int n = gcf(num, den);


num = num / n;
den = den / n;
}

// Greatest Common Factor


//
int Fraction::gcf(int a, int b) {
if (a % b == 0)
return abs(b);
else
return gcf(b, a % b);
}

// Lowest Common Multiple


//
int Fraction::lcm(int a, int b){
return (a / gcf(a, b)) * b;
}

Fraction Fraction::add(Fraction other) {


Fraction fract;
int lcd = lcm(den, other.den);
int quot1 = lcd/den;
int quot2 = lcd/other.den;
fract.set(num * quot1 + other.num * quot2, lcd);
fract.normalize();
return fract;
}

Fraction Fraction::mult(Fraction other) {


Fraction fract;
fract.set(num * other.num, den * other.den);
fract.normalize();
return fract;
}
CONSTRUCTOR DE COPIERE
// SA se defineasca un constructor de COPIERE

#include "stdafx.h"

270
#include <iostream>
using namespace std;

class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(Fraction const &src);

void set(int n, int d) {num = n; den = d; normalize();}


int get_num() {return num;}
int get_den() {return den;}
Fraction add(Fraction other);
Fraction mult(Fraction other);
private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};

int main() {
Fraction f1(3, 4);
Fraction f2(f1);

Fraction f3 = f1.add(f2);

cout << "The value of f3 is ";


cout << f3.get_num() << "/";
cout << f3.get_den() << endl;
return 0;
}

// ---------------------------------------------------
// FRACTION CLASS FUNCTIONS

Fraction::Fraction(Fraction const &src) {


cout << "Now executing copy constructor." << endl;
num = src.num;
den = src.den;
}

// Normalize: put fraction into a standard form, unique


// for each mathematically different value.
//
void Fraction::normalize(){

// Handle cases involving 0

if (den == 0 || num == 0) {
num = 0;
den = 1;
}

// Put neg. sign in numerator only.

if (den < 0) {
num *= -1;
den *= -1;
}

271
// Factor out GCF from numerator and denominator.

int n = gcf(num, den);


num = num / n;
den = den / n;
}

// Greatest Common Factor


//
int Fraction::gcf(int a, int b) {
if (a % b == 0)
return abs(b);
else
return gcf(b, a % b);
}

// Lowest Common Multiple


//
int Fraction::lcm(int a, int b){
return (a / gcf(a, b)) * b;
}

Fraction Fraction::add(Fraction other) {


Fraction fract;
int lcd = lcm(den, other.den);
int quot1 = lcd/den;
int quot2 = lcd/other.den;
fract.set(num * quot1 + other.num * quot2, lcd);
fract.normalize();
return fract;
}

Fraction Fraction::mult(Fraction other) {


Fraction fract;
fract.set(num * other.num, den * other.den);
fract.normalize();
return fract;
}

// Exercitiul 12.3.1.txt
// Aceasta versiune a programului fract4.cpp rescrie un constructor
de copiere
// sub forma unei functii in linie.
#include "stdafx.h"

#include <iostream>
using namespace std;

class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}

272
Fraction(Fraction const &src) {num = src.num; den = src.den;}

void set(int n, int d) {num = n; den = d; normalize();}


int get_num() {return num;}
int get_den() {return den;}
Fraction add(Fraction other);
Fraction mult(Fraction other);
private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};

int main() {
Fraction f1(3, 4);
Fraction f2(f1);

Fraction f3 = f1.add(f2);

cout << "The value of f3 is ";


cout << f3.get_num() << "/";
cout << f3.get_den() << endl;
return 0;
}

void Fraction::normalize(){

// Handle cases involving 0

if (den == 0 || num == 0) {
num = 0;
den = 1;
}

// Put neg. sign in numerator only.

if (den < 0) {
num *= -1;
den *= -1;
}

// Factor out GCF from numerator and denominator.

int n = gcf(num, den);


num = num / n;
den = den / n;
}

// Greatest Common Factor


//
int Fraction::gcf(int a, int b) {
if (a % b == 0)
return abs(b);
else
return gcf(b, a % b);
}

// Lowest Common Multiple


//
int Fraction::lcm(int a, int b){
return (a / gcf(a, b)) * b;

273
}

Fraction Fraction::add(Fraction other) {


Fraction fract;
int lcd = lcm(den, other.den);
int quot1 = lcd/den;
int quot2 = lcd/other.den;
fract.set(num * quot1 + other.num * quot2, lcd);
fract.normalize();
return fract;
}

Fraction Fraction::mult(Fraction other) {


Fraction fract;
fract.set(num * other.num, den * other.den);
fract.normalize();
return fract;
}

// Exercitiul 12.3.2.txt
// Aceasta versiune a programului fract4.cpp revizuieste
constructorul de copiere
// astfel incat sa faca apel la functia set in loc sa stabileasca
direct valoarea
// membrilor de date num si den.
//
// Aceasta abordare isi pierde putin din eficienta fata de situatia
cand constructorul
// este setat ca o functie in linie. Cu toate acestea, el apeleaza
functia normalize,
// lucru care nu este neaparat necesar. (Cand copiati o fractie
existenta, puteti
// presupune ca valoarea sa a fost deja normalizata.)

#include "stdafx.h"

#include <iostream>
using namespace std;

class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(Fraction const &src);

void set(int n, int d) {num = n; den = d; normalize();}


int get_num() {return num;}
int get_den() {return den;}
Fraction add(Fraction other);
Fraction mult(Fraction other);
private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};

int main() {

274
Fraction f1(3, 4);
Fraction f2(f1);

Fraction f3 = f1.add(f2);

cout << "The value of f3 is ";


cout << f3.get_num() << "/";
cout << f3.get_den() << endl;
return 0;
}

// ---------------------------------------------------
// FRACTION CLASS FUNCTIONS

Fraction::Fraction(Fraction const &src) {


cout << "Now executing copy constructor." << endl;
set(src.num, src.den);
normalize();
}

void Fraction::normalize(){

// Handle cases involving 0

if (den == 0 || num == 0) {
num = 0;
den = 1;
}

// Put neg. sign in numerator only.

if (den < 0) {
num *= -1;
den *= -1;
}

// Factor out GCF from numerator and denominator.

int n = gcf(num, den);


num = num / n;
den = den / n;
}

// Greatest Common Factor


//
int Fraction::gcf(int a, int b) {
if (a % b == 0)
return abs(b);
else
return gcf(b, a % b);
}

// Lowest Common Multiple


//
int Fraction::lcm(int a, int b){
return (a / gcf(a, b)) * b;
}

Fraction Fraction::add(Fraction other) {


Fraction fract;
int lcd = lcm(den, other.den);

275
int quot1 = lcd/den;
int quot2 = lcd/other.den;
fract.set(num * quot1 + other.num * quot2, lcd);
fract.normalize();
return fract;
}

Fraction Fraction::mult(Fraction other) {


Fraction fract;
fract.set(num * other.num, den * other.den);
fract.normalize();
return fract;
}

SUPRAINCARCAREA(DEFINIREA NOUA) A
OPERATORILOR

//Sa se defineasca operatorul care aduna coordonatele unor puncte


//si care face diferenta intre coordonatele unor puncte

#include "stdafx.h"

#include <iostream>
using namespace std;

class Point {
private: // Data members (private)
int x, y;
public: // Constructors
Point() {};
Point(int new_x, int new_y) {set(new_x, new_y);}
Point(const Point &src) {set(src.x, src.y);}

// Operations

Point add(const Point &pt);


Point sub(const Point &pt);
Point operator+(const Point &pt) {return add(pt);}
Point operator-(const Point &pt) {return sub(pt);}

// Other member functions

void set(int new_x, int new_y);


int get_x() const {return x;}
int get_y() const {return y;}
};

int main() {

Point point1(20, 20);


Point point2(0, 5);
Point point3(-10, 25);
Point point4 = point1 + point2 + point3;

cout << "The point is " << point4.get_x();


cout << ", " << point4.get_y() << "." << endl;

276
return 0;
}

void Point::set(int new_x, int new_y) {


if (new_x < 0)
new_x *= -1;
if (new_y < 0)
new_y *= -1;
x = new_x;
y = new_y;
}

Point Point::add(const Point &pt) {


Point new_pt;
new_pt.x = x + pt.x;
new_pt.y = y + pt.y;
return new_pt;
}

Point Point::sub(const Point &pt) {


Point new_pt;
new_pt.x = x - pt.x;
new_pt.y = y - pt.y;
return new_pt;
}

// Exercitiul 13.1.1.txt
// Aceasta versiune a programului point3.cpp indica de cate ori sunt
apelati
// constructorul predefinit si constructorul de copiere.

#include "stdafx.h"

#include <iostream>
using namespace std;

class Point {
private: // Data members (private)
int x, y;
public: // Constructors
Point()
{set(0, 0); cout << "Inside default constructor" << endl; } //
ALTERED CODE

Point(int new_x, int new_y) {set(new_x, new_y);}

Point(const Point &src)


{set(src.x, src.y); cout << "Inside copy constructor" << endl;
// ALTERED CODE
}

// Operations

Point add(const Point &pt);


Point sub(const Point &pt);
Point operator+(const Point &pt) {return add(pt);}
Point operator-(const Point &pt) {return sub(pt);}

// Other member functions

277
void set(int new_x, int new_y);
int get_x() const {return x;}
int get_y() const {return y;}
};

int main() {

Point point1(20, 20);


Point point2(0, 5);
Point point3(-10, 25);
Point point4 = point1 + point2 + point3;

cout << "The point is " << point4.get_x();


cout << ", " << point4.get_y() << "." << endl;

return 0;
}

void Point::set(int new_x, int new_y) {


if (new_x < 0)
new_x *= -1;
if (new_y < 0)
new_y *= -1;
x = new_x;
y = new_y;
}

Point Point::add(const Point &pt) {


Point new_pt;
new_pt.x = x + pt.x;
new_pt.y = y + pt.y;
return new_pt;
}

Point Point::sub(const Point &pt) {


Point new_pt;
new_pt.x = x - pt.x;
new_pt.y = y - pt.y;
return new_pt;
}

// Exercitiul 13.1.2.txt
// Acest program creeaza si testeaza operatii de inmultire (*) intre
// clasa Point si tipul de date int.

#include "stdafx.h"

#include <iostream>
using namespace std;

class Point {
private: // Data members (private)
int x, y;
public: // Constructors
Point() {};
Point(int new_x, int new_y) {set(new_x, new_y);}
Point(const Point &src) {set(src.x, src.y);}

// Operations

278
Point add(const Point &pt);
Point sub(const Point &pt);
Point operator+(const Point &pt) {return add(pt);}
Point operator-(const Point &pt) {return sub(pt);}

friend Point operator*(const Point &pt, const int &n); // FRIEND


DECL.
friend Point operator*(const int &n, const Point &pt);

// Other member functions

void set(int new_x, int new_y);


int get_x() const {return x;}
int get_y() const {return y;}
};

int main() {

Point point1(20, 20);


Point point2 = point1 * 4; // TEST
MULTIPLICATION WITH INT'S

cout << "The point is " << point2.get_x();


cout << ", " << point2.get_y() << "." << endl;

return 0;
}

void Point::set(int new_x, int new_y) {


if (new_x < 0)
new_x *= -1;
if (new_y < 0)
new_y *= -1;
x = new_x;
y = new_y;
}

Point Point::add(const Point &pt) {


Point new_pt;
new_pt.x = x + pt.x;
new_pt.y = y + pt.y;
return new_pt;
}

Point Point::sub(const Point &pt) {


Point new_pt;
new_pt.x = x - pt.x;
new_pt.y = y - pt.y;
return new_pt;
}

// POINT CLASS FRIEND FUNCTIIONS

Point operator*(const Point &pt, const int &n) {


Point new_pt;
new_pt.set(pt.x * n, pt.y * n);
return new_pt;
}

279
Point operator*(const int &n, const Point &pt) {
Point new_pt;
new_pt.set(pt.x * n, pt.y * n);
return new_pt;
}
//sa se defineasca operatori personalizati pentru
//lucrul cu fractiile

#include "stdafx.h"

#include <iostream>
using namespace std;

class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(const Fraction &src);

void set(int n, int d) {num = n; den = d; normalize();}


int get_num() const {return num;}
int get_den() const {return den;}
Fraction add(const Fraction &other);
Fraction mult(const Fraction &other);
Fraction operator+(const Fraction &other)
{return add(other);}
Fraction operator*(const Fraction &other)
{return mult(other);}

private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};

int main() {
Fraction f1(1, 2);
Fraction f2(1, 3);

Fraction f3 = f1 + f2;

cout << "1/2 + 1/3 = ";


cout << f3.get_num() << "/";
cout << f3.get_den() << "." << endl;
return 0;
}

// ---------------------------------------------------
// FRACTION CLASS FUNCTIONS

Fraction::Fraction(Fraction const &src) {


num = src.num;
den = src.den;
}

// Normalize: put fraction into a standard form, unique


// for each mathematically different value.
//
void Fraction::normalize(){

280
// Handle cases involving 0

if (den == 0 || num == 0) {
num = 0;
den = 1;
}

// Put neg. sign in numerator only.

if (den < 0) {
num *= -1;
den *= -1;
}

// Factor out GCF from numerator and denominator.

int n = gcf(num, den);


num = num / n;
den = den / n;
}

// Greatest Common Factor


//
int Fraction::gcf(int a, int b) {
if (a % b == 0)
return abs(b);
else
return gcf(b, a % b);
}

// Lowest Common Multiple


//
int Fraction::lcm(int a, int b){
return (a / gcf(a, b)) * b;
}

Fraction Fraction::add(const Fraction &other) {


Fraction fract;
int lcd = lcm(den, other.den);
int quot1 = lcd/den;
int quot2 = lcd/other.den;
fract.set(num * quot1 + other.num * quot2, lcd);
fract.normalize();
return fract;
}

Fraction Fraction::mult(const Fraction &other) {


Fraction fract;
fract.set(num * other.num, den * other.den);
fract.normalize();
return fract;
}
// Exercitiul 13.2.1.txt
// Acest program solicita o serie de valori fractionare, le aduna pe
toate
// si afiseaza suma.

#include "stdafx.h"

281
#include <iostream>
using namespace std;

class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(const Fraction &src);

void set(int n, int d) {num = n; den = d; normalize();}


int get_num() const {return num;}
int get_den() const {return den;}
Fraction add(const Fraction &other);
Fraction mult(const Fraction &other);
Fraction operator+(const Fraction &other)
{return add(other);}
Fraction operator*(const Fraction &other)
{return mult(other);}

private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};

int main() {
Fraction fraction_sum(0, 0);
Fraction fraction_new;
int numerator, denominator;

while (1) { // MAIN LOOP


cout << "Enter numerator (0 to exit): ";
cin >> numerator;
if (numerator == 0) // BREAK ON ZERO
break;
cout << "Enter denominator: ";
cin >> denominator;
fraction_new.set(numerator, denominator);
fraction_sum = fraction_sum + fraction_new;
}
cout << "The sum of the fractions is: ";
cout << fraction_sum.get_num() << "/";
cout << fraction_sum.get_den() << "." << endl;

return 0;
}

// ---------------------------------------------------
// FRACTION CLASS FUNCTIONS

Fraction::Fraction(Fraction const &src) {


num = src.num;
den = src.den;
}

// Normalize: put fraction into a standard form, unique


// for each mathematically different value.
//
void Fraction::normalize(){

282
// Handle cases involving 0

if (den == 0 || num == 0) {
num = 0;
den = 1;
}

// Put neg. sign in numerator only.

if (den < 0) {
num *= -1;
den *= -1;
}

// Factor out GCF from numerator and denominator.

int n = gcf(num, den);


num = num / n;
den = den / n;
}

// Greatest Common Factor


//
int Fraction::gcf(int a, int b) {
if (a % b == 0)
return abs(b);
else
return gcf(b, a % b);
}

// Lowest Common Multiple


//
int Fraction::lcm(int a, int b){
return (a / gcf(a, b)) * b;
}

Fraction Fraction::add(const Fraction &other) {


Fraction fract;
int lcd = lcm(den, other.den);
int quot1 = lcd/den;
int quot2 = lcd/other.den;
fract.set(num * quot1 + other.num * quot2, lcd);
fract.normalize();
return fract;
}

Fraction Fraction::mult(const Fraction &other) {


Fraction fract;
fract.set(num * other.num, den * other.den);
fract.normalize();
return fract;
}

//Sa se defineasca mai multe functii diferite pentru fiecare operator


#include "stdafx.h"
#include <iostream>
using namespace std;

class Fraction {
private:

283
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(int n) {set(n, 1);}
Fraction(const Fraction &src);

void set(int n, int d) {num = n; den = d; normalize();}


int get_num() const {return num;}
int get_den() const {return den;}
Fraction add(const Fraction &other);
Fraction mult(const Fraction &other);
Fraction operator+(const Fraction &other)
{return add(other);}
Fraction operator*(const Fraction &other)
{return mult(other);}
int operator==(const Fraction &other);
friend ostream &operator<<(ostream &os, Fraction &fr);

private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};

int main() {
Fraction f1(1, 2);
Fraction f2(1, 3);

Fraction f3 = f1 + f2 + 1;

cout << "1/2 + 1/3 + 1 = " << f3 << endl;


return 0;
}

// ---------------------------------------------------
// FRACTION CLASS FUNCTIONS

Fraction::Fraction(Fraction const &src) {


num = src.num;
den = src.den;
}

// Normalize: put fraction into a standard form, unique


// for each mathematically different value.
//
void Fraction::normalize(){

// Handle cases involving 0

if (den == 0 || num == 0) {
num = 0;
den = 1;
}

// Put neg. sign in numerator only.

if (den < 0) {
num *= -1;
den *= -1;
}

284
// Factor out GCF from numerator and denominator.

int n = gcf(num, den);


num = num / n;
den = den / n;
}

// Greatest Common Factor


//
int Fraction::gcf(int a, int b) {
if (a % b == 0)
return abs(b);
else
return gcf(b, a % b);
}

// Lowest Common Multiple


//
int Fraction::lcm(int a, int b){
return (a / gcf(a, b)) * b;
}

Fraction Fraction::add(const Fraction &other) {


Fraction fract;
int lcd = lcm(den, other.den);
int quot1 = lcd/den;
int quot2 = lcd/other.den;
fract.set(num * quot1 + other.num * quot2, lcd);
fract.normalize();
return fract;
}

Fraction Fraction::mult(const Fraction &other) {


Fraction fract;
fract.set(num * other.num, den * other.den);
fract.normalize();
return fract;
}

int Fraction::operator==(const Fraction &other) {


return (num == other.num && den == other.den);
}

// ---------------------------------------------------
// FRACTION CLASS FRIEND FUNCTION

ostream &operator<<(ostream &os, Fraction &fr) {


os << fr.num << "/" << fr.den;
return os;
}

// Exercitiul 13.3.1.txt
// Acest exemplu revizuieste programul din exemplul 13.3 astfel incat
afiseaza
// iesirea din clasa Fraction in format (num, den).

#include "stdafx.h"

#include <iostream>

285
using namespace std;

class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(int n) {set(n, 1);}
Fraction(const Fraction &src);

void set(int n, int d) {num = n; den = d; normalize();}


int get_num() const {return num;}
int get_den() const {return den;}
Fraction add(const Fraction &other);
Fraction mult(const Fraction &other);
Fraction operator+(const Fraction &other)
{return add(other);}
Fraction operator*(const Fraction &other)
{return mult(other);}
int operator==(const Fraction &other);
friend ostream &operator<<(ostream &os, Fraction &fr);

private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};

int main() {
Fraction f1(1, 2);
Fraction f2(1, 3);

Fraction f3 = f1 + f2 + 1;

cout << "1/2 + 1/3 + 1 = " << f3 << endl;


return 0;
}

// ---------------------------------------------------
// FRACTION CLASS FUNCTIONS

Fraction::Fraction(Fraction const &src) {


num = src.num;
den = src.den;
}

// Normalize: put fraction into a standard form, unique


// for each mathematically different value.
//
void Fraction::normalize(){

// Handle cases involving 0

if (den == 0 || num == 0) {
num = 0;
den = 1;
}

// Put neg. sign in numerator only.

286
if (den < 0) {
num *= -1;
den *= -1;
}

// Factor out GCF from numerator and denominator.

int n = gcf(num, den);


num = num / n;
den = den / n;
}

// Greatest Common Factor


//
int Fraction::gcf(int a, int b) {
if (a % b == 0)
return abs(b);
else
return gcf(b, a % b);
}

// Lowest Common Multiple


//
int Fraction::lcm(int a, int b){
return (a / gcf(a, b)) * b;
}

Fraction Fraction::add(const Fraction &other) {


Fraction fract;
int lcd = lcm(den, other.den);
int quot1 = lcd/den;
int quot2 = lcd/other.den;
fract.set(num * quot1 + other.num * quot2, lcd);
fract.normalize();
return fract;
}

Fraction Fraction::mult(const Fraction &other) {


Fraction fract;
fract.set(num * other.num, den * other.den);
fract.normalize();
return fract;
}

int Fraction::operator==(const Fraction &other) {


return (num == other.num && den == other.den);
}

// ---------------------------------------------------
// FRACTION CLASS FRIEND FUNCTION -- THIS IS THE REVISED FUNCTION
CODE

ostream &operator<<(ostream &os, Fraction &fr) {


os << "(" << fr.num << ", " << fr.den << ")";
return os;
}
// Exercitiul 13.3.2.txt
// Acest program adauga functiile operator> si operator<
// in programul fract7.cpp si apoi testeaza aceste functii.

287
#include "stdafx.h"

#include <iostream>
using namespace std;

class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(int n) {set(n, 1);}
Fraction(const Fraction &src);

void set(int n, int d) {num = n; den = d; normalize();}


int get_num() const {return num;}
int get_den() const {return den;}
Fraction add(const Fraction &other);
Fraction mult(const Fraction &other);
Fraction operator+(const Fraction &other)
{return add(other);}
Fraction operator*(const Fraction &other)
{return mult(other);}
int operator==(const Fraction &other);
int operator>(const Fraction &other); // DECLARATION OF >
FNCT.
int operator<(const Fraction &other); // DECLARATION OF <
FNCT.
friend ostream &operator<<(ostream &os, Fraction &fr);

private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};

int main() {
Fraction f1(1, 2);
Fraction f2(1, 3);

if (f1 > f2) // TEST > FUNCTION


cout << "1/2 > 1/3" << endl;
else
cout << "1/2 is not > 1/3" << endl;

if (f1 < f2) // TEST < FUNCTION


cout << "1/2 < 1/3" << endl;
else
cout << "1/2 is not < 1/3" << endl;

return 0;
}

// ---------------------------------------------------
// FRACTION CLASS FUNCTIONS

Fraction::Fraction(Fraction const &src) {


num = src.num;
den = src.den;
}

288
// Normalize: put fraction into a standard form, unique
// for each mathematically different value.
//
void Fraction::normalize(){

// Handle cases involving 0

if (den == 0 || num == 0) {
num = 0;
den = 1;
}

// Put neg. sign in numerator only.

if (den < 0) {
num *= -1;
den *= -1;
}

// Factor out GCF from numerator and denominator.

int n = gcf(num, den);


num = num / n;
den = den / n;
}

// Greatest Common Factor


//
int Fraction::gcf(int a, int b) {
if (a % b == 0)
return abs(b);
else
return gcf(b, a % b);
}

// Lowest Common Multiple


//
int Fraction::lcm(int a, int b){
return (a / gcf(a, b)) * b;
}

Fraction Fraction::add(const Fraction &other) {


Fraction fract;
int lcd = lcm(den, other.den);
int quot1 = lcd/den;
int quot2 = lcd/other.den;
fract.set(num * quot1 + other.num * quot2, lcd);
fract.normalize();
return fract;
}

Fraction Fraction::mult(const Fraction &other) {


Fraction fract;
fract.set(num * other.num, den * other.den);
fract.normalize();
return fract;
}

int Fraction::operator==(const Fraction &other) {


return (num == other.num && den == other.den);

289
}

int Fraction::operator>(const Fraction &other) { // NEW FNCT.


DEFINITION
return ((num * other.den) > (den * other.num));
}

int Fraction::operator<(const Fraction &other) { // NEW FNCT.


DEFINITION
return ((num * other.den) < (den * other.num));
}

// ---------------------------------------------------
// FRACTION CLASS FRIEND FUNCTION

ostream &operator<<(ostream &os, Fraction &fr) {


os << fr.num << "/" << fr.den;
return os;
}

FUNCTII PRIETEN
// Exercitiul 13.3.3.txt
// Acest program adauga functia operator<< la clasa Point.
// Functia este declarata ca prieten al clasei.

#include "stdafx.h"

#include <iostream>
using namespace std;

class Point {
private: // Data members (private)
int x, y;
public: // Constructors
Point() {};
Point(int new_x, int new_y) {set(new_x, new_y);}
Point(const Point &src) {set(src.x, src.y);}

// Operations

Point add(const Point &pt);


Point sub(const Point &pt);
Point operator+(const Point &pt) {return add(pt);}
Point operator-(const Point &pt) {return sub(pt);}

friend ostream &operator<<(ostream &os, Point &pt); // FUNCTION


DECLARED

// Other member functions

void set(int new_x, int new_y);


int get_x() const {return x;}
int get_y() const {return y;}
};

int main() {

Point point1(20, 20);


Point point2(0, 5);

290
Point point3(-10, 25);
Point point4 = point1 + point2 + point3;

cout << "The point is " << point4 << endl; // TEST OPERATOR<<
FUNCT.

return 0;
}

void Point::set(int new_x, int new_y) {


if (new_x < 0)
new_x *= -1;
if (new_y < 0)
new_y *= -1;
x = new_x;
y = new_y;
}

Point Point::add(const Point &pt) {


Point new_pt;
new_pt.x = x + pt.x;
new_pt.y = y + pt.y;
return new_pt;
}

Point Point::sub(const Point &pt) {


Point new_pt;
new_pt.x = x - pt.x;
new_pt.y = y - pt.y;
return new_pt;
}

ostream &operator<<(ostream &os, Point &pt) { // FUNCTION DEFINITION


os << "(" << pt.x << ", " << pt.y << ")";
return os;
}

ALOCAREA DINAMICA A MEMORIEI


Pointeri către obiecte

Exact aşa cum pot fi definiţi pointeri către alte tipuri de variabile, pot exista şi
pointeri către obiecte. Când se doreşte acces la membrii unei clase cu ajutorul unui
pointer către un obiect, se foloseşte operatorul săgeată ( -> ) în locul operatorului
punct. Se poate atribui unui pointer adresa unui membru public al unui obiect şi apoi
să aveţi acces la acel membru folosind pointerul.
Se poate elimina orice nepotrivire folosind un modelator (adică o conversie de tip) dar
astfel se trece peste mecanismul de verificare a tipului din C++. În C++, se realizează
o verificare mai strictă a tipurilor decît în C (unde se poate atribui orice tip de valoare
oricărui pointer), atunci cînd sînt implicaţi pointeri.
Pointerul this
Cînd este apelată o funcţie membru, i se pasează automat un argument implicit
(care nu apare în lista de parametri), care este un pointer către obiectul care a generat
apelul (adică obiectul care a invocat funcţia : obiect.functie(...) ). Acest pointer este
numit this.
La membrii unei clase se poate dobîndi acces direct din cadrul unei funcţii membru,
fără nici un specificator de obiect sau de clasă.

291
Există două restricţii legate de this :

 Funcţiile friend nu sînt membri ai clasei, deci nu le sînt pasaţi pointeri this.
 Funcţiile membre de tip static nu au nici ele un pointer this.

Pointeri către tipuri derivate

În general, un pointer de un anumit tip nu poate indica decît spre un obiect de


acelaşi tip. Totuşi, o excepţie care se referă la clase derivate (şi care este necesară în
anumite situaţii !) este admisă. Astfel, un pointer din clasa de bază poate fi folosit ca
un pointer spre oricare obiect al oricărei clase derivate din clasa de bază. Atenţie,
reciproca nu este adevărată ! Un pointer din clasa derivată nu poate indica spre un
obiect din clasa de bază. Mai mult, chiar dacă se poate folosi un pointer din clasa de
bază pentru a indica un obiect derivat, putem avea acces doar la membrii de tipul
derivat, care au fost importaţi din clasa de bază. Deci nu putem avea acces prin
intermediul acelui pointer, la membrii adăugaţi de clasa derivată (şi justificarea este
logică şi imediată: un pointer din clasa de bază nu poate indica ceva ce nu are de unde
să cunoască - adică membrii adăugaţi - în schimb, poate indica acei membri care sînt
de fapt tot din clasa de bază - dar care sînt moşteniţi, “cunoscuţi” de clasa derivată).
Acest inconvenient poate fi rezolvat prin convertirea unui pointer din clasa de bază
într-unul derivat şi astfel se dobîndeşte acces la întreaga clasă derivată.
Pointeri către membrii clasei

C++ permite generarea unui tip special de pointeri care indică generic spre un
membru al unei clase, nu către un anumit exemplar al acelui membru dintr-un obiect.
Acest tip de pointer este numit pointer către un membru al clasei sau pe scurt pointer
la membru. Acesta nu e acelaşi lucru cu un pointer normal. Un astfel de pointer
asigură doar o poziţionare (un offset) într-un obiect din clasa membrului, unde poate
fi găsit acel membru. Deoarece pointerii la membri nu sînt chiar pointeri în înţelesul
pe care îl cunoaştem, nu li se pot aplica operatorii obişnuiţi în operarea cu pointeri
normali: . şi -> . Pentru a avea acces la membrul unei clase prin intremediul unui
pointer de acest tip, vor trebui folosiţi operatorii speciali pentru pointeri la membri: .*
şi ->* .
Referinţe

O referinţă este un pointer implicit, care acţionează ca un alt nume al unui


obiect. O utilizare importantă a referinţei este crearea funcţiilor care folosesc
trasnmiterea parametrului prin referinţă şi nu metoda implicită din C++, apelarea prin
valoare.
În C, pentru a apela prin referinţă, trebuie pasată funcţiei, explicit, adresa
argumentului. Iată mai jos un program care foloseşte această modalitate ne-
automatizată pentru a transmite un parametru (un întreg) prin referinţă.
Transmiterea referinţelor către obiecte

S-a văzut în precedentul capitol că atunci cînd un obiect este transmis unei funcţii ca
argument, se face automat o copie a acelui obiect, ba mai mult, cînd este realizată
acea copie, nici nu e apelat constructorul obişnuit al clasei (fiind realizată doar o copie
exactă, fără iniţializările şi celelalte operaţii conţinute în constructor). În schimb, la
terminarea funcţiei, este apelat destructorul copiei. Dacă nu se doreşte apelarea

292
destructorului, se poate realiza transmiterea obiectului prin referinţă. La acest gen de
apel, aşa cum ne şi aşteptăm, nu se face o copie a obiectului ci manipularea datelor are
loc chiar în obiectul transmis ca referinţă. Deci destructorul nu mai este apelat la
terminarea funcţiei.
Referinţe independente

Cea mai obişnuită utilizare pentru referinţe este pasarea argumentelor prin
referinţă şi obţinerea valorii returnate de funcţie. Totuşi, pot fi declarate şi referinţe ca
simple variabile. Acest tip de referinţă se numeşte referinţă independentă.
La crearea unei referinţe independente, tot ceea ce se creează este de fapt un al
doilea nume pentru o variabilă. Toate variabilele de tip referinţă independentă trebuie
iniţializate la creare.
Restricţii

Există mai multe restricţii care se aplică referinţelor :

 O referinţă nu se poate referi la altă referinţă (adică nu poate fi obţinută adresa unei
referinţe).
 Nu pot fi create matrice de referinţe.
 Nu se poate crea un pointer spre o referinţă.
 O referinţă nu se poate defini pentru un cîmp de biţi.
 O variabilă de tip referinţă trebuie iniţializată la declarare, dar nu trebuie
iniţializată dacă este membru al unei clase, parametru de funcţie sau valoare
returnată.
 Referinţele nule nu sînt permise.

Observaţie

Următorul aspect este de fapt legat de stilul de programare. Unii programatori


adoptă nişte convenţii legate de asocierea operatorilor * sau &. Astfel :

int& p; // asociat cu tipul


int &p; // asociat cu variabila

cele două declaraţii sînt echivalente funcţional dar asocierea cu numele tipului reflectă
dorinţa programatorilor ca limbajul C++ să pună la dispoziţie un pointer distinct
pentru tip (tipul întreg, în cazul nostru). Dar sintaxa din C++nu presupune
distributivitatea operatorilor într-o listă de parametri. De aceea se pot uşor formula
declaraţii greşite. Astfel :

int* a,b;

creează un pointer de tip întreg, nu doi, aşa cum am fi dorit. Într-adevăr, în C++ ,
operatorii * sau & se referă doar la următoarea variabilă şi nu la tipul variabilelor,
deşi văzînd linia-sursă am fi tentaţi să credem că atît a cît şi b ar fi pointeri. Această
confuzie este frecventă chiar şi la programatorii buni, cînd nu sînt atenţi.
Din punctul de vedere al compilatorului, este indiferentă forma de scriere de
mai sus. Pentru evitarea confuziilor, se recomandă asocierea operatorilor de mai sus
totuşi cu variabilele.

293
Operatorii de alocare dinamică din C++

În limbajul C, după cum se cunoaşte, alocarea dinamică a memoriei este


realizată de funcţiile malloc() şi free(). Pentru compatibilitatea de jos în sus, funcţiile
acestea de alocare dinamică sînt valabile şi în C++, dar există aici nişte funcţii proprii,
de fapt nişte operatori, mai uşor de folosit : new şi delete. Utilizarea acestora prezintă
numeroase avantaje.
Operatorul new returnează un pointer către memoria alocată. Ca şi malloc(),
new alocă memorie din zona heap (zona de memorie liberă). Dacă nu există memorie
suficientă pentru alocare, se returnează un pointer nul. Operatorul delete eliberează
memoria alocată anterior prin utilizarea operatorului new. Formele generale de
utilizare ale celor doi operatori sînt:

p_var=new tip;
...
delete p_var;

Aici, p_var este o variabilă de tip pointer care primeşte un pointer spre
memoria care este suficient de mare pentru a păstra un element de tipul tip.
Operatorul delete trebuie să fie folosit doar cu un pointer valid, alocat deja prin new.
Folosirea oricărui alt tip de pointer cu delete duce la un rezultat imprevizibil şi
aproape sigur determină probleme, chiar căderea sistemului.
Deşi new şi delete efectuează funcţii similare cu malloc() şi free(), ele
prezintă mai multe avantaje:

 new alocă automat memorie suficientă pentru păstrarea obiectelor de tipul


specificat (deci nu trebuie determinată mărimea obiectului cu sizeof).
Astfel, se elimină orice posibilitate de eroare în privinţa spaţiului de
alocare.
 new returnează automat un pointer de tipul specificat, nefiind necesară
utilizarea unui modelator de tip, aşa cum trebuia făcut cu malloc().
 Atît new cît şi delete pot fi supraîncărcaţi, permiţînd crearea unui sistem
de alocare propriu.
 Prin utilizarea new memoria poate fi iniţializată cu o valoare cunoscută,
scriind în instrucţiunea cu new o valoare după numele tipului :

p_var=new tip_var (initializator)


Alocare de memorie pentru obiecte

Obiectelor li se poate aloca memorie dinamic, folosind new. Cînd se face


această alocare, se creează un obiect şi se returnează un pointer către el. Obiectul creat
dinamic se comportă ca oricare alt obiect. Cînd este creat, este apelat constructorul,
dacă există. Atunci cînd este apelat delete (deci se eliberează memoria ocupată), se
execută funcţia destructor, dacă există.
Parametrii funcţiei constructor ai obiectului sînt specificaţi după numele tipului, la fel
ca şi pentru alte tipuri de iniţializări.
Se poate face alocare dinamică şi pentru matricele de obiecte, dar deoarece
matricele de obiecte create cu new nu pot fi iniţializate, trebuie să ne asigurăm că una
din funcţiile constructor este neapărat fără parametri. În caz contrar, compilatorul va

294
semnala eroare (deoarece ar trebui să iniţializeze un obiect care nu permite
iniţializarea). Prin folosirea delete [], funcţia destructor va fi apelată pentru fiecare
obiect al clasei.

//Sa se aloce memorie pentru un vector,sa se faca media elementelor


sale
//si sa se elibereze memoria ocupata

#include "stdafx.h"

#include <iostream>
using namespace std;

int main() {
int sum = 0;
int n;
int *p;

cout << "Enter number of items: ";


cin >> n;

p = new int[n]; // Allocate n integers

for (int i = 0; i < n; i++) {


cout << "Enter item #" << i << ": ";
cin >> p[i];
sum += p[i];
}
cout << "Here are the items: ";
for (int i = 0; i < n; i++)
cout << p[i] << ", ";
cout << endl;
cout << "The total is: " << sum << endl;
cout << "The average is: " << (double) sum / n << endl;

delete [] p; // Release n integers.

return 0;
}

// Exercitiul 14.1.1.txt
// Acest program modifica scriptul new1.cpp pentru a utiliza un tip
double
// ca tip de baza pentru o matrice in loc de tipul int.
//se aloca memorie pentru elementele unei matrice cu elemete reale

#include "stdafx.h"

#include <iostream>
using namespace std;

int main() {
double sum = 0.0; // TYPE ALTERED TO DOUBLE HERE.
int n;
double *p; // TYPE OF *p ALTERED TO DOUBLE.

cout << "Enter number of items: ";


cin >> n;

p = new double[n]; // Allocate n double -- ALTERED FROM INT

295
for (int i = 0; i < n; i++) {
cout << "Enter item #" << i << ": ";
cin >> p[i];
sum += p[i];
}
cout << "Here are the items: ";
for (int i = 0; i < n; i++)
cout << p[i] << ", ";
cout << endl;
cout << "The total is: " << sum << endl;
cout << "The average is: " << sum / n << endl;

delete [] p; // Release n integers.

return 0;
}
//sa se creeze un analizator lexical adica un program care
//sa imparta in cuvinte o fraza dandu-se un delimitator
//ex:3/4/5 =>
// 3
// 4
// 5

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

class StringParser {
private:
int pos;
char *input_str;
char *delimiters;

public:
StringParser(char *inp, char *delim)
{input_str = inp; delimiters = delim; pos = 0; }

StringParser(char *inp)
{input_str = inp; delimiters = ","; pos = 0; }

char *get();
int get_int();
int more() {return input_str[pos] != '\0'; }
void reset() {pos = 0;}
};

int main() {
char input_str[100];
char *p;

cout << "Enter input line: ";


cin.getline(input_str, 99);

StringParser parser(input_str, "/,");

while (parser.more()) {
p = parser.get(); // Get ptr to newly allocated string
cout << p << endl; // Print it

296
delete [] p; // Release string memory
}

return 0;
}

// ----------------------------------------------
// STRINGPARSER CLASS FUNCTIONS

char *StringParser::get() {
int j = 0;
char *new_str;
new_str = new char[100];

// Consume initial delimiters, if any

while (strchr(delimiters, input_str[pos]))


pos++;

// Copy characters as long as none is a


// delimiter or end of string (null)

while (input_str[pos] != '\0' &&


! strchr(delimiters, input_str[pos]))

new_str[j++] = input_str[pos++];

// Finish string and return it.

new_str[j] = '\0';
return new_str;
}

int StringParser::get_int() {
char *p = get();
return atoi(p);
delete [] p;
}

// Exercitiul 14.2.1.txt
// Acest program modifica scrptul din exemplul 14.2 astfel incat sa
utilizeze
// functia membru get_int() (limitind intrarile la valori intregi)
in locul
// functiei get().

#include "stdafx.h"

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

class StringParser {
private:
int pos;
char *input_str;
char *delimiters;

public:
StringParser(char *inp, char *delim)

297
{input_str = inp; delimiters = delim; pos = 0; }

StringParser(char *inp)
{input_str = inp; delimiters = ","; pos = 0; }

char *get();
int get_int();
int more() {return input_str[pos] != '\0'; }
void reset() {pos = 0;}
};

int main() {
char input_str[100];
int n; // USE INTEGER RATHER THAN CHAR* STRING

cout << "Enter input line: ";


cin.getline(input_str, 99);

StringParser parser(input_str, "/,");

while (parser.more()) {
n = parser.get_int(); // GET AN INTEGER FROM NEXT SUBSTRING
cout << n << endl; // Print it
}

return 0;
}

// ----------------------------------------------
// STRINGPARSER CLASS FUNCTIONS

char *StringParser::get() {
int j = 0;
char *new_str;
new_str = new char[100];

// Consume initial delimiters, if any

while (strchr(delimiters, input_str[pos]))


pos++;

// Copy characters as long as none is a


// delimiter or end of string (null)

while (input_str[pos] != '\0' &&


! strchr(delimiters, input_str[pos]))

new_str[j++] = input_str[pos++];

// Finish string and return it.

new_str[j] = '\0';
return new_str;
}

int StringParser::get_int() {
char *p = get();
return atoi(p);
delete [] p;
}
// Copierea unui subsir intr-un sir prin alocare dinamica

298
#include "stdafx.h"

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

class StringParser {
private:
int pos;
char *input_str;
char *delimiters;

public:
StringParser(char *inp, char *delim)
{input_str = inp; delimiters = delim; pos = 0; }

StringParser(char *inp)
{input_str = inp; delimiters = ","; pos = 0; }

char *get(char *dest); // ALTERED DECL. - INCLUDES DESTINATION


STRING
int get_int();
int more() {return input_str[pos] != '\0'; }
void reset() {pos = 0;}
};

int main() {
char input_str[100];
char substr[100]; // USES A STATIC STRING -- THIS SHOULD BE
LARGE
// ENOUGH TO CONTAIN ANY POSSIBLE
SUBSTRING.

cout << "Enter input line: ";


cin.getline(input_str, 99);

StringParser parser(input_str, "/,");

while (parser.more()) {
parser.get(substr); // GET NEXT SUBSTRING INTO THE STRING
VAR.
cout << substr << endl; // Print it
}

return 0;
}

// ----------------------------------------------
// STRINGPARSER CLASS FUNCTIONS

char *StringParser::get(char *dest) {


int j = 0;

// Consume initial delimiters, if any

while (strchr(delimiters, input_str[pos]))


pos++;

// Copy characters as long as none is a


// delimiter or end of string (null)

299
while (input_str[pos] != '\0' &&
! strchr(delimiters, input_str[pos]))

dest[j++] = input_str[pos++];

// Finish string and return it.

dest[j] = '\0';
return dest;
}

int StringParser::get_int() { // THIS FUNCTION MUST ALSO BE


REVISED, AS IT
char temp[256]; // CALLS THE GET FUNCTION.
get(temp);
return atoi(temp);
}
DESTRUCTORI SI CUVANTUL CHEIE this
//sa se creeze un destructor care scoate din memorie un sir de
caractere
#include "stdafx.h"

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

class String {
private:
char *ptr;
public:
String();
String(char *s);
~String();

int operator==(const String &other);


operator char*() {return ptr;}
};

int main() {
String a("STRING 1");
String b("STRING 2");
cout << "The value of a is: " << endl;
cout << a << endl;
cout << "The value of b is: " << endl;
cout << b << endl;
}

// ----------------------------------
// STRING CLASS FUNCTIONS

String::String() {
ptr = new char[1];
ptr[0] = '\0';
}

String::String(char *s) {
int n = strlen(s);
ptr = new char[n + 1];

300
strcpy(ptr, s);
}

String::~String() {
delete [] ptr;
}

int String:: operator==(const String &other) {


return (strcmp(ptr, other.ptr) == 0);
}

// Exercitiul 15.1.1.txt
// Aceasta versiune a programului string1.cpp testeaza
// constructorul prestabilit String().

#include "stdafx.h"

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

class String {
private:
char *ptr;
public:
String();
String(char *s);
~String();

int operator==(const String &other);


operator char*() {return ptr;}
};

int main() {
String a("STRING 1");
String b("STRING 2");
String c; // NEW OBJECT DECL.
cout << "The value of a is: " << endl;
cout << a << endl;
cout << "The value of b is: " << endl;
cout << b << endl;

// PRINT VALUE OF C BETWEEN BRACKETS:

cout << "The value of c is between these brackets<";


cout << c << ">" << endl;
}

// ----------------------------------
// STRING CLASS FUNCTIONS

String::String() {
ptr = new char[1];
ptr[0] = '\0';
}

String::String(char *s) {
int n = strlen(s);
ptr = new char[n + 1];
strcpy(ptr, s);

301
}

String::~String() {
delete [] ptr;
}

int String:: operator==(const String &other) {


return (strcmp(ptr, other.ptr) == 0);
}
// sa se supraincarce (defineasca) intr-o clsa operatori de
concaternare

#include "stdafx.h"

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

class String {
private:
char *ptr;
public:
String();
String(char *s);
String(const String &src);
~String();

String& operator=(const String &src)


{cpy(src.ptr); return *this;}

String& operator=(char *s)


{cpy(s); return *this;}

String operator+(char *s);


int operator==(const String &other);
operator char*() {return ptr;}

void cat(char *s);


void cpy(char *s);
};

int main() {
String a, b, c;
a = "I ";
b = "am ";
c = "so ";
String d = a + b + c + "very happy!\n";
cout << d;
return 0;
}

// ----------------------------------
// STRING CLASS FUNCTIONS

String::String() {
ptr = new char[1];
ptr[0] = '\0';
}

String::String(char *s) {
int n = strlen(s);

302
ptr = new char[n + 1];
strcpy(ptr, s);
}

String::String(const String &src) {


int n = strlen(src.ptr);
ptr = new char[n + 1];
strcpy(ptr, src.ptr);
}

String::~String() {
delete [] ptr;
}

int String:: operator==(const String &other) {


return (strcmp(ptr, other.ptr) == 0);
}

String String::operator+(char *s) {


String new_str(ptr);
new_str.cat(s);
return new_str;
}

// cpy -- Copy string function


//
void String::cpy(char *s) {
delete [] ptr;
int n = strlen(s);
ptr = new char[n + 1];
strcpy(ptr, s);
}

// cat -- Concatenate string function


//
void String::cat(char *s) {

// Allocate sufficient room for new string data.

int n = strlen(ptr) + strlen(s);


char *p1 = new char[n + 1];

// Copy data to this new memory block.

strcpy(p1, ptr);
strcat(p1, s);

// Release old memory block and update ptr.

delete [] ptr;
ptr = p1;
}

// Exercitiul 15.2.1.txt
// Acest exemplu revizuieste programul string2.cpp astfel incat sa
suporte functia
// operator+ sub forma unei functii prieten globale.

#include "stdafx.h"

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

class String {
private:
char *ptr;
public:
String();
String(char *s);
String(const String &src);
~String();

String& operator=(const String &src)


{cpy(src.ptr); return *this;}

String& operator=(char *s)


{cpy(s); return *this;}

// NEW DECLARATIONS -- FRIEND FUNCTIONS

friend String operator+(String str1, String str2);


friend String operator+(char *s, String str);
friend String operator+(String str, char *s);

int operator==(const String &other);


operator char*() {return ptr;}

void cat(char *s);


void cpy(char *s);
};

int main() {
String a, b, c;
a = "I ";
b = "am ";
c = "so ";

// THIS NEXT STATEMENT TESTS THE FRIEND FUNCTIONS

String d = "Let me say that " + a + b + c + "very happy!\n";


cout << d;
return 0;
}

// ----------------------------------
// STRING CLASS FUNCTIONS

String::String() {
ptr = new char[1];
ptr[0] = '\0';
}

String::String(char *s) {
int n = strlen(s);
ptr = new char[n + 1];
strcpy(ptr, s);
}

String::String(const String &src) {


int n = strlen(src.ptr);

304
ptr = new char[n + 1];
strcpy(ptr, src.ptr);
}

String::~String() {
delete [] ptr;
}

int String:: operator==(const String &other) {


return (strcmp(ptr, other.ptr) == 0);
}

// cpy -- Copy string function


//
void String::cpy(char *s) {
delete [] ptr;
int n = strlen(s);
ptr = new char[n + 1];
strcpy(ptr, s);
}

// cat -- Concatenate string function


//
void String::cat(char *s) {

// Allocate sufficient room for new string data.

int n = strlen(ptr) + strlen(s);


char *p1 = new char[n + 1];

// Copy data to this new memory block.

strcpy(p1, ptr);
strcat(p1, s);

// Release old memory block and update ptr.

delete [] ptr;
ptr = p1;
}

// GLOBAL FRIEND FUNCTIONS IMPLEMENTING THE + OPERATOR


// THESE MUST SUPPORT EVERY COMBINATION ALLOWED OF
// char* AND string TYPE.

String operator+(String str1, String str2) {


String new_str(str1);
new_str.cat(str2);
return new_str;
}

String operator+(String str, char *s) {


String new_str(str);
new_str.cat(s);
return new_str;
}

String operator+(char *s, String str) {


String new_str(s);

305
new_str.cat(str);
return new_str;
}

// Exercitiul 15.2.2.txt
// Acest program modifica declaratiile din string2.cpp
// astfel incat fiecare functie care are un argument de tipul
// char* sa foloseasca un argument de tipul const char*.

#include "stdafx.h"

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

class String {
private:
char *ptr;
public:
String();
String(const char *s); // ALTERED LINE
String(const String &src);
~String();

String& operator=(const String &src)


{cpy(src.ptr); return *this;}

String& operator=(const char *s) // ALTERED LINE


{cpy(s); return *this;}

String operator+(const char *s); // ALTERED LINE


int operator==(const String &other);
operator char*() {return ptr;}

void cat(const char *s); // ALTERED LINE


void cpy(const char *s); // ALTERED LINE
};

int main() {
String a, b, c;
a = "I ";
b = "am ";
c = "so ";
String d = a + b + c + "very happy!\n";
cout << d;
return 0;
}

// ----------------------------------
// STRING CLASS FUNCTIONS

String::String() {
ptr = new char[1];
ptr[0] = '\0';
}

String::String(const char *s) { // ALTERED LINE


int n = strlen(s);
ptr = new char[n + 1];

306
strcpy(ptr, s);
}

String::String(const String &src) {


int n = strlen(src.ptr);
ptr = new char[n + 1];
strcpy(ptr, src.ptr);
}

String::~String() {
delete [] ptr;
}

int String:: operator==(const String &other) {


return (strcmp(ptr, other.ptr) == 0);
}

String String::operator+(const char *s) { // ALTERED LINE


String new_str(ptr);
new_str.cat(s);
return new_str;
}

// cpy -- Copy string function


//
void String::cpy(const char *s) { // ALTERED LINE
delete [] ptr;
int n = strlen(s);
ptr = new char[n + 1];
strcpy(ptr, s);
}

// cat -- Concatenate string function


//
void String::cat(const char *s) { // ALTERED LINE

// Allocate sufficient room for new string data.

int n = strlen(ptr) + strlen(s);


char *p1 = new char[n + 1];

// Copy data to this new memory block.

strcpy(p1, ptr);
strcat(p1, s);

// Release old memory block and update ptr.

delete [] ptr;
ptr = p1;
}
MOSTENIRE-IN PROGRAMAREA PE OBIECT VISUAL
C++.NET
Moştenirea

Moştenirea este una dintre caracteristicile cele mai importante ale unui limbaj
de programare OO. În C++ moştenirea este realizată prin acceptarea ca o clasă să
încorporeze în declararea sa altă clasă. Moştenirea permite construirea unei ierarhii

307
de clase, trecerea de la cele mai generale la cele mai particulare. Procesul acesta
implică pentru început definirea clasei de bază, care stabileşte calităţile comune ale
tuturor obiectelor ce vor deriva de aici. Clasa de bază reprezintă cea mai generală
descriere. Clasele derivate (obţinute prin moştenire) din clasa de bază se numesc chiar
clase derivate. O clasă derivată include toate caracteristicile clasei de bază şi în plus
calităţi proprii acelei clase.

//sa se prezinte un exemplu de subclasa la fractii

#include "stdafx.h"

#include <iostream>
using namespace std;

class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(int n) {set(n, 1);}
Fraction(const Fraction &src);

void set(int n, int d) {num = n; den = d; normalize();}


int get_num() const {return num;}
int get_den() const {return den;}
Fraction add(const Fraction &other);
Fraction mult(const Fraction &other);
Fraction operator+(const Fraction &other)
{return add(other);}
Fraction operator*(const Fraction &other)
{return mult(other);}
int operator==(const Fraction &other);
friend ostream &operator<<(ostream &os, Fraction &fr);

private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};

class FloatFraction : public Fraction {


public:
double get_float() {
return static_cast<double>(get_num())/get_den();}
};

int main() {
FloatFraction fract1;

fract1.set(1, 2);
cout << "Value of 1/2 is " << fract1.get_float() << endl;

308
fract1.set(3, 5);
cout << "Value of 3/5 is " << fract1.get_float() << endl;
return 0;
}

Fraction::Fraction(Fraction const &src) {


num = src.num;
den = src.den;
}

void Fraction::normalize(){

if (den == 0 || num == 0) {
num = 0;
den = 1;
}

// Put neg. sign in numerator only.

if (den < 0) {
num *= -1;
den *= -1;
}

// Factor out GCF from numerator and denominator.

int n = gcf(num, den);


num = num / n;
den = den / n;
}

// Greatest Common Factor


//
int Fraction::gcf(int a, int b) {
if (a % b == 0)
return abs(b);
else
return gcf(b, a % b);
}

// Lowest Common Multiple


//
int Fraction::lcm(int a, int b){
return (a / gcf(a, b)) * b;
}

Fraction Fraction::add(const Fraction &other) {


Fraction fract;
int lcd = lcm(den, other.den);
int quot1 = lcd/den;
int quot2 = lcd/other.den;
fract.set(num * quot1 + other.num * quot2, lcd);

309
fract.normalize();
return fract;
}

Fraction Fraction::mult(const Fraction &other) {


Fraction fract;
fract.set(num * other.num, den * other.den);
fract.normalize();
return fract;
}

int Fraction::operator==(const Fraction &other) {


return (num == other.num && den == other.den);
}

// ---------------------------------------------------
// FRACTION CLASS FRIEND FUNCTION

ostream &operator<<(ostream &os, Fraction &fr) {


os << fr.num << "/" << fr.den;
return os;
}
// Exercitiul 16.1.1.txt
// Acest program modifica scriptul floatfract1.cpp astfel incat sa
// contina o functie set_float().

#include "stdafx.h"

#include <iostream>
using namespace std;

class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(int n) {set(n, 1);}
Fraction(const Fraction &src);

void set(int n, int d) {num = n; den = d; normalize();}


int get_num() const {return num;}
int get_den() const {return den;}
Fraction add(const Fraction &other);
Fraction mult(const Fraction &other);
Fraction operator+(const Fraction &other)
{return add(other);}
Fraction operator*(const Fraction &other)
{return mult(other);}
int operator==(const Fraction &other);
friend ostream &operator<<(ostream &os, Fraction &fr);

private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};

class FloatFraction : public Fraction {

310
public:
double get_float() {
return static_cast<double>(get_num())/get_den();}

void set_float(double x);

};

int main() {
FloatFraction fract1;

fract1.set_float(0.5);
cout << "Value of 0.5 is " << fract1.get_float() << endl;
fract1.set_float(0.6);
cout << "Value of 0.6 is " << fract1.get_float() << endl;
return 0;
}

void FloatFraction::set_float(double x) {
int new_val = static_cast<int>(x * 100.0);
set(new_val, 100);
}

// ---------------------------------------------------
// FRACTION CLASS FUNCTIONS

Fraction::Fraction(Fraction const &src) {


num = src.num;
den = src.den;
}

// Normalize: put fraction into a standard form, unique


// for each mathematically different value.
//
void Fraction::normalize(){

// Handle cases involving 0

if (den == 0 || num == 0) {
num = 0;
den = 1;
}

// Put neg. sign in numerator only.

if (den < 0) {

311
num *= -1;
den *= -1;
}

// Factor out GCF from numerator and denominator.

int n = gcf(num, den);


num = num / n;
den = den / n;
}

// Greatest Common Factor


//
int Fraction::gcf(int a, int b) {
if (a % b == 0)
return abs(b);
else
return gcf(b, a % b);
}

// Lowest Common Multiple


//
int Fraction::lcm(int a, int b){
return (a / gcf(a, b)) * b;
}

Fraction Fraction::add(const Fraction &other) {


Fraction fract;
int lcd = lcm(den, other.den);
int quot1 = lcd/den;
int quot2 = lcd/other.den;
fract.set(num * quot1 + other.num * quot2, lcd);
fract.normalize();
return fract;
}

Fraction Fraction::mult(const Fraction &other) {


Fraction fract;
fract.set(num * other.num, den * other.den);
fract.normalize();
return fract;
}

int Fraction::operator==(const Fraction &other) {


return (num == other.num && den == other.den);
}

ostream &operator<<(ostream &os, Fraction &fr) {


os << fr.num << "/" << fr.den;
return os;
}
// Exercitiul 16.1.1.txt
// Acest program modifica scriptul floatfract1.cpp astfel incat sa
includa
// functia set_float().

#include "stdafx.h"
#include <iostream>
using namespace std;

312
class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(int n) {set(n, 1);}
Fraction(const Fraction &src);

void set(int n, int d) {num = n; den = d; normalize();}


int get_num() const {return num;}
int get_den() const {return den;}
Fraction add(const Fraction &other);
Fraction mult(const Fraction &other);
Fraction operator+(const Fraction &other)
{return add(other);}
Fraction operator*(const Fraction &other)
{return mult(other);}
int operator==(const Fraction &other);
friend ostream &operator<<(ostream &os, Fraction &fr);

private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};

class FloatFraction : public Fraction {


public:

FloatFraction(double x) {set_float(x); } // ADD CONSTRUCTOR

double get_float() {
return static_cast<double>(get_num())/get_den();}

void set_float(double x);

};

int main() {
FloatFraction fract1(0.5), fract2(0.6);

cout << "Value of 0.5 is " << fract1.get_float() << endl;


cout << "Value of 0.6 is " << fract2.get_float() << endl;
return 0;
}

void FloatFraction::set_float(double x) {
int new_val = static_cast<int>(x * 100.0);
set(new_val, 100);

313
}

Fraction::Fraction(Fraction const &src) {


num = src.num;
den = src.den;
}

// Normalize: put fraction into a standard form, unique


// for each mathematically different value.
//
void Fraction::normalize(){

// Handle cases involving 0

if (den == 0 || num == 0) {
num = 0;
den = 1;
}

// Put neg. sign in numerator only.

if (den < 0) {
num *= -1;
den *= -1;
}

// Factor out GCF from numerator and denominator.

int n = gcf(num, den);


num = num / n;
den = den / n;
}

// Greatest Common Factor


//
int Fraction::gcf(int a, int b) {
if (a % b == 0)
return abs(b);
else
return gcf(b, a % b);
}

// Lowest Common Multiple


//
int Fraction::lcm(int a, int b){
return (a / gcf(a, b)) * b;
}

Fraction Fraction::add(const Fraction &other) {


Fraction fract;
int lcd = lcm(den, other.den);
int quot1 = lcd/den;
int quot2 = lcd/other.den;
fract.set(num * quot1 + other.num * quot2, lcd);
fract.normalize();
return fract;
}

Fraction Fraction::mult(const Fraction &other) {

314
Fraction fract;
fract.set(num * other.num, den * other.den);
fract.normalize();
return fract;
}

int Fraction::operator==(const Fraction &other) {


return (num == other.num && den == other.den);
}

// ---------------------------------------------------
// FRACTION CLASS FRIEND FUNCTION

ostream &operator<<(ostream &os, Fraction &fr) {


os << fr.num << "/" << fr.den;
return os;
}

 metoda este si importul unui fisier sub forma


#include<nume_fiesier.cpp> exemplu #include "Fract7.cpp"
dar
1) el trebuie salvat in directorul unde avem exemplele de mostenire

C:\Documents and Settings\ticatica\My Documents\


adica in :
Visual Studio Projects\e16import1
2)trebuie sa-l importam in proiectul nostru cu comanda:
proiect/add existing item

315
aleg calea spre fisier

open
4)Fisierul de imoprtat trebuie sa nu contina sectiunea main()
deci sa aiba continutul de mai jos:
#include <iostream>
using namespace std;

class Fraction {
private:
int num, den; // Numerator and denominator.
public:
Fraction() {set(0, 1);}
Fraction(int n, int d) {set(n, d);}
Fraction(int n) {set(n, 1);}
Fraction(const Fraction &src);

void set(int n, int d) {num = n; den = d; normalize();}


int get_num() const {return num;}
int get_den() const {return den;}
Fraction add(const Fraction &other);
Fraction mult(const Fraction &other);
Fraction operator+(const Fraction &other)
{return add(other);}
Fraction operator*(const Fraction &other)
{return mult(other);}
int operator==(const Fraction &other);
friend ostream &operator<<(ostream &os, Fraction &fr);

private:
void normalize(); // Put fraction into standard form.
int gcf(int a, int b); // Greatest Common Factor.
int lcm(int a, int b); // Lowest Common Denominator.
};

316
// ---------------------------------------------------
// FRACTION CLASS FUNCTIONS

Fraction::Fraction(Fraction const &src) {


num = src.num;
den = src.den;
}

// Normalize: put fraction into a standard form, unique


// for each mathematically different value.
//
void Fraction::normalize(){

// Handle cases involving 0

if (den == 0 || num == 0) {
num = 0;
den = 1;
}

// Put neg. sign in numerator only.

if (den < 0) {
num *= -1;
den *= -1;
}

// Factor out GCF from numerator and denominator.

int n = gcf(num, den);


num = num / n;
den = den / n;
}

// Greatest Common Factor


//
int Fraction::gcf(int a, int b) {
if (a % b == 0)
return abs(b);
else
return gcf(b, a % b);
}

// Lowest Common Multiple


//
int Fraction::lcm(int a, int b){
return (a / gcf(a, b)) * b;
}

Fraction Fraction::add(const Fraction &other) {


Fraction fract;
int lcd = lcm(den, other.den);
int quot1 = lcd/den;
int quot2 = lcd/other.den;
fract.set(num * quot1 + other.num * quot2, lcd);
fract.normalize();
return fract;
}

Fraction Fraction::mult(const Fraction &other) {

317
Fraction fract;
fract.set(num * other.num, den * other.den);
fract.normalize();
return fract;
}

int Fraction::operator==(const Fraction &other) {


return (num == other.num && den == other.den);
}

// ---------------------------------------------------
// FRACTION CLASS FRIEND FUNCTION

ostream &operator<<(ostream &os, Fraction &fr) {


os << fr.num << "/" << fr.den;
return os;
}
5)scriu contiunutul fisierului nou (cel cu subclasa si il execut) dar sa contina #include
"Fract7.cpp"
// Sa se creeze o subclasa prin includerea altui fisier
//cu clasa de baza

#include "stdafx.h"

#include <iostream>
#include "Fract7.cpp"
using namespace std;

class FloatFraction : public Fraction {


public:
double get_float() {
return static_cast<double>(get_num())/get_den();}

void set_float(double x); // NEW DECLARATION

};

int main() {
FloatFraction fract1;

fract1.set_float(0.5);
cout << "Value of 0.5 is " << fract1.get_float() << endl;
fract1.set_float(0.6);
cout << "Value of 0.6 is " << fract1.get_float() << endl;
return 0;
}

void FloatFraction::set_float(double x) {
int new_val = static_cast<int>(x * 100.0);
set(new_val, 100);
}
POLIMORIFISM
Polimorfismul cu functii virtuale

318
Polimorfismul in C++ este admis atit in timpul compilarii cit si in
timpul rularii. polimorfismul din timpul rularii este realizat folosind
mostenirea si functiile virtuale.
Functiile virtuale

O functie virtuala este declarata ca fiind virtual in clasa de baza si redefinita de


o clasa derivata. Redefinirea functiei in clasa derivata are prioritate fata de definirea
functiei din clasa de baza. O functie virtuala declarata in clasa de baza actioneaza ca
un substitut pentru pastrarea datelor care specifica o clasa generala de actiuni si
declara in general forma interfetei. Redefinirea unei functii virtuale intr-o clasa derivata
ofera operatiile efective pe care le executa functia. deci o functie virtuala defineste o
clasa generala de actiuni iar redefinirea ei introduce o metoda specifica.
Utilizarea obisnuita a unei functii virtuale (deci folosind operatorul punct) nu
difera de cea a altor functii membre. Insa utilitatea deosebita a functiilor virtuale,
respectiv, realizarea polimorfismului, decurge din folosirea pointerilor pentru apelul
acestora. Cind un pointer indica spre un obiect derivat care contine o functie virtuala,
la executie se determina automat care dintre versiunile functiei sa fie apelata, in
functie de tipul obiectului spre care indica pointerul. De aceea, cind sint indicate
obiecte diferite, se executa versiunile corespunzatoare ale functiilor virtuale.
La redefinire cuvintul cheie virtual nu mai este necesar, dar nu este eroare daca totusi
il folosim.
Proprietati ale functiilor virtuale

Functiile virtuale si utilizarea acestora sint caracterizate de anumite proprietati :

a. Atributul virtual este mostenit

Mostenirea transmite si natura virtuala a unei functii. Aceasta inseamna ca atunci


cind o
clasa derivata care a mostenit o functie virtuala este ea insasi folosita ca o clasa de
baza pentru o alta clasa derivata, functia virtuala poate fi in continuare suprascrisa.
Deci o functie ramine virtuala indiferent de cite ori este mostenita.
Polimorfismul din timpul rularii (ca in exemplul de mai sus) este permis doar
folosind pointeri, adica exact in modul prezentat in exemplu.
Aparent, redefinirea unei functii virtuale intr-o clasa derivata pare similara cu
supraincarcarea functiei (overload). Exista totusi mai multe diferente. Cea mai
importanta este aceea ca prototipul pentru o functie virtuala redefinita trebuie sa
coincida cu cel specificat in clasa de baza (la supraincarcare, numarul sau tipurile
parametrilor trebuie sa difere !). Daca prototipul difera la redefinire, compilatorul va
considera functia respectiva o simpla functie supraincarcata si avantajele folosirii
functiilor virtuale se pierd.
Exista o serie de restrictii la utilizarea functiilor virtuale:
- acestea nu pot fi membri static ai clasei, de asemenea nu pot fi nici
friend;
- functiile constructor nu pot fi virtuale (in schimb functiile destructor
pot fi).

319
Datorita restrictiilor si diferentelor dintre functiile supraincarcate si cele virtuale,
pentru descrierea redefinirii functiei virtuale intr-o clasa derivata se foloseste operandul
suprascriere.
O clasa care include o functie virtuala se numeste clasa
polimorfica.
b. Functiile virtuale sint ierarhizate

S-a vazut ca o functie declarata virtual in clasa de baza poate fi suprascrisa de o


clasa
derivata. Functia nu trebuie neaparat sa fie suprascrisa. Daca functia nu
este suprascrisa in clasa derivata, pentru un obiect din clasa derivata este
valabila forma functiei definite in clasa de baza.
Functii virtuale pure

S-a vazut ca in cazul ueni ierarhii, va fi folosita functia virtuala a clasei


precedente in ordine ierarhica, daca ea nu este redefinita in cadrul clasei curente. Dar
se poate chiar ca in clasa de baza sa nu fie definita (decit declarata) nici o functie
virtuala. Motive pot sa fie mai multe: sint situatii cind la nivelul clasei de baza nu sint
suficiente informatii pentru a permite crearea unei functii virtuale sau altele in care
dorim sa ne asiguram ca toate clasele deerivate suprascriu functiile virtuale.
O functie virtuala pura este o functie virtuala care nu are definitie in clasa de
baza. Declararea unei asemenea functii are urmatoarea forma generala :

virtual tip nume_functie(lista_parametri) = 0;

Orice clasa derivata trebuie sa asigure o definire fiecarei functii


virtuale pure. Daca aceasta cerinta nu este indeplinita, compilatorul
sesizeaza eroare.
In practica programarii in C++ se folosesc citeodata clasele abstracte. Acestea sint
clase care contin cel putin o functie virtuala pura. Deoarece o clasa abstracta contine
una sau mai multe functii pentru care nu exista definitii (adica sint functii virtuale
pure), nu pot fi create obiecte de tipul acelei clase. O clasa abstracta este un tip
incomplet care este folosit doar pentru mai usoara definire a claselor derivate.
Chiar daca nu pot fi create obiecte de tipul unei clase abstracte, se pot crea
pointeri si referinte pentru astfel de clase. Aceasta permite claselor abstracte sa admita
polimorfismul in timpul rularii, care consta din selectarea functiei virtuale corecte de
catre pointerii clasei de baza.
Utilizarea functiilor virtuale

Unul dintre aspectele esentiale ale programarii orientate pe obiecte este


principiul “o interfata – metode multiple”. Aceasta inseamna ca poate fi definita o
clasa generala de actiuni pentru care interfata este aceeasi, iar fiecare instanta a clasei
generale care defineste operatiile efective corespunde propriei sale situatii specifice.
Deci o clasa de baza poate fi folosita pentru a defini natura unei interfete cu o clasa
generala, iar fiecare clasa derivata introduce apoi operatiile specifice cerute de tipurile
de date folosite de tipul derivat.

320
Una dintre caile cele mai indicate pentru a asigura transpunerea in practica a
principiului “o interfata – metode multiple” este folosirea functiilor virtuale, a claselor
abstracte si a polimorfismului in timpul rularii. Folosind aceste caracteristici, se pot
realiza ierarhii care sa faca trecerea de la general la specific (de la clasa de baz aspre
clasele derivate), respectind astfel si unul din principiile ingineriei programarii –
abstractizarea. Conform acestei filosofii, trebuie definite toate caracteristicile si
interfetele comune ale unei clase de baza. De asemenea, se folosesc functii virtuale
pentru a defini interfata care va fi folosita de clasele derivate. In esenta, in clasa de
baza trebuie create si definite toate referirile la cazul general, iar clasele derivate
completeaza detaliile specifice.
O utilizare importantă a claselor abstracte şi a funcţiilor virtuale este cea a bibliotecilor de
clase. Un utilizator poate crea propria bibliotecă de clase generice şi extensibile care vor fi
refolosite de alţi utilizatori. Aceştia vor moşteni clasa generală creată iniţial, care defineşte
interfaţa şi elementele comune şi vor defini doar acele funcţii specifice clasei derivate.

Legături iniţiale, legături ulterioare

Legat de cele discutate, mai trebuie precizate două noţiuni folosite frecvent :

Legăturile iniţiale (early bindings) se referă la evenimentele care apar în timpul


compilării şi semnifică faptul că toate informaţiile necesare pentru a apela o funcţie sînt
cunoscute în timpul compilării (altfel spus, legăturile iniţiale arată că legăturile dintre un obiect
şi o apelare de funcţie se realizează în timpul compilării). Exemple din această categorie includ
apelările de funcţii normale (inclusiv funcţiile standard de bibliotecă), apelările de funcţii
supraîncărcate şi operatori supraîncărcaţi. Avantajul legăturilor iniţiale este eficienţa :
deoarece toate informaţiile necesare pentru a apela o funcţie sînt determinate în timpul
compilării, aceste tipuri de funcţii sînt foarte rapide.

Legăturile ulterioare (late bindings) se referă la apelările de funcţii care nu sînt rezolvate
pînă în momentul rulării. Pentru realizarea legăturilor ulterioare sînt utilizate funcţiile virtuale.
În acest caz, apelarea efectivă a funcţiei virtuale este determinată de tipul obiectului spre care
indică pointerul prin care îl accesăm. Deoarece în majoritatea cazurilor acesta nu poate fi
determinat în timpul compilării, obiectul şi funcţia nu sînt legate pînă în momentul rulării.
Avantajul legăturilor ulterioare este flexibilitatea : spre deosebire de legăturile iniţiale, cele
ulterioare permit crearea programelor care să răspundă la evenimentele care apar în timpul
rulării fără să fie necesară crearea unui cod suplimentar pentru selectarea situaţiilor şi apelurilor
dorite. Însă, deoarece rezolvarea direcţionării apelurilor este împinsă spre execuţia programului,
acesta va fi mai lent.
// Prin apelul aceleasi functii ca denumire a unui obiect dintr-o
//subclasa a unei functii din clasa de baza si aceleasi functii dar
redefinita
//in subclasa dar ca si continut diferita
//Sa se exemplifice acest lucru
//EX:1
// 2
// 1
// 2
// 1

#include "stdafx.h"

#include <iostream>

321
using namespace std;

class Horse
{
public:
void Gallop(){ cout << "Galloping...\n"; }
virtual void Fly() { cout << "Horses can't fly.\n" ; }
private:
int itsAge;
};

class Pegasus : public Horse


{
public:
virtual void Fly() { cout << "I can fly! I can fly! I can
fly!\n"; }
};

const int NumberHorses = 5;


int main()
{
Horse* Ranch[NumberHorses];
Horse* pHorse;
int choice,i;
for (i=0; i<NumberHorses; i++)
{
cout << "(1)Horse (2)Pegasus: ";
cin >> choice;
if (choice == 2)
pHorse = new Pegasus;
else
pHorse = new Horse;
Ranch[i] = pHorse;
}
cout << "\n";
for (i=0; i<NumberHorses; i++)
{
Ranch[i]->Fly();
delete Ranch[i];
}
return 0;
}

// Sa se apeleze aceleasi destructori si constructori


//pentru mai multe clase si subclase

#include "stdafx.h"
#include <iostream>

using namespace std;

typedef int HANDS;


enum COLOR { Red, Green, Blue, Yellow, White, Black, Brown } ;
enum BOOL { FALSE, TRUE };
class Horse
{
public:
Horse(COLOR color, HANDS height);
virtual ~Horse() { cout << "Horse destructor...\n"; }
virtual void Whinny()const { cout << "Whinny!... "; }

322
virtual HANDS GetHeight() const { return itsHeight; }
virtual COLOR GetColor() const { return itsColor; }
private:
HANDS itsHeight;
COLOR itsColor;
};

Horse::Horse(COLOR color, HANDS height):


itsColor(color),itsHeight(height)
{
cout << "Horse constructor...\n";
}

class Bird
{
public:
Bird(COLOR color, BOOL migrates);
virtual ~Bird() {cout << "Bird destructor...\n"; }
virtual void Chirp()const { cout << "Chirp... "; }
virtual void Fly()const
{
cout << "I can fly! I can fly! I can fly! ";
}
virtual COLOR GetColor()const { return itsColor; }
virtual BOOL GetMigration() const { return itsMigration; }

private:
COLOR itsColor;
BOOL itsMigration;
};

Bird::Bird(COLOR color, BOOL migrates):


itsColor(color), itsMigration(migrates)
{
cout << "Bird constructor...\n";
}

class Pegasus : public Horse, public Bird


{
public:
void Chirp()const { Whinny(); }
Pegasus(COLOR, HANDS, BOOL,long);
~Pegasus() {cout << "Pegasus destructor...\n";}
virtual long GetNumberBelievers() const
{
return itsNumberBelievers;
}

private:
long itsNumberBelievers;
};

Pegasus::Pegasus(
COLOR aColor,
HANDS height,
BOOL migrates,
long NumBelieve):
Horse(aColor, height),
Bird(aColor, migrates),
itsNumberBelievers(NumBelieve)
{

323
cout << "Pegasus constructor...\n";
}

int main()
{
Pegasus *pPeg = new Pegasus(Red, 5, TRUE, 10);
pPeg->Fly();
pPeg->Whinny();
cout << "\nYour Pegasus is " << pPeg->GetHeight();
cout << " hands tall and ";
if (pPeg->GetMigration())
cout << "it does migrate.";
else
cout << "it does not migrate.";
cout << "\nA total of " << pPeg->GetNumberBelievers();
cout << " people believe it exists.\n";
delete pPeg;
return 0;
}

// Sa se puna in evidenta faptul ca apelul destructorilor este


//exact invers ca ordine decat al constructorilor

#include "stdafx.h"
#include <iostream>

using namespace std;

typedef int HANDS;


enum COLOR { Red, Green, Blue, Yellow, White, Black, Brown } ;
enum BOOL { FALSE, TRUE };

class Animal // common base to both horse and bird


{
public:
Animal(int);
virtual ~Animal() { cout << "Animal destructor...\n"; }
virtual int GetAge() const { return itsAge; }
virtual void SetAge(int age) { itsAge = age; }
private:
int itsAge;
};

Animal::Animal(int age):
itsAge(age)
{
cout << "Animal constructor...\n";
}

class Horse : public Animal


{
public:
Horse(COLOR color, HANDS height, int age);
virtual ~Horse() { cout << "Horse destructor...\n"; }
virtual void Whinny()const { cout << "Whinny!... "; }
virtual HANDS GetHeight() const { return itsHeight; }
virtual COLOR GetColor() const { return itsColor; }
protected:
HANDS itsHeight;
COLOR itsColor;

324
};

Horse::Horse(COLOR color, HANDS height, int age):


Animal(age),
itsColor(color),itsHeight(height)
{
cout << "Horse constructor...\n";
}

class Bird : public Animal


{
public:
Bird(COLOR color, BOOL migrates, int age);
virtual ~Bird() {cout << "Bird destructor...\n"; }
virtual void Chirp()const { cout << "Chirp... "; }
virtual void Fly()const
{ cout << "I can fly! I can fly! I can fly! "; }
virtual COLOR GetColor()const { return itsColor; }
virtual BOOL GetMigration() const { return itsMigration; }
protected:
COLOR itsColor;
BOOL itsMigration;
};

Bird::Bird(COLOR color, BOOL migrates, int age):


Animal(age),
itsColor(color), itsMigration(migrates)
{
cout << "Bird constructor...\n";
}

class Pegasus : public Horse, public Bird


{
public:
void Chirp()const { Whinny(); }
Pegasus(COLOR, HANDS, BOOL, long, int);
~Pegasus() {cout << "Pegasus destructor...\n";}
virtual long GetNumberBelievers() const
{ return itsNumberBelievers; }
virtual COLOR GetColor()const { return Horse::itsColor; }
virtual int GetAge() const { return Horse::GetAge(); }
private:
long itsNumberBelievers;
};

Pegasus::Pegasus(
COLOR aColor,
HANDS height,
BOOL migrates,
long NumBelieve,
int age):
Horse(aColor, height,age),
Bird(aColor, migrates,age),
itsNumberBelievers(NumBelieve)
{
cout << "Pegasus constructor...\n";
}

int main()
{
Pegasus *pPeg = new Pegasus(Red, 5, TRUE, 10, 2);

325
int age = pPeg->GetAge();
cout << "This pegasus is " << age << " years old.\n";
delete pPeg;
return 0;
}

// Fie ca Cercul sa fie o subclasa a doua clase si fiecare


//din clase sa aiba constructori diferiti pe care sa-i apleze aceasta
subclasa
//ex:2 3 0
#include "stdafx.h"

#include <iostream>
using namespace std;
enum BOOL { FALSE, TRUE };
class Shape
{
public:
Shape(){}
~Shape(){}
virtual long GetArea() { return -1; } // error
virtual long GetPerim() { return -1; }
virtual void Draw() {}
private:
};

class Circle : public Shape


{
public:
Circle(int radius):itsRadius(radius){}
~Circle(){}
long GetArea() { return 3 * itsRadius * itsRadius; }
long GetPerim() { return 9 * itsRadius; }
void Draw();
private:
int itsRadius;
int itsCircumference;
};

void Circle::Draw()
{
cout << "Circle drawing routine here!\n";
}

class Rectangle : public Shape


{
public:
Rectangle(int len, int width):
itsLength(len), itsWidth(width){}
~Rectangle(){}
virtual long GetArea() { return itsLength * itsWidth; }
virtual long GetPerim() {return 2*itsLength + 2*itsWidth; }
virtual int GetLength() { return itsLength; }
virtual int GetWidth() { return itsWidth; }
virtual void Draw();
private:
int itsWidth;
int itsLength;
};

326
void Rectangle::Draw()
{
for (int i = 0; i<itsLength; i++)
{
for (int j = 0; j<itsWidth; j++)
cout << "x ";

cout << "\n";


}
}

class Square : public Rectangle


{
public:
Square(int len);
Square(int len, int width);
~Square(){}
long GetPerim() {return 4 * GetLength();}
};

Square::Square(int len):
Rectangle(len,len)
{}

Square::Square(int len, int width):


Rectangle(len,width)

{
if (GetLength() != GetWidth())
cout << "Error, not a square... a Rectangle??\n";
}

int main()
{
int choice;
BOOL fQuit = FALSE;
Shape * sp;

while (1)
{
cout << "(1)Circle (2)Rectangle (3)Square (0)Quit: ";
cin >> choice;

switch (choice)
{
case 1: sp = new Circle(5);
break;
case 2: sp = new Rectangle(4,6);
break;
case 3: sp = new Square(5);
break;
default: fQuit = TRUE;
break;
}
if (fQuit)
break;

sp->Draw();
cout << "\n";
}
return 0;

327
}

// Sa se scrie o aplicatie care pune in evidenta faptul ca


//o clasa poate apela constructorii subclaselor dar nu si invers

#include "stdafx.h"

#include <iostream>
using namespace std;
enum COLOR { Red, Green, Blue, Yellow, White, Black, Brown } ;
enum BOOL { FALSE, TRUE };

class Animal // common base to both horse and bird


{
public:
Animal(int);
virtual ~Animal() { cout << "Animal destructor...\n"; }
virtual int GetAge() const { return itsAge; }
virtual void SetAge(int age) { itsAge = age; }
virtual void Sleep() const = 0;
virtual void Eat() const = 0;
virtual void Reproduce() const = 0;
virtual void Move() const = 0;
virtual void Speak() const = 0;
private:
int itsAge;
};

Animal::Animal(int age):
itsAge(age)
{
cout << "Animal constructor...\n";
}

class Mammal : public Animal


{
public:
Mammal(int age):Animal(age)
{ cout << "Mammal constructor...\n";}
~Mammal() { cout << "Mammal destructor...\n";}
virtual void Reproduce() const
{ cout << "Mammal reproduction depicted...\n"; }
};

class Fish : public Animal


{
public:
Fish(int age):Animal(age)
{ cout << "Fish constructor...\n";}
virtual ~Fish() {cout << "Fish destructor...\n"; }
virtual void Sleep() const { cout << "fish snoring...\n"; }
virtual void Eat() const { cout << "fish feeding...\n"; }
virtual void Reproduce() const
{ cout << "fish laying eggs...\n"; }
virtual void Move() const
{ cout << "fish swimming...\n"; }
virtual void Speak() const { }
};

class Horse : public Mammal


{

328
public:
Horse(int age, COLOR color ):
Mammal(age), itsColor(color)
{ cout << "Horse constructor...\n"; }
virtual ~Horse() { cout << "Horse destructor...\n"; }
virtual void Speak()const { cout << "Whinny!... \n"; }
virtual COLOR GetItsColor() const { return itsColor; }
virtual void Sleep() const
{ cout << "Horse snoring...\n"; }
virtual void Eat() const { cout << "Horse feeding...\n"; }
virtual void Move() const { cout << "Horse running...\n";}

protected:
COLOR itsColor;
};

class Dog : public Mammal


{
public:
Dog(int age, COLOR color ):
Mammal(age), itsColor(color)
{ cout << "Dog constructor...\n"; }
virtual ~Dog() { cout << "Dog destructor...\n"; }
virtual void Speak()const { cout << "Whoof!... \n"; }
virtual void Sleep() const { cout << "Dog snoring...\n"; }
virtual void Eat() const { cout << "Dog eating...\n"; }
virtual void Move() const { cout << "Dog running...\n"; }
virtual void Reproduce() const
{ cout << "Dogs reproducing...\n"; }

protected:
COLOR itsColor;
};

int main()
{
Animal *pAnimal=0;
int choice;
BOOL fQuit = FALSE;

while (1)
{
cout << "(1)Dog (2)Horse (3)Fish (0)Quit: ";
cin >> choice;

switch (choice)
{
case 1: pAnimal = new Dog(5,Brown);
break;
case 2: pAnimal = new Horse(4,Black);
break;
case 3: pAnimal = new Fish (5);
break;
default: fQuit = TRUE;
break;
}
if (fQuit)
break;

pAnimal->Speak();
pAnimal->Eat();

329
pAnimal->Reproduce();
pAnimal->Move();
pAnimal->Sleep();
delete pAnimal;
cout << "\n";
}
return 0;
}
SUPRAINCARCAREA FUNCTIILOR
Supraîncărcarea

Supraîncărcarea funcţiilor şi a operatorilor (overloading) sînt esenţiale pentru


programarea în C++. Aceste două caracteristici oferă posibilitatea realizării polimorfismului şi
adaugă limbajului flexibilitate şi externsibilitate.
Deoarece supraîncărcarea operatorilor este mai dificil de abordat şi necesită înţelegerea
supraîncărcării funcţiilor, aceasta din urmă va fi tratată întîi.
Supraîncărcarea funcţiilor

Supraîncărcarea funcţiilor reprezintă folosirea aceluiaşi nume pentru două sau mai
multe funcţii. Fiecare redefinire a funcţiei trebuie să folosească tipuri diferite de parametri de
apel sau număr diferit de parametri. Compilatorul poate detecta care funcţie trebuie apelată, pe
baza acestor diferenţe.
Trebuie reţinut că nu pot fi supraîncărcate două funcţii care diferă doar prin tipul
returnat.
Ambiguităţi şi anacronisme la supraîncărcarea funcţiilor

Sînt situaţii în care compilatorul nu poate discerne între funcţiile supraîncărcate.


Această situaţie se numeşte (ca şi de altfel în sensul general al situaţiei de tipul acesta)
ambiguă. Aceste situaţii sînt depistate de compilator şi semnalate ca erori fatale şi programul
nu este compilat. Principala cauză de ambiguităţi este conversia automată de tip pe care o
realizează C++. Astfel, compilatorul C++ încearcă să convertească automat argumentele
folosite pentru apelul de funcţii în tipurile argumentelor aşteptate de funcţiile respective.
Supraîncărcarea funcţiilor constructor

Ca oricare altă funcţie, constructorii pot fi şi aceştia supraîncărcaţi. De fapt, această


supraîncărcare se practică foarte des (au fost cîteva exemple chiar în cursurile precedente).
Adresa unei funcţii supraîncărcate

În C putem să atribuim adresa unei funcţii, unui pointer şi apoi să aelăm funcţia
folosind pointerul. La fel se poate proceda (s-a văzut în cursurile precedente) şi în C++. O
complicaţie survine la supraîncărcarea funcţiilor, deoarece în această situaţie doar declararea
corespunzătoare a pointerului poate face diferenţierea.
Supraîncărcarea operatorilor

În C++ pot fi supraîncărcaţi aproape toţi operatorii. Supraîncărcarea acestora este strîns
legată de supraîncărcarea funcţiilor. În C++ supraîncărcarea operatorilor poate să determine
efectuarea unor operaţii speciale relativ la clasele create. Astfel, o memorie stivă poate fi
încărcată cu un element, folosind operatorul + supraîncărcat corespunzător, respectiv - pentru

330
extragere. Supraîncărcarea nu afectează vreuna din semnificaţiile originale ale utilizării
operatorului supraîncărcat.
Operatorii se supraîncarcă folosind funcţiile operator. O astfel de funcţie defineşte
operaţiile specifice pe care le va efectua operatorul supraîncărcat relativ la clasa în care este
destinat să lucreze. Funcţiile operator pot sau nu să fie membre ale clasei în care vor opera. De
obicei, cînd funcţiile operator nu sînt membre, sînt măcar funcţii friend. Cele două situaţii
(cînd sînt membre, respectiv cînd sînt friend) trebuie tratate diferit.

Funcţiile operator membre

Forma generică a definirii unor astfel de funcţii este :

tip_returnat nume_clasa::operator#(lista_argumente)
{
... // aici vor fi operatiile care reprezinta redefinirea
// operatorului
}
La operandul -, a trebuit să fim atenţi la ordine : operandul din dreapta semnului trebuie scăzut
din operandul din stînga (ordinea naturală) şi ţinînd cont de operandul care generază apelul
funcţiei operator-() (adică acel operand care va transmite un pointer this), a rezultat
exprimarea aparent curioasă din definirea funcţiei operand respective.
Pe de altă parte, trebuie remarcat că în C++, în lipsa unei supraîncărcări, operatorul =
devine un operator de copiere membru cu membru. În exemplul prezentat, funcţia operator=()
a returnat *this, ceea ce a permis realizarea atribuirilor multiple (de altfel, aceasta este raţiunea
pentru care a fost supraîncărcat acest operator).
Ultimul lucru pe care îl remarcăm este legat de supraîncărcarea operatorului unar.
Evident, acesta nu are parametri, deoarece acţionează asupra unui singur operand, care este deja
transmis prin this.

Simbolul # trebuie înlocuit cu operatorul a cărui supraîncărcare se defineşte.

// SA se supraincarece o functie pentru intregi si reale

#include "stdafx.h"

#include <iostream>
using namespace std;
int supra(int ); // prima functie are un parametru intreg
double supra(double ); // iar a doua are parametru double

main()
{
cout << supra(19) << " "; // apelul primei functii
cout << supra(5.4) << "\n"; //apelul celeilalte functii

return 0;
}

// acum sint definite cele doua functii


int supra(int i)
{
return i;
}

331
double supra(double d)
{
return d;
}
// Sa se supraincarce o functie cu numar diferit de paramatrii

#include "stdafx.h"
#include <iostream>
using namespace std;

int supra1(int ); // un parametru


int supra1(int ,int ); // doi parametri (aceeasi denumire a
// functiei)

main()
{
cout << supra1(11) << " "; // apelul primei functii
cout << supra1(5,4) << "\n"; //apelul celeilalte functii

return 0;
}

// acum sint definite cele doua functii


int supra1(int i)
{
return i;
}

int supra1(int i, int j)


{
return i*j;
}
// Sa se supraincarece functiile constructor

#include "stdafx.h"

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

class data {
int zi, luna, an;
public:
data(char *);
data(int, int, int );
void arata_data();
};

// constructor de initializare cu sir (forma zz/ll/aa)


data::data(char *s)
{
sscanf(s, "%s%*c%s%*c%s", &zi, &luna, &an);
}
// constructor de initializare cu intregi (zi, luna, an)
data::data(int z, int l, int a)
{
zi=z;
luna=l;
an=a;
}
void data::arata_data()

332
{
cout << zi << "/" << luna<< "/"<<an<<"\n";
}

main()
{
data d1(4, 3, 98), d2("10/04/98");

d1.arata_data();
d2.arata_data();

return 0;
}
SUPRAINCARCAREA OPERATORILOR
// Sa se prezinte supraincarcarea operatorului PLUS

#include "stdafx.h"

#include <iostream>
using namespace std;
class loc{
int longit, latit;
public:
loc(){} // necesar pentru constructii de obiecte
// temporare
loc(int lg, int lt) {
longit=lg;
latit=lt;
}
void arata() {
cout << longit << " ";
cout << latit <<"\n";
}
loc operator+(loc ot);
};

loc loc::operator+(loc ot) // supraincarcarea operatorului +


{
loc tmp; // folosim un obiect temporar

tmp.longit=ot.longit+longit; // aici sint operatiile


tmp.latit=ot.latit+latit;

return tmp; // obiectul este returnat


}

main()
{
loc ob1(10,20), ob2(15,25); // se creeaza doua obiecte
// initializate

ob1.arata(); // se va afisa 10 20
ob2.arata(); // se va afisa 15 25

ob1=ob1+ob2; // aici se foloseste supraincarcarea


ob1.arata(); // se va afisa 25 45

return 0;
}

333
// Sa se supraincarce patru operatori

#include "stdafx.h"
#include <iostream>
using namespace std;

class loc{
int longit, latit;
public:
loc(){} // necesar pentru constructii de obiecte
// temporare
loc(int lg, int lt) {
longit=lg;
latit=lt;
}
void arata() {
cout << longit << " ";
cout << latit <<"\n";
}
loc operator+(loc ot);
loc operator-(loc ot);
loc operator=(loc ot);
loc operator++();
};

loc loc::operator+(loc ot) // supraincarcarea operatorului +


{
loc tmp; // folosim un obiect temporar

tmp.longit=ot.longit+longit; // aici sint operatiile


tmp.latit=ot.latit+latit;

return tmp; // obiectul este returnat


}
loc loc::operator-(loc ot) // supraincarcarea operatorului -
{
loc tmp; // folosim un obiect temporar
// atentie la ordinea operanzilor
tmp.longit= longit-ot.longit; // aici sint operatiile
tmp.latit= latit-ot.latit;

return tmp; // obiectul este returnat


}
loc loc::operator=(loc ot) // supraincarcarea operatorului =
{
loc tmp; // folosim un obiect temporar

longit=ot.longit; // aici sint operatiile


latit=ot.latit;

return *this; // aici este returnat chiar obiectul


// care a generat apelarea
}
// Atentie ! urmeaza un operator unar (nu are parametri - oare //
de ce ?)
loc loc::operator++() // supraincarcarea operatorului ++
{
// nu mai folosim un obiect temporar
longit++; // aici sint operatiile
latit++;

334
return *this; // de asemenea este returnat chiar
// obiectul care a generat apelarea, de fapt a operat
// direct asupra obiectului

main()
{
loc ob1(10,20), ob2(15,25), ob3(3,7); // se creeaza
// trei obiecte initializate

ob1.arata(); // se va afisa 10 20
ob2.arata(); // se va afisa 15 25

++ob1; // oare ce se intimpla ?


ob1.arata(); // se afiseaza 11 21

ob2=++ob1;
ob1.arata(); // afiseaza 12 22
ob2.arata(); // afiseaza tot 12 22

ob1=ob2=ob3; // se poate si atribuire multipla


ob1.arata(); // evident se va afisa 3 7
ob2.arata(); // se va afisa tot 3 7

return 0;
}
Matrice, pointeri şi referinţe
//sa se creeze o matrice de obiecte
#include "stdafx.h"
#include <iostream>
using namespace std;

class cl {
int i;
public:
cl(int j){ i = j; }
int da_i() { return i; }
};

main()
{
c1 mo[ 3] = { 1, 2, 3 }; // initializare
int i;
for ( i = 0; i < 3 ; i ++)
cout << mo[ i ] . da_i() << endl;
return 0;
}

//sa se puna in evidenta pointari catre obiecte ( nu preia primul


//element din matrice)
#include<stdafx.h>
#include <iostream>
using namespace std;
class cl {
int i;
public:
cl(int j) { i = j; }
int da_i() { return i; }
};

335
main()
{
cl ob(23), *p;
p = &ob; // da adresa lui ob
cout << p->da_i(); // foloseste -> pentru a apela da_i()
return 0;
}
// Sa se puna pointer prin deplasarea in matrice

#include<stdafx.h>
#include <iostream>
using namespace std;
class cl {
int i;
public:
cl() { i = 0; }
cl(int j) { i = j; }
int da_i() { return i; }
};

main()
{
cl ob[ 3 ] = { 1, 2, 3 };
cl *p;
int i;

p = ob; // preia inceputul matricei


for ( i = 0; i < 3; i++) {
cout << p->da_i() << endl;
p ++; // indica spre urmatorul obiect
}
return 0;
}
// Afisarea unui ponter catre un membru public al clasei
#include<stdafx.h>
#include <iostream>
using namespace std;
class acces_p{
public:
int i;
acces_p(int j) {i=j; }
};

main()
{
acces_p poin(1);
int *p ,i;

p=&poin.i; // se preia adresa lui poin.i

cout << *p; // si se afiseaza cu acces prin pointer


return i;
}
// Sa se puna in evidenta folosirea pointerului THIS
//(adică obiectul care a invocat funcţia : obiect.functie(...) ).
//adica in loc de obiect se oune THIS
//Funcţiile friend nu sînt membri ai clasei, deci nu le sînt pasaţi
pointeri this.
//Funcţiile membre de tip static nu au nici ele un pointer this.
//

336
#include<stdafx.h>
#include <iostream>
using namespace std;
class putere{
double b;
int e;
double rez;
public:
putere(double, int );
double rezultat() {return this->rez; }
};

putere::putere(double baza, int exp)


{
this ->b=baza;
this->e=exp;
this->rez=1;
if (exp==0) return;
for ( ; exp>0; exp--) this->rez=this->rez * this->b;

main()
{
putere x(65.3, 4), y(1.35, 5), z(200.1, 0); // 3 obiecte

cout << x.rezultat() << endl;


cout << y.rezultat() <<endl;
cout << z.rezultat() << endl;

return 0;
}
//Sa se puna in evidenta folosirea pointerului THIS
//(adica obiectul care a invocat functia : obiect.functie(...) )
//acici el se subintelege ca e din clasa curenta

#include<stdafx.h>
#include <iostream>
using namespace std;
class putere{
double b;
int e;
double rez;
public:
putere(double, int );
double rezultat() {return rez;}
};

putere::putere(double baza, int exp)


{
b=baza;
e=exp;
rez=1;
if (exp==0) return;
for ( ; exp > 0; exp--) rez=rez * b;
}

main()
{
putere x(65.3, 4), y(1.35, 5), z(200.1, 0); // 3 obiecte

337
cout << x.rezultat() << endl;
cout << y.rezultat() << endl;
cout << z.rezultat() << endl;

return 0;
}
//Sa se puna in evidenta pointer catre functii si date membru
//ai unei clase
#include<stdafx.h>
#include <iostream>
using namespace std;
class c1{
public:
c1(int i) {val=i; }
int val;
int val_dubla() {return val+val; }
};
main()
{
int c1::*date; // pointer la o data membru
int (c1::*func)(); // pointer la o functie membru
c1 ob1(1), ob2(2); // crearea a doua obiecte

date=&c1::val; // obtinem offsetul pentru val


func=&c1::val_dubla;// iar aici obtinem offsetul pentru
// functia val_dubla()

// acum putem profita de pointerii la membri obtinuti mai sus


cout << "Iata date obtinute cu pointeri la membri :";
cout << ob1.*date << " " << ob2.*date << endl;
cout << "Acum folosim pointeri la functii membre : ";
cout << (ob1.*func)() << " " << (ob2.*func)() << endl;

return 0;
}
//cu pointari sa se puna in evidenta
//transmiterea datelor prin referinta
#include<stdafx.h>
#include <iostream>
using namespace std;
void neg(int *);

main()
{
int in;
in=100;
cout << in << " este negat ";
neg(&in); // se transmite adresa explicit
cout << in << endl;

return 0;
}

void neg(int *i)


{
*i= - *i;
}
//transmiterea datelor explicit prin referinta
#include<stdafx.h>
#include <iostream>

338
using namespace std;
void neg(int &i); // i este referinta

main()
{
int in;
in=100;
cout << in << " este negat ";
neg(in); // nu e nevoie de &
cout << in << endl;

return 0;
}

void neg(int &i)


{
i= - i; // i este referinta deci nu e nevoie de *
}

//explicit transmiterea datelor prin referinta


#include<stdafx.h>
#include <iostream>
using namespace std;
void schimb(int &, int & );

main()
{
int a,b;
a=1;
b=2;

cout << " a si b: " << a << " " << b << " ";
schimb(a, b); // aici schimbam ; vedem ca nu trebuie
// scris cu &
cout << " a si b: " << a << " " << b << " "
;

return 0;
}

void schimb (int &i, int &j)


{
int temp;

temp=i; // nu trebuie sa lucram cu *


i=j;
j=temp;
}
// Transmiterea referintelor catre obiecte
#include "stdafx.h"
#include <iostream>
using namespace std;

class nu_distruge{
int k;
public:
int i;
nu_distruge(int );
~nu_distruge();
void neg(nu_distruge &ob) {ob.i = -ob.i; } // nu se va
// crea obiect temporar

339
};

nu_distruge::nu_distruge(int valinit) // constructorul


{
cout << "Construieste " << valinit << "\n";
k=valinit;
}

nu_distruge::~nu_distruge() // destructorul
{
cout << "Distruge " << k << "\n";
}

main()
{
nu_distruge ob(1); // un obiect initializat

ob.i=10;
ob.neg(ob); // la apel se transmite obiectul prin
// referinta

cout << ob.i << "\n";

return 0;
}

//referinte independente(pasarea argumentelor prin referinţă şi


//obţinerea valorii returnate de funcţie. )
#include "stdafx.h"
#include <iostream>
using namespace std;
main()
{
int a;
int &ref=a; // aceasta e o referinta independenta

a=1;
cout << a << " " << ref << "\n";

ref=10;
cout << a << " " << ref << "\n";

int b=39;
ref=b; // aici, valoarea lui b trece de fapt in a
cout << a << " " << ref << "\n";

ref--; // decrementeaza pe a in realitate


cout << a << " " << ref << "\n";

return 0;

}
Operatorii de alocare dinamică din C++
//Sa se aloce dinamic un intreg si sa se elibereze spatiul
#include "stdafx.h"
#include <iostream>
using namespace std;
#include <stdlib.h>

main()

340
{
int *p;
p=new int; // aloca spatiu pentru un intreg
if (!p) {
cout << "Eroare de alocare\n";
exit(1);
}
*p=190;

cout << "La " << p << " " ;


cout << " este valoarea " << *p << "\n";

delete p;
return 0;
}
//sa se supraincarce operatorii de alocare dinamica
#include "stdafx.h"
#include <iostream>
using namespace std;
#include <stdlib.h>

main()
{
int *p;
p=new int(314); // aloca spatiu pentru un intreg
// dar si initializeaza
if (!p) {
cout << "Eroare de alocare\n";
exit(1);
}
*p=190;

cout << "La " << p << " " ;


cout << " este valoarea " << *p << "\n";

delete p;
return 0;
}
//alocarea dintr-o data a memoriei pentru 10 obiecte
//si eliberarea memoriei
#include "stdafx.h"
#include <iostream>
using namespace std;
#include <stdlib.h>

main()
{
int *p, i; // (ati retinut ca doar primul e pointer ?)

p=new int [10]; // se aloca memorie pentru 10 intregi


if(!p){
cout << "Eroare de alocare\n";
exit(1);
}
for (i=0; i<10; i++) p[i]=i;
for (i=0; i<10; i++) cout << p[i] << " ";

delete [] p; // aici eliberam memoria ocupata de


// cei 10 intregi
}
//sa se puna in evidenta pointarii catre o constanta

341
#include "stdafx.h"
#include <iostream>
using namespace std;
const int* u;
int const* v;
int d = 1;
int* const w = &d;
const int* const x = &d; // (1)
int const* const x2 = &d; // (2)
int main() {} ///:~

342

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