Subprogramele Predefinite (Funcții de Sistem) în C++


1. Obiectivele lecției:

  • Să înțeleagă conceptul de subprograme predefinite în C++.
  • Să învețe cum să utilizeze funcțiile de sistem pentru diverse operații.
  • Să implementeze exemple practice cu funcții predefinite din biblioteci standard.

2. Ce sunt subprogramele predefinite?

  • Definiție: Subprogramele predefinite, cunoscute și ca funcții de sistem, sunt funcții oferite de bibliotecile standard ale limbajului C++ pentru a realiza operații comune fără a fi nevoie să fie implementate de utilizator.
  • Exemple de utilizare: Operații matematice, manipularea șirurilor, gestionarea fișierelor, manipularea timpului, și altele.

3. Categorii de funcții predefinite


1. Funcții matematice (<cmath> sau <math.h>)

FuncțieDescriereExemplu
sqrt(x)Rădăcina pătrată a lui x.sqrt(16) -> 4.0
pow(x, y)Ridică x la puterea y.pow(2, 3) -> 8.0
abs(x)Valoarea absolută a lui x.abs(-5) -> 5
ceil(x)Rotunjire în sus la cel mai apropiat întreg.ceil(4.2) -> 5.0
floor(x)Rotunjire în jos la cel mai apropiat întreg.floor(4.8) -> 4.0
log(x)Logaritm natural al lui x.log(10) -> 2.3026
exp(x)Ridică e la puterea x.exp(1) -> 2.718
sin(x), cos(x), tan(x)Funcții trigonometrice.sin(3.14) -> ~0.0

Exemplu: Utilizarea funcțiilor matematice

#include <iostream>

#include <cmath>

using namespace std;

int main() {

    double numar = 25.0;

    cout << „Rădăcina pătrată: ” << sqrt(numar) << endl;

    cout << „Puterea a doua: ” << pow(numar, 2) << endl;

    cout << „Valoarea absolută: ” << abs(-numar) << endl;

    return 0;

}


2. Funcții pentru șiruri de caractere (<cstring>)

FuncțieDescriereExemplu
strlen(sir)Returnează lungimea șirului.strlen(„abc”) -> 3
strcmp(sir1, sir2)Compară două șiruri lexicografic.strcmp(„abc”, „abd”) -> -1
strcpy(dest, src)Copiază șirul src în dest.strcpy(dest, „hello”)
strcat(dest, src)Concatenează șirul src la sfârșitul lui dest.strcat(dest, ” world”)
strtok(sir, delim)Împarte un șir în segmente.strtok(„a,b,c”, „,”) -> „a”

Exemplu: Funcții pentru șiruri

#include <iostream>

#include <cstring>

using namespace std;

int main() {

    char sir1[50] = „Salut”;

    char sir2[] = ” lume!”;

    strcat(sir1, sir2);

    cout << „Concatenare: ” << sir1 << endl;

    cout << „Lungime: ” << strlen(sir1) << endl;

    return 0;

}


3. Funcții pentru manipularea timpului (<ctime>)

FuncțieDescriereExemplu
time(NULL)Returnează timpul curent în secunde de la epoca UNIX.time(NULL) -> 1672444800
localtime(&time)Conversie timp în structura tm (timp local).localtime(&t)
strftime(buffer, size, format, &time)Formatare timp.strftime(buf, 80, „%Y-%m-%d”, &t)
clock()Returnează timpul procesorului folosit de program.clock()

Exemplu: Afișarea timpului curent

#include <iostream>

#include <ctime>

using namespace std;

int main() {

    time_t timpCurent = time(NULL);

    tm* timpLocal = localtime(&timpCurent);

    cout << „Ora curenta: ” << timpLocal->tm_hour << „:”

         << timpLocal->tm_min << „:” << timpLocal->tm_sec << endl;

    return 0;

}


4. Funcții pentru generarea numerelor aleatoare (<cstdlib>)

FuncțieDescriereExemplu
rand()Generează un număr aleator între 0 și RAND_MAX.rand()
srand(seed)Inițializează generatorul cu un număr specific (seed).srand(time(NULL))

Exemplu: Generarea numerelor aleatoare

#include <iostream>

#include <cstdlib>

#include <ctime>

using namespace std;

int main() {

    srand(time(NULL));

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

        cout << „Numar aleator: ” << rand() % 100 << endl; // Număr între 0 și 99

    }

    return 0;

}


5. Activități practice pentru elevi

  1. Scrieți un program care calculează aria unui cerc folosind funcția pow și M_PI (constantă din <cmath>).
  2. Realizați un program care verifică dacă două șiruri sunt identice utilizând funcția strcmp.
  3. Implementați un program care generează 10 numere aleatoare între 1 și 50 și le afișează sortate.

