Introdu textul pe care doresti sa-l cauti:Aplicatia:
a IX-a A
Introducere în C++
Introducere în C++

Limbajul C++ a fost inventat de către Bjarne Stroustrup în 1979, ca o extindere a limbajului C. Limbajul C a fost inventat în 1969-1973 de către Dennis Ritchiepentru a realiza sistemul de operare Unix. Astfel, aproape toate programele scrise în C pot fi compilate în C++, eventual cu foarte puține modificări.

Limbaje de programare

Limbajele de programare sunt limbaje asemănătoare cu limbajul uman. Conțin cuvinte (destul de puține), semne de punctuație, operații matematice și au reguli de scriere. Programele care rulează pe orice calculator au fost scrise într-un limbaj de programare. Există numeroase limbaje programare, precum C, C++, Pascal, Java, Python, PHP, Javascript, etc.

Programul scris într-un limbaj de programare se numește program sursă și trebuie traduse într-un limbaj pe care îl înțelege procesorul, numit cod mașină, sau program executabil. Pentru anumite limbaje de programare operația de traducere se numește compilare (cazul lui C, C++, Pascal, etc.), pentru alte limbaje (PHP, Python, Javascript, etc.) operația de traducere se numește interpretare . Traducerea este realizată de un program specializat numit compilator  sau interpretor.

Limbajul C++ este un limbaj compilat. Etapele scrierii unui program în C++ sunt:

  • editarea programului C++; se obține fișierul sursă, cu extensia .cpp
  • compilarea fișierului sursă; aici se verifică corectitudinea sintactică a programului (corectitudinea cuvintelor folosite, prezența semnelor de punctuație, etc.); dacă programul este corect sintactic, se va obține fișierul obiect, cu extensia .o sau .obj
  • editarea de legături; se stabilesc legături între fișierul obiect curent și alte fișiere obiect, ale programatorului sau incluse în compilator; în urma acestei etape se obține programul executabil. În Windows, fișierele executabile au extensia .exe;
  • programul executabil poate fi lansat în execuție (rulat).

Primul program C++

Cum scriem un program C++? Avem nevoie cel puțin de un editor de text pentru scrierea sursei și de un compilator C++. Deși fișierul sursă poate fi realizat cu orice editor de text, de cel mai multe ori folosim un IDE . Un IDE pentru C/C++ foarte utilizat este Code::Blocks. Acest articol prezintă modul de instalare a pachetului Code::Blocks pe calculator, împreună cu compilatorul MinGW, iar acest articol prezintă pașii necesari pentru a realiza un program C++ în Code::Blocks.

Să considerăm un prim program C++:

view source

print?

// primul program C++

#include <iostream>

using namespace std;

int main()

{

/*

primul program C++

il scriem in Code::Blocks

*/

cout << "Hello world";

return 0;

}

Dacă vom compila și rula acest program, pe ecran va apărea:

Hello world

Să analizăm acest program. El este alcătuit din mai multe linii:

  1. // primul program C++
    Această linie reprezintă un 
    comentariu. Comentariile sunt texte explicative care nu influențează comportamentul programului. Ele sunt pentru programatori, pentru a înțelege mai repede semnificația programului. Acest comentariu începe de la cele două caractere slash // și se termină la sfârșitul liniei.
  2. #include <iostream>
    Liniile care încep cu 
    # se numesc directive preprocesor. Ele sunt interpretate înainte de compilarea propriu-zisă, de către un program numit preprocesor. În cazul nostru, directiva #include <iostream> cere preprocesorului să includă în sursă o secțiune a codului C++ standard, header-ul iostream, care permite realizarea operațiilor de citire și afișare – la noi afișarea mesajului Hello world pe ecran.
  3. int main()
    Această linie reprezintă declararea unei funcții. În esență, o functie este un grup de instructiuni care un un nume dat; în acest caz, funcția se numește 
    main și este alcătuită din toate instrucțiunile care urmează. Vom discuta pe larg despre functii mai târziu.
    Funcția numită 
    main este specială în toate programele C++; această funcție este apelată când se lansează în execuție programul și trebuie să apară în orice program C++.
  4. {
    Parantezele acolade de la linia 4 și 10 delimitează instrucțiunile care fac parte din funcția 
    main
  5. /*
  6. primul program C++
  7. il scriem in Code::Blocks
  8. */
    Și acesta este un comentariu. Textele cuprinse între 
    /* și */ nu influențează comportamentul programului. Ele pot să ocupe mai multe linii, sau pot să apară în interiorul unei linii.
  9. cout << "Hello world";
    Aceasta este o instrucțiune C++. O instrucțiune este o construcție (expresie, comandă) care face ceva. Instrucțiunile sunt “miezul” programelor, ele stabilind comportamentul acestora. Instrucțiunile dintr-un program se execută în ordine, una după alta.
    Această instrucțiune produce afișarea pe ecran a atextului 
    Hello world. Ea este alcătuită din trei părți. std::cout semnifică dispozitivul standard de ieșire (standard character output) – de cele mai multe ori ecranul calculatorului. A doua parte este operatorul de inserție <<, care indică faptul că ceea ce urmează este inserat în std::cout (trimis spre ecran). A treia parte este textul, "Hello world", cuprins între ghilimele, care va fi inserat în std::cout.
    Să observăm prezența caracterului 
    ; la sfârșitul instrucțiunii. Orice instructiune C++ trebuie să se termine cu ;, la fel cum orice propoziție în limba română se termină cu caracterul . (punct).

Una dintre cele mai frecvente erori de sintaxă este să uităm să scriem ; la finalul unei instrucțiuni.

  1. return 0;
    Această instrucțiune marchează finalul execuției funcției 
    main și a programului nostru. Valoarea 0 semnifica faptul că programul s-a încheiat cu succes! 
    Dacă în programul nostru ar fi fost și alte instrucțiuni după instrucțiunea 
    return 0;, acestea nu s-ar mai fi executat.
  2. }
    Acolada închisă 
    } reprezintă finalul funcției main.

Să reținem că nu toate liniile programului produc efecte la executarea programului. Unele linii (comentariile) sunt scrise numai pentru a ușura înțelegerea programului de către cel care îl citește/scrie. Mai mult, nu este obligatoriu ca fiecare instrucțiune să fie scrisă pe o singură linie. Următoarele trei exemple de funcție main au acelați efect:

view source

print?

int main()

{

cout << "Salut";

return 0;

}

view source

print?

int main() {  cout << "Salut"return 0; }

view source

print?

int main()

{

cout << "Salut";

return 0;

}

Instrucțiunea using namespace std;

În C++, identificatorii sunt grupați în spații de nume – namespaces. Există un spațiu de nume predefinit, cu numele std, din care fac parte toți identificatorii din biblioteca C++ standard.

Comentarii

Comentariile sunt texte care pot să apară în programul sursă și nu sunt luate în considerare la compilare. Ele sunt citite doar de către oameni, pentru a explica anumit secțiuni mai importante din program. Așa cum am văzut mai sus, în C++ sunt două tipuri de comentarii:

  • // comentariu pe o linie
  • /* comentariu de tip bloc */

Comentariul pe o linie începe de caracterele // și se termină la finalul liniei. Comentariul de tip bloc începe la /*, se termină la */ și se poate întinde pe mai multe linii.

Comentariile sunt importante! Trebuie să învățăm să scriem cod pe care să-l înțelegem și peste o zi sau un an, iar prezență comentariilor este un pas înainte.

 

Tipuri de date C/C++
Tipuri de date C/C++

Tipul de date reprezintă un concept foarte important în C/C++. Orice dată (constantă sau variabilă) este de un numit tip. Tipul datei precizează ce valori poate avea acea dată și ce operații se pot face cu ea.

În C/C++ tipurile de date sunt:

  1. Tipuri simple

o  Tipuri întregi

o    Tipuri reale

o    Tipul pointer

o  Tipul  bool

  1. Tipuri derivate

o  Tipul tablou

o    Tipul structură

o    Tipul enumerare

Acest articol se referă numai la tipurile simple.

Tipurile întregi

Tipurile întregi permit memorarea de valori întregi. Tipul de bază este int. O dată de tip int poate memora valori întregi cuprinse între -2^31  și 2^31-1.

Tipurile întregi diferă prin numărul de octeți necesari pentru memorarea datei, tipul datei (cu semn sau fără semn) și implicit intervalul de valori pe care le pate lua respectiva dată. Tipurile întregi sunt:

Denumire tip

Reprezentare

-

int

4 octeți cu semn

-2147483648 ...

2147483647

unsigned int

4 octeți fără semn

0 ... 4294967295

long int

4 octeți cu semn

-2147483648 ... 2147483647

unsigned

long int

4 octeți fără semn

0 ... 4294967295

short int

2 octeți cu semn

-32768 ... 32767

unsigned short int

2 octeți fără semn

0 ... 65535

 

long long int

8 octeți cu semn

unsigned long long int

8 octeți fără semn

char

1 octet cu semn

-128 ... 127

unsigned char

1 octet fără semn

0 ... 255

Tipurile char și  unsigned char  memorează valori întregi. La afișarea unei date de acest tip nu se va afișa numărul pe care îl memorează ci caracterul care are are codul ASCII egal cu acel număr. Operația de citire a unei date de acest tip este similară.

Tipurile reale – în virgulă mobilă

Memorează valori reale, reprezentate prin mantisă și exponent. În acest mod se pot reprezenta valori foarte mari, dar precizia reprezentării poate fi slabă – numărul de cifre semnificative memorate poate fi mult mai mic decât numărul de cifre din număr.

Tipurile reale sunt:

·         float – se reprezinta pe 4 octeți;

·         double – se reprezinta pe 8 octeți;

·         long ouble – se reprezinta pe 10 octeți;

Tipul pointer

O dată de tip pointer memorează o adresă de memorie – de exemplu adresa unei variabile. Vom reveni asupra tipului pointer mai târziu.

Tipul bool

Anumite operații care se fac cu datele au ca rezultat valori de adevăr: adevărat sau false. În anumite limbaje de programare există un tip de date care memorează exact aceste două valori.

În limbajele ,ai evoluate de C++ există tipul  

bool. Acest tip conține două valori: literalii true și false. De fapt, acestea sunt redenumiri ale valorilor 1 și 0.

Variabile și constante C/C++
Variabile și constante C/C++

Orice program prelucrează date. Acestea se află în memoria RAM a calculatorului, și pot fi variabile (valoarea datei se poate modifica) sau constante  (valoarea nu se poate modifica).

Variabile

variabilă reprezintă o locație de memorie unde se află o valoare de un anumit tip. Orice variabilă este caracterizată de:

  • adresa variabilei. Memoria RAM a calculatorului este adresată – fiecare octet (byte) din memorie are asociat un număr de ordine, începând de la 0. Acest număr reprezintă adresa acelui byte și se afișează implicit în baza 16.
  • identificatorul variabilei – reprezintă un nume pentru variabilă – legătura dintre variabilă si adresa ei. Identificatorul respectă următoarele reguli:
    • conține litere mari, mici ale alfabetului englez cifre și caracterul de subliniere '_' – underline. Literele mari sunt considerate diferite de cele mici, astfel că Raspunsraspuns și RASPUNS reprezintă identificatori diferiți.
    • primul caracter nu poate fi cifră. Deși este posibil ca un identificator să înceapă cu '_', nu este recomandat, pentru a evita anumite conflicte cu identificatori de sistem.
    • nu există limite legate de lungimea unui identificator, dar numai primele 31 de caractere sunt semnificative.
  • tipul variabilei – stabilește ce fel de valori poate să ia variabila, între ce limite sunt acestea, precum și ce operații pot fi realizate cu variabila. Citește aici despre tipurile de date!
  • domeniul de vizibilitate – reprezintă zona din program în care variabila există și poate fi utilizată. Variabilele pot fi globale sau locale.
    • variabilele locale se declară într-un bloc (între paranteze acolade {...}) și sunt vizibile doar în acel bloc. Au valori inițiale aleatorii.
    • variabilele globale se declară în exteriorul oricărui bloc și sunt vizibile în toate blocurile care urmează declarării. Sunt inițializate cu 0.

