1. Ce este un subprogram si de ce il folosim?
- Reutilizare: scrii o data, apelezi de 1000 de ori
- Claritate: programul principal devine mai scurt si mai usor de citit
- Depanare: un bug se repara intr-un singur loc, nu in 50 de copii
- Testare: poti testa fiecare subprogram independent
Un subprogram este ca o tasta de scurtatura pe un sistem de taste programabile: apesi o singura tasta si ea executa automat o secventa predefinita. Definesti secventa o singura data, o folosesti la infinit.
# Fara subprograme - cod repetitiv (problematic) print("--- Bun venit la magazin ---") # ... calcule ... print("--- Bun venit la magazin ---") # Cu subprograme - cod curat si reutilizabil def antet(): print("--- Bun venit la magazin ---") antet() # apel 1 antet() # apel 2 - acelasi cod, fara duplicare
--- Bun venit la magazin --- --- Bun venit la magazin ---
2. Anatomia unui subprogram: antet, corp, return
Antet (capul) — Corp (blocul de instructiuni) — Return (rezultatul returnat apelantului)
# ANTET: cuvant cheie + NUME + parametri formali def suma(a, b): # CORP: instructiunile care se executa rezultat = a + b # RETURN: valoarea trimisa inapoi apelantului return rezultat # APEL: folosim numele + argumente actuale r = suma(7, 3) print("7 + 3 =", r) print("20 + 15 =", suma(20, 15))
7 + 3 = 10 20 + 15 = 35
- Parametri formali = variabilele din definitie (
a, bin exemplu) - Argumente actuale = valorile transmise la apel (
7, 3sau20, 15) - Definitia = scriem subprogramul o singura data (blocul
def) - Apelul = folosim subprogramul apelandu-l dupa nume
3. Functii vs Proceduri (void)
return valoare).Procedura = subprogram care efectueaza o actiune fara a returna un rezultat util (Python: implicit
None; C++: tip void).
# PROCEDURA: efectueaza o actiune, nu returneaza nimic def afiseaza_bun_venit(nume): print(f"Bun venit, {nume}!") # FUNCTIE: calculeaza si returneaza def calculeaza_aria(baza, inaltime): aria = (baza * inaltime) / 2 return aria afiseaza_bun_venit("Ana") afiseaza_bun_venit("Ion") a = calculeaza_aria(6, 4) print(f"Aria triunghiului: {a}")
Bun venit, Ana! Bun venit, Ion! Aria triunghiului: 12.0
Daca subprogramul calculeaza ceva ce ai nevoie mai tarziu → functie cu return.
Daca subprogramul face ceva vizibil (afiseaza, scrie in fisier) → procedura fara return.
In C++ tipul returnat este obligatoriu in antet. Procedura foloseste void. Tipul este necesar pentru fiecare parametru.
#include <iostream> using namespace std; // void = procedura: nu returneaza nimic void afiseazaBunVenit(string nume) { cout << "Bun venit, " << nume << "!" << endl; } // double = functie: returneaza un numar real double calculeazaAria(double baza, double inaltime) { return (baza * inaltime) / 2.0; } int main() { afiseazaBunVenit("Ana"); afiseazaBunVenit("Ion"); double a = calculeazaAria(6, 4); cout << "Aria triunghiului: " << a << endl; return 0; }
Bun venit, Ana! Bun venit, Ion! Aria triunghiului: 12
4. Variabile locale, globale si domeniu de vizibilitate
Variabila globala = declarata IN AFARA oricarei functii; vizibila din tot programul.
total = 0 # variabila GLOBALA def adauga(x): global total # declaram ca vrem sa modificam globalul total += x def demo_local(): mesaj = "sunt local" # variabila LOCALA print(mesaj) # mesaj dispare cand functia se termina adauga(5) adauga(3) print("Total:", total) demo_local() # print(mesaj) # NameError: mesaj nu exista in afara functiei!
Total: 8 sunt local
Evita variabilele globale modificabile — creeaza dependente ascunse. Prefera sa transmiti date prin parametri si sa primesti rezultate prin return.
In C++ variabilele globale sunt declarate in afara oricarei functii. Variabilele locale sunt in interiorul blocului { }.
#include <iostream> using namespace std; int total = 0; // GLOBALA void adauga(int x) { total += x; } void demoLocal() { int lungime = 10; // LOCALA cout << "Lungime locala: " << lungime << endl; } int main() { adauga(5); adauga(3); cout << "Total: " << total << endl; demoLocal(); return 0; }
Total: 8 Lungime locala: 10
5. Parametri cu valori implicite (default) EXCLUSIV INTENSIV — C++
Parametrii pot avea valori implicite: daca apelantul nu transmite valoarea, se foloseste cea din definitie. Aceasta reduce numarul de variante de apel necesare.
# Python: parametru cu valoare implicita def putere(baza, exponent=2): return baza ** exponent print(putere(3)) # 3^2 = 9 (exponent implicit) print(putere(2, 10)) # 2^10 = 1024 (exponent explicit)
9 1024
In C++ parametrii cu valoare implicita trebuie sa fie la sfarsitul listei. Tipul fiecarui parametru se declara explicit.
#include <iostream> using namespace std; int putere(int baza, int exp = 2) { int rez = 1; for (int i = 0; i < exp; i++) rez *= baza; return rez; } int main() { cout << putere(3) << endl; cout << putere(2, 10) << endl; return 0; }
9 1024
Python: def suma(a, b): # fara tipuri explicite
C++: int suma(int a, int b) { } # cu tipuri obligatorii
6. Recursia: functia care se apeleaza pe sine EXCLUSIV INTENSIV — C++
n! = n x (n-1)! si 0! = 1! = 1 (cazul de baza)
# Python: factorial recursiv def factorial(n): if n <= 1: # caz de baza: OPRIRE return 1 return n * factorial(n - 1) # apel recursiv print("5! =", factorial(5)) print("10! =", factorial(10))
5! = 120 10! = 3628800
factorial(3)
= 3 * factorial(2)
= 2 * factorial(1)
= 1 (caz de baza, OPRIRE)
= 2 * 1 = 2
= 3 * 2 = 6
In C++ recursia functioneaza identic. Folosim long long pentru factorial mare (evitam overflow la int).
#include <iostream> using namespace std; long long factorial(int n) { if (n <= 1) return 1; return n * factorial(n - 1); } int main() { cout << "5! = " << factorial(5) << endl; cout << "10! = " << factorial(10) << endl; return 0; }
5! = 120 10! = 3628800
Timp: O(n) — un apel per nivel.
Spatiu: O(n) — n cadre pe stiva de apel. La n mare: Stack Overflow.