6. Scheme logice

  1. Calcul matematic:
    • Start -> Apel funcție matematică -> Returnează rezultat -> Stop.
  2. Manipularea șirurilor:
    • Start -> Citire șiruri -> Apel funcție (strlen, strcat, etc.) -> Afișare rezultat -> Stop.
  3. Generare aleatorie:
    • Start -> Inițializare generator -> Generare număr -> Afișare -> Stop.

7. Concluzie

  • Funcțiile predefinite din C++ oferă soluții rapide și eficiente pentru probleme comune.
  • Alegerea funcției corecte depinde de tipul de problemă: matematică, manipulare șiruri, timp sau generare aleatoare.
  • Practica utilizării funcțiilor predefinite ajută la dezvoltarea rapidă a programelor.

Subprograme Definite de Utilizator în C++


1. Obiectivele lecției:

  • Să înțeleagă conceptul de subprograme definite de utilizator în C++.
  • Să învețe să declare, să definească și să utilizeze funcții create de utilizator.
  • Să implementeze exemple practice care folosesc funcții pentru a rezolva probleme comune.

2. Ce sunt subprogramele definite de utilizator?

  • Definiție: Subprogramele definite de utilizator sunt funcții create de programator pentru a rezolva probleme specifice. Acestea sunt module independente care pot fi apelate de mai multe ori în program, reducând redundanța și îmbunătățind lizibilitatea codului.
  • Avantaje:
    • Reutilizare de cod.
    • Organizare mai bună a programului.
    • Debugging mai simplu.

3. Structura unei funcții în C++

  1. Declarație (prototip):

tip_returnare nume_functie(parametrii_opționali);

  1. Definiție:

tip_returnare nume_functie(parametrii_opționali) {

    // Bloc de instrucțiuni

    return valoare; // opțional, dacă tipul de returnare este void

}

  1. Apelare:

nume_functie(argumente_opționale);


4. Categorii de funcții

  1. Funcții fără parametri și fără returnare:
    • Utilizate pentru operații simple care nu necesită intrări sau ieșiri.

Exemplu:

#include <iostream>

using namespace std;

void salut() {

    cout << „Salut, lume!” << endl;

}

int main() {

    salut(); // Apel funcție

    return 0;

}


  1. Funcții cu parametri, dar fără returnare:
    • Utilizate pentru operații care necesită intrări, dar nu returnează valori.

Exemplu:

#include <iostream>

using namespace std;

void afiseazaSuma(int a, int b) {

    cout << „Suma este: ” << a + b << endl;

}

int main() {

    afiseazaSuma(3, 5);

    return 0;

}


  1. Funcții fără parametri, dar cu returnare:
    • Returnează o valoare calculată, fără a avea nevoie de intrări.

Exemplu:

#include <iostream>

using namespace std;

int daNumarAleator() {

    return 42;

}

int main() {

    cout << „Numărul generat: ” << daNumarAleator() << endl;

    return 0;

}


  1. Funcții cu parametri și cu returnare:
    • Cele mai versatile funcții, care primesc intrări și returnează o valoare.

Exemplu:

#include <iostream>

using namespace std;

int inmulteste(int a, int b) {

    return a * b;

}

int main() {

    int rezultat = inmulteste(4, 5);

    cout << „Rezultatul este: ” << rezultat << endl;

    return 0;

}


5. Transmiterea parametrilor

  1. Prin valoare:
    • Parametrii sunt copiați, iar modificările nu afectează variabilele originale.

Exemplu:

void modifica(int x) {

    x = 10;

}

  1. Prin referință:
    • Se transmite adresa variabilei, iar modificările afectează variabila originală.

Exemplu:

void modifica(int& x) {

    x = 10;

}

  1. Prin pointer:
    • Similar cu referința, dar se folosește sintaxa pointerilor.

Exemplu:

void modifica(int* x) {

    *x = 10;

}


6. Funcții recursive

  • Definiție: O funcție care se apelează pe ea însăși pentru a rezolva o problemă divizată în subprobleme.
  • Exemplu: Factorial

#include <iostream>

using namespace std;

int factorial(int n) {

    if (n == 0) {

        return 1;

    }

    return n * factorial(n – 1);

}

int main() {

    cout << „Factorial de 5: ” << factorial(5) << endl;

    return 0;

}


7. Exemple practice

  1. Funcție pentru determinarea maximului dintre două numere:

int maxim(int a, int b) {

    return (a > b) ? a : b;

}

  1. Funcție pentru verificarea unui număr prim:

bool estePrim(int n) {

    if (n < 2) return false;

    for (int i = 2; i * i <= n; i++) {

        if (n % i == 0) return false;

    }

    return true;

}

  1. Funcție pentru calculul sumei elementelor dintr-un vector:

int sumaVector(int vec[], int dim) {

    int suma = 0;

    for (int i = 0; i < dim; i++) {

        suma += vec[i];

    }

    return suma;

}


