• Nu S-Au Găsit Rezultate

Evoluția limbajelor de programare Cod mașină

N/A
N/A
Protected

Academic year: 2022

Share "Evoluția limbajelor de programare Cod mașină"

Copied!
231
0
0

Text complet

(1)

Programare orientată obiect

Limbajul C++

(2)

Evoluția limbajelor de programare Cod mașină

programul în format binar, executat direct de processor Limbaj de asamblare

instrucțiuni in format binar înlocuit cu mnemonice, etichete simbolice pentru access la memorie

Procedural

descompune programul în proceduri/funcții Modular

descompune programul în module Orientat obiect

descompune programul într-o multime de obiecte care interacționeaza

(3)

Paradigma de programare orientată-object

Este metodă de proiectare şi dezvoltare a programelor:

Oferă o abstractizare puternică și flexibilă

Programatorul poate exprima soluția în mod mai natural (se concentrează pe structura soluției nu pe structura calculatorului)

Descompune programul într-un set de obiecte, obiectele sunt elementele de bază

Obiectele interacționeaza pentru a rezolva problema, există relații între clase

Tipuri noi de date modeleaza elemente din spațiul problemei, fiecare obiect este o instanța a unui tip de data (clasă)

Un obiect este o entitate care:

are o stare

poate executa anumite operații (comportament) Poate fi privit ca și o combinație de:

date (atribute)

metode Concepte:

obiect

clasă

metodă (mesaj) Proprietăți:

abstractizare

încapsulare

moștenire

polimorfism

(4)

Limbajul de programare C/C++

De ce C/C++:

Folosit la scară largă atât în mediul academic cât și în industrie

limbaj hybrid , implementeaza toate conceptele necesare pentru programare orientat obiect (C++)

multe limbaje de programare au evoluat din C/C++ (Java, C#). Este mult mai usor să înveţi aceste limbaje daca ştii C/C++

Advantaje:

Concis, cod lizibil

Performanţă: programele scrise în c/c++ în general sunt mai rapide decât cele scrise în alte limbaje de programare

Întreţinere: codul fiind concis programatorul are de întreținut un volum mai mic de cod

Portabil: se pot scrie aplicații pentru orice fel de procesor, sistem de operare

Productivitate: C++ a fost creat cu scopul principal de a mari productivitate (față de C).

(5)

Limbaje compilate. Procesul de compilare

Programul C/C++ trebuie compilat pentru a putea fi executat.

Programul scris în fisiere text ( fişiere soursă ) trebuie transformat în cod binar ce poate fi executat de procesor:

Fişiere sursa - fişiere text, conţin programul scris într-un limbaj de programare

| - compilatorul, analizează fișierele și crează fișiere obiect

Fișiere Obiect - fișiere intermediare, conține bucați incomplete din programul final

| - linker, combină mai multe fișiere obiect și crează programul care poate fi executat de calculator

Executabil

| - sistemul de operare, încarca fișierul executabil în memorie și executa programul

|

Program in memorie

În C/C++, pașii sunt executate înaintea rulării programului .

În unele limbaje transformarea se execută în timpul rulării. Acesta este una dintre motivele pentru care C/C++ în general are o performanță mai bună decât alte limbaje mai recente.

Python (Interpretat) vs C/C++ (compilat)

(6)

Mediu de dezvoltare pentru C/C++ (IDE - Integrated Development Environment)

Compilator

MinGW - - Minimalist GNU for Windows, implementare nativă Windows pentru compilatorul GNU Compiler Collection (GCC)

MinSYS – colecție de utilitare GNU (bash, make, gawk, grep)

Eclipse IDE

Eclipse CDC – mediu de dezvoltare integrat pentru C/C++ bazat pe platforma Eclipse

Colecție de pluginuri care ofera instrumentele necesare pentru a dezvolta aplicații în C/C++

Project C - Hello Word

(7)

Elemente de bază

C/C++ este case sensitive (a <> A) Identificator:

Secvență de litere si cifre , începe cu o literă sau “_”(underline).

Nume pentru elemente elemente din program (nume variabile, funcții, tipuri, etc)

Ex. i, myFunction, rez, Cuvinte rezervate (Keywords):

Identificatori cu semantica specială pentru compilator

int, if, for, etc.

Literals:

Constante specificate direct în codul sursă

Ex. “Hello”, 72, 4.6, ‘c’

Operatori:

aritmetici, pe biti, relaționali, etc

+,-, <<

Separatori:

Semne de punctuație folosite pentru a defini structura programului

; { } , ( ) Whitespace:

Caractere ignorate de compilator

space, tab, linie nouă Commentarii:

// this is a single line comment

/* This is a

* multiline comment */

sunt ignorate de compilator

(8)

Tipuri de date

Un tip de date definește domeniul de valori și operațiile ce sunt definite pentru valorile din domeniu

Tipuri de date (Built in):

Name Description Size Range

char Character or small integer. 1byte signed: -128 to 127 unsigned: 0 to 255 short int

(short)

Short Integer. 2bytes signed: -32768 to 32767

unsigned: 0 to 65535

int Integer. 4bytes signed: -2147483648 to

2147483647

unsigned: 0 to 4294967295 long int

(long)

Long integer. 4bytes signed: -2147483648 to

2147483647

unsigned: 0 to 4294967295 float Floating point number. 4bytes +/- 3.4e +/- 38 (~7 digits) double Double precision floating point number. 8bytes +/- 1.7e +/- 308 (~15

digits) long double Long double precision floating point

number.

8bytes +/- 1.7e +/- 308 (~15 digits)

wchar_t Wide character. 2 or 4

bytes

1 wide character

operații: +, -, *, /, %

relații: <, >, <=, >=, ==, !=

operațiile se pot executa doar dacă operanzii sunt de tipuri compatibile

precedența operatorilor dicteaza ordinea de execuție

(9)

Vectori

Daca T e un tip de dată:

T[n] – este un vector cu n elemente de tip T

indicii sunt de la 0 la n-1

operatorul de indexare: [ ]

vector multidimensional : t[n][m]

#include <stdio.h>

int main() {

int a[5]; // create an array with 5 elements a[0] = 1; //index start from 0

a[1] = 2;

printf("a[0]=%d \n", a[0]);

printf("a[1]=%d \n", a[1]);

//!!! a[2] uninitialised printf("a[2]=%d \n", a[2]);

int b[] = { 1, 2, 3, 5, 7 };

printf("b[0]=%d \n", b[0]);

b[0] = 10;

printf("b[0]=%d \n", b[0]);

return 0;

}

(10)

Structuri (Record)

• este o colectie de elemente de tipuri diferite

• permite gruparea diferitelor tipuri de date simple într-o structură

struct name{

type1 field1;

type2 field2 }

struct car{

int year;

int nrKm;

}

car c;

c.year = 2010 c.nrKm = 30000;

#include <stdio.h>

//introduce a new struct called Car typedef struct {

int year;

int km;

} Car;

