Programare în C++, folosind Code::Blocks
Îndrumător pentru începători

NOTĂ:

O problemă poate fi rezolvată prin scrierea unui program în multe moduri.
În materialul care urmează nu am urmărit eficiența, ci ușurința înțelegerii de către un începător.
Soluțiile propuse se pot scrie mai simplu, sau mai eficient, dar asta ar presupune încărcarea cu detalii 
care pentru un începător pot fi derutante.

Aplicația Code::Blocks

Code::Blocks este un mediu integrat de dezvoltare (în engleză IDE: Integrated Development Environment)

În acest mediu putem scrie, apoi compila și rula programe scrise într-unul din limbajele disponibile (C/C++/Fortran)

Este o aplicație oferită gratuit, care poate fi descărcată și utilizată după instalarea pe calculatorul propriu.

Site-ul pe care puteți găsi programul este http://www.codeblocks.org/

Pentru a putea compila (transforma textul scris de noi într-un cod pe care să-l înțeleagă calculatorul), pentru a-l putea apoi rula,
este necesar să avem instalat și un compilator.

Code::Blocks poate fi descărcat în mai multe versiuni, inclusiv unele care includ și un compilator.
Versiunea stabilă curentă, care include și compilatoarele necesare, este codeblocks-16.01mingw_fortran-setup.exe

Aplicația poate fi descărcată, apoi pornită, rularea ei având ca efect instalarea întregului pachet.

Crearea unei aplicații tip consolă noi

La adresa http://clase.ro/PL_AP/video/creare_proiect_CodeBlocks.avi se află un mic film, care arată pașii necesari.

Porniți Code::Blocks din meniul Start

La prima pornire vi se va cere să confirmați că aplicația poate folosi compilatorul disponibil. Veți accepta opțiunea aleasă.

Din meniul de pornire alegeți Create a new project

Din fereastra de dialog, care se deschide, alegeți Console application apoi selectați butonul Go.

Alegeți Next >

Alegeți C++, apoi Next >

Ca titlu (în Project title:) puteți alege orice, eu recomand p201702071545, adică litera p, cifrele anului, lunii, zilei, orei și minutului curent

Ca folder pentru proiect (în Folder to create project in:) puteți alege orice folder, eu recomand 20170207, adică data curentă,
de preferință ca subfolder într-un folder dedicat programelor (de exemplu, d:\_user\progs\20170207)

apoi alegeți Next >

În fereastra următoare, puteți alege direct Finish

În felul acesta se va deschide interfața, împărțită în patru regiuni principale:

SUS vedeți meniurile și barele de comenzi (cerculețul galben, ca o rotiță dințată, permite compilarea, triunghiul verde, rularea dacă a reușit compilarea)

În STÂNGA trebuie să vedeți panoul de Management. Dacă el nu se vede, îl puteți redeschide din meniul View/Manager (sau cu scurtătura Shift+F2)

ÎN CENTRU apar programul și fișierele deschise. În primul moment nu este nimic în el.

JOS se văd mesajele, cele mai importante apar sub tab-ul Build messages, care va indica dacă în programul scris de dvs. apare erori și/sau avertismente

Vizualizarea codului sursă

În stânga, în fereastra de Management, sub tab-ul Projects (cel mai din stânga), vedeți o structură arborescentă:
Începe cu Workspace
sub acesta (-) p201702071545 (sau ce nume ați ales pentru proiect)
sub acesta (+) Sources (sursele)

Cu click pe acel (+) puteți deschide în continuare. Făceți-o!

Apare o iconiță ca o pagină, lângă ea main.cpp

Cu dublu-click pe iconița ca o pagină puteți vizualiza, în fereastra centrală, programul sursă minimal, pregătit de Code::Blocks

structura arborescentă în fereastra Management

DACĂ trebuie să creați fișiere suplimentare (de exemplu, un fișier pentru valori de test, date.in), cu click dreapta pe numele proiectului (pe p201702071545),
puteți alege Open Project Folder in File Folder, care vă va muta  două taburi mai încolo, în aceeași fereastră, și vă va arăta folderele și fișierele din proiectul curent.