8. Activități practice pentru elevi

  1. Scrieți o funcție care determină dacă un număr este par sau impar.
  2. Realizați o funcție care calculează suma cifrelor unui număr.
  3. Implementați o funcție care verifică dacă un șir este palindrom.

9. Scheme logice

  1. Funcție simplă:
    • Start -> Parametru -> Instrucțiuni -> Returnare (opțional) -> Stop.
  2. Funcție recursivă:
    • Start -> Verificare condiție de bază -> Apel recursiv -> Returnare rezultat -> Stop.

10. Concluzie

  • Subprogramele definite de utilizator sunt esențiale pentru a structura și organiza programele complexe.
  • Alegerea parametrilor și a tipului de returnare depinde de cerințele problemei.
  • Practica și utilizarea subprogramelor ajută la dezvoltarea unor soluții modulare și eficiente.

Variabile Locale și Globale. Domeniu de Vizibilitate în C++


1. Obiectivele lecției:

  • Să înțeleagă diferența dintre variabilele locale și globale.
  • Să înțeleagă conceptul de domeniu de vizibilitate.
  • Să implementeze exemple practice pentru utilizarea corectă a variabilelor locale și globale.

2. Variabile locale

  1. Definiție:
    • Variabilele locale sunt declarate în interiorul unui bloc de cod, cum ar fi o funcție sau un bloc delimitat de {}.
    • Sunt accesibile doar în interiorul blocului în care au fost declarate.
  2. Caracteristici:
    • Sunt create atunci când blocul de cod începe execuția și sunt distruse când blocul se termină.
    • Au o vizibilitate limitată la blocul în care sunt definite.
  3. Exemplu:

#include <iostream>

using namespace std;

void afiseaza() {

    int x = 10; // Variabilă locală

    cout << „Valoarea lui x: ” << x << endl;

}

int main() {

    afiseaza();

    // cout << x; // Eroare: x nu este vizibil în main

    return 0;

}


3. Variabile globale

  1. Definiție:
    • Variabilele globale sunt declarate în afara oricărei funcții și sunt accesibile în orice parte a programului, după punctul lor de declarație.
  2. Caracteristici:
    • Sunt create odată cu începutul programului și distruse odată cu terminarea programului.
    • Pot fi accesate și modificate de oriunde, ceea ce poate duce la conflicte dacă nu sunt utilizate cu atenție.
  3. Exemplu:

#include <iostream>

using namespace std;

int x = 20; // Variabilă globală

void afiseaza() {

    cout << „Valoarea lui x în afiseaza(): ” << x << endl;

}

int main() {

    cout << „Valoarea lui x în main(): ” << x << endl;

    afiseaza();

    return 0;

}


4. Domeniul de vizibilitate (Scope)

  1. Definiție:
    • Domeniul de vizibilitate reprezintă partea programului în care o variabilă poate fi accesată.
  2. Tipuri de domeniu de vizibilitate:
    • Bloc local: Vizibilitate limitată la blocul în care variabila este declarată.
    • Bloc global: Vizibilitate pe tot parcursul programului, după declarație.
    • Blocuri imbricate: Variabilele declarate în blocuri interioare ascund variabilele cu același nume din blocurile exterioare.

5. Conflicte între variabile locale și globale

  1. Utilizarea numelor identice:
    • O variabilă locală cu același nume ca o variabilă globală va ascunde variabila globală în interiorul blocului său.
  2. Exemplu:

#include <iostream>

using namespace std;

int x = 50; // Variabilă globală

void afiseaza() {

    int x = 10; // Variabilă locală

    cout << „Variabilă locală x: ” << x << endl;

    cout << „Variabilă globală x: ” << ::x << endl; // Accesare variabilă globală

}

int main() {

    afiseaza();

    cout << „Variabilă globală x în main(): ” << x << endl;

    return 0;

}


6. Avantaje și dezavantaje

  1. Variabile locale:
    • Avantaje:
      • Evită conflictele dintre funcții.
      • Utilizează memoria doar pe durata blocului în care sunt folosite.
    • Dezavantaje:
      • Nu sunt accesibile din alte funcții sau părți ale programului.
  2. Variabile globale:
    • Avantaje:
      • Accesibile din orice funcție, facilitând partajarea datelor.
    • Dezavantaje:
      • Pot duce la conflicte dacă sunt folosite neglijent.
      • Pot face debugging-ul mai dificil.

7. Exemple practice

  1. Exemplu: Utilizarea variabilelor globale pentru configurări comune

#include <iostream>

using namespace std;

const int MAX_VAL = 100; // Variabilă globală constantă

void verifica(int val) {

    if (val > MAX_VAL) {

        cout << „Valoarea depășește limita maximă!” << endl;

    } else {

        cout << „Valoarea este validă.” << endl;

    }

}