int main() {

Car car, car2;

//initialise fields car.year = 2001;

car.km = 20000;

printf("Car 1 fabricated:%d Km:%d \n", car.year, car.km);

//!!! car2 fields are uninitialised

printf("Car 1 fabricated:%d Km:%d \n", car2.year, car2.km);

return 0;

}

(11)

Declarații de variabile

Introduce un nume în program, asocieaza numele cu un tip

Se aloca memorie conform tipului variabilei

Tipul variabilei este folosit de compilator pentru a decide care sunt valorile si operațiile posibile

Valoarea este nedefinită după declarare.

Este recomandat sa combinăm declarația cu inițializarea

Trebuie ales nume sugestiv pentru orice variabilă din program

Variabila trebuie inițializată dupa declarație cu o valoare

<type> <identifier>

Ex. int i long rez int j=7

Constante

numerice: 1, 12, 23.5

sir de caractere: “Hello World”

caracter: ‘c’

(12)

Referințe și pointeri

- Pointer este un tip de date special, folosit pentru a lucra cu adresse de memorie - poate stoca adresa unei variabile, adres unei locații de memorie

Declarare

- ca și orice variabilă de alt tip doar ca se pune '*' ânainte de numele variabilei.

Ex: int *a; long *a, char *a Operatori

- address of '&': - returneaza adressa de memorie unde este stocat valoarea dintr- o variabilă

- dereferencing '*' - returneaza valoarea stocata în locația de memorie specificată

#include <stdio.h>

int main() { int a = 7;

int *pa;

printf("Value of a:%d address of a:%p \n", a, &a);

//assign the address of a to pa pa = &a;

printf("Value of pa:%d address of pa:%p \n", *pa, pa);

//a and pa refers to the same memory location a = 10;

printf("Value of pa:%d address of pa:%p \n", *pa, pa);

return 0;

}

(13)

Instrucțiuni

Toate instrucțiunile se termina cu: ; (excepție instrucțiunea compusă)

Expresii: a = b+c; i++; a==b Instrucțiune vidă: ;

Instrucțiunea compusă:

{

//multiple statements here }

Atribuire

Operator de atribuire: =

Atribuie o valoare la o variabilă (inițializează sau scimba valoare variabilei)

(14)

if, if-else, else if

if (condition){

//statements executed only if the condition is true }

if (condition){

//statements executed if the condition is true } else {

//statements executed only if the condition is not true }

if (condition1){

//statements executed if the condition1 is true } else if (condition2){

//statements executed only if condition1 is not true and the condition2 is true }

condition, condition1, condition2 - sunt expressii

orice expresie are o valoare

valoarea 0 înseamnă fals, orice altă valoare înseamnă adevărat

(15)

switch-case

switch(expression) {

case constant1:

statementA1 statementA2 ...

break;

case constant2:

statementB1 statementB2 ...

break;

...

default:

statementZ1 statementZ2 ...

}

Se evalueaza expresia, daca valoarea este egal cu constant1 atunci tot ce e pe ramura case constant1: se execută pană la primul break;

Dacă nu e egal cu constant1 se verifică cu constant2, 3...

Dacă nici o constantă nu este egală cu rezultatul expresiei atunci se

executa ramura default

(16)

Instrucțiuni repetitive

Execută repetat un set de instrucțiuni

while , do-while

while(condition) {

statement1 statement2

}

Cât timp condiția este adevarată (!=0) se execută corpul de instrucțiuni

do {

statement1 statement2

}

while(condition);

(17)

for

for(initialization; condition; incrementation) {

//body }

initialization – inițializează una sau mai multe variabile incrementation – se execută la fiecare iterație

condition – se verifică la fiecare iterație, cât timp e adivărat corpul de instrucțiuni se execută

for(initialization; condition; incrementation) {

statement1 statement2

}

initialization while(condition) {

statement1 statement2

incrementation }

(18)

Citire/Scriere

printf() - tipărește în consola (la ieșirea standard)

#include <stdio.h>

int main() { int nr = 5;

float nrf = 3.14;

char c = 's';

char str[] = "abc";

printf("%d %f %c %s", nr, nrf , c, str);

return 0;

}

scanf() - citește de la tastatura

int main() { int nr;

float f;

printf("Enter a decimal number:");

//read from the command line and store the value in nr scanf("%d", &nr);

printf("The number is:%d \n", nr);

printf("Enter a float:");

if (scanf("%f", &f) == 0) {

printf("Error: Not a float:");

} else {

printf("The number is:%f", f);

}

//wait until user enters 'e' while(getchar()!='e');

return 0;

}

(19)

Calculator numere raționale

Problem statement

Profesorul are nevoie de un program care permite elevilor să învețe despre numere raționale. Programul ajută studenții să efectueze operații aritmetice cu numere raționale

#include <stdio.h>

int main() {

int totalM = 0;

int totalN = 1;

int m;

int n;

while (1) {

printf("Enter m, then n to add\n");

scanf("%d", &m);

scanf("%d", &n);

totalM = totalM * n + m * totalN;

totalN = totalN * n;

printf("Total: %d/%d\n", totalM, totalN);

}

return 0;

}

(20)

Funcții

Funcția main este executat cand lansam in execuție un program C/C++

Declarare

<result type> name ( <parameter list>);

<result-type> - tipul rezultatului, poate fi orice tip sau void daca funcția nu returnează nimic

<name> - numele funcției

<parameter-list> - parametrii formali

Corpul funcției nu face parte din declarare

Definiție

<result type> name(<parameter list>){

//statements - the body of the function }

return <exp> rezultatul expresiei se returnează, execuția funcției se termina

o funcție care nu este void trebuie neapărat sa returneze o valoare prin expresia ce urmează dupa return

declararea trebuie sa corespunda cu definiția (numele parametrilor poate fi

diferit)

(21)

Specificații

Nume sugestiv

O scurtă descriere a funcției (ce face)

Semnificația parametrilor

condiții asupra parametrilor (precondiții)

ce se returnează

relația dintre parametri și rezultat (post condiții)

/*

* Verify if a number is prime

* nr - a number, nr>0

* return true if the number is prime (1 and nr are the only dividers)

*/

bool isPrime(int nr);

precondiții - sunt condiții care trebuie sa fie satisfacute de parametrii actuali inainte de a executa corpul funcției

postcondiții - condiții care sunt satisfacute dupa execuția funcției Apelul de funcții

name (<parameter list>);

Toate expresiile date ca parametru sunt evaluate înainte de execuția funcției

Parametrii actuali trebuie sa corespundă cu parametri formal (număr,poziție,tip)

declarația trebuie sa apară înainte de apel Supraîncărcare (Overloading)

Pot exista mai multe funcții cu același nume (dar parametrii formali diferiți)

La apel se va executa funcția care corespunde parametrilor actuali

(22)

Vizibilitate (scope)

Locul unde declarăm variabila determină vizibilitate lui (unde este variabila accesibilă).

Variabile, funcții declarate in interiorul unei instrucțiuni compuse ({ }) sunt vizibile doar in interiorul instrucțiunii compuse

Funcțiile au domeniul lor de vizibilitate - variabilele definite in interiorul funcțiilor sunt accesibile doar în funcție, ele sunt distruse dupa apelul funcției. (variabile locale)

Variabilele definite in afara funcțiilor sunt accesibile în orice funcție (variabile

globale).

(23)

Transmiterea parametrilor : prin valoare sau prin referinţă Transmitere prin valoare:

La apelul funcţiei se face o copie a parametriilor.

Schimbările făcute în interiorul funcţiei nu afectează variabilele exterioare.

Este mecanismul implicit de transmitere a parametrilor în C

Transmitere prin referinţă:

La apelul funcţiei se transmite adressa locaţiei de memorie unde se află valoarea variabilei.

Modificările din interiorul funcţiei sunt vizibile şi în afară.

void byValue(int a) { a = a + 1;

}

void byRef(int* a) {

*a = *a + 1;

}

int main() { int a = 10;

byValue(a);

printf("Value remain unchanged a=%d \n", a);

byRef(&a);

printf("Value changed a=%d \n", a);

return 0;

}

Vectorul este transmis prin referinţă

(24)

Calculator

/*

* Return the greatest common divisor of two natural numbers.

* Pre: a, b >= 0, a*a + b*b != 0 */

int gcd(int a, int b) { if (a == 0) {

return b;

} else if (b == 0) { return a;

} else {

while (a != b) { if (a > b) {

a = a - b;

} else {

b = b - a;

} }

return a;

} }

/*

* Add (m, n) to (toM, toN) - operation on rational numbers * Pre: toN != 0 and n != 0

*/

void add(int* toM, int* toN, int m, int n) {

*toM = *toM * n + *toN * m;

*toN = *toN * n;

int gcdTo = gcd(abs(*toM), abs(*toN));

*toM = *toM / gcdTo;

*toN = *toN / gcdTo;

}

//global variables. Store the current total int totalM = 0;

int totalN = 1;

int main() { int m,n;

while (1) {

printf("Enter m, then n to add\n");

scanf("%d", &m);scanf("%d", &n);

add(&totalM, &totalN, m, n);

printf("Total: %d/%d\n", totalM, totalN);

}

return 0;

}

(25)

Curs 1

– Introducere - POO – Limbajul C

• sintaxă

• tipuri de date

• instructiuni

• funcții

(26)

Funcții

Declarare

<result type> name ( <parameter list>);

<result-type> - tipul rezultatului, poate fi orice tip sau void daca funcția nu returnează nimic

<name> - numele funcției

<parameter-list> - parametrii formali

Corpul funcției nu face parte din declarare

Definiție

<result type> name(<parameter list>){

//statements - the body of the function }

return <exp> rezultatul expresiei se returnează, execuția funcției se termina

o funcție care nu este void trebuie neapărat sa returneze o valoare prin expresia ce urmează dupa return

declararea trebuie sa corespunda cu definiția (numele parametrilor poate fi diferit)

Funcția main este executat cand lansam in execuție un program C/C++

(27)

Specificații

Nume sugestiv

O scurtă descriere a funcției (ce face)

Semnificația parametrilor

condiții asupra parametrilor (precondiții)

ce se returnează

relația dintre parametri și rezultat (post condiții)

/*

* Verify if a number is prime

* nr - a number, nr>0

* return true if the number is prime (1 and nr are the only dividers)

*/

bool isPrime(int nr);

precondiții - sunt condiții care trebuie sa fie satisfacute de parametrii actuali inainte de a executa corpul funcției

postcondiții - condiții care sunt satisfacute dupa execuția funcției Apelul de funcții

name (<parameter list>);

Toate expresiile date ca parametru sunt evaluate înainte de execuția funcției

Parametrii actuali trebuie sa corespundă cu parametri formal (număr,poziție,tip)

declarația trebuie sa apară înainte de apel Supraîncărcare (Overloading)

Pot exista mai multe funcții cu același nume (dar parametrii formali diferiți)

La apel se va executa funcția care corespunde parametrilor actuali

(28)

Vizibilitate (scope)

Locul unde declarăm variabila determină vizibilitate lui (unde este variabila accesibilă).

Variabile locale

variabila este vizibila doar în interiorul instrucțiunii compuse ({ }) unde a fost delcarată

variabilele declarate în interiorul funcției sunt vizibile (accesibile) doar în funcție

instrucțiunile if, if else, for, while au domeniul propriu de vizibilitate

Incercarea de a accesa o variabilă în afara domeniului de vizibilitate genereaza eroare la compilare.

Ciclul de viață a unei variabile începe de la declararea lui si se termină când execuția iese din domeniul de vizibilitate a variabilei (variabila se distruge, memoria ocupată se elibereaza)

Global Variables

Variabilele definite in afara funcțiilor sunt accesibile în orice funcție, domeniul lor de vizibilitate este întreg aplicația

Se recomandă evitarea utilizării variabilelor globale (există soluții mai

bune care nu necesită variabile globale)

(29)

Transmiterea parametrilor : prin valoare sau prin referinţă Transmitere prin valoare:

La apelul funcţiei se face o copie a parametriilor.

Schimbările făcute în interiorul funcţiei nu afectează variabilele exterioare.

Este mecanismul implicit de transmitere a parametrilor în C

Transmitere prin referinţă:

La apelul funcţiei se transmite adressa locaţiei de memorie unde se află valoarea variabilei.

Modificările din interiorul funcţiei sunt vizibile şi în afară.

void byValue(int a) { a = a + 1;

}

void byRef(int* a) {

*a = *a + 1;

}

int main() { int a = 10;

byValue(a);

printf("Value remain unchanged a=%d \n", a);

byRef(&a);

printf("Value changed a=%d \n", a);

return 0;

}

Vectorul este transmis prin referinţă

(30)

Calculator

/*

* Return the greatest common divisor of two natural numbers.

* Pre: a, b >= 0, a*a + b*b != 0 */

int gcd(int a, int b) { if (a == 0) {

return b;

} else if (b == 0) { return a;

} else {

while (a != b) { if (a > b) {

a = a - b;

} else {

b = b - a;

} }

return a;

} }

/*

* Add (m, n) to (toM, toN) - operation on rational numbers * Pre: toN != 0 and n != 0

*/

void add(int* toM, int* toN, int m, int n) {

*toM = *toM * n + *toN * m;

*toN = *toN * n;

int gcdTo = gcd(abs(*toM), abs(*toN));

*toM = *toM / gcdTo;

*toN = *toN / gcdTo;

}

//global variables. Store the current total int totalM = 0;

int totalN = 1;

int main() { int m,n;

while (1) {

printf("Enter m, then n to add\n");

scanf("%d", &m);scanf("%d", &n);

add(&totalM, &totalN, m, n);

printf("Total: %d/%d\n", totalM, totalN);

}

return 0;

}

(31)

Funcții de test

Assert

#include <assert.h>

void assert (int expr);

expr – Se evaluează expresia. Daca e fals (=0) metoda assert generează o eroare și se termină execuția aplicației

Mesajul de eroare depinde de compilator (pot fi diferențe in funcție de compilator), conține informații despre locul unde a aparut eroarea (fisierul, linia), expresiea care a generat eroare.

Vom folosi instrucțiunea assert pentru a crea teste automate.

#include <assert.h>

/*

* greatest common divisor . * Pre: a, b >= 0, a*a + b*b != 0 * return gdc

*/

int gcd(int a, int b) { a = abs(a);

b = abs(b);

if (a == 0) { return b;

}

if (b == 0) { return a;

}

while (a != b) { if (a > b) {

a = a - b;

} else {

b = b - a;

} }

return a;

}

/**

* Test function for gcd */

void test_gcd() {

assert(gcd(2, 4) == 2);

assert(gcd(3, 27) == 3);

assert(gcd(7, 27) == 1);

assert(gcd(7, -27) == 1);

}

(32)

Review: Calculator – varianta procedurală

Profesorul are nevoie de un program care permite elevilor să învețe despre numere raționale. Programul ajută studenții să efectueze operații aritmetice cu numere raționale

/**

* Test function for gcd */

void test_gcd() {

assert(gcd(2, 4) == 2);

assert(gcd(3, 27) == 3);

assert(gcd(7, 27) == 1);

assert(gcd(7, -27) == 1);

} /*

* Add (m, n) to (toM, toN) - operation on rational numbers * Pre: toN != 0 and n != 0

*/

void add(int* toM, int* toN, int m, int n) {

*toM = *toM * n + *toN * m;

*toN = *toN * n;

int gcdTo = gcd(abs(*toM), abs(*toN));

*toM = *toM / gcdTo;

*toN = *toN / gcdTo;

}

int main() { test_gcd();

int totalM = 0, totalN = 1;

int m, n;

while (1) {

printf("Enter m, then n to add\n");

scanf("%d", &m);

scanf("%d", &n);

add(&totalM, &totalN, m, n);

printf("Total: %d/%d\n", totalM, totalN);

}

return 0;

}

(33)

Principii de proiectare pentru funcții

Fiecare funcție sa aibă o singură responsabilitate (Single responsability principle)

Folosiți nume sugestive (nume funcție, nume parametrii, variabile)

Folosiți reguli de denumire (adauga_rational, adaugaRational, CONSTANTA), consistent în toată aplicația

Specificați fiecare funcție din aplicație

Creați teste automate pentru funcții

Funcția trebuie sa fie usor de testat, (re)folosit, înțeles și modificat

Folosiți comentarii în cod (includeți explicații pentru lucruri care nu sunt evidente în cod)

Evitați (pe cât posibil) funcțiile cu efect secundar

(34)

Modular programming in C++.

Modulul este o colecție de funcții si variabile care oferă o funcționalitate bine definită.

Fișiere Header .

Declarațiile de funcții sunt grupate într-un fisier separat – fișier header (.h).

Implementarea (definițiile pentru funcții) intr-un fisier separat (.c/.cpp)

Scop

Separarea interfeței (ce oferă modulul) de implementare (cum sunt implementate funcțiile)

Separare specificații, declarații de implementare

Modulele sunt distribuite in general prin: fișierul header + fisierul binar cu implementările (.dll,.so)

• Nu e nevoie să dezvălui codul sursă (.c/.cpp )

Cei care folosesc modulul au nevoie doar de declarațiile de funcții (fișierul header)

nu si de implementări (codul din fișierele .c/.cpp)

(35)

Directive de preprocessare

Preprocesarea are loc inainte de compilare.

cod sursă – preprocessare – compilare – linkeditare – executabil

Permite printre altele: includere de fisiere header, definire de macrouri, compilare condiționată

Directiva Include

#include <stdio.h>

Pentru a avea access la funcțiile declarate intr-un modul (bibiliotecă de funcții) se folosește directiva #include

Preprocessorul include fisierul referit în fișierul sursă în locul unde apare directiva

avem două variante pentru a referi un modul: < > sau “”

#include "local.h” //cauta fișierul header relativ la directorul current al aplicației

#include <header> // caută fișierul header între bibliotecile system

(standard compiler include paths )

(36)

Aplicații modulare C/C++

Codul este inparțit in mai multe fisiere header (.h) si implementare (.c)

• fișierele .h conțin declarații (interfața)

• .c conține definiția (implementarea) funcțiilor

se grupeaza funcții in module astfel încât modulul sa ofere o funcționalitate bine definită (puternic coeziv)

Când un fișier .h se modifică este nevoie de recompilarea tuturor modulelor care îl referă (direct sau indirect)

• Fișierele .c se pot compila separat, modificarea implementării nu afectează modulele care folosesc (ele referă doar definițiile din header) Headerul este un contract între cel care dezvoltă modulul și cel care

folosește modulul.

Detaliile de implementare sunt ascunse in fișierul .h

(37)

Review: Calculator versiune modulară

Module:

calculatorui.c – interfața utilizator

calculator.h, calculator.c - TAD Calculator, operatii cu calculator

rational.h, rational.c - TAD rational, operatii cu numere rationale

util.h, util.c - funcții utile de operații cu numere (gcd)

(38)

Declarație multiplă – directivele #ifndev și #define

Într-un program mai complex este posibil ca un fișier header sa fie inclus de mai multe ori. Asta ar conduce la declarații multiple pentru funcții

Soluție: se folosesc directivele de preprocesare #ifndef, #ifdef, #define, #endif

Se poate verifica daca modulul a fost deja inclus, respectiv sa marcăm cand un modul a fost inclus (prin definirea unei etichete)

#ifndef RATIONAL_H_ /* verify if RATIONAL_H_ is already defined, the rest

(until the #endif will be processed only if RATIONAL_H_ is not defined*/

#define RATIONAL_H_ /* define RATIONAL_H_ so next time the prepocessor will not include this */

/**

* New data type to store rational numbers */

typedef struct { int a, b;

} Rational;

/**

* Compute the sum of 2 rational numbers * a,b rational numbers

* rez - a rational number, on exit will contain the sum of a and b */

void sum(Rational nr1, Rational nr2, Rational &rez);

#endif /* RATIONAL_H_ */

(39)

Principii de proiectare pentru module

Separați interfața de implementare

Headerul conține doar declarații, implementările în fișierul .c

Includeți la începutul fișierului header un comentariu, o scurta descriere a modulului

Creați module puternic coezive

fiecare modul o singură funcționalitate, are o singură responsabilitate

Șablonul - Arhitectură stratificată

Straturi: ui, control, model, validation, repository

◦ Controlul dependențelor - Fiecare nivel depinde doar de nivelul următor

Tip abstract de date – TAD

operatiile definite in header (interfață) /implementarea in .c

ascundere detalii de implementare

specificații abstracte (independent de implementare, ce face

nu cum)

(40)

Biblioteci standard

#include <stdio.h>

Operatii de intrare/iesire

#include <math.h>

Funcții matematice – abs, sqrt, sin, exp, etc

#include <string.h>

sirul de caractere in C - vector de char care se termina cu caracterul '\0' strncpy – copiează string

strcat – concatenează string strcmp – compară stringuri strlen – lungimea stringului

#include<stdio.h>

#include<string.h>

int main(void) {

char arr[4]; // for accommodating 3 characters and one null '\0' byte.

char *ptr = "abc"; //a string containing 'a', 'b', 'c', '\0'

memset(arr, '\0', sizeof(arr)); //reset all

strncpy(arr, ptr, sizeof("abc")); // Copy the string printf("\n %s \n", arr);

arr[0] = 'p';

printf("\n %s \n", arr);

return 0;

}

(41)

Pointeri

Pointer este un tip de date , folosit pentru a lucra cu adresse de memorie - poate stoca adresa unei variabile, adres unei locații de memorie

Operatori:

'&','*'

#include <stdio.h>

int main() { int a = 7;

int *pa;

printf("Value of a:%d address of a:%p \n", a, &a);

//assign the address of a to pa pa = &a;

printf("Value of pa:%d address of pa:%p \n", *pa, pa);

//a and pa refers to the same memory location a = 10;

printf("Value of pa:%d address of pa:%p \n", *pa, pa);

return 0;

}

(42)

Null pointer

- valoare specială (0) pentru a indica faptul ca pointerul nu referă o memorie validă Pointer invalid (Dangling pointer)

Adresa refertă de pointer e invalid

#include <stdio.h>

int main() {

//init to null int *pa1 = NULL;

int *pa2;

//!!! pa2 refers to an unknown addres

*pa2 = 6;

if (pa1==NULL){

printf("pa1 is NULL");

}

return 0;

}

#include <stdio.h>

int* f() {

int localVar = 7;

printf("%d\n", localVar);

return &localVar;

}

int main() {

int* badP = f();

//!!! *badP refera o adresa de memorie //care a fost deja eliberata

printf("%d\n", *badP);

}

(43)

Vectori / pointeri - Aritmetica pointerilor

O variabila de tip vector - un pointer la primul element al vectorului

• vectorul este transmis prin referinta (se transmita adresa de memorie al primului element din vector – nu se face o copie).

• Indicele porneste de la 0 – primul element este la distantă 0 fața de începutul vectorului.

• Expresia array[3] – compilatorul calculează care este locația de memorie la distanță 3 față de începutul vectorului.

• Cu funcția sizeof(var) se poate afla numarul de bytes ocupat de valoarea din var (depinde de tipul lui var)

Aritmetica pointerilor

Folosirea de operații adăugare/scadere pentru a naviga in memorie (adrese de memorie)

#include <stdio.h>

int main() {

int t[3] = { 10, 20, 30 };

int *p = t;

//print the first elem

printf("val=%d adr=%p\n", *p, p);

//move to the next memory location (next int) p++;

//print the element (20)

printf("val=%d adr=%p\n", *p, p);

return 0;

p++ în funcție de tipul valorii referite de pointer, compilatorul calculeaza

urmatoarea adressa de memorie.

(44)

Gestiunea memoriei

Pentru variabilele declarate intr-o aplicație, compilatorul aloca memorie pe stivă (o zonă de memorie gestionat de compilator)

int f(int a) { if (a>0){

int x = 10; //memory for x is allocated on the stack }

//here x is out of scope and the memory allocated for x is no longer reserved //the memory can be reused

return 0;

}

int f(int a) { int *p;

if (a>0){

int x = 10;

p = &x;

}

//here p will point to a memory location that is no longer reserved *p = 5; //!!! undefined behavior, the program may crash

return 0;

}

Memoria este automat eliberată de compilator în momentul în care execuția părăseste domeniul de vizibilitate a variabilei.

La iesire dintr-o funcție memoria alocată pentru variabile locale este eliberată automat de compilator

(45)

Alocare dinamică

Folosind funcțiile malloc(size) și free(pointer) programatorul poate aloca memorie pe Heap – zonă de memorie gestionat de programator

#include <stdio.h>

#include <stdlib.h>

int main() {

//allocate memory on the heap for an int int *p = malloc(sizeof(int));

*p = 7;

printf("%d \n", *p);

//Deallocate free(p);

//allocate space for 10 ints (array) int *t = malloc(10 * sizeof(int));

t[0] = 0;

t[1] = 1;

printf("%d \n", t[1]);

//dealocate free(t);

return 0;

} /**

* Make a copy of str * str - string to copy * return a new string */

char* stringCopy(char* str) { char* newStr;

int len;

len = strlen(str) + 1; // +1 for the '\0'

newStr = malloc(sizeof(char) * len); // allocate memory strcpy(newStr, str); // copy string

return newStr;

}

Programatorul este responsabil sa dealoce memoria

(46)

Memory leak

Programul aloca memorie dar nu dealoca niciodata, memorie irosită

int main() { int *p;

int i;

for (i = 0; i < 10; i++) { p = malloc(sizeof(int));

//allocate memory for an int on the heap

*p = i * 2;

printf("%d \n", *p);

}

free(p); //deallocate memory

//leaked memory - we only deallocated the last int return 0;

}

(47)

void*

O funcție care nu returneaza nimic

void f() { }

Nu putem avea variabile de tip void dar putem folosi pointer la void - void*

#include <stdio.h>

#include <stdlib.h>

int main() { void* p;

int *i=malloc(sizeof(int));

*i = 1;

p = i;

printf("%d /n", *((int*)p));

long j = 100;

p = &j;

printf("%ld /n", *((long*)p));

free(i);

return 0;

}

Se pot folos void* pentru a crea structuri de date care funcționeaza cu orice tip de elemente

Probleme: verificare egalitate între elemente de tip void* , copiere elemente

(48)

Vector dinamic

typedef void* Element;

typedef struct { Element* elems;

int lg;

int capacitate;

} VectorDinamic;

/**

*Creaza un vector dinamic * v vector

* post: vectorul e gol */

VectorDinamic * creazaVectorDinamic();

/**

* Adauga un element in vector * v - vector dinamic

* el - elementul de adaugat */

void add(VectorDinamic *v, Element el);

/**

*Returneaza elementul de pe pozitia data * v - vector

* poz - pozitie, poz>=0

* returneaza elementul de pe pozitia poz */

Element get(VectorDinamic *v, int poz);

/**

*Initializeaza vectorul * v vector

* post: vectorul e gol */

VectorDinamic * creazaVectorDinamic() { VectorDinamic *v =

malloc(sizeof(VectorDinamic));

v->elems = malloc(INIT_CAPACITY * sizeof(Element));

v->capacitate = INIT_CAPACITY;

v->lg = 0;

return v;

} /**

* Elibereaza memoria ocupata de vector */

void distruge(VectorDinamic *v) { int i;

for (i = 0; i < v->lg; i++) { free(v->elems[i]);

}

free(v->elems);

free(v);

}

/**

* Aloca memorie aditionala pentru vector */

void resize(VectorDinamic *v) { int nCap = 2*v->capacitate;

Element* nElems=

malloc(nCap*sizeof(Element));

//copiez din vectorul existent int i;

for (i = 0; i < v->lg; i++) { nElems[i] = v->elems[i];

}

//dealocam memoria ocupata de vector free(v->elems);

v->elems = nElems;

v->capacitate = nCap;

} /**

* Adauga un element in vector * v - vector dinamic

* el - elementul de adaugat */

void add(VectorDinamic *v, Element el) { if (v->lg == v->capacitate) {

resize(v);

}

v->elems[v->lg] = el;

v->lg++;

}

(49)

Pointer la funcții

void (*funcPtr)(); // a pointer to a function

void *funcPtr(); // a function that returns a pointer

void func() {

printf("func() called...");

}

int main() {

void (*fp)(); // Define a function pointer fp = func; // Initialise it

(*fp)(); // Dereferencing calls the function void (*fp2)() = func; // Define and initialize (*fp2)(); // call

}

Putem folosi pointer la funcții în structurile de date generice typedef elem (*copyPtr)(elem&, elem);

typedef int (*equalsPtr)(elem, elem);

(50)

Limbajul de programare C++

Urmașul limbajului C apărut în anii 80 (C cu clase), dezvoltat inițial de Bjarne Stroustrup

Bibliografie: B. Stroustup, The C++ Programming Language, Addison Wesley

Limbajul C++

• multiparadigmă

• suportă paradidma orientat obiect (clase, obiecte, polimorfism, moștenire)

• tipuri noi – bool, referință

• spații de nume (namespace)

• șabloane (templates)

• excepții

• bibliotecă de intrări/ieșiri (IO Streams)

• STL (Standard Template Library)

(51)

Tipul de date mulțime - modular, implementat in C++

/*set.h*/

struct Mult;

typedef Mult* Set;

/**

* Create an empty set. Need to be invoked before we can use the set * n - the maximum number of element in the set; m - the set

*/

void createSet(Set &m, int n);

/**

* Add an element to the set

* m - the set; e the element to be added * return 0 if we can not add the element */

int add(Set m, Element e);

/*set.cpp*/

#include "set.h"

struct Mult { Element* e;

int c;

int max;

};

/**

* Release the memory allocated for this set */

void destroyM(Set& m) {

for (int i = 0; i < m->c; i++) destroyE(m->e[i]);

delete[] m->e;

delete m;

} /**

* Add an element to the set

* m - the set; e the element to be added * return 0 if we can not add the element */

int add(Set m, Element e) { if (m->c == m->max)

return 0;

if (!(contains(m, e))) { (m->c)++;

atrib(e, m->e[(m->c) - 1]);

}

return 1;

}

(52)

Tipul bool

domeniu de valori: adevărat (true) sau fals (false)

/**

* Verifica daca un numar e prim * nr numar intreg

* return true daca nr e prim */

bool ePrim(int nr) { if (nr <= 1) {

return false;

}

for (int i = 2; i < nr - 1; i++) { if (nr % i == 0) {

return false;

} }

return true;

}

(53)

Tipul referință

data_type &reference_name;

int y = 7;

int &x = y; //make x a reference to, or an alias of, y

Dacă schimbăm x se schimbă și y și invers, sunt doar două nume pentru același locație de memorie (alias)

Tipul referință este similar cu pointere:

sunt pointeri care sunt automat dereferențiate cănd folosim variabile

nu se poate schimba adresa referită /**

* C++ version

* Sum of 2 rational number */

void sum(Rational nr1, Rational nr2, Rational &rez) { rez.a = nr1.a * nr2.b + nr1.b * nr2.a;

rez.b = nr1.b * nr2.b;

int d = gcd(rez.a, rez.b);

rez.a = rez.a / d;

rez.b = rez.b / d;

} /**

* C version

* Sum of 2 rational number */

void sum(Rational nr1, Rational nr2, Rational *rez) { rez->a = nr1.a * nr2.b + nr1.b * nr2.a;

rez->b = nr1.b * nr2.b;

int d = gcd(rez->a, rez->b);

rez->a = rez->a / d;

rez->b = rez->b / d;

}

(54)

Const Pointer 1 const type*

int j = 100;

const int* p2 = &j;

Valoarea nu se poate schimba folosind pointerul Se poate schimba adresa referită

const int* p2 = &j;

cout << *p2 << "\n";

//change the memory address (valid) p2 = &i;

cout << *p2 << "\n";

//change the value (compiler error)

*p2 = 7;

cout << *p2 << "\n";

2 type * const

int * const p3 = &j;

Valoarea se poate schimba folosind acest pointer dar adressa de memorie referită nu se poate schimba

int * const p3 = &j;

cout << *p2 << "\n";

//change the memory address (compiler error) p3 = &i;

cout << *p3 << "\n";

//change the value (valid)

*p3 = 7;

cout << *p3 << "\n";

3 const type* const

const int * const p4 = &j;

Atât adresa cât și valoarea sunt constante

(55)

Paradigma de programare orientată-object

Este metodă de proiectare şi dezvoltare a programelor:

Oferă o abstractizare puternică și flexibilă

Programatorul poate exprima soluția în mod mai natural (se concentrează pe structura soluției nu pe structura calculatorului)

Descompune programul într-un set de obiecte, obiectele sunt elementele de bază

Obiectele interacționeaza pentru a rezolva problema, există relații între clase

Tipuri noi de date modeleaza elemente din spațiul problemei, fiecare obiect este o instanța a unui tip de data (clasă)

Un obiect este o entitate care:

are o stare

poate executa anumite operații (comportament) Poate fi privit ca și o combinație de:

date (atribute)

metode Concepte:

obiect

clasă

metodă (mesaj) Proprietăți:

abstractizare

încapsulare

moștenire

polimorfism

(56)

Caracteristici:

Încapsulare:

- capacitatea de a grupa date și comportament – controlul accesului la date/funcții,

– ascunderea implementării

– separare interfață de implementare

Moștenire

– Refolosirea codului

Polimorfism

– comportament adaptat contextului

– în funcție de tipul actual al obiectului se decide metoda apelată în

timpul execuției

(57)

Clase și obiecte în C++

Class: Un tip de dată definit de programator. Descrie caracteristicile unui lucru.

Grupează:

date – atribute

comportament – metode

Clasa este definită într-un fișier header (.h) Sintaxă:

/**

* Represent rational numbers */

class Rational { public:

//methods /**

* Add an integer number to the rational number */

void add(int val);

/**

* multiply with a rational number * r rational number

*/

void mul(Rational r);

private:

//fields (members) int a;

int b;

};

(58)

Definiții de metode

Metodele declarate în clasă sunt definite într-un fisier separat (.cpp)

Se foloseste operatorul :: (scope operator) pentru a indica apartanența metodei la clasă Similar ca și la module se separa declarațiile (interfața) de implementări

/**

* Add an integer number to the rational number */

void Rational::add(int val) { a = a + val * b;

}

Se pot defini metode direct in fișierul header. - metode inline class Rational {

public:

/**

* Return the numerator of the number */

int getNumerator() { return a;

} /**

* Get the denominator of the fraction */

int getDenominator() { return b;

} private:

//fields (members) int a;

int b;

Putem folosi metode inline doar pentru metode simple (fără cicluri)

Compilatorul inserează (inline) corpul metodei în fiecare loc unde se apelează metoda.

(59)

Obiect

Clasa descrie un nou tip de data.

Obiect - o instanța noua (o valoare) de tipul descris de clasă Declarație de obiecte

<nume_clasă> <identificator>;

se alocă memorie suficientă pentru a stoca o valoare de tipul <nume_clasă>

obiectul se inițializează apelând constructorul implicit (cel fără parametrii)

pentru initializare putem folosi si constructori cu parametri (dacă în clasă am definit constructor cu argumente)

'

Rational r1 = Rational(1, 2);

Rational r2(1, 3);

Rational r3;

cout << r1.toFloat() << endl;

cout << r2.toFloat() << endl;

cout << r3.toFloat() << endl;

(60)

Acces la atribute (câmpuri) În interiorul clasei

int getDenominator() { return b;

}

Când implementăm metodele avem acces direct la attribute int getNumerator() {

return this->a;

}

Putem accesa atributul folosind pointerul this. Util daca mai avem variabile cu același nume în metodă (parametru, variabilă locală)

this: pointer la instanța curentă. Avem acces la acest pointer în toate metodele clasei, toate metodele membre din clasă au acces la this.

Putem accesa atributele și în afara clasei (dacă sunt vizibile)

Folosind operatorul '.' object.field

Folosind operatorul '->' dacă avem o referință (pointer) la obiect object_reference-

>field is a sau (*object reference).field

Referințe

DOCUMENTE SIMILARE

De¸si ˆın ambele cazuri de mai sus (S ¸si S ′ ) algoritmul Perceptron g˘ ase¸ste un separator liniar pentru datele de intrare, acest fapt nu este garantat ˆın gazul general,

Pentru a suprprinde acest aspect, cuvintele care apar m˘ acar de 5 ori ˆın datele de antrenament ¸si dac˘ a apar de 5 ori mai des ˆın glume decˆ at ˆın non-glume sunt p˘

 Memoria EEPROM poate fi utilizată pentru stocarea de informaţii între &#34;sesiuni&#34; (va memora datele chiar și când Arduino nu este alimentat)..  Biblioteca EEPROM.h

Rezultatul final a fost un set clar de criterii pentru ICD‑10 și pentru instrumentele de evaluare, care pot asigura datele necesare clasificării tulburărilor în funcție de

Se stabileşte calitatea modelului creat pe baza acestor ponderi pentru TOATE dintre datele de intrare. Se ajustează ponderile în funcţie de

 Învăţare supervizată  datele de antrenament sunt deja etichetate cu elemente din E, iar datele de test trebuie. etichetate cu una dintre etichetele din E pe baza unui model

mitul 1: cea mai importantă este interfața mitul 2: cel mai important este programul. mitul 3: cele mai importante sunt datele fapt: sunt

Cu toate acestea, în cazul în care scopul este de a obține hărți rapid, Google Maps este o opțiune bună și foarte bine documentată, atât pentru dispozitivul mobil, cât și