Cu click dreapta pe calea proiectului, puteți accesa meniul New File..., care începe dialogul pentru crearea acestui fișier nou.

PROGRAMUL C++ minimal

La deschiderea fișierului main.cpp, veți observa un program deja creat

programul C++ minimal, oferit de Code::Blocks

instrucțiunea „ cout << "Hello world!" << endl; nu este strict necesară, ea poate fi ștearsă fără nici o consecință negativă.

Ea există însă pentru ca să putem verifica buna funcționare a lui Code::Blocks

Click pe iconița pentru compilare (cea galbenă), sau Ctrl+F9, va începe compilarea.

Dacă totul a mers bine, o să vedem în partea de jos, sub tab-ul Build messages, un mesaj în care apare „ 0 error(s) ”, adică programul s-a compilat corect.

În acest caz, cu click pe iconița pentru rulare (cea verde), sau cu Ctrl+F10, putem porni programul.

O să apară o fereastră de comandă, în care apare mesajul „ Hello world! ”, și faptul că execuția s-a terminat cu codul 0, adică totul a fost bine.

(dacă scrisul în această fereastră vi se pare prea mic, faceți click pe iconița din partea stânga-sus a ferestrei, alegeți Font, alegeți un font cu TT și o dimensiune mai mare, apoi OK)

Fereastra (CONSOLA) în care apare rezultatul rulării

Pentru a închide această fereastră este suficient să apăsăm orice tastă de pe tastatură.


 

LINIILE programului minimal

Programul minimal, oferit la pornirea Code::Blocks, are cinci linii principale

în linia 1, directiva

#include <iostream>

Explicația liniei:

limbajul C/C++ se dorește să creeze programe cât mai eficiente, mai rapide. De aceea, un program C/C++ NU va include la compilare decât strictul necesar.

Tot ce nu este strict necesar (iar scrierea de mesaje pe ecran, sau citirea tastaturii intră în această categorie) este pus separat, ÎN BIBLIOTECI.

Dacă e nevoie de acele părți, directiva #include va informa compilatorul să caute ACELE biblioteci și să le adauge la program.

Biblioteca iostream (Input/Output Stream = Flux de Intrare/Ieșire) este folosită pentru a putea folosi CONSOLA (ecranul și tastatura)

Ea a fost inclusă în acest program, pentru ca să putem folosi ulterior cout (Console OUTput = Ieșirea către Consolă = Scrierea pe ecran)

Așadar, linia 1 înseamnă: „Compilatorule, te rog să incluzi în acest program și conținutul bibliotecii iostream, ca să pot scrie pe ecran”

în linia 3, declarația

using namespace std;

Explicația liniei:

limbajul C/C++ permite folosirea aceleiași denumiri de funcție/variabilă/etc. în contexte diferite. Un spațiu de nume (namespace) este un mod de a unifica folosirea unui set de denumiri. Denumirea completă este spațiu_de_nume::denumire

Denumirile cout, cin sau endl aparțin spațiului de nume standard (std).

În mod normal, ar trebui să scriem std::cout, std::cin, respectiv std::endl.

Ca să evităm această repetare, anunțăm compilatorul că toate aceste denumiri trebuie înțelese ca fiind luate din spațiul de nume std.

Așadar, linia 3 înseamnă: „Compilatorule, dacă întâlnești cout, cin sau endl, să știi că ele sunt precedate de std::”

în linia 5 (plus 6 și 9) găsim declarația principalei funcții din program, funcția main()

               int main()
{

}

Explicația liniei:

UN PROGRAM C/C++ ESTE FORMAT DIN FUNCȚII

1. Fiecare funcție are un tip (rezultatul returnat de funcție, de exemplu int, dacă returnează un număr întreg, sau void, dacă nu returnează nimic)
2. Fiecare funcție are o denumire
3. Fiecare funcție are o listă de argumente, scrisă între paranteze (lăsăm parantezele goale dacă nu există argumente)
4. Fiecare funcție are un corp, în care sunt scrise instrucțiunile necesare pentru a obține rezultatul/efectul dorit la apelarea funcției