În C/C++, variabilele trebuie declarate, precizând tipul și identificatorul. Sintaxa este:

Tip_de_date Lista_identificatori ;

unde

Tip_de_date poate fi orice tip C++ corect (citește aici despre tipurile de date), iar Lista_identificatori  este alcătuită din cel puțin un identificator. Dacă sunt mai mulți, se vor separa prin caracterul virgulă ,.

Exemple:print?

int a , x;

S-au declarat două variabile, cu numele a și x ce vor putea memora valori numere întregi dintr-un interval pe care îl vom studia mai târziu.

Următorii identificatori C++ sunt corecți: anumarNumaralt_numara2b_suma – nerecomandat, un_nume_de_variabila_foarte_lung.

Următorii identificatori C++ sunt incorecți:

  • 2a – începe cu cifră. Identificatorii pot începe cu litere sau '_'
  • alt numar – conține caracter interzis: spațiu
  • un-numar – contine caracter interzis: minus
  • număr – conține litera ă. Identificatorii pot conține numai litere ASCII – din alfabetul englez.

Constante

Constantele sunt date care nu-și modifică valoarea în timpul execuției programului. Pot fi constante cu nume, sau constante literale, date direct prin valoarea lor.

Constante simbolice

Constantele simbolice (cu nume) pot fi precizate în două moduri:

  • prin directiva define. Exemplu:

#define MAX 101

  • se pot declara variabile cu modificatorul const , iar valoarea lor nu mai poate fi modificată. Exemplu:

const int MAX = 101;

Literali

Într-un program pot apărea valori constante, fie că sunt numere, caractere sau șiruri de caractere. Acestea se mai numesc constante literale sau  literali.

Constante întregi

Reprezintă numere întregi – fără parte fracționară. Pot fi:

  • Constante zecimale – în baza 10  : 176 -54 0. Pot conține cifrele: 0 1 2 3 4 5 6 7 8 9
  • Constante octale – în baza 8  : 015 062. Pot conține cifrele: 0 1 2 3 4 5 6 7 și încep întotdeauna cu 0.
  • Constante hexazecimale – în baza 16  : 0x15 0x6f 0xff. Pot conține cifrele: 0 1 2 3 4 5 6 7 8 9 A B C D E F și încep întotdeauna cu 0x.

Constante reale

Reprezintă numere reale și se mai numesc în virgulă mobilă. Separatorul zecimal este caracterul punct '.' și pot apărea în două forme:

  • scrierea standard: -1.5 14.974
  • scrierea științifică, cu mantisă și exponent. Numărul -0.567E+2  înseamnă  -0.567*10+2, adică -56.7-0567 reprezintă mantisa, iar -2 reprezintă exponentul.

Constante caracter – char

Sunt alcătuite dintr-un caracter, delimitat de apostroafe: '. De exemplu:  'a' 'B' '~' '?'. O categorie aparte de caractere este dată de secvențele ESCAPE. O secvență escape este alcătuită din două caractere, dintre care primul este backslash: \. Dintre secvențele escape amintim:

  • '\b' – Backspace
  • '\f' – Form feed
  • '\n' – Newline
  • '\r' – Return
  • '\t' – TAB orizontal
  • '\\' – Backslash
  • '\'' – Apostrof
  • '\"' – Ghilimele
  • '\?' – Semn de întrebare
  • '\0' -Caracterul nul

Constante șir de caractere

Sunt delimitate de ghilimele " . Pot să conțină secvențe escape. Exemple:

"numar""n = ""Am terminat.\n"

Cuvinte rezervate

Nu orice cuvânt poate fi utilizat pe post de identificator. Există în C++ o listă de cuvinte care au o semnificație bine determinată și nu pot fi utilizate în alt scop. Ele se numesc cuvinte rezervate (keywords) și sunt următoarele:

alignas
alignof
and
and_eq
asm
auto
bitand
bitor
bool
break
case
catch
char
char16_t
char32_t
class
compl
concept
const
constexpr
const_cast
continue
decltype
default
delete
do
double
dynamic_cast

else
enum
explicit
export
extern
false
float
for
friend
goto
if
inline
int
long
mutable
namespace
new
noexcept
not
not_eq
nullptr
operator
or
or_eq
private
protected
public
register
reinterpret_cast

requires
return
short
signed
sizeof
static
static_assert
static_cast
struct
switch
template
this
thread_local
throw
true
try
typedef
typeid
typename
union
unsigned
using
virtual
void
volatile
wchar_t
while
xor
xor_eq

 

Intrări/Ieșiri în C++
Intrări/Ieșiri în C++

Operațiile de de intrare/ieșire sunt operațiile prin care un program primește date sau afișează rezultate. Aceste operații trebuie privite din perspectiva programului

  • operații de intrare: datele intră în program, programul citește date
  • operații de ieșire: datele ies din program, programul afișează date

Practic, datele care intră în program/ies din program sunt șiruri de caractere pe care programul le primește/le trimite

Limbajul C++ oferă o modalitate uniformă de a realiza operațiile de intrare/ieșire, indiferent dacă se fac la consolă, în fișiere, sau cu alte dispozitive care prelucrează caractere. Este vorba despre vorba despre stream  sau flux. Stream-ul poate fi privit ca o înșiruire de caractere care sunt trimise într-o ordine bine determinată de la o sursă la o destinație. Programul va insera caractere în stream (dacă este un stream de ieșire, care afișează date) sau va extrage caractere din stream (dacă este un stream de intrare, din care se citesc date).

Biblioteca standard C++ permite lucrul cu mai multe categorii de stream-uri. Dintre acestea vom discuta în continuare despre stream-urile cu consola, dispozitivul standard de intrare-ieșire, altfel spus stream-uri care permit citirea de la tastatură și afișarea pe ecran. Obiectele care permit aceste operații sunt:

  • cin – stream standard de intrare
  • cout – stream standard de ieșire

În continuare vom vorbi despre cout și cin – stream-ul standard de ieșire și de intrare. 

Stream-ul de ieșire cout

În cele mai multe cazuri, dispozitivul standard de ieșire este ecranul și poate fi accesat cu stream-ul cout. Pentru aceasta,  cout se folosește împreună cu operatorul de inserție  <<, urmat de data care se va afișa:

view source

print?

cout << "Salut"; // afiseaza pe ecran Salut

cout << 17; // afiseaza numarul 17 pe ecran

cout << n; // afiseaza pe ecran valoarea variabilei n

Operatorul cout afișează în stream-ul din stânga valoarea din dreapta. Să observăm că "Salut" este delimitat de ghilimele, deoarece este o constantă literal de tip șir de caractere, iar x nu este delimitată de ghilimele, deoarece este o variabilă.

Dacă textul care urmează după << este între ghilimele, se va afișa ca atare. Dacă nu este între ghilimele, se consideră că este o variabilă, și se afișează valoarea ei.

view source

print?

cout << "Salut"; //afiseaza cuvantul Salut

cout << Salut; // afiseaza valoare variabilei Salut

Putem afișa mai multe valori în aceeași instrucțiune:

view source

print?

cout << "Ana " << "are" << " mere."; // se va afisa Ana are mere

sau

view source

print?

int nr_mere = 17;

cout << "Ana " << "are " << nr_mere << " mere."; // se va afisa Ana are 17 mere

cout nu adaugă automat sfârșit de linie sau spatii. De exemplu:

view source

print?

cout << "Aceasta este o";

cout << "propozitie mai lunga!";

va afișa:

Aceasta este opropozitie mai lunga!

Pentru a insera spațiu între o și  propoziție, îl precizăm explicit:

view source

print?

cout << "Aceasta este o "; // este un spatiu dupa o

cout << "propozitie mai lunga!";

sau

view source

print?

cout << "Aceasta este o";

cout << " propozitie mai lunga!"; // la inceput este un spatiu

Dacă vrem să afișăm pe linii diferite procedăm astfel:

view source

print?

cout << "Aceasta este o\n";

cout << "propozitie mai lunga!";

O altă variantă este să folosim manipulatorul endl pentru a întrerupe linia. De exemplu:

view source

print?

cout << "Aceasta este o" << endl;

cout << "propozitie mai lunga!";

Ambele variante de mai sus vor afișa:

Aceasta este o

propozitie mai lunga!

endl produce un caracter rând nou, exact ca și inserarea lui \n, dar mai face ceva: endl golește buffer stream-ului cout, adică forțează afișarea pe ecran tuturor caracterelor inserate în stream până în acest moment. endl produce întârzieri în execuția programului, deci trebuie folosit cu precauție.

Stream-ul de intrare cin

În cele mai multe cazuri, dispozitivul standard de intrare este tastatura și poate fi accesat cu stream-ul cin. Pentru aceasta,  cin se folosește împreună cu operatorul de extragere  >>, urmat de variabila în care se va memora valoarea extrasă (variabila care se va citi):

view source

print?

1.int n;

2.cin >> n;

Mai întâi se declară variabila n, apoi se citește o valoare pentru ea – se extrage din cin o valoare care se memorează în variabila n. La execuție, programul așteaptă să se introducă o valoare de la tastatură. De fapt, caracterele introduse sunt transmise programului numai când se apasă tasata ENTER.

Să considerăm următorul program:

view source

print?

#include <iostream>

using namespace std;

int main()

{

int n = 7;

cout << "n = ";

cin >> n;

cout << "n este " << n << endl;

cout << "patratul lui n este " << n * n << endl;

return 0;

}

Rezultatul său depinde de valoare introdusă pentru n. Ar putea fi:

n = 25

n este 25

patratul lui n este 625

Dar dacă se nu se introduce un număr?

n = salut

n este 0

patratul lui n este 0

La operația de extragere din cin contează tipul variabilei de după >>. Caracterele din stream sunt interpretate în funcție de tipul variabilei. Dacă aceste caractere nu corespund cu tipul variabilei, operația de extragere eșuează.

Se pot citi valorile a două sau mai multe variabile în aceeași instrucțiune:

view source

print?

cin >> x >> y;

este echivalent cu

view source

print?

cin >> x;

cin >> y;

În ambele cazuri se așteaptă introducerea a două valori; acestea pot fi separate/precedate prin orice fel de caractere albe: spații, TAB-uri, caractere rând nou.

Una dintre cele mai frecvente erori este inversarea operatorilor pentru stream-urile cin și cout, sau citirea valorii unei constante. Următoarele instrucțiuni sunt greșite:

view source

print?

cout >> "Salut";

cin << n;

cin >> "Salut";

 

Operatori C++
Operatori C++

Computerele prelucrează date! Le citesc de la tastatură, le memorează în variabile (sau constante), le afișează pe ecran. Și mai fac cu ele diverse operații. Noi suntem obișnuiți să facem operații aritmetice (adunări, scăderi, etc.), dar în C++ există multe alte operații.

operație este alcătuită din operanzi și  operator. Operanzii reprezintă datele cu care se fac operațiile, iar operatorul este simbolul care stabilește ce operație se face cu operanzii. Din punct de vedere a numărului de operanzi, operațiile (operatorii) pot fi:

  • unare – se aplică la un singur operator (de exemplu -7, operația de schimbare a semnului unui număr);
  • binare – se aplică la doi operatori (de exemplu adunarea numerelor, 2+5);
  • ternare – se aplică la trei operatori. Există un singur operator ternar în C++, operatorul condițional și va fi analizat mai jos.

Operanzii pot fi variabile, constante, literali, rezultatele unor funcții, rezultatele altor operații. O operație care are ca operanzi alte operații se numește expresie.

Fiecare operație C++ are un rezultat!

Acest articol analizează o parte a operatorilor C++, cei mai frecvent utilizați:

Operatorii aritmetici: +- */%

În exemplele de mai jos, considerăm variabilele:

  • N = 11 și M = 3 de tip int
  • X = 11 și Y = -3.5 de tip double.

Operatorii aritmetici unari: +-