int main() {

    int valoare = 120;

    verifica(valoare);

    return 0;

}

  1. Exemplu: Preferința pentru variabile locale

#include <iostream>

using namespace std;

int suma(int a, int b) {

    int rezultat = a + b; // Variabilă locală

    return rezultat;

}

int main() {

    cout << „Suma: ” << suma(5, 7) << endl;

    return 0;

}


8. Activități practice pentru elevi

  1. Scrieți un program care utilizează o variabilă globală pentru a număra câte funcții au fost apelate.
  2. Realizați un program care demonstrează cum o variabilă locală ascunde o variabilă globală cu același nume.
  3. Implementați un program care folosește variabile locale pentru a calcula produsul elementelor unui vector.

9. Scheme logice

  1. Accesarea variabilelor:
    • Start -> Declarare variabilă globală -> Declarare variabilă locală -> Verificare accesibilitate -> Stop.
  2. Conflicte între variabile:
    • Start -> Declarare variabile cu același nume (global/local) -> Utilizare variabilă locală -> Accesare explicită a variabilei globale -> Stop.

10. Concluzie

  • Variabilele locale sunt utilizate pentru scopuri specifice, limitând vizibilitatea acestora la un bloc.
  • Variabilele globale sunt utile pentru date care trebuie partajate între mai multe funcții, dar pot genera conflicte dacă nu sunt gestionate cu atenție.
  • Alegerea tipului de variabilă depinde de cerințele programului, iar o bună practică este utilizarea minimă a variabilelor globale.

Mecanismul de Transmitere a Datelor prin Parametrii în C++


1. Obiectivele lecției:

  • Să înțeleagă conceptul de parametri formali și actuali.
  • Să exploreze metodele de transmitere a datelor: prin valoare, prin referință și prin adresă.
  • Să implementeze exemple practice pentru fiecare tip de apel.

2. Parametrii formali și parametrii actuali

  1. Parametrii formali:
    • Variabilele declarate în lista de parametri a funcției.
    • Reprezintă datele de intrare așteptate de funcție.
    • Există doar pe durata execuției funcției.

Exemplu:

void afiseazaSuma(int a, int b) { // a și b sunt parametri formali

    cout << „Suma este: ” << a + b << endl;

}

  1. Parametrii actuali:
    • Valorile sau variabilele transmise funcției în momentul apelului.
    • Se asociază cu parametrii formali.

Exemplu:

int main() {

    afiseazaSuma(3, 5); // 3 și 5 sunt parametri actuali

    return 0;

}


3. Metode de transmitere a parametrilor


1. Apel prin valoare

  1. Definiție:
    • Parametrul formal primește o copie a valorii parametrului actual.
    • Modificările asupra parametrului formal nu afectează parametrul actual.
  2. Exemplu:

void modificaValoare(int x) {

    x = 10; // Parametrul actual nu este afectat

}

int main() {

    int numar = 5;

    modificaValoare(numar);

    cout << „Valoarea lui numar: ” << numar << endl; // Afișează 5

    return 0;

}

  1. Avantaje:
    • Simplu de utilizat.
    • Parametrul actual rămâne neschimbat.
  2. Dezavantaje:
    • Ineficient pentru tipuri mari de date (copierea consumă timp și memorie).

2. Apel prin referință

  1. Definiție:
    • Parametrul formal devine un alias pentru parametrul actual.
    • Modificările asupra parametrului formal afectează direct parametrul actual.
  2. Exemplu:

void modificaReferinta(int& x) {

    x = 10; // Parametrul actual este modificat

}

int main() {

    int numar = 5;

    modificaReferinta(numar);

    cout << „Valoarea lui numar: ” << numar << endl; // Afișează 10

    return 0;

}

  1. Avantaje:
    • Eficient (nu se face copiere).
    • Permite modificarea valorii originale.
  2. Dezavantaje:
    • Poate duce la erori dacă modificările sunt nedorite.

3. Apel prin adresă

  1. Definiție:
    • Parametrul formal primește adresa parametrului actual.
    • Accesul și modificarea se fac prin dereferențiere.
  2. Exemplu:

void modificaAdresa(int* x) {

    *x = 10; // Parametrul actual este modificat

}

int main() {

    int numar = 5;

    modificaAdresa(&numar); // Transmite adresa lui numar

    cout << „Valoarea lui numar: ” << numar << endl; // Afișează 10

    return 0;

}

  1. Avantaje:
    • Eficient și flexibil (permite modificări și acces la memoria parametrului actual).
  2. Dezavantaje:
    • Sintaxa mai complicată.
    • Necesită atenție pentru a evita erorile legate de pointeri.

4. Compararea metodelor de transmitere

