Primul item de la Subiectul III la BAC informatică îți cere să scrii definiția completă a unui subprogram în C++. În modelul actual valorează 10 puncte (verifică întotdeauna ultimul model oficial pe subiecte.edu.ro). Algoritmul cerut e de obicei unul clasic — cifre, divizori, numere prime, CMMDC — dar punctele se pierd des pe detalii: un nume schimbat, un parametru transmis greșit, un return lipsă sau un caz limită uitat. Mai jos ai o metodă în cinci pași și două exemple rezolvate complet.

Cum arată enunțul

Enunțul are aproape mereu aceeași structură: „Subprogramul X are un/doi parametri, … prin care primește …, și … prin care furnizează …. Subprogramul returnează …. Scrieți definiția completă a subprogramului.” Urmează un exemplu cu valori concrete. Fiecare bucată din propoziția asta se traduce direct în cod:

În enunțÎn cod
„are parametrul n, prin care primește un număr natural”int n (prin valoare)
„parametrul s, prin care furnizează…”int &s (prin referință)
„subprogramul returnează…”funcție cu tip + return
nu returnează nimic, doar furnizează prin parametrivoid
„primește un tablou v cu n elemente”int v[], int n

Ordinea parametrilor din antet trebuie să fie exact ordinea din enunț, iar numele subprogramului se copiază literă cu literă, inclusiv majusculele (nrDiv nu e același lucru cu nrdiv).

Metoda în cinci pași

  1. Scrie antetul primul, direct din enunț: tip, nume, parametri în ordine, cu & doar unde ți se cere să „furnizezi”.
  2. Alege tipul datelor după intervalele din enunț: până la 109 încape în int; dacă un rezultat poate depăși aproximativ 2·109 (de exemplu un produs), folosește long long.
  3. Scrie algoritmul cu variabile locale inițializate explicit.
  4. Verifică pe exemplul din enunț, de mână, cu un mic tabel de valori.
  5. Verifică un caz limită: cea mai mică valoare din interval, numărul 0, un vector cu un singur element, situația în care „nu există” rezultat.
La BAC: se cere doar definiția subprogramului. Nu e nevoie de main, de #include sau de citiri, iar subprogramul nu trebuie să citească sau să afișeze nimic dacă enunțul nu spune explicit asta. Datele vin prin parametri, rezultatele pleacă prin return sau prin referințe.

Exemplul 1: subprogram care returnează o valoare

Subprogramul cifreImpare are un singur parametru, n, prin care primește un număr natural (n ∈ [0, 109]). Subprogramul returnează numărul format din cifrele impare ale lui n, în ordinea în care apar în acesta, sau −1 dacă n nu are nicio cifră impară. Exemplu: pentru n = 23541 se returnează 351.

Antetul rezultă imediat: int cifreImpare(int n). Parcurgem cifrele de la dreapta la stânga, deci ca să păstrăm ordinea, fiecare cifră impară găsită trebuie pusă în fața celor deja găsite. Pentru asta ținem o putere a lui 10, p.

int cifreImpare(int n)
{
    int rez = 0, p = 1;
    while (n > 0)
    {
        int c = n % 10;
        if (c % 2 == 1)
        {
            rez = c * p + rez;
            p = p * 10;
        }
        n = n / 10;
    }
    if (p == 1) return -1;   // nu s-a găsit nicio cifră impară
    return rez;
}

Verificare pe exemplu, n = 23541:

cifra cimpară?rezp
1da110
4nu110
5da51100
3da3511000
2nu3511000

Cazuri limită: pentru n = 0 bucla nu se execută, p rămâne 1 și se returnează −1 — corect, pentru că 0 e cifră pară. Pentru n = 2468, la fel. De ce nu testăm rez == 0? Pentru că aici ar funcționa, dar în variante ale problemei (de exemplu „cifrele pare”) numărul format poate fi chiar 0, iar testul pe p sau un contor separat e sigur în orice situație.

Exemplul 2: rezultat furnizat prin referință

Subprogramul nrDiv are doi parametri: n, prin care primește un număr natural (n ∈ [1, 109]), și k, prin care furnizează numărul de divizori ai lui n. Exemplu: pentru n = 12, k = 6.

Nu se spune „returnează”, ci „furnizează prin parametrul k”, deci funcția e void, iar k are &. Cum n poate fi până la 109, nu merge să încercăm toți divizorii de la 1 la n; mergem până la √n și numărăm divizorii în perechi (d și n/d).

void nrDiv(int n, int &k)
{
    k = 0;
    for (int d = 1; d * d <= n; d++)
        if (n % d == 0)
        {
            k++;                    // d
            if (d != n / d) k++;    // perechea lui, n / d
        }
}

Pentru n = 12: d = 1 (perechea 12), d = 2 (perechea 6), d = 3 (perechea 4), deci k = 6. Pentru n = 16: d = 1 (16), d = 2 (8), d = 4 (perechea e tot 4, se numără o singură dată), deci k = 5. Linia k = 0; e esențială: k e o variabilă din afara subprogramului și poate conține orice înainte de apel. Iar d * d <= n nu depășește int, pentru că d nu trece de aproximativ 31 623.

Ce urmărește, în general, corectorul

Baremele oficiale acordă de obicei puncte separate pentru antetul corect, pentru algoritmul propriu-zis și pentru furnizarea rezultatului, plus punctaj pentru declararea corectă a datelor. Detaliile diferă de la an la an, așa că citește baremul fiecărei simulări pe care o rezolvi. Concluzia practică: un antet corect și un return corect aduc puncte chiar dacă algoritmul are o scăpare, iar un antet greșit te poate costa puncte chiar dacă restul e perfect.

Greșeli care costă puncte

De reținut