În C++ există operațiile unare + și -+ returnează valoarea operandului, iar - returnează valoarea operandului cu semn schimbat.

Exemple

  •  + X = 11
  • - Y = 3
  • - + N = -11

Operatorii aritmetici binari: +-*/%

  • + : adunarea a două numere
  • - : scăderea a două numere
  • * : înmulțirea a două numere
  • / : împărțirea a două numere
  • % : restul împărțirii a două numere întregi (modulo)
  • În C++ nu există un operator pentru ridicarea la putere!

Adunarea, scăderea și înmulțirea se comportă conforma așteptărilor, ca la matematică. Operația de împărțire și operația modulo necesită niște explicații suplimentare.

Împărțirea întreagă și împărțirea zecimală

Operația de împărțire are două moduri de lucru, în funcție de tipul operanzilor.

  • Dacă operanzii sunt de tip întreg (intshortchar, etc.), se va realiza împărțirea întreagă, iar rezultatul operației / este câtul împărțirii întregi.
  • Dacă operanzii sunt de tip real (floatdoublelong double), se va realiza împărțirea zecimală, iar rezultatul operației / este rezultatul acestei împărțiri, “cu virgulă”.

Exemple

  • N / M = 3
  • X / Y = -3.14286
  • X / 2.0 = 5.5
  • M / 2 = 1
  • M / 2.0 = 1.5

Ultima împărțire este deosebită. Cei doi operanzi au tipuri diferite: M = 3 este de tip int, iar 2.0 este de tip double. Aici intervine operația de conversie implicită: în mod automat, operandul M se consideră ca fiind de tip double , împărțirea este împărțire reală și are rezultatul 1.5 .

Operatorul modulo %

Operația modulor are sens numai dacă ambii operanzi sunt de tip întreg – împărțirea cu rest are sens numai în această situație. Iată câteva exemple:

N % M = 2 : restul împărțirii lui 11 la 3 este 2
30 % 10 = 0

Operatorul modulo este util în multe situații. El poate fi utilizat pentru a afla ultima cifră a unui număr natural: ultima cifră a lui 276  este 276 % 10 adică  6, sau pentru a verifica dacă un număr N  este divizor al lui M. În caz afirmativ, M % N este  0.

Observații suplimentare

  • nu se poate face împărțire la 0.
  • dacă cel puțin un operand al împărțirii întregi sau al operației modulo este negativ, rezultatul operației depinde de versiunea compilatorului C++ folosit. O variantă de evaluare, utilizată în unele compilatoare, este efectuarea operației cu operanzii în valoare absolută și apoi aplicarea regulii semnelor.

Operatorii relaționali: <> <=>===!=

Un operatori relațional stabilește dacă între două numere (operanzii) are loc o anumită relație. Rezultatul acestei operații este adevărat  sau fals. Rezultatul operațiilor relaționale poate fi 0  sau 1:

  • rezultatul este 1 dacă relația este adevărată
  • rezultatul este 0 dacă relația este falsă

Fie N = 11 și M = 3. Operațiile relaționale sunt:

  • operații de comparare (comparații)
    • mai mic <N < M este fals, adică 0
    • mai mare >N > M este adevărat, adică 1
    • mai mic sau egal <=M <= N este 1
    • mai mare sau egal >=M >= N este 0
  • operația de egalitate == ; N == M este fals, adică 0
  • operația de neegalitate (diferit, not egal) != N != M este adevărat, adică 1 .

Un dintre cele mai frecvente erori este folosirea pentru operația de egalitate a operatorului =, în loc de ==. Operatorul = reprezintă operația de atribuire !

Operatorii logici: !||&&

Operatorii logici au operanzi de tip valori de adevăr și rezultat valori de adevăr. Istoric, operațiile logice sunt legate de numele matematicianului englez George Boole, cel care a pus bazele acestei ramuri a matematicii și a inventat algebra booleană și calculul propozițional.

În C++, operatorii logici pot fi aplicați oricăror valori numerice, și au ca rezultat una din valorile 0 sau 1. În exemplele de mai jos vom folosi literalii true și false, de tip bool.

Negația: !

  • ! true este false. Orice valoare nenulă negată devine 0.
  • ! false este true0 negat devine 1.

Disjuncția: ||

  • false || false → false
  • false || true → true
  • true || false → true
  • true || true → true

Conjuncția: &&

  • false && false → false
  • false && true → false
  • true && false → false
  • true && true → true

Legile lui De Morgan

Fie p și q două valori booleene (pot fi rezultatele unor expresii, de exemplu). Atunci:

  • !(p && q) == !p || !q
  • !(p || q) == !p && !q

Să luăm ca exemplu apartenența unei valori la un interval:

  • x[a,b]
  • expresia echivalentă C++ este x ≥ a && x ≤ b
  • conform legilor lui De Morgan, prin negare obținem: !(x ≥ a) || !(x ≤ b)
  • deoarece !(x ≥ a) este echivalent cu x<a, obținem:
  • x < a || x > b
  • folosind intervalele obținem: x (-∞,b) (a,+∞), adică x [a,b]

Operatorul de atribuire: =

Atribuirea este operația prin care o variabilă primește valoarea unei expresii:

variabila = expresie

Expresia poate avea orice fel de rezultat, dacă tipul său acesta este identic cu al variabilei, sau poate fi convertit la tipul variabilei. În cazul tipurile întregi, reale, bool, oricare dintre acestea poate fi convertit la la oricare altul, eventual cu pierderea unor date.

Exemple:

#include <iostream>

using namespace std;

int  main()

{

int  n , m; // valori aleatorii

double x , y; // valori aleatorii

n = 5; // valoare lui n devine 5

cout << n << endl;

m = n + 2; // valoare lui m devine 7

cout << m << endl;

n = n + 3; // valoarea lui n devine 5 + 3, adica 8

cout << n << endl;

x = m / 5; // valoarea lui x devine 8 / 5, adica 1. ATENTIE! este impartire intreaga

cout << x << endl;

y = 5; // valoarea lui y devine 5, de tip double. Are loc conversia lui 5 de tip int la double

cout << y << endl;

x = m / y; // valoarea lui x devine 1.4, deoarece impartirea este zecimala. Are loc conversia valorii lui m la double, apoi se face impartirea

cout << x << endl;

return  0;

}

Atribuirea este o operație, deci are rezultat! Rezultatul operației de atribuire este chiar variabila care primește valoare.

Nu confundați atribuirea cu operația de egalitate ==.

Este posibilă și realizarea unor atribuiri multiple, ca mai jos:

int a , b, c;

a = b = c = 10;

Toate variabilele vor primi valoarea 10.

Următoarea atribuire este mai interesantă:

n = n + 4;

Ea se efectuează astfel (să considerăm, ca exemplu, că valoarea inițială a lui n este 5):

  • mai întâi se calculează expresia din dreapta, în care se folosește valoarea curentă a lui nn + 4  este 5 + 4 adică 9
  • valoarea expresiei din dreapta se atribuie variabilei din stânga, deci n devine 9 .

Notă: În membru stâng al unei atribuiri poate fi nu doar o variabilă, ci o expresie de tip lvalue. Prin lvalue se înțelege left value, adică tocmai o expresie ce poate “în stânga” unei atribuiri. Variabilele sunt expresii lvalue, dar există și altfel de expresii, despre care vom vorbi mai târziu, care sunt lvalue.

Operatorii de atribuire compusă: +=-=*=/=%=>>= <<=&= ^=|=

În programare sunt foarte frecvente atribuirile de forma:

x = x * 5;

în care unei variabile i se aplică o anumită operație aritmetică (în exemplul de mai sus *) iar rezultatul se memorează chiar în acea variabilă. Pentru a facilita scrierea codului în aceste situații, în C++ există atribuirea compusă:

var OP= expresie, echivalentă cu var = var OP expresie

Astfel, atribuirea x = x * 5  este echivalentă cu x *= 5.

Operatorii de incrementare și decrementare: ++ --

Prin incrementarea unei variabile se înțelege mărirea valorii sale cu 1. Similar, prin decrementarea unei variabilă se înțelege micșorarea valorii sale cu 1.

Operația de incrementare a variabilei X poate fi:

  • postincrementareX ++. Efectul expresiei este mărirea valorii lui X cu  1, iar rezultatul expresiei este valoarea inițială a lui X.
  • preincrementare++ X. Efectul expresiei este mărirea valorii lui X cu  1, iar rezultatul expresiei este valoarea mărită a lui X.

Exemplu pentru postincrementare:

int  x = 5 , y = 10;

y = x ++; // y primeste valoare lui (x++), adica valoarea initiala a lui x

cout << x << " "  << y; // 6 5

Exemplu pentru preincrementare:

int  x = 5 , y = 10;

y = ++ x; // y primeste valoare lui (++x), adica valoarea marita a lui x

cout << x << " "  << y; // 6 6

Operația de decrementare  a variabilei X poate fi:

  • postdecrementareX ++. Efectul expresiei este micșorarea valorii lui X cu 1 , iar rezultatul expresiei este valoarea inițială a lui X.
  • predecrementare++ X. Efectul expresiei este micșorarea valorii lui X cu  1, iar rezultatul expresiei este valoarea micșorată a lui X.

Operatorul condițional: ?

Operatorul condițional este singurul operator ternar (cu trei operanzi) din C++. Sintaxa lui este:

expresie1 ? expresie2 : expresie3

și se evaluează astfel:

  • se evaluează expresie1
  • dacă rezultatul lui expresie1 este nenul (adevărat), se evaluează expresie2 și rezultatul acestei expresii va fi rezultatul operației ?
  • dacă rezultatul lui expresie1 este nul (fals), se evaluează expresie3 și rezultatul acestei expresii va fi rezultatul operației ?

expresie2 și  expresie3 trebuie să aibă rezultate de același tip, sau de tipuri compatibile

Exemplu:

int  x;

cin >> x;

cout << (x % 2 == 0? "par"  : "impar");

Operatorul virgulă: ,

În anumite situații, regulile de sintaxă ale limbajului C++ solicită prezența unei singure operații, dar logica programului cere prezența mai multor operații. Acestea pot fi grupate cu ajutorul operatorului ,. Sintaxa acestei operații este;

expresie1 , expresie2

Modul de evaluare este:

  • se evaluează mai întâi expresie1, apoi expresie2  – important, dacă în expresie2 apar variabile care se modifică în expresie1
  • rezultatul operației este rezultatul lui expresie2

Exemple:

int  x , y , z;

x = 1 , y = 2 , z = 3;

x ++, y = x + 2, z -= x; // este semnificativa ordinea in care s-au evaluat cele trei expresii

cout << x << " " << y << " " << z; // 2 4 1

Operatorii pe biți: &|^~<< >>

Operatorii pe biți reprezintă o temă avansată de programare. Ei permit manipularea directă și foarte rapidă a biților care formează reprezentarea în memorie a unei date. Vom trata această temă într-un alt articol.

Operatorul de conversie explicită

În anumite situații trebuie să considerăm o expresie de un anumit tip ca fiind de alt tip. Acest lucru poate fi realizat prin operatorul de conversie:

(tip_nou) expresie

Exemple:

int  x = 2;

cout << 7 / x << endl; // 3 - este impartire intreaga

cout << 7 / (double) x; // 3.5 - este impartire zecimala

char  p = 'a';

cout << (int)p << endl; // 97, codul ASCII al lui 'a'

cout << p - 32 << endl; // 65

cout << (char)(p - 32); // A - carcaterul cu codul ASCII 65

Alți operatori

Limbajul C++ conține și alți operatori, dintre care:

  • ( ) – modificarea priorității unei operații, apel de funcție
  • [ ] – indexarea unui tablou
  • .-> – acces la membrii unei structuri
  • &* – referențiere (determinarea adresei unei variabile), dereferențiere (accesare variabilei de la o adresă)
  • newdelete – alocare și dealocarea memoriei
  • <<>> – inserare și extragere din stream
  • :: operatorul de acces/rezoluție

Prioritatea operatorilor