CaracteristicăApel prin valoareApel prin referințăApel prin adresă
Modificarea parametrului actualNuDaDa
Eficiență pentru tipuri mariScăzutăRidicatăRidicată
SimplitateSimplăModeratăMai complicată

5. Exemple practice


Exemplu 1: Schimbarea valorilor a două variabile

  • Prin referință:

void swap(int& a, int& b) {

    int temp = a;

    a = b;

    b = temp;

}

int main() {

    int x = 5, y = 10;

    swap(x, y);

    cout << „x: ” << x << „, y: ” << y << endl; // x: 10, y: 5

    return 0;

}

  • Prin adresă:

void swap(int* a, int* b) {

    int temp = *a;

    *a = *b;

    *b = temp;

}

int main() {

    int x = 5, y = 10;

    swap(&x, &y);

    cout << „x: ” << x << „, y: ” << y << endl; // x: 10, y: 5

    return 0;

}


Exemplu 2: Calcularea sumei elementelor unui vector

  • Prin referință:

int suma(const int& a, const int& b) {

    return a + b;

}

int main() {

    int x = 5, y = 10;

    cout << „Suma: ” << suma(x, y) << endl; // Suma: 15

    return 0;

}


6. Activități practice pentru elevi

  1. Scrieți un program care folosește apelul prin referință pentru a tripla valoarea unei variabile.
  2. Implementați o funcție care folosește apelul prin adresă pentru a calcula produsul a două numere.
  3. Realizați un program care calculează suma elementelor unui vector, folosind apelul prin valoare și prin referință.

7. Scheme logice

  1. Apel prin valoare:
    • Start -> Transmite copie -> Modifică copia -> Nu afectează originalul -> Stop.
  2. Apel prin referință:
    • Start -> Transmite referință -> Modifică variabila originală -> Stop.
  3. Apel prin adresă:
    • Start -> Transmite adresa -> Dereferențiere și modificare -> Stop.

8. Concluzie

  • Alegerea metodei de transmitere a parametrilor depinde de cerințele programului:
    • Prin valoare: Pentru date care nu trebuie modificate și sunt mici.
    • Prin referință: Pentru date mari care necesită modificări.
    • Prin adresă: Pentru cazuri complexe care implică acces la locația memoriei.
  • Practica este esențială pentru a înțelege și aplica corect fiecare metodă.

Clasificarea Funcțiilor Definite de Utilizator: Funcții Procedurale și Funcții Operand


1. Obiectivele lecției:

  • Să înțeleagă diferența dintre funcțiile procedurale și funcțiile operand.
  • Să identifice utilizarea fiecărui tip de funcție.
  • Să implementeze exemple practice pentru a evidenția diferențele.

2. Ce sunt funcțiile definite de utilizator?

  • Funcțiile definite de utilizator sunt module create pentru a rezolva probleme specifice. Acestea pot fi clasificate în funcții procedurale și funcții operand pe baza scopului lor și a modului în care sunt utilizate.

3. Clasificarea funcțiilor


1. Funcții Procedurale

  1. Definiție:
    • Sunt funcții care realizează o serie de operații, fără a returna o valoare semnificativă.
    • Rezultatul lor este de obicei afișat sau utilizat pentru efecte secundare (ex.: modificarea unei structuri de date, afișarea unui mesaj).
  2. Caracteristici:
    • Tipul de returnare este de obicei void.
    • Utilizate pentru sarcini care nu necesită o valoare de ieșire.
  3. Exemple de utilizare:
    • Afișarea unui mesaj.
    • Modificarea unui vector.
    • Scrierea în fișiere.
  4. Exemplu:

#include <iostream>

using namespace std;

void afiseazaMesaj() {

    cout << „Aceasta este o funcție procedurală.” << endl;

}

int main() {

    afiseazaMesaj();

    return 0;

}


2. Funcții Operand

  1. Definiție:
    • Sunt funcții care efectuează o operație și returnează un rezultat.
    • Rezultatul este utilizat direct în program.
  2. Caracteristici:
    • Tipul de returnare este diferit de void (ex.: int, double, string).
    • Pot fi utilizate în expresii sau pentru atribuire.
  3. Exemple de utilizare:
    • Calculul unei sume.
    • Determinarea unui număr maxim.
    • Returnarea unei valori transformate.
  4. Exemplu:

#include <iostream>

using namespace std;

int suma(int a, int b) {

    return a + b;

}

int main() {

    int rezultat = suma(3, 5);

    cout << „Suma este: ” << rezultat << endl;

    return 0;

}


4. Diferențe între funcții procedurale și funcții operand

CaracteristicăFuncții ProceduraleFuncții Operand
Tipul de returnarevoidTipuri precum int, double
ScopRealizează operații sau efecteCalculează și returnează valori
ExempleAfișare, modificări de dateCalcul, comparații, transformări
Utilizare în expresiiNuDa