Între toate funcțiile, una este deosebită, funcția main()

Ea este singura funcție obligatorie într-un program. 

La rulare, executarea programului începe EXACT DE LA această funcție!

Așadar, liniile 5, 6 și 9 înseamnă: „Compilatorule, funcția mea principală
                                                                               va returna un număr întreg:  int
                                                                                ea are numele, evident, main
                                                                                 nu are parametri:   ( )
                                                                                  corpul ei începe în linia 6:   {
                                                                                   și se termină în linia 9:  }

în linia 7, apare prima instrucțiune din funcția main():

cout << "Hello world!"  << endl;

Explicația liniei:

această instrucțiune are ca efect trimiterea către ecran a două lucruri:

un text: „Hello world!”

un salt la linie nouă: endl

ca orice instrucțiune, ea se termină cu un terminator de linie (;)

cout este denumirea ieșirii consolă (ecranul) (Console OUT)

Așadar, linia 7 înseamnă: „Compilatorule, te rog să trimiți către ecran, în ordine, întâi un text, format din caracterele H e l l o spațiu w o r l d și !, apoi un cod pentru trecerea la linie nouă”

în linia 8, apare a doua (și ultima instrucțiune din funcția main():

return 0;

Explicația liniei:

funcția main() a fost declarată ca având un rezultat întreg ( int main() )

return este instrucțiunea care trimite rezultatul generat de funcție.

în cazul nostru, acest rezultat este 0

Toate funcțiile care returnează un rezultat, îl returnează funcției care le-a apelat.

Funcția main() este singura excepție, ea returnează rezultatul către sistemul de operare, de unde a fost pornit programul.

De regulă, un program apelat de sistemul de operare va returna un rezultat, care descrie modul în care a reușit rularea lui. Tradițional, valoarea zero este asociată cu „totul a fost bine”

Așadar, linia 8 înseamnă: „Compilatorule, când termini programul, la sfârșitul funcției main(), te rog să transmiți către sistemul de operare rezultatul 0”

ZONELE unui program

Programul minimal, oferit la pornirea Code::Blocks, poate fi extins:

- cu mai multe directive, pentru includerea altor biblioteci, de exemplu biblioteca fstream (File STREAM - flux (prin) fișiere), sau cmath (funcții matematice)

- cu declararea, apoi descrierea altor funcții, apelate de main(), sau între ele.

un program cu mai multe componente

I. Întâi, anunțăm compilatorul ce biblioteci dorim să folosim

În exemplu de mai sus, sunt incluse trei biblioteci:

#include <iostream>
#include <fstream>
#include <cmath>  

iostream : Input/Output Stream : flux de intrări/ieșiri : pentru folosirea tastaturii (cin >> ...), scrierea către ecran (cout << ...)

fstream: File Stream : flux (prin) fișiere : pentru a putea folosi fișiere pentru citirea datelor/scrierea rezultatelor (ca să mențin imaginea mică nu am folosit efectiv aceaste procedee)

cmath: Funcții matematice : pentru a putea folosi funcții matematice mai avansate, precum sin, cos ...

II. În al doilea rând, anunțăm că vom folosi spațiul de nume std (standard). Ca să nu trebuiască să scriem std:: în fața fiecărei apariții a cuvintelor cin, cout, endl

using namespace std;

III. În al treilea rând, în cazul în care programul nostru are și alte funcții, în afară de main(), este bine să declarăm ÎNTÂI forma acestor funcții

float trig(float);

anunță că va exista (încă nu există AICI) o funcție cu numele trig, care are un singur argument, un număr real (float) și care returnează un rezultat care va fi tot un număr real, float

Vă rog să observați că AICI, la declarare, linia se termină cu „ ; ”!!!

Linia int main() NU se termină cu „ ; ”, nici mai jos, definiția efectivă a funcției trig()

IV. Apoi începe programul principal:

IV.1: Întâi apare antetul (capul) funcției main:

                 int main()
{

anunță că funcția principală (cu numele impus, obligatoriu, main) nu are parametri (perechea de paranteze fără nimic între ele, și va returna un rezultat întreg (acel zero, care apare în linia 22: return 0; )
Acolada de deschidere începe corpul funcției main()

IV.2: Declarația de variabile

O VARIABILĂ ESTE UN LOC, cu nume, de tip cunoscut, în care putem plasa o valoare, pentru a o putea folosi ulterior

Acest program, dat ca exemplu, folosește o singură variabilă:

float x;

- numele ei este x

- tipul ei este „număr real”: float

- la început, nu se știe ce valoare conține, poate fi oricât (C/C++ NU dau o valoare inițială variabilelor declarate. Pur și simplu rezervă un spațiu de memorie pentru fiecare dintre ele, iar ce se află, accidental, acolo, devine valoarea inițială!!!)

IV.3 Instrucțiuni de intrare și ieșire, prin care aflăm valoarea varibilei

Scopul este să aflăm ce valoare dorește utilizatorul să fie în variabila x.

DAR, ca să aflăm un răspuns, TREBUIE ÎNTÂI să întrebăm ceva (altfel, utilizatorul va sta în fața unui ecran negru, neștiind ce vrem de la el, trebuie să facă oarece, sau trebuie să aștepte)

De aceea:

IV.3.a Scriem pe ecran o întrebare: 

cout << "x =";

adică: trimitem către cout (Console OUTput: consola de ieșire: ecranul) textul format din caracterele „x” „spațiu” „=”
NU am adăugat un „<< endl”, deoarece NU vrem să trecem pe linie nouă, ci să rămânem acolo, după semnul „=”

IV.3.b Apoi luăm de la tastatură, acționată de utilizator, valoarea pentru x

cin >> x;

adică, dinspre cin (Console INput: consola de intrare: tastatura) preluăm valoarea (număr real) pentru x. 

Fiind un limbaj/program dezvoltat în mediul anglo-saxon, numerele cu „virgulă zecimală” se vor scrie cu „punct zecimal”. De exemplu, în loc de PI (aprox. 3,1415962... vom tasta 3.1415962...)

IV.3.c Apoi (apelând funcția matematică trig(), vom afișa pe ecran rezultatul calculului valorii funcției în x)

cout << "functia(" << x << ")=" << trig(x) << endl;

Instrucțiunea va trimite că cout (consola de ieșire, ecranul) CINCI elemente:

   1. Întâi textul format din caracterele ”f u n c t i a spațiu (

   2. Apoi, valoarea actuală a lui x, abia citită;

   3. Apoi, textul format din caracterele „) =

   4. Apoi, valoarea returnată de funcția trig(), atunci când este apelată cu valoarea abia citită pentru x;

   5. Apoi, o cerere de salt la linie nouă

IV.4 În final, terminăm funcția main(), implicit execuția programului, revenind la sistemul de operare cu rezultatul 0

return 0;

V. Observăm că am folosit deja funcția trig(), fără să fi spus despre ea decât că va exista, că are un argument, că acesta este un număr real, iar rezultatul oferit de funcție este tot un număr real.
Acum este momentul să dăm definiția completă a acestei funcții.

Compilatorul a putut compila programul până acum, pentru că știa aceste informații. El deja a rezervat o adresă, unde va fi pus codul programului, cu informația că acelui segment i se va trimite un număr întreg, iar acolo unde funcția este apelată, trebuie pus un număr real, rezultatul apelului.

Acum urmează instrucțiunile care, compilate, vor permite efectuarea acestor calcule.

V.1 Întâi, postăm capul funcției:

                           float trig(float x)
{

V.2 Apoi scrie instrucțiunile care permit obținerea valorii funcției trig, folosind valoarea transmisă funcției, aflată în argumentul x

pentru ca să returneze un rezultat, funcția utilizează tot instrucțiunea return

Spre deosebire de funcția main(), aici, return va trimite rezultatul către locul în care funcția a fost apelată, înlocuind acolo apelul funcției cu rezultatul executării ei. Observăm că expresia care, după ce este evaluată, va fi returnată, poate fi așezată imediat după cuvântul return

    return sin(x)+cos(x);

V.3 O acoladă va închide (și termina) funcția

}

Iată și rezultatul rulării programului, dacă utilizatorul a tastat valoare 3.1415962 (aproximativ PI)


 

Program exemplu

Fișierul date.in conține două linii

pe prima linie este un număr întreg, n (2 < n < 20)

pe a doua linie se află n numere întregi, de cel mult patru cifre fiecare, scrie unul după celălalt, separate prin câte un spațiu.

Să se scrie un program care

citește numărul n

apoi citește cele n numere și le scrie pe ecran, pe măsură ce le citește, câte una pe linie

Cum gândim acest program?

CA SĂ PUTEM OPERA CU FIȘIERE DE INTRARE IEȘIRE, trebuie inclusă biblioteca fstream 

iar ca să putem scrie pe ecran, trebuie inclusă biblioteca iostream

1. fișierul date.in este un fișier, care se va afla în folderul în care se va executa programul.

Acest fișier

1.1 - trebuie deschis în modul citire ( ifstream = Input File STREAM)

pentru asta:

1.1.1 - trebuie declarat un identificator (de exemplu sursa), ca reprezentând un fișier de intrare
1.1.2 - acest identificator trebuie asociat cu fișierul fizic date.in

1.2 - apoi va trebui să citim UN NUMĂR, acel n

1.3 - apoi va trebui să citim, pe rând, MAI MULTE NUMERE (mai exact, n numere).
După citirea fiecărui număr, el trebuie afișat pe ecran

pentru asta:

1.3.1 trebuie să parcurgem în mod repetat, de la 1 la n (sau de la 0 la n-1), adică de n-ori, o aceeași secvență.
Deoarece știm de câte ori repetăm secvența, vom putea folosi o instrucțiune for. În instrucțiunea for vom folosi o variabilă de ciclare (un contor).
Aceasta este o variabilă de tip întreg, care va lua inițial valoarea 0, apoi va crește cu câte 1 la fiecare parcurgere, repetăm asta cât timp valoarea este mai mică decât numărul n

1.3.2 la fiecare parcurgere
citim câte o valoare nouă din fișierul date.in, folosind identificatorul sursa
afișăm numărul citi pe ecran

1.4 - în final, fișierul trebuie închis

 toate operațiile cu fișierul date.in vor fi efectuate prin intermediul identificatorului sursa asociat de la început cu el

Iată codul

#include <iostream>
#include <fstream>            
//pentru intrări/ieșiri către fișiere

using namespace std;

int main()
{
    int n;                  
// numărul n este întreg, va fi citit din fișier
    int valoare;             // tot un număr întreg, în el vom citi cele n numere
    
    ifstream sursa;          
// acest identificator va descrie fișierul
    sursa.open("date.in");   // îl asociem cu fișierul fizic
    
    sursa >> n;              
// citim primul număr
    
    for(int i=0; i<n; i++)  
//i este un întreg, ia valori de la 0 la n-1
    {
        sursa >> valoare;        
// citim din fișier o nouă valoare
        cout << valoare << endl; // afișăm numărul citit pe ecran
    }
    
    sursa.close();          
// închidem fișierul, nu mai avem nevoie de el

    return 0;                // terminăm programul, returnăm 0
}

 


 

Program exemplu

Să se scrie în fișierul date.out toate numerele naturale, de la 20 la 200, fiecare pe câte un rând nou

Cum gândim acest program?

Fișierul date.out trebuie deschis în modul scriere

Îl vom asocia cu un identificator, de exemplu rezultate

Numerele de la 20 la 200 se pot genera printr-un ciclu for

O variabilă i, întreagă, va lua valori de la 20 la 200 (inclusiv), fiecare valoare o scriem imediat în fișier

La sfârșit, fișierul se va închide

scrierea numerelor de la 20 la 200 în fișierul date.out


 

Program exemplu

Fișierul date.in are pe prima linie un număr natural n, (2 < n < 20)
Pe a doua linie se află n numere întregi, de cel mult patru cifre, separate prin câte un spațiu.

Să se citească n, apoi cele n numere.
Să se afle cel mai mic și cel mai mare dintre aceste numere și să se afișeze pe ecran

Să se scrie în fișierul date.out toate numerele din al doilea rând din date.in care NU sunt extreme, separate prin câte un spațiu.

Cum gândim acest program?

Fișierul date.in trebuie deschis în modul citire, date.out trebuie deschis în modul scriere.

Le vom asocia, respectiv, cu identificatorul sursa și rezulate

    ifstream sursa; //Input File Stream - ifstream

        sursa.open("date.in");

    ofstream rezultat; //Output File Stream - ofstream

        rezultat.open("date.out")

(nu uităm că trebuie să includem biblioteca fstream - File STREAM, cu o directivă #include, la începutul programului

Vom citi din sursa cu sursa >> ...

Vom scrie în rezultat cu rezultat << ...

Vom utiliza, ca variabile numerice:

   n, un număr întreg

  minim, maxim, două numere întregi

Cum găsim acest minim și acest maxim?

1. Numerele citite sunt întregi, deci nu există aprioric un cel mai mic, sau un cel mai mare (cum ar fi 0, cel mai mic număr natural)

2. Primul număr citit, dintre cele n, ar putea fi și cel mai mare, și cel mai mic.

3. Apoi, fiecare următor număr, dacă este mai mare ca maximul actual, maximul va crește la el, dacă este mai mic ca minimul actual, minimul va scădea la el

Observăm că primul număr are un statut special.

Citirea nu se va face de la 1 la n (sau de la 0 la n-1) continuu.

ÎNTÂI citim primul număr.

APOI citim restul, de la 2 la n (sau de la 1 la n-1)

ALTCEVA:

NU putem folosi numerele citite o singură dată, ci trebuie să trecem prin ele de cel puțin două ori:

ÎNTÂI ca să aflăm maximul și minimul

APOI ca să aflăm care dintre ele nu sunt extreme (și trebuie scrise în date.out)

Ca să nu citim de două ori din date.in, va trebui să folosim o variabilă VECTOR

AICI folosim informația că 2<n<20 ... deci n nu trece de 20, adică sunt cel mult 20 (de fapt 19) numere în al doilea rând. Așadar, vectorul care să le cuprindă pe toate poate avea doar 20 de componente

PROGRAMUL

//1. biblioteci incluse

#include <iostream>

#include <fstream>

//2 spațiu de nume

using namespace std;

int main()

{

   // deschidem cele două fișiere

   ifstream sursa;

   sursa.open("date.in");

   ofstream rezultate;

   rezultate.open("date.out");

   //variabile

   int n;  // numărul de numere din al doilea rând

   int minim, maxim; // cel mai mic și cel mai mare dintre celedouă numere

  int valori[20]; // cele maximum 20 numere din al doilea rând

  //citim câte numere sunt

  sursa >> n;

  //citim numerele din al doilea rând, direct în vector

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

      sursa >> valori[i];

  // putem închide sursa, nu mai avem nevoie de ea, numerele sunt deja în valori[ 0 ] valori[ 1 ] valori[ 2 ] ... valori[ n-1 ]

  sursa.close();

  // căutăm minimul și maximul

  // prima ipoteză, ar fi chiar primul număr

   minim = maxim = valori[0];

   // apoi verificăm dacă am greșit cumva

   // comparând cu toate cele n-1 numere rămase

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

   {

        if ( minim > valori[ i ] )

               minim = valori[ i ];  // avem un nou minim

       if ( maxim < valori[ i ] ) 

             maxim = valori[ i ];   // avem un nou maxim

    }

  // acum știm deja adevăratul minim și maxim, le putem afișa

   cout << "cel mai mic numar = " << minim << endl;

   cout << " cel mai mare numar = " <<  maxim << endl;

  // scriem în fișierul de ieșire toate numerele diferite de minim și de maxim

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

    if( valori[i] < maxim)

       if ( valori[i] > minim )

          rezultate << valori[i] << " ";

  // acum putem închide și fișierul de ieșire

   rezultate.close();

   // și termina programul

   return 0;

}

sursa în Code::Blocks

exemplu de date de intrare

afișările pe ecran