Prioritatea operatorilor stabilește ordinea în care se evaluează o expresie care conține mai mulți operatori, de diverse feluri – ordinea în care se efectuează operațiile.

Asocierea operatorilor stabilește ordinea în care se evaluează o expresie ce conține mai mulți operatori cu aceeași prioritate. Poate fi de la stânga la dreapta sau de la dreapta la stânga.

Atât prioritatea, cât și asocierea operatorilor poate fi modificată folosind paranteze rotunde ()

 

Funcții C++ predefinite
Funcții C++ predefinite

funcție este un ansamblu de instrucțiuni care prelucrează un set de date de intrare, numite parametri sau argumente și obține un rezultat. Când folosim funcțiile, acestea apar în expresii ca operand, valoarea operandului fiind de fapt rezultatul funcției, obținut în urma prelucrării valorilor curente ale parametrilor.

De exemplu, în C++ nu există nicio operație prin care să calculăm rădăcina pătrată a unui număr real, de exemplu 5–√5. Acest lucru poate fi realizat folosind funcția sqrt, prin apelul sqrt(5); acesta trebuie realizat într-o expresie, de exemplu o afișare:

cout << sqrt(5);

Despre funcția sqrt (și de fapt despre orice funcții), trebuie cunoscute niște informații specifice, pentru a ști cum și când o putem folosi:

  • numele funcției
  • numărul parametrilor
  • tipul parametrilor
  • tipul rezultatului

Aceste informații sunt precizate printr-un mecanism de declarare a funcției, numit prototip. De exemplu funcția sqrt determină rădăcina pătrată dintr- un număr real (nenegativ) iar rezultatul său este de asemenea număr real. Prototipul său este:

double sqrt(double);

Prototipurile funcțiilor din aceeași categorie sunt grupate într-un fișier header. Acesta trebuie inclus în programul nostru, prin directiva #include. De exemplu, dacă folosim operațiile de de citire/scriere vom include header-ul iostream, iar dacă folosim funcțiile matematice vom include header-ul cmath.

Câteva funcții cu caracter matematic

Denumire

Header

Prototip

Rezultat

abs

cstdlib

int double(int x)

Valoarea absolută a argumentului, |x||x|, număr întreg

abs

cmath

double double(double x)

Valoarea absolută a argumentului, |x||x|, număr real

sqrt

cmath

double sqrt(double x)

Rădăcina pătrată a argumentului, x−−√x

pow

cmath

double pow(double x, double y)

xyxy

sin

cmath

double sin(double x)

sinxsinx

cos

cmath

double cos(double x)

cosxcosx

tan

cmath

double tan(double x)

tanxtanx

floor

cmath

double floor(double x)

Cel mai mare întreg mai mic sau egal cu x

ceil

cmath

double ceil(double x)

Cel mai mic întreg mai mare sau egal cu x

 

Structura liniară
Structura liniară

Structura liniară este reprezentată de instrucțiuni care se execută la fel la fiecare executare a programului (sau a secvenței de program), indiferent care sunt valorile variabilelor cu care se lucrează.

Instrucțiunea expresie

Instrucțiunea expresie este cel mai frecvent folosit tip de instrucțiune dintr-un program C++. O expresie devine instrucțiune dacă este urmată de ;.

Sintaxa:

Expresie ;

Exemple:

view source

print ?

x = 2;

x ++;

cout << x;

Notă: În C++, operațiile de intrare/ieșire folosind stream-uri sunt și ele operații. În exemplul de mai sus, cout și x sunt operanzii, iar << este operatorul. Rezultat operației este o adresă de memorie, a stream-ului cout.

Instrucțiunea declarativă

Printr-o instrucțiune declarativă se pot declara identificatori de un anumit tip. Identificatorii pot fi variabile, dar vom vedea mai târziu că pot fi și funcții.

Sintaxa este:

Tip_de_date Lista_identificatori ;

unde

Tip_de_date poate fi orice tip C++ corect (intdouble, etc.), iar  Lista_identificatori este alcătuită din cel puțin un identificator. Dacă sunt mai mulți, se vor separa prin caracterul virgulă ,.

Exemple:

view source

print ?

int x, y , z;

double a;

Instrucțiunea compusă

Instrucțiunea compusă sau blocul este o grupare de declarații și instrucțiuni închise între acolade {}. Ele au fost introduse cu scopul de a folosi mai multe instrucțiuni acolo unde sintaxa cere o singură instrucțiune. Instrucţiunea compusă sau blocul sunt echivalente sintactic cu o singură instrucţiune.

Blocul determină și un domeniu de vizibilitate pentru identificatori. Mai precis, identificatorii declarați într-un bloc vor fi eliminați la terminarea acestuia.

După acolada închisă } nu se scrie ;!

Exemple:

view source

print ?

#include <iostream>

using namespace std;

int main(){

int x = 5;

{

int x = 7;

cout << x << endl; // se va afisa 7

}

cout << x << endl; // se va afisa 5

return 0;

}

Instrucțiunea return

O instrucţiune return permite ieşirea dintr-o funcţie și transmiterea controlului apelantului funcției. O funcţie poate returna valori apelantului său, prin intermediul unei instrucţiuni return.

Sintaxă:

return;

sau

return expresie ;

În primul caz valoarea returnată nu este definită. În al doilea caz valoarea expresiei este returnată apelantului funcţiei.

Instrucțiunea vidă

În numite situații, sintaxa limbajului C++ cere prezența unei instrucțiuni într-un anumit punct al programului, dar logica acestuia nu cere acest lucru. Aici intervine instrucțiunea vidă, cu următoarea sintaxă:

;

La întâlnirea instrucțiunii vide nu se va executa nicio acțiune.

Structura alternativă
Structura alternativă

În anumite situații, este necesară executarea unor instrucțiuni în cadrul unui program numai în anumite condiții. Numite și structuri de decizie, structurile alternative permit rezolvarea unor asemenea situații.

Instrucțiunea if

Instrucțiunea if este cea mai utilizată structură alternativă.

Sintaxa ei are două forme:

Varianta 1

if ( Expresie ) Instrucțiune1;
          else Instrucțiune2;

Varianta 2

if ( Expresie ) Instrucțiune1;

Mod de execuție:

Instrucțiunea if se execută în felul următor:

  • se evaluează Expresia
  • dacă valoarea ei este nenulă
    • se execută Instrucțiune1;
    • se continuă cu instrucțiunea care urmează după if
  • dacă valoare expresiei este nulă
    • dacă există clauza else
      • se execută Instrucțiune2;
      • se continuă cu instrucțiunea care urmează după if
    • dacă nu există clauza else, se continuă cu instrucțiunea care urmează după if

Observații:

  • Varianta 2 (fără clauza else) a instrucțiunii if este echivalentă cu următoarea, în care Instructiune2; este o instrucțiune vidă:

if ( Expresie ) Instrucțiune1;
else ;

  • Instrucțiune1; se execută numai dacă Expresie este nenulă (condiție adevărată). Instrucțiune2; se execută numai dacă Expresie este nulă (condiție falsă). În nicio situație nu se execută ambele instrucțiuni!
  • Instrucțiune1; și Instrucțiune2; pot fi orice fel de instrucțiuni, inclusiv instrucțiunea vidă și inclusiv o altă instrucțiune if.
  • Dacă logica programului o cere, Instrucțiune1; și/sau Instrucțiune2; pot fi instrucțiuni compuse, care să conțină mai multe instrucțiuni.
  • if testează valoarea numerică pentru Expresie, nu valoarea de adevăr. De aceea, scrierile:
    if(Expresie) ...
    și
    if(Expresie != 0) ...
    sunt echivalente. La fel și scrierile:
    if(! Expresie) ...
    și
    if(Expresie == 0) ...

Exemple:

Următoarea secvență decide dacă un număr întreg citi este par sau nu:

view source

print ?

int x;

cin >> x;

if(x % 2 == 0)

cout << x << " este par";

     else

cout << x << " este impar";

Următoarea secvență citește două numere n m și stabilește dacă m este divizor al lui  n, tratând cazul m=0. Este un exemplu de instrucțiuni if imbricate (una în alta).

view source

print ?

int n , m;

cin >> n >> m;

if(m == 0)

cout <<"nu putem imparti la zero!";

else

if(n % m == 0)

cout << m << " divide pe " << n << endl;

else

cout << m << " nu divide pe " << n << endl;

Următoarea secvență testează egalitatea cu 0 a unei expresii în forma scurtă, fără a folosi operatorii de egalitate:

view source

print ?

if( n )

cout << n << " nenul";

else

cout << n << " este nul";

Instrucțiunea switch

Instrucțiunea switch permite executarea unor instrucțiuni, în funcție de egalitatea unei expresii cu anumite valori numerice constante:

Sintaxa:

switch ( Expresie )
{
case Constanta_1: Grup_Instructiuni_1;

break;

case Constanta_2: Grup_Instructiuni_2;

break;

 …

case Constanta_N: Grup_Instructiuni_N;

 break;

default: Grup_Instructiuni_default;

break;
}

Mod de execuție:

  • se evaluează Expresie
  • dacă valoarea expresiei este egală cu una dintre valorile constante din clauzele case, se execută instrucțiunile din grupul de instrucțiuni corespunzător, apoi se trece la instrucțiunea de după switch
  • dacă valoarea expresiei nu este egală cu niciuna dintre valorile constante din clauzele case, se verifică existența clausei default;
    • dacă există clauza default, se execută instrucțiunile din grupul de instrucțiuni corespunzător clauzei default, apoi se trece la instrucțiunea de după switch
    • dacă nu există clauza default, se trece la instrucțiunea de după switch

Observații:

  • Valorile din clauzele case trebuie să fie constante întregi.
  • În fiecare grup de instrucțiuni pot să apară oricâte instrucțiuni, de orice tip, eventual niciuna. Nu este necesară utilizarea instrucțiunii compuse.
  • Prezență instrucțiunii break; nu este obligatorie, dar lipsa ei modifică modul de execuție al instrucțiunii. În exemplul de mai jos:

view source

print ?

switch(n)

{

case 1:

cout << "n = 1\n";

case 2:

cout << "n = 2\n";

break;

case 3:

cout << "n = 3\n";

break;

}

dacă valoarea lui n este 1, se va afișa:

n = 1

n = 2

Mai exact, se execută toate instrucțiunile de la clauza case corespunzătoare valorii expresiei până la prima instrucțiune break; întâlnită.

Exemple:

În exemplul de mai jos se afișează (aproximativ) numele zilei din săptămână în funcție de numărul ei.

view source

print ?

#include <iostream>

using namespace std;

int main(){

int zi;

cin >> zi;

switch(zi)

{

case 1:

cout << "Luni\n"; break;

case 2:

cout << "Marti\n"; break;

case 3:

cout << "Miercuri\n"; break;

case 4:

cout << "Joi\n"; break;

case 5:

cout << "Vineri\n"; break;

case 6:

case 7:

cout << "WEEKEND!!!\n"; break;

default:

cout << "Numarul zilei este incorect\n"; break;

}

return 0;

}

Observați mai sus că în clauza case 6: nu avem instrucțiuni. Dacă variabila zi are valoarea 6 sau 7 se va afișa:

 

Structuri repetitive
Structuri repetitive

Structurile repetitive execută o instrucțiune de un anumit număr de ori, sau cât timp o condiție este adevărată. Se mai numesc și bucle sau cicluri.

Structurile repetitive pot fi:

  • cu număr cunoscut de pași (iterații) – se cunoaște de la început de câte ori se va execută instrucțiunea
  • cu număr necunoscut de pași (iterații). Instrucțiunea se execută cât timp o condiție este adevărată. La fiecare pas se va evalua condiția, iar dacă aceasta este adevărată se va executa instrucțiunea.

Structurile repetitive cu număr necunoscut de pași pot fi:

  • cu test inițial: mai întâi se evaluează condiția; dacă este adevărată se execută instrucțiunea și procesul se reia.
  • cu test final: mai întâi se execută instrucțiunea, apoi se evaluează condiția; Dacă este adevărată, procesul se reia.