5. Exemple practice


Exemplu 1: Modificarea unui vector (procedurală)

#include <iostream>

using namespace std;

void cresteElemente(int vec[], int dim) {

    for (int i = 0; i < dim; i++) {

        vec[i] += 1;

    }

}

int main() {

    int vector[5] = {1, 2, 3, 4, 5};

    cresteElemente(vector, 5);

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

        cout << vector[i] << ” „;

    }

    return 0;

}


Exemplu 2: Calcularea mediei unui vector (operand)

#include <iostream>

using namespace std;

double calculeazaMedia(int vec[], int dim) {

    int suma = 0;

    for (int i = 0; i < dim; i++) {

        suma += vec[i];

    }

    return static_cast<double>(suma) / dim;

}

int main() {

    int vector[5] = {1, 2, 3, 4, 5};

    double media = calculeazaMedia(vector, 5);

    cout << „Media este: ” << media << endl;

    return 0;

}


6. Combinarea funcțiilor procedurale și operand

  1. Exemplu complet:
    • Procedural: Afișarea unui rezultat.
    • Operand: Calculul unui rezultat.

#include <iostream>

using namespace std;

double calculeazaMedia(int vec[], int dim) {

    int suma = 0;

    for (int i = 0; i < dim; i++) {

        suma += vec[i];

    }

    return static_cast<double>(suma) / dim;

}

void afiseazaMedia(double media) {

    cout << „Media calculată este: ” << media << endl;

}

int main() {

    int vector[5] = {1, 2, 3, 4, 5};

    double media = calculeazaMedia(vector, 5);

    afiseazaMedia(media);

    return 0;

}


7. Activități practice pentru elevi

  1. Scrieți o funcție procedurală care afișează toate elementele pare dintr-un vector.
  2. Implementați o funcție operand care determină produsul elementelor unui vector.
  3. Realizați un program care folosește o funcție operand pentru a calcula factorialul unui număr și o funcție procedurală pentru afișare.

8. Scheme logice

  1. Funcție procedurală:
    • Start -> Realizează operația -> Fără returnare -> Stop.
  2. Funcție operand:
    • Start -> Efectuează calculul -> Returnează rezultatul -> Stop.

9. Concluzie

  • Funcțiile procedurale sunt utile pentru realizarea operațiilor fără a returna un rezultat semnificativ.
  • Funcțiile operand sunt esențiale pentru calcularea și returnarea rezultatelor în expresii.
  • O bună organizare a funcțiilor ajută la crearea de programe clare, eficiente și ușor de întreținut.

Subprograme Recursive – Funcții Direct Recursive în C++


1. Obiectivele lecției:

  • Să înțeleagă conceptul de funcții recursive.
  • Să înțeleagă ce sunt funcțiile direct recursive.
  • Să implementeze exemple practice care folosesc recursivitatea directă pentru a rezolva probleme.

2. Ce este recursivitatea?

  1. Definiție:
    • Recursivitatea este o tehnică de programare în care o funcție se apelează pe ea însăși pentru a rezolva o problemă prin divizarea acesteia în subprobleme mai simple.
  2. Condiții necesare pentru o funcție recursivă:
    • Cazul de bază: O condiție care oprește recursivitatea.
    • Cazul recursiv: Funcția se apelează pe ea însăși cu o versiune mai simplă a problemei.

3. Ce sunt funcțiile direct recursive?

  1. Definiție:
    • O funcție este direct recursivă dacă se apelează pe ea însăși în interiorul definiției sale.
  2. Exemplu simplu:

void functieRecursiva() {

    cout << „Aceasta este o functie recursiva directa.” << endl;

    functieRecursiva(); // Apel direct recursiv

}

  1. Utilizare:
    • Calcularea factorialului.
    • Seria Fibonacci.
    • Parcurgerea structurilor de date, cum ar fi arborii.

4. Avantajele și dezavantajele recursivității

AvantajeDezavantaje
Simplifică soluția pentru probleme complexe.Poate duce la depășirea stivei de apeluri (stack overflow).
Cod mai concis și mai lizibil pentru probleme recursive.Consumă mai multă memorie din cauza apelurilor recursive.
Ușor de aplicat pentru probleme de tip divide-and-conquer.Performanță mai slabă decât soluțiile iterative în anumite cazuri.

5. Exemple practice


Exemplu 1: Calcularea Factorialului

  1. Definiție matematică:
    n!=n⋅(n−1)!n! = n \cdot (n – 1)!n!=n⋅(n−1)!, cu 0!=10! = 10!=1.
  2. Implementare:

#include <iostream>

using namespace std;

int factorial(int n) {

    if (n == 0) {

        return 1; // Cazul de bază

    }

    return n * factorial(n – 1); // Apel recursiv

}

int main() {

    int numar = 5;

    cout << „Factorial de ” << numar << ” este: ” << factorial(numar) << endl;

    return 0;

}


Exemplu 2: Seria Fibonacci

  1. Definiție matematică:
    F(n)=F(n−1)+F(n−2)F(n) = F(n – 1) + F(n – 2)F(n)=F(n−1)+F(n−2), cu F(0)=0F(0) = 0F(0)=0 și F(1)=1F(1) = 1F(1)=1.
  2. Implementare:

#include <iostream>

using namespace std;

int fibonacci(int n) {

    if (n == 0) {

        return 0; // Cazul de bază

    }

    if (n == 1) {

        return 1; // Cazul de bază

    }

    return fibonacci(n – 1) + fibonacci(n – 2); // Apel recursiv

}

int main() {

    int numar = 6;

    cout << „Al ” << numar << „-lea număr din seria Fibonacci este: ” << fibonacci(numar) << endl;

    return 0;

}


Exemplu 3: Suma elementelor unui vector

  1. Problema: Calculați suma elementelor unui vector folosind recursivitatea.
  2. Implementare:

#include <iostream>

using namespace std;

int sumaVector(int vec[], int dim) {

    if (dim == 0) {

        return 0; // Cazul de bază

    }

    return vec[dim – 1] + sumaVector(vec, dim – 1); // Apel recursiv

}

int main() {

    int vector[] = {1, 2, 3, 4, 5};

    int dim = 5;

    cout << „Suma elementelor este: ” << sumaVector(vector, dim) << endl;

    return 0;

}


Exemplu 4: Parcurgerea unui arbore binar (preordine)

  1. Problema: Parcurgeți un arbore binar folosind recursivitatea.
  2. Implementare:

#include <iostream>

using namespace std;

struct Nod {

    int valoare;

    Nod* stanga;

    Nod* dreapta;

};

void parcurgePreordine(Nod* radacina) {

    if (radacina == NULL) {

        return; // Cazul de bază

    }

    cout << radacina->valoare << ” „;

    parcurgePreordine(radacina->stanga); // Apel recursiv

    parcurgePreordine(radacina->dreapta); // Apel recursiv

}

int main() {

    Nod* radacina = new Nod{1, new Nod{2, NULL, NULL}, new Nod{3, NULL, NULL}};

    cout << „Parcurgerea preordine: „;

    parcurgePreordine(radacina);

    return 0;

}


6. Probleme tipice rezolvate cu recursivitate

  1. Calcularea puterii unui număr: xn=x⋅xn−1x^n = x \cdot x^{n-1}xn=x⋅xn−1.
  2. Determinarea cifrei maxime dintr-un număr.
  3. Inversarea unui șir de caractere.

7. Activități practice pentru elevi

  1. Scrieți o funcție recursivă care calculează suma cifrelor unui număr.
  2. Implementați o funcție recursivă care verifică dacă un șir este palindrom.
  3. Scrieți o funcție recursivă care calculează valoarea maximă dintr-un vector.

8. Scheme logice

  1. Funcție recursivă:
    • Start -> Verificare caz de bază -> Apel funcție pe subproblemă -> Combinare rezultat -> Stop.
  2. Funcție direct recursivă pentru factorial:
    • Start -> Dacă n==0n == 0n==0, returnează 1 -> Apel recursiv n∗factorial(n−1)n * factorial(n – 1)n∗factorial(n−1) -> Stop.

9. Concluzie

  • Funcțiile directe recursive sunt o soluție elegantă pentru probleme de tip divide-and-conquer.
  • Este important să definim corect cazul de bază pentru a evita buclele infinite.
  • Practica ajută la înțelegerea recursivității și la utilizarea acesteia în mod eficient.

Subprograme Recursive – Funcții Indirect Recursive în C++


1. Obiectivele lecției:

  • Să înțeleagă conceptul de funcții indirect recursive.
  • Să învețe diferențele dintre recursivitatea directă și cea indirectă.
  • Să implementeze exemple practice de funcții indirect recursive.

2. Ce este recursivitatea indirectă?

  1. Definiție:
    • Recursivitatea indirectă apare atunci când o funcție A apelează o funcție B, iar funcția B apelează din nou funcția A. Astfel, funcțiile implicate se apelează reciproc pentru a rezolva problema.
  2. Structura generală:

void A() {

    // Operații

    B(); // Funcția A apelează funcția B

}

void B() {

    // Operații

    A(); // Funcția B apelează funcția A

}

  1. Cerințe pentru recursivitatea indirectă:
    • Definirea unui caz de bază pentru a opri apelurile recursive.
    • Asigurarea unei secvențe finite de apeluri între funcții.

3. Diferența dintre recursivitatea directă și indirectă