Instrucțiunea care se execută în mod repetat poartă numele de corp al structurii repetitivecorp al cicluluicorp al buclei și de foarte multe ori este o instrucțiune compusă.

Instrucțiunea while

Instrucțiunea while este o structură repetitivă cu număr necunoscut de pași și test inițial.

Sintaxa:

while (Expresie) Instructiune;

Mod de execuție:

  1. Se evaluează Expresie
  2. Dacă Expresie este nenulă
    • Se execută Instructiune;
    • Se reia pasul 1.
  3. Dacă Expresie este nulă, se trece la instrucțiunea de după while.

Observații

  • Instructiune; se execută cât timp Expresie este nenulă – condiție adevărată.
  • Dacă Expresie este de început vidă, Instructiune; nu se execută deloc.
  • Instructiune; poate fi orice fel de instrucțiune, dar una singură. Dacă sunt necesare mai multe instrucțiuni, se va folosi instrucțiunea compusă.
  • Este necesar ca cel puțin o variabilă care apare în Expresie să-și modifice valoarea în Instructiune;. Altfel se obține o buclă infinită.

Exemplu:

Următorul program citește valoarea variabilei n și calculează suma primelor n numere naturale. Rulați-l analizând rezultatul pentru diverse valori ale lui n, inclusiv 0.

view source

print ?

#include <iostream>

using namespace std;

int main ()

{

int n;

cin >> n;

int S = 0;

int i = 1;

while(i <= n)

{

S += i;

i ++;

}

cout << S << endl;

return 0;

}

Instrucțiunea do ... while

Instrucțiunea do ... while este o structură repetitivă cu număr necunoscut de pași și test final.

Sintaxa:

do Instructiune;
while ( Expresie );

Mod de execuție:

  1. Se execută Instructiune;
  2. Se evaluează Expresie
  3. Dacă Expresie este nenulă, se reia pasul 1.
  4. Dacă Expresie este nulă, se trece la instrucțiunea de după do ... while.

Observații

  • Instructiune; se execută cât timp Expresie este nenulă – condiție adevărată.
  • Dacă Expresie este de început vidă, Instructiune; se execută exact o dată. În orice situație, Instructiune se execută cel puțin o dată.
  • Instructiune; poate fi orice fel de instrucțiune, dar una singură. Dacă sunt necesare mai multe instrucțiuni, se va folosi instrucțiunea compusă.
  • Este necesar ca cel puțin o variabilă care apare în Expresie să-și modifice valoarea în Instructiune;. Altfel se obține o buclă infinită.

Exemplu:

Următorul program citește valoarea variabilei n și calculează suma primelor n numere naturale. Rulați-l analizând rezultatul pentru diverse valori ale lui n, inclusiv 0.

#include <iostream>

using namespace std;

int main ()

{

int n;

cin >> n;

int S = 0;

int i = 1;

do

{

S += i;

i ++;

}

while(i <= n);

cout << S << endl;

return 0;

}

Instrucțiunea for

Instrucțiunea for este o structură repetitivă cu număr necunoscut de pași și test inițial, echivalentă cu while.

Sintaxa:

for ( Expresie_de_Initializare ; Expresie_de_Testare ; Expresie_de_Continuare ) Instructiune;

Mod de execuție:

  1. Se evaluează Expresie_de_Initializare
  2. Se evaluează Expresie_de_Testare
  3. Dacă Expresie_de_Testare este nenulă:
    • Se execută Instructiune;.
    • Se evaluează Expresie_de_Continuare.
    • Se revine la pasul 2.
  4. Dacă Expresie_de_Testare este nulă, se trece la instrucțiunea de după for.

Observații

  • Instrucțiunea for este echivalentă cu instrucțiunea while. Sintaxa descrisă mai sus este echivalentă cu:

Expresie_de_Initializare ;
while ( Expresie_de_Testare )
{
Instructiune;

  Expresie_de_Continuare ;
}

  • Instructiune; se execută cât timp Expresie_de_Testare este nenulă – condiție adevărată.
  • Dacă Expresie_de_Testare este de început vidă, Instructiune; nu se execută deloc, iar Expresie_de_Continuare nu se mai evaluează.
  • Instructiune; poate fi orice fel de instrucțiune, dar una singură. Dacă sunt necesare mai multe instrucțiuni, se va folosi instrucțiunea compusă.
  • Este necesar ca cel puțin o variabilă care apare în Expresie_de_Testare să-și modifice valoarea în Instructiune; sau la evalurea Expresiei_de_Continuare. Altfel se obține o buclă infinită.
  • Cele trei expresii, de_Initializare_de_Testare și _de_Continuare sunt separate prin caracterul ; – obligatoriu!
  • Oricare dintre cele trei expresii, de_Initializare_de_Testare și _de_Continuare, eventual toate, poate să lipsească. În acest caz avem expresii vide. Dacă Expresie_de_Testare este vidă, rezultatul său este nenul!
  • Expresie_de_Initializare se execută o singură dată. Poate să conțină și declararea unor variabile. În acest caz, variabilele vor exista numai în instrucțiunea for.

Exemplu:

Următorul program citește valoarea variabilei n și calculează suma primelor n numere naturale. Rulați-l analizând rezultatul pentru diverse valori ale lui n, inclusiv 0.

#include <iostream>

using namespace std;

int main ()

{

int n;

cin >> n;

int S = 0;

for(int i = 1; i <= n ; i ++)

S += i;

cout << S << endl;

return 0;

}

Instrucțiunea break

Instrucțiunea break are sens și poate fi folosită numai în instrucțiunile switchwhiledo ... while și break.

Sintaxa:

break ;

Mod de execuție

Am văzut semnificația instrucțiunii break atunci când apare în instrucțiunea switch.

Efectul instrucțiunii break când apare într-o instrucțiune repetitivă este întreruperea execuției acesteia și trecerea la instrucțiunea care urmează celei repetitive.

Exemplu:

?

#include <iostream>

using namespace std;

int main ()

{

int n;

cin >> n;

int S = 0;

for(int i = 1; i <= n ; i ++)

{

S += i;

if(i == 5)

break;

}

cout << S << endl;

return 0;

}

  • Dacă valoarea lui n este cel mult 5, se va afișa suma numerelor de la 1 la n.
  • Dacă n >= 5 se va afișa întotdeauna 15, deoarece execuția lui for se întrerupe, datorită lui break, când i este 5.
a X-a A
Tablouri unidimensionale
Tablouri unidimensionale

Un tablou unidimensional se declară în C++ astfel:

tipDeBază denumire[Dimensiune];

de exemplu:

int X[10];

Ne putem imagina tabloul declarat mai sus astfel (valorile elementelor sunt aleatorii):

Spunem că fiecare element are un indice. Indicii unui tablou sunt între 0 și Dimensiune-1, deci în exemplul nostru între 0 și 9.

Observație: Nu este necesar la declarare tabloul să fie singura variabilă declarată în instrucțiunea declarativă. Următoarea instrucțiune este corectă sintactic.

int n, X[10], m, Y[100], p;

Care sunt valorile inițiale ale elementelor tabloului? Regula este aceeași ca pentru alte variabile:

  • elementele unui tablou declarat global (în afara oricărei funcții) sunt inițializate cu 0;
  • elementele unui tablou declarat local (în interiorul unei funcții) sunt inițializate cu valori aleatorii. Faptul că anumite implementări la compilatorului C++ inițializează și variabilele local cu 0 nu este o regulă, ea nu este garantată de standardul C++.

Referirea unui element

Referirea unui element se face prin operatorul de indexare[], care are prioritate maximă. De exemplu:

X[0], X[5], X[i]

Aici X este identificatorul tabloului (denumirea), iar 05 sau i sunt indicii. Este necesar ca programatorul (adică TU!) să se asigure că valoarea indicelui se găsește în intervalul potrivit pentru tabloul dat (în exemplul nostru între 0 și 9).

Un element al tabloului, referit prin indice este tratat ca o variabilă oarecare de tipul stabilit la declarare. Următoarele expresii/instrucțiuni sunt corecte:

int X[10];
cin >> X[0];
X[0] = 17;
cout << X[0];
cout << X[0] / 5;

Observație: C++ nu verifică dacă valoarea indicelui face parte din intervalul stabilit prin declararea tabloului. Dacă indicele are o valoare în afara acestui interval, comportamentul programului este impredictibil.

Este necesar ca programatorul să se asigure că valorile indicilor sunt corecte.

Dimensiunea unui tablou unidimensional

La declararea unui tablou unidimensional se precizează o dimensiune pentru acesta. Aceasta reprezintă o dimensiune fizică a tabloului – numărul maxim de elemente pe care le-ar putea avea acesta, conform restricțiilor problemei.

De cele mai multe ori, în program nu se folosesc toate elementele tabloului. De regulă, enunțul unei probleme cu tablouri este:

“Se citește un vector cu n elemente, numere …. Să se …..”

Este deci necesar ca în program să avem o variabilă – de regulă se notează n, care să reprezinte dimensiunea logică a tabloului – numărul de elemente ale tabloului care la un moment dat sunt utilizate în program.

Parcurgerea unui tablou unidimensional

Parcurgerea unui tablou reprezintă referirea fiecărui element al tabloului, într-o anumită ordine. Referirea elementului se face prin intermediul indicelui, cu ajutorul operatorului de indexare.

Următorul exemplu declară un tablou cu 100 de elemente și memorează în primele n elemente ale tabloului valoarea 1. După cum știm deja, n trebuie să respecte relația n<=100. În caz contrar, comportamentul programului devine impredictibil – foarte probabil execuția sa va fi oprită de sistemul de operare.

int X[100], n;
//n = .... ;
for(int i = 0 ; i < n ; i ++)
    X[i] = 1;

De regulă, parcurgerea tabloului se face în ordinea crescătoare a indicelor, de la 0 la n-1. Făcând o analogie cu axa numerelor, putem spune că parcurgerea se face de la stânga spre dreapta. Tabloul poate fi parcurs și de la dreapta la stânga, adică în ordinea descrescătoare a indicilor, de la n-1 la 0:

for(int i = n - 1 ; i >= 0 ; i 
--)
    X[i] = 1;

Citirea unui vector

int 
X[100], n;

De fapt, în cele mai multe cazuri nu se poate face citirea unui tablou unidimensional (vector), adică

cin >> X;

Instrucțiunea de mai sus duce de regulă la eroare de sintaxă. În schimb, se pot citi elementele tabloului, în ordine, cu ajutorul parcurgerii:

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

Afișarea unui vector

int 
X[100], n;

La fel ca în cazul citirii, în cele mai multe cazuri nu se poate face nici afișarea unui vector, adică

cout <<  X;

Spre deosebire de citire, afișarea unui tablou cu ajutorul operatorului de inserție << nu duce la eroare de sintaxă, însă nu se vor afișa elementele tabloului, ci o adresă (de exemplu 0x7ffc9711bcd0), reprezentând adresa primului element al tabloului. Elementele tabloului se pot afișa prin parcurgere, în ordinea dorită:

for(int i = 0 ; i < n ; i ++)
    cout << X[i] << ' ';

sau

for(int i = n - 1 ; i >= 0 ; i --)
    cout << X[i] << ' ';

Indexare de la 0 și indexare de la 1

Orice tablou C++ are fizic elementele indexate de la 0 la Dimensiune-1. De exemplu, dacă avem nevoie de un tablou cu n≤100 elemente întregi, îl vom declara:

int V[100];

iar elementele vor avea indici între 0 și 99. Astfel, primul element al tabloului este V[0], al doilea este V[1], …, ultimul este V[n-1].

Dacă dorim, putem ignora elementul V[0]  (pur și simplu nu îl folosim, el există însă în continuare), și atunci toate operațiile (citire, afișare, parcurgere) vor utiliza elementele V[1] (primul element), V[1] (al doilea element), …, V[n]  (ultimul element).

Trebuie de asemenea să tratăm cu atenție declararea tabloului, dimensiunea fizică trebuind să fie mai mare cu 1 decât valoarea precizată în problemă. Dacă de exemplu, n≤100, declararea va fi:

int V[101];

Acest lucru este necesar pentru a exista elementul V[100].

Tablouri unidimensionale / Ștergeri și inserări de elemente
Tablouri unidimensionale / Ștergeri și inserări de elemente

Operațiile de ștergere a unui element dintr-un vector, sau de inserare a unui element nou într-un vector sunt frecvente în practică: avem o listă cu elevii dintr-o clasă și un elev pleacă, sau un alt elev vine. Cum actualizăm lista?

Ștergerea

Să considerăm următoarea problemă :

Se dă un șir X cu n elemente întregi și un număr p. Să se șteargă din șirul X elementul aflat pe poziția p.

Să considerăm următorul vector cu n=10 elemente și p=4.

Dorim să eliminăm din vector elementul de indice 4, cel cu valoarea X[4] = 34. În urma eliminării vectorul trebuie să arate astfel:

Cum procedăm?

  • elementele cu indici p+1p+2, …, n-1 se mută spre stânga cu o poziție
  • dimensiunea n a tabloului se micșorează cu 1

Ștergerea se face astfel:

for(int i 
= p ; i < n - 1; i ++)
    X[i] = X[i+1];
n --;

Ștergerea mai multor valori din șir

Considerăm următoarea problemă :

Considerăm un șir X cu n elemente întregi. Să se elimine din șir toate elementele pare.

Rezolvare:

  • parcurgem șirul și analizăm elementul curent X[p];
  • dacă elementul X[p] este par, aplicăm algoritmul de mai sus pentru ștergerea elementului cu indicele p.

Este necesar să realizăm cu atenție parcurgerea. Următoarea secvență:

for (int p = 0 ; p < n ; p ++)
    if(X[p] % 2 == 0) {
        for(int i = p ; i < n - 1; i ++)
            X[i] = X[i+1];
        n --;
    }

nu funcționează corect dacă în șir sunt elemente consecutive cu proprietatea dorită (de a fi pare), deoarece al doilea element par nu va fi analizat, deci nu va fi eliminat din șir. O soluție bună este să parcurgem elementele în ordine inversă:

for (int p = n - 1 ; p >= 0 ; p --)
    if(X[p] % 2 == 0) {
        for(int i = p ; i < n - 1; i ++)
            X[i] = X[i+1];
        n --;
    }

Adăugarea unui element într-un vector

Adăugarea unui element într-un vector înseamnă mărirea dimensiunii logice n a vectorului și memorarea în ultimul element a noii valori. Următoarele secvențe adaugă o valoare într-un vector indexat de la 0.

X[n] = val;
n ++;

sau, mai condensat:

X[n++] = val;

Următoarele secvențe adaugă o valoare într-un vector indexat de la 1.

n ++;
X[n] = val;

sau, mai condensat:

X[++n] = val;

Inserarea unui element într-un vector

Considerăm următoarea problemă :

Se dă un șir X cu n elemente întregi, o valoare întreagă val și un număr p. Să se insereze pe poziția p în șir valoarea val.

Similar cu algoritmul de ștergere a unui element dintr-un vector, și cel de inserare presupune modificarea elementelor din dreapta lui X[p]. De data aceasta elementele vor fi mutate spre dreapta, începând cu ultimul. Elementul X[p] se înlocuiește cu noua valoare, iar dimensiunea logică a vectorului crește, fără a depăși însă dimensiunea fizică.

for(int i = n - 1 ; i >= p ; i --)
    X[i+1] = X[i];
X[p] = val;
n ++;

Inserarea mai multor valori în șir

Se dă un vector cu n elemente naturale. Să se insereze după fiecare element par, jumătatea sa.

Principial, procedăm astfel:

  • parcurgem șirul
  • dacă elementul curent X[p] este par
    • inserăm pe poziția p+1 valoarea X[p]/2

Dacă parcurgerea se face de la stânga spre dreapta, există riscul unor inserări suplimentare, ca în acest exemplu:

Tablouri unidimensionale / Verificarea unor proprietăți
Tablouri unidimensionale / Verificarea unor proprietăți

Se pot formula foarte multe probleme în care se cere să se verifice dacă elementele unui vector respectă diverse proprietăți, dar toate se pot reduce în cele din urmă la una dintre următoarele:

  • să se verifice dacă toate elementele unui vector dat respectă o anumită regulă;
  • să se verifice dacă într-un vector dat există elemente care respectă o anumită regulă.

O rezolvare ar putea fi să numărăm elementele care respectă regula. La final:

  • dacă numărul de elemente care respectă regula este egal cu numărul totale de elemente din vector, atunci toate elementele respectă regula
  • dacă numărul de elemente care respectă regula este nenul, atunci există elemente care respectă regula.

Altă rezolvare, mai bună, ne permite să oprim parcurgerea când suntem siguri că vectorul respectă sau nu proprietatea dorită. Vom folosi o variabilă booleană (cu valori true sau false1 sau 0, …):

  • dacă la final variabila are valoarea true, atunci vectorul respectă regula,
  • dacă la final variabila are valoare false, atunci vectorul nu respectă regula.

Toate elementele respectă regula

  • inițializăm variabila cu true
  • parcurgem vectorul
    • dacă elementul curent nu respectă regula dorită
      • variabila devine false
      • parcurgerea vectorului poate opri

Secvențe C++:

bool OK = true;
for(int i = 0 ; i < n && OK ; i ++)
    if(X[i] - nu respectă regula)
        OK = false;

sau

bool OK = true;
for(int i = 0 ; i < n ; i ++)
    if(X[i] - nu respectă regula)
    {
        OK = false;
        break;
    }

sau

bool OK = true;
int i = 0;
while(i < n && OK)
{
    if(X[i] - nu respectă regula)
        OK = false;
    else
        i ++;
}

Există elemente care respectă regula

  • inițializăm variabila cu false
  • parcurgem vectorul
    • dacă elementul curent respectă regula dorită
      • variabila devine true
      • parcurgerea vectorului poate opri

Secvențe C++:

bool OK = false;
for(int i = 0 ; i < n && !OK ; i ++)
    if(X[i] - respectă regula)
        OK = true;

sau

bool OK = false;
for(int i = 0 ; i < n ; i ++)
    if(X[i] - respectă regula)
    {
        OK = true;
        break;
    }

sau

bool OK = false;
int i = 0;
while(i < n && !OK)
{
    if(X[i] - respectă regula)
        OK = true;
    else
        i ++;
}
Tablouri unidimensionale / Sortarea tablourilor
Tablouri unidimensionale / Sortarea tablourilor

Sortarea unui tablou reprezintă o rearanjare a elementelor astfel încât valorile acestora să fie într-o anumită ordine. De regulă ordinea cerută este cea crescătoare sau descrescătoare.

Există numeroase metode de sortare, conform Wikipedia .

Din punct de vedere al eficienței, avem:

algoritmi mai puţin eficienţi

    1. metoda bulelor
    2. sortarea prin selecție
    3. sortarea prin inserție
    4. metoda minimului
    5. etc.
  • algoritmi eficienți,
  1. QuickSort
  2. MergeSort
  3. HeapSort
Ordonarea unui sir - Metoda "bulelor" (Bubble Sort)
Ordonarea unui sir - Metoda "bulelor" (Bubble Sort)

Se citeşte un sir de numere întregi si se cere sa se ordoneze elementele acestui sir crescâtor

A: 7 , 4 , 5 , 3 , 9 , 1    (înainte)

A: 1 , 3 , 4 , 5 , 7 , 9     (după)

Ideea care stă la baza acestei metode este următoarea: se parcurge sirul, comparându-se elementele consecutive din şir două câte două. Dacă acestea nu sunt în relatia dorita ("³" sau "£") se schimba valorile elemntelor.

Printr-o parcurgere a şirului şi efectuarea comparaţilor obţinem:            


 4, 7, 5, 3, 9, 1

 4, 5, 7, 3, 9, 1

 4, 5, 3, 7, 9, 1

 4, 5, 3, 7, 1, 9

 Comparăm  A[i] > A[i+1]   dacă da, atunci cele două valori se interschimbă.

Se observă că, după o parcurgere a vectorului, şirul obţinut nu este ordonat deci este necesară reluarea procedeului descris anterior.


int n, 
v[100];
//citire v[] cu n elemente
int sortat = 0;
while (sortat==0)
{
  sortat = 1;
  for(int i = 0 ; i < n ; i ++)
    if(v[i] > v[i+1])
    {
      int aux = v[i];
      v[i] = v[i+1];
      v[i+1] = aux;
      sortat = 0;
    }
}


Video Bubble Sort

Sortarea prin selecţie sau Select Sort
Sortarea prin selecţie sau Select Sort
Algoritmul constă în alegerea celui mai mic element dintr-un vector şi aşezarea lui pe prima poziţie, repetată pentru şiruri din ce în ce mai scurte. Metoda necesită un timp de lucru care depinde  de numărul de elemente din vector, iar algoritmul metodei se reprezintă prin structuri repetitive cu
număr cunoscut de paşi.
În cazul unui vector sortat crescător, primul element (cu indice 1) este cel mai mic dintre cele cu indici de la 1 la n, cel de-al doilea este cel mai mic dintre cele cu indici de la 2 la n ş.a.m.d. Să considerăm un vector în care elementele cu indici de la 1 la i-1 sunt deja sortate. Pentru a continua procesul de sortare, dintre elementele rămase (cu indici de la i până la n) trebuie găsit cel mai mic (cu indice isel) şi adus în poziţia i.


Pas 1 : Se citeste vectorul

Pas 2 : Se parcurge vecorul de la prima pana la penultima pozitie ( 1 => n-1 )

Pas 2.1 : Se considera valoarea minima cea din pozitia i si se pastreaza valoarea intr-o variabila k

Pas 2.2 : Parcurgem de la elementul urmatorul pana la sfarsit si cautam valoarea minima

Pas 2.2.1 : Pastram valoarea nou gasita in variabila min si schimbam pozitia.

Pas 2.3 : Interschimbam cele 2 valori ( i cu k )

Pas 3 : Se reia de la pasul 2 pana la penultima valoare

Pas 4 : Se afiseaza vectorul



#include <iostream>
using namespace std;
int main()
{
int v[100],i,n,min,k,aux,j;
cout<<"n= ";cin>>n;
for(i=1;i<=n;i++)
{             
   cout<<"v["<<i<<"]= ";
   cin>>v[i];
}
for(i=1;i<=n-1;i++)
{
                min=v[i];
                k=i;
                for(j=i+1;j<=n;j++)
                    if(v[j]<min)
                    {
                       min=v[j];
                       k=j;
                    }
                aux=v[i];
                v[i]=v[k];
                v[k]=aux;
}
cout<<"Vectorul sortat este: ";
for(i=1;i<=n;i++)
      cout<<v[i]<<" ";
return 0;
}


Video Select Sort

Sortarea prin inserție (Insertion Sort)
Sortarea prin inserție (Insertion Sort)

Sortarea prin inserție  (Insertion Sort) se bazează pe următoarea idee:

  • fie un vector  X[] cu n elemente;
  • dacă secvența cu indici 01, …,  i-1 este ordonată, atunci putem insera elementul  X[i] în această secvență astfel încât să fie ordonată secvența cu indici 01, …, i-1i.
  • luăm pe rând fiecare element X[i] și îl inserăm în secvența din stânga sa
  • la final întreg vectorul va fi ordonat

O reprezentare a algoritmului este:

  • parcurgem vectorul cu indicele i
    • inserăm pe X[i] în secvența din stânga sa; pentru inserare se mută unele elemente din secvență spre dreapta

Exemplu: Să ordonăm următorul vector, în care n=5:

sortarea prin inserție presupune următoarele transformări ale vectorului:

int n, X[100];
//citire X[] cu n elemente
for(int i = 1 ; i < n ; i ++)
{
    int x = a[i];
    int p = i - 1;
    while(p >= 0 && a[p] > x)
      {  a[p + 1] = a[p]; p --; }
    a[p + 1] = x;
}
Video Insertion Sort
Sortare stabilind poziţia definitivă prin numărare
Sortare stabilind poziţia definitivă prin numărare

Sortare stabilind  pozia  definitivă prin   numărare

Această metodă constă în construirea unui nou tablou B care are aceeaşi dimensiune ca şi tabloul

în care depunem elementele din  A, ordonate crescător.

Vom lua fiecare element şi îl vom compara cu fiecare  alt element din şir pentru a  putea reţine în variabila k  numărul elementelor care sunt mai mici decât elementul considerat. Astfel, vom afla poziţia pe care trebuiesă-l punem pe acesta în şirul B. Da în problemă avem nevoie de  şirul ordonat tot în tabloul A, vom copia  în A întreg tabloul B.

  Subalgoritm Numărare(n,A

   1: pentru i =1,n execută

2:      k = 0

3:      pentru j=1,n execută

4:          dacă (A[i] < A[j]) atunci

5:                k = k +  1           { numărăm câte elemente sunt mai mici det A[i] 

              sfarsit daca

          sfarsit pentru

6:          B[k1] = A [i]          { pe A[i] îl punem pe poziţia co respunzătoare din  B 

     sfarsit pentru

7:                A = B        copiem peste şirul A întreg şirul B }

 Exemplu

 Fie tabloul  A cu 4 ele mente: 7, 2, 3, –1.

i

j

Relaţia

k

bk +  1

1

1

=  j

0

 

1

2

7 > 2

1

 

1

3

7 >  3

2

 

1

4

7 >  –1

3

b4 =  7

2

1

2 <  7

0

 

2

2

= j

0

 

2

3

2 < 3

0

 

2

4

2 >  –1

1

b2 = 2

3

1

3 < 7

0

 

3

2

3 >  2

1

 

3

3

=  j

1

 

3

4

3 > –1

2

b3 =  3

4

1

–1 <  7

0

 

4

2

–1 < 2

0

 

4

3

–1 <  3

0

 

4

4

= j

0

b1 = –1

Algoritmul funcţionea în această formă dacă elementele tabloului A sunt distincte altfel în B vor răne elemente necopiate din A, deoarece două elemente egale se vor copia în B pe  acee aşi poziţie. 

Tablouri unidimensionale / Interclasarea tablourilor
Tablouri unidimensionale / Interclasarea tablourilor

Considerăm două tablouri unidimensionale cu elemente numere întregi ordonate crescător. Se dorește construirea unui alt tablou, care să conțină valorile din cele două tablouri, în ordine.

O soluție foarte eficientă este interclasarea:

  • considerăm două tablouri, cu n, respectiv m elemente, ordonate crescător
  • cele două tablouri se parcurg concomitent;
  • se alege valoarea mai mică dintre cele două elemente curente
    • se adaugă în al treilea tablou
    • se avansează numai în tabloul din care am ales valoarea de adăugat
  • parcurgerea unuia dintre cele două tablouri se încheie
  • toate elementele din celălalt tablou, neparcurse încă, sunt adăugate în tabloul destinație
  • tabloul destinație are p = n + m elemente

int n,a[100000], m , b[100000], p, c[200000];

//citire a[] cu n elemente
//citire b[] cu m elemente

int i = 0 , j = 0;
p = 0;
while(i < n && j < m)
    if(a[i] < b[j])
        c[p ++] = a[i ++];
    else
        c[p ++] = b[j ++];
while(i < n)
    c[p ++] = a[i ++];
while(j < m)
    c[p ++] = b[j ++];
Observație: Doar una dintre instrucțiunile while(i < n)... și while(j < m)... se va 
executa, deoarece exact una dintre condițiile i < n și j < m este adevărată. În prima 
structură repetitivă, la fiecare pas, doar una dintre variabilele i și j se mărește, deci la final una dintre 
condiții este adevărată și una este falsă.
a XI-a A
Tablouri bidimensionale (matrice)
Tablouri bidimensionale (matrice)

Tablouri bidimensionale – matrice

 Un tablou cu două dimensiuni se numeşte matrice.

Declarare
                     int a[50][100], n, m, i, j;
S-a declarat:
– o matrice cu maxim 50 de linii şi 100 de coloane, numerotarea se face de la 0 sau de la 1.
– n- numarul efectiv de linii;
– m-numarul efectiv de coloane;
– i- contor pentru linie
– j- contor pentru coloane
Citire:
                    for(i=1; i<=n;i++)
                       for(j=1;j<=m;j++)
                        {   cout<<”a[“<<i<<”][“<<j<<”]=”;

cin>>a[i][j];

  }

Afisare:
                  for(i=1;i<=n;i++)
                         {
                           for(j=1;j<=j;j++)
                                 cout<<a[i][j]<<” “;
                                       cout<<“ ”;
                          }

 Matrice patratica

Într-o matrice pătratică numarul de linii= numarul de coloane (n=m).

Într-o matrice pătratică avem:

  •                                 Diagonala principala elementele a[i][i], cu i=1,n        sau         a[i][i], cu i=0,n-1
  •                                 Diagonala secundara elementele a[i][n-i+1], i=1,n        sau         a[i][n-i-1], i=0,n-1

Zonele determinate de diagonale:
I.
               Pe diagonala principală i=j
               Sub diagonala principala: i>j
               Deasupra diagonalei principale: i<j
II.
               Pe diagonala secundară j=n-i+1
               Sub diagonala secundara: j>n-i+1
               Deasupra diagonalei secundare:j<n-i+1


Siruri de caractere (citire, tiparire)
Siruri de caractere (citire, tiparire)

ȘIRURI DE CARACTERE

Limbajul C/C++ permite initializarea unui tablou de caractere printr-o constanta sir, care include automat caracterul  NULL

Caracterul NULL '\0' se adauga atutomat dupa ultimul caracter din sir.

'\n' - caracterul linie noua     deci cout<<endl;    chivalent cu  cout<<'\n';

 

Exemplu :

char vect[11]=”calculator”;

char vect[]=”calculator”; (compilatorul face calculul numarului de octeti necesari)

char vect[100]=”calculator”; (s-au rezervat mai multi octeti decat era necesar)

1               Sirurile de caractere sunt de fapt tablouri de caractere, care au ca ultim element un terminator de sir, caracterul NULL. Exemplu:

char tc[5] = {’a’, ’b’, ’c’, ’d’, ’e’};     // tablou de caractere

char sc[5] = {’a’, ’b’, ’c’, ’d’, ’\0’};    // sir de caractere cu elementele abcd Ultima initializare este echivalenta cu:

char sc[5] = ”abcd”;      //sau char sc[] = ”abcd”; char sc1[5] = ”abcd”;

char s[10];

cout<<sc<<endln;    //afiseaza abcd
cout<<tc<<endl;     //eroare: tabloul de caractere nu contine terminatorul de sir, deci nu poate fi afisat ca sir
cout<<s<<endl;         // eroare: tablou neinitializat 
cout<<sc1[0];        // afiseaza primul  caracter din  sirul sc1 
cout<<sc1[2];       / / afiseaza al treilea element din sirul  sc1
sc1[1]=’K’;             // elementului din sir de indice 1 i se atribuie valoarea K;

 

CITIREA / AFISAREA SIRURILOR DE CARACTERE

Sirurile de caractere pot fi initializate inca de la declarare sau citite pe parcursul programului.

a.          Citirea unui sir de caractere se poate face ca citirea oricarui tablou, intr-un for, caracter cu caracter

(desi nu este recomandata). In acest caz, terminatorul de sir nu este memorat automat, el trebuie pus explicit dupa ultimul caracter din sir.

 

Exemplu:

char c[20];

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

cin>>c[i];

cout<<c<<endl; //se va afisa sirul format din cele 6 caractere, urmat de caractere reziduale”,

//initializate implicit la compilare, din cauza ca n-a fost pus terminatorul de sir

c[6]='\0';

cout<<c<<endl; //a fost pus terminatorul de sir, deci sirul va fi afisat corect

  b.      Se poate face pur si simplu, folosind cin>>. Caracterul nul este adaugat automat. Dezavantajul este ca in acest fel nu se pot citi siruri care contin mai multe cuvinte separate prin spatii. Citirea sirului se sfarseste la intalnirea primului caracter blank (de ex, daca se citeste ora de informatica, variabila c va retine numai ora”).

Exemplu char c[30]; cin>>c; cout<<c;

  c.    Se poate folosi o functie speciala pentru citirea sirurilor de caractere, inclusa in bibliotecstring.h (varianta recomandata).

Exemplu

char a[30],x;int  nr;             cin.get(a,nr,x );

Functia cin.get citeste un sir de caractere sau pana cand au fost citite nr-1 caractere, sau daca s-a

intalnit caracterul x. Al treilea parametru poate lipsi, caz in care el este implicit caracterul \n (new line). Sunt citite si caracterele albe, caracterul NULL este inserat automat iar caracterul transmis ca ultim parametru nu este inserat in sir.

E xemplu

char a[30];

cin.get(a,5,’s’);         //daca se citeste sirul maimuta, variabila a va retine  maim” 

cin.get(a,15,’s’);  //daca se citeste sirul maimuta, variabila a va retine  maimuta” 

cin.get(a,15,’t’);   //daca se citeste sirul maimuta, variabila a va retine  maimu”

2                   cin.get(a,4,’t’);         //daca se citeste sirul maimuta, variabila a va retine  mai

cin.get(a,10);      //daca se citeste sirul maimuta, variabila a va retine  maimuta”

                   Functia cin.get( ) fara parametri are rolul de a citi un caracter (alb sau nu).

 

Observatie : In cazul utilizarii repetate a functiei cin.get(a,nr,x), dupa fiecare folosire trebuie citit caracterul de la sfarsitul fiecarui sir , adica ‟\n‟ (in caz contrar, acest caracter va fi incarcat la inceputul urmatorului sir, a carui citire se termina la caracterul Enter, deci citirea celui de-al doilea sir se termina inainte de a incepe, iar al doilea sir va fi sirul vid). Aceasta citire a caracterului \n‟ se realizeaza folosind cin.get() fara parametri.

 

Exemplu

char a[30],b[30];

cin.get(a,15);

cin.get(b,10);

Daca se incearca citirea sirurilor sarbatoare si vacanta, se observa ca a=sarbatoare, b=

(nici nu apucam sa citim sirul b). Varianta corecta este:

cin.get(a,15);

cin.get();

cin.get(b,10);

 

Afisarea unui sir de caractere se face folosind cout.

                                                     cout<<a;

Se poate afisa si caracter cu caracter, ca in cazul tablourilor, dar aceasta varianta nu este recomandata.

FUNCTII PENTRU OPERATII CU SIRURI DE CARACTERE
FUNCTII PENTRU OPERATII CU SIRURI DE CARACTERE

Functiile pentru operatii cu siruri se gasesc in header-ul .

Ø Functia strlen

int strlen (nume_sir); returneaza lungimea efectiva a unui sir (fara a numara terminatorul de sir).

Ex emplu:

char a[50]=”ora de informatica”;  =>   strlen(a) = 18

Ø Functia strcpy

strcpy(sir_destinatie,sir_sursa); copiaza sirul sir_ sursa in sir_destinatie (se simuleaza atribuirea a=b) .

ATENTIE!! Nu este permisa atribuirea intre doua siruri de caractere folosind operatorul = . Atribuirea se  face folosind functia strcpy .

Exemplu:

char a[50]=”primul sir”,b[40]=”al doilea sir”;

a=b;  //eroare

strcpy(a,b);  =>     a = ”al doilea sir”; b=”al doilea sir”;

 

Ø Functia strcat

strcat(dest,sursa); adau ga sirului dest sirul sursa. Sirul sursa ramane nemodificat. Operatia se numeste concatenare si nu este comutativa.

Exemplu:

char *a=”vine ”,*b=”vacanta?”; strcat(a,b);   =>  a = ”vine vacanta?”;

 

Ø Functia strncat

strncat(dest,sursa,nr); adauga dest primele nr caractere din sirul sursa. Sirul sursa ramane

1                             nemodificat.

E xem plu:

char *a=”vine ”,*b=”vacanta?”; strncat(a,b,4); =>  a = ”vine vaca”;

 

Ø Functia strchr

strchr(sir,c); are rolul de a cauta caracterul c in sirul sir. Cautarea se face de la stanga la dreapta, iar functia intoarce adresa subsirului care incepe cu prima aparitie a caracterului c. Daca nu este gasit caracterul, functia returneaza 0. Diferenta dintre adresa sirului initial si cea a subsirului returnat reprezinta chiar pozitia caracterului cautat in sirul dat.

Exemplu:

char *a=”acesta este un sir”, b=’t’, c=’x’, *d;      

                        cout<  =>       se tipareste   ”ta este un sir”;

cout< => nu se tipareste nimic (se tipareste 0 daca se face o conversie la int a lui strchr(a,c) ;

d= strchr(a,b);

cout<<”Caracterul apare prima data la pozitia ”<a;

 

Ex: Sa se afiseze toate pozitiile unui caracter intr-un sir

#include

#include using namespace std; int main()

{char a[100],*p,c;

cin.get(a,100); cin>>c; p=strchr(a,c); while (p)

{cout<<"Pozitia "<

p=strchr(p,c);}

return 0;}

Ø Functia strrchr

                     strrchr(sir,c); are acelasi rol cu strchr, cu deosebirea ca returnea za adresa ultimei aparitii a caracterului (cautarea se face de la dreapta spre stanga; r = right)

                       Ø Functia st rcmp

int strcmp(sir1,sir2); are rolul de a compara doua siruri de caract ere. Valoarea returnata este <0 (daca sir1< sir2), =0 (daca sir1=sir2) si >0 (daca sir1>sir2). Functia strcmp face distinctie intre literele mari si cele mici ale alfabetului.

Obs : Functia strcmp returneaza diferenta dintre codurile ASC II ale primelor caractere care nu coincid

  • Functia stricmp

int stricmp(sir1,sir2); – are acelasi rol cu strcmp, cu deosebirea ca nu face distinctie intre literele mari si cele mici ale alfabetului (i = ignore).

 Functia strstr

strstr(sir1,sir2); – are rolul de a identifica daca sirul sir2 este subsir al sirului sir1. Daca este, functia returneaza adresa de inceput a subsirului sir2 in sirul sir1, altfel returneaza adresa 0. In cazul in care sir2 apare de mai multe ori in sir1, se returneaza adresa de inceput a primei aparitii. Cautarea se face de la stanga la dreapta

 Functia strtok

  • strtok(sir1,sir2); – are rolul de a separa sirul sir1 in mai multe siruri (cuvinte) separate intre ele prin unul sau mai multe caractere cu rol de separa Sirul sir2 este alcatuit din unul sau mai multe caractere

cu rol de separator.

Functia strtok actioneaza in felul urmator:

o Primul apel trebuie sa fie de forma strtok(sir1,sir2); Functia intoarce adresa primului caracter al primei entitati. Dupa prima entitate, separatorul este inlocuit automat prin caracterul nul.

o Urmatoarele apeluri sunt de forma strtok(NULL,sir2); De fiecare data, functia intoarce adresa de inceput a urmatoarei entitati, adaugand automat dupa ea caracterul nul.

o Cand sirul nu mai contine entitati, functia returneaza adresa nula.

 Exemplu:

//Sa se separe cuvintele dintr-un text.

#include <iostream.h>

#include <string.h>

int main()

{char text[100],cuv[10][10],*p,*r,separator[]=",. !?";int i=0,nr=0; clrscr();

cout<<"Dati sirul:";cin.get(text,100); strcpy(p,text);  p=strtok(p,separator);

while (p)

 {strcpy(cuv[++nr],p); p=strtok(NULL,separator);}

cout<<"Sunt "<<nr<<" cuvinte:"<<endl; for (i=1;i<=nr;i++) cout<<cuv[i]<<endl; return 0;}

 

  • Functia strspn cu forma generala

int strspn(sir1,sir2); – are rolul de a returna numarul de caractere ale sirului sir1 (caractere consecutive care incep obligatoriu cu primul caracter) care se gasesc in sirul sir2.

Exemplu:

strspn(“AB2def”,”1B3AQW”); à returneaza 2, pentru ca primele 2 caractere „A‟ si „B‟ din sir1 se gasesc in sir2.

strspn(“FAB2def”,”16A32BF”); à returneaza 0, deoarece caracterul „F‟ cu care incepe sir1 nu se gaseste in sir2.

 Functia strcspn cu forma generala

int strspn(sir1,sir2); – are rolul de a returna numarul de caractere ale sirului sir1 (caractere consecutive care incep obligatoriu cu primul caracter) care nu se gasesc in sirul sir2.

 

Exemplu:

strspn(“AB2def”,”123”); à returneaza 2, pentru ca primele 2 caractere din sir1 nu se gasesc in

sir2.

 

 

//Se citeste un sir de caractere care nu contine caractere albe. Sa se decida daca sirul este alcatuit exclusiv din caractere numerice.

#include <iostream>

#include <string.h> using namespace std; int main()

{char text[100],cifre[]="0123456789"; cout<<"Dati sirul:";cin.get(text,100);

  • if (strcspn(cifre,text)==strlen(text)) cout<<"exclusiv numeric";

else

cout<<”nenumeric”;

return 0;}

 

  • Functia strlwr cu forma generala

strlwr(sir); – are rolul de a converti toate literele mari din sir in litere mici. Restul caracterelor raman neschimbate.

 

  • Functia strupr cu forma generala

strupr(sir); – are rolul de a converti toate literele mici din sir in litere mari. Restul caracterelor raman neschimbate

 Functia strbrk cu forma generala

strpbrk(sir1,sir2); – actioneaza in felul urmator:

o Cauta primul caracter al sirului sir1 in sir2. Daca este gasit, returneaza adresa sa din cadrul sirului sir1 si executia se termina. Altfel, se trece la pasul urmator.

o Cauta al doilea caracter al sirului sir1 in sir2. Daca este gasit, returneaza adresa sa din cadrul sirului sir1 si executia se termina. Altfel, se trece la pasul urmator.

o …

o Daca nici un caracter al sirului sir1 nu apartine sirului sir2, functia returneaza adresa nula.

 

Functia atof cu forma generala

double atof(sir); – converteste un sir catre tipul double. Daca aceasta conversie esueaza (se intalneste un caracter nenumeric), valoarea intoarsa este 0. Aceasta functie (ca si cele similare) necesita includerea librariei stdlib.h.

 Functia atoi cu forma generala

int atoi(sir); – converteste un sir catre tipul int. Daca aceasta conversie esueaza (se intalneste un caracter nenumeric), valoarea intoarsa este 0.

 Functia atol cu forma generala

long atol(sir); – converteste un sir catre tipul long. Daca aceasta conversie esueaza (se intalneste un caracter nenumeric), valoarea intoarsa este 0.

 Functia itoa cu forma generala

itoa(int valoare,sir,int baza); – converteste o valoare de tip int in sir, care este memorat in variabila sir. Baza retine baza de numeratie catre care sa se faca conversia. In cazul bazei 10, sirul retine si eventualul semn -.

  • Functia ltoa cu forma generala

ltoa(long valoare,sir,int baza); – converteste o valoare de tip long int in sir, care este memorat in variabila sir.

  • Functia ultoa cu forma generala

ultoa(unsigned long valoare,sir,int baza); – converteste o valoare de tip unsigned long in sir, care este memorat in variabila sir.

SUBPROGRAME
SUBPROGRAME

Subprogramele sunt părţi ale unui program, identificabile prin nume, care se pot activa (apela) la cerere prin intermediul acestor nume.

Prezenţa subprogramelor implică funcţionarea în strânsă legătură a două noţiuni: definiţia unui subprogram şi apelul unui subprogram.

Definiţia unui subprogram reprezintă de fapt descrierea unui proces de calcul cu ajutorul variabilelor virtuale (parametri formali) iar apelul unui subprogram nu este altceva decât execuţia procesului de calcul pentru cazuri concrete (cu ajutorul parametrilor reali, (efectivi, actuali) ).

 

Structura unui subprogram C++

Un subprogram (funcţie) are o definiţie şi atâtea apeluri câte sunt necesare.

 

Definiţia unei funcţii are forma generală:

 

tip_returnat   nume_funcţie    (lista parametrilor formali)

{

instrucţiune;      // corpul funcţiei

return valoare;

}

Tip_returnat

Reprezintă tipul rezultatului calculat şi returnat de funcţie şi poate fi: int, char, char*, long, float, void, etc.

În cazul în care tipul rezultatului este diferit de void, corpul funcţiei trebuie să conţină cel puţin o instrucţiune return. Înstrucţiunea return va specifica valoarea calculată şi returnată de funcţie care trebuie să fie de acelaşi tip ca şi tip_returnat.

Nume_funcţie

Reprezintă numele dat funcţiei de către cel ce o defineşte, pentru a o putea apela.

Lista_parametrilor_formali

Reprezintă o listă de declaraţii de variabile separate prin virgulă. Această listă poate să fie şi vidă.

Instrucţiune

Este o instrucţiune vidă sau o instrucţiune simplă sau o instrucţiune compusă.

Există două tipuri de subprograme:

  ü  De tip funcție – returnează o valoare

  ü  De tip procedură (void)  - nu returnează direct o valoare, dar poate returna prin intermediul parametrilor săi.

În cazul subprogramului de tip procedură Tip_returnat este void, instrucțiunea return nu apare.

Apelul unei funcţii . Revenirea dintr-o funcţie

 

Apelul unui subprogram care nu returnează o valoare (procedură)  are forma generală:

 

nume_funcţie (lista parametrilor actuali);

 

parametru efectiv = parametru actual = parametru real = parametru de apel

lista parametrilor actuali = fie vidă, fie o expresie sau mai multe despărţite prin virgulă

O funcţie care returnează o valoare poate fi apelată fie printr-o instrucţiune de apel simplă (cazul funcţiilor care nu returnează valori) şi în plus poate fi apelată ca operand al unei expresii. În cazul în care funcţia se apelază print-o instrucţiune de apel simplă, rezultatul funcţiei se pierde. Când funcţia se apelează ca operand, valoarea returnată va fi utilizată în expresie.

La apelul unei funcţii, valorile parametrilor efectivi se atribuie parametrilor formali corespunzători. În cazul în care unul din tipul unui paramatru efectiv diferă de tipul parametrului formal corespunzător, parametrul efectiv va fi convertit spre parametru formal (dacă este posibil, altfel compilatorul generează eroare).

În momentul în care se întâlneşte un apel de funcţie, controlul execuţiei programul este transferat primei instrucţiuni din funcţie, urmând a se executa secvenţial instrucţiunile funcţiei.

Apel funcție

Apel procedură

Z = nume_funcţie (lista parametrilor actuali);

 

cout<<(nume_funcţie (lista parametrilor actuali);

 

if (nume_funcţie (lista parametrilor actuali)….)

 

while (nume_funcţie (lista parametrilor actuali)….)

 

 

nume_funcţie (lista parametrilor actuali);

 

STRUCTURA UNUI SUBPROGRAM

Variabilele dintr-un program C++ pot fi clasificate în:

1. Variabile globale                 2. Variabile locale                   3. Parametri formali

1. Variabile globale

·         Se declară în afara oricărei funcţii din program

·         Sunt alocate static, în segmentul de date al programului

·         Sunt iniţializate implicit, cu valoarea 0

·         Au domeniul de vizibilitate tot fişierul sursă, adică pot fi folosite din locul în care au fost definite şi până la sfârşitul fişierului

·         Au alocat spaţiu în memorie tot timpul rulării programului

 

2. Variabile locale

·         Se declară doar în interiorul unei funcţii din program, inclusiv în funcţia main ()

·         Nu sunt iniţializate implicit, dacă nu sunt iniţializate explicit de programator, reţin o valoare oarecare, numită valoare reziduală