CaracteristicăRecursivitate directăRecursivitate indirectă
DefinițieO funcție se apelează pe ea însăși.Două sau mai multe funcții se apelează reciproc.
Exemple comuneFactorial, FibonacciFuncții care validează reguli complexe.
ComplexitateMai simplă de implementat și înțeles.Necesită planificare mai atentă.

4. Exemple practice


Exemplu 1: Determinarea parității unui număr

  1. Problema: Determinați dacă un număr este par sau impar folosind recursivitate indirectă.
  2. Implementare:

#include <iostream>

using namespace std;

void esteImpar(int n);

void estePar(int n) {

    if (n == 0) {

        cout << „Numărul este par.” << endl;

        return; // Caz de bază

    }

    esteImpar(n – 1); // Apel recursiv indirect

}

void esteImpar(int n) {

    if (n == 0) {

        cout << „Numărul este impar.” << endl;

        return; // Caz de bază

    }

    estePar(n – 1); // Apel recursiv indirect

}

int main() {

    int numar = 5;

    estePar(numar); // Pornește determinarea

    return 0;

}


Exemplu 2: Validarea unei secvențe de reguli

  1. Problema: Validarea unui șir care trebuie să alterneze între vocale și consoane.
  2. Implementare:

#include <iostream>

#include <cstring>

using namespace std;

void verificaConsoana(const char* sir, int index);

void verificaVocala(const char* sir, int index) {

    if (sir[index] == ‘\0’) {

        cout << „Șirul este valid.” << endl;

        return; // Caz de bază

    }

    if (strchr(„aeiouAEIOU”, sir[index])) {

        verificaConsoana(sir, index + 1); // Apel recursiv indirect

    } else {

        cout << „Șir invalid: așteptam o vocală la poziția ” << index << endl;

    }

}

void verificaConsoana(const char* sir, int index) {

    if (sir[index] == ‘\0’) {

        cout << „Șirul este valid.” << endl;

        return; // Caz de bază

    }

    if (!strchr(„aeiouAEIOU”, sir[index])) {

        verificaVocala(sir, index + 1); // Apel recursiv indirect

    } else {

        cout << „Șir invalid: așteptam o consoană la poziția ” << index << endl;

    }

}

int main() {

    const char* sir = „aBcDeF”;

    verificaVocala(sir, 0); // Pornește validarea

    return 0;

}


Exemplu 3: Calculul sumelor alternative

  1. Problema: Calculați suma numerelor pozitive și negative dintr-un vector, alternând între apeluri.
  2. Implementare:

#include <iostream>

using namespace std;

int sumaNegative(const int vec[], int dim, int index);

int sumaPozitive(const int vec[], int dim, int index) {

    if (index == dim) {

        return 0; // Caz de bază

    }

    if (vec[index] > 0) {

        return vec[index] + sumaNegative(vec, dim, index + 1); // Apel recursiv indirect

    }

    return sumaNegative(vec, dim, index + 1);

}

int sumaNegative(const int vec[], int dim, int index) {

    if (index == dim) {

        return 0; // Caz de bază

    }

    if (vec[index] < 0) {

        return vec[index] + sumaPozitive(vec, dim, index + 1); // Apel recursiv indirect

    }

    return sumaPozitive(vec, dim, index + 1);

}

int main() {

    int vector[] = {1, -2, 3, -4, 5};

    int dim = 5;

    int suma = sumaPozitive(vector, dim, 0);

    cout << „Suma totală este: ” << suma << endl;

    return 0;

}


5. Avantaje și dezavantaje ale recursivității indirecte

AvantajeDezavantaje
Permite modelarea unor probleme complexe în mod elegant.Poate fi dificil de urmărit fluxul de apeluri.
Poate simplifica implementarea unor reguli interdependente.Performanță mai scăzută decât soluțiile iterative.
Ajută la separarea logicii în funcții mai mici și clare.Crește riscul de depășire a stivei de apeluri.

6. Activități practice pentru elevi

  1. Implementați două funcții recursive indirecte care determină dacă toate cifrele unui număr sunt impare sau pare.
  2. Scrieți un program care folosește recursivitatea indirectă pentru a calcula suma și produsul elementelor unui vector.
  3. Realizați două funcții care validează dacă un șir începe și se termină cu același caracter, alternând apelurile.

7. Scheme logice

  1. Fluxul recursivității indirecte:
    • Start -> Funcția A -> Apelă funcția B -> Apelă funcția A -> Condiție de oprire -> Stop.
  2. Diagrama de apeluri:

A -> B -> A -> … -> Stop


8. Concluzie

  • Recursivitatea indirectă este o tehnică utilă pentru probleme complexe care implică relații între mai multe funcții.
  • Este important să definim clar cazul de bază pentru a preveni buclele infinite.
  • Separarea logicii între funcții ajută la claritatea și modularitatea codului.

Similar Posts

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *