Dacă te uiți pe lucrări corectate de la BAC informatică, vezi un tipar: punctele nu se pierd pe probleme pe care elevul nu le-a înțeles, ci pe detalii. Un contor neinițializat, o condiție inversată, un indice care pornește de la 0 în loc de 1. Partea bună e că aceste greșeli sunt puține și previzibile. Mai jos le găsești pe cele mai des întâlnite, cu exemple în C++ și cu soluția pentru fiecare.
1. Variabile neinițializate
În C++, o variabilă locală declarată fără valoare inițială conține „gunoi” — orice valoare se afla în memorie. Programul de mai jos poate afișa orice:
int n, s, x;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> x;
s = s + x; // s nu a fost inițializat!
}
Regula: sumele și contoarele pornesc de la 0, produsele de la 1. Pentru maxim și minim, cea mai sigură inițializare e primul element citit. Dacă inițializezi maximul cu 0, iar toate valorile sunt negative, rezultatul va fi greșit.
2. = în loc de ==
În pseudocod, = înseamnă comparație. În C++, = este atribuire. Linia if (x = 0) compilează, dar îi dă lui x valoarea 0 și condiția devine falsă întotdeauna. Când traduci un algoritm, verifică fiecare dacă și fiecare cât timp: comparațiile se scriu ==, iar ≠ devine !=.
3. Condiția de la repetă … până când
Structura repetă … până când c se oprește când c devine adevărată. În C++, do … while continuă cât timp condiția e adevărată. Așa că trebuie să o negi:
// repetă … până când n = 0
do {
s = s + n % 10;
n = n / 10;
} while (n != 0); // NU while (n == 0)
La condiții compuse aplici legile lui De Morgan: până când a = 0 sau b = 0 devine while (a != 0 && b != 0).
4. Împărțirea întreagă
Dacă s și n sunt de tip int, atunci s / n e tot un întreg, chiar dacă rezultatul îl pui într-un double. Pentru s = 7 și n = 2:
double m1 = s / n; // 3, nu 3.5
double m2 = s * 1.0 / n; // 3.5
double m3 = (double)s / n; // 3.5
Invers, în pseudocod, [a/b] înseamnă partea întreagă, iar în C++ pe numere naturale e simplu a / b. Dacă însă a e real, ai nevoie de conversie explicită: (int)a.
5. Depășirea tipului int
Un int reține valori până la aproximativ 2,1 miliarde (2³¹ − 1 = 2.147.483.647). Dacă enunțul spune că numerele au cel mult 9 cifre și trebuie să le aduni, suma poate depăși această limită. La fel, produsul a două numere de ordinul 100.000 iese din int. Folosește long long pentru sume mari, produse și oglinditul unui număr de 9–10 cifre.
6. Indici care pornesc de unde nu trebuie
Enunțurile de BAC numerotează de obicei elementele de la 1. Dacă tu citești vectorul de la 0, nu e greșit, dar trebuie să fii consecvent peste tot. Greșelile tipice:
- citești
v[1] … v[n], dar parcurgi cufor (i = 0; i < n; i++)— pierzi ultimul element și îl prelucrezi pev[0], care nu are valoare; - compari vecinii cu
v[i]șiv[i+1]pentruipână lan— ieși din vector la ultimul pas; bucla trebuie să meargă până lan - 1; - la matrice cu indici de la 0, diagonala secundară e
i + j == n - 1, nui + j == n + 1(care e varianta pentru indici de la 1).
7. Ai distrus valoarea lui n
Algoritmul pe cifre îl reduce pe n la 0. Dacă enunțul îți cere să afișezi numărul inițial sau să-l compari cu oglinditul său, ai nevoie de o copie:
int copie = n, ogl = 0;
while (copie != 0) {
ogl = ogl * 10 + copie % 10;
copie = copie / 10;
}
if (ogl == n) cout << "palindrom";
8. Citirea din fișier cu eof()
Varianta while (!f.eof()) { f >> x; … } pare logică, dar dacă fișierul se termină cu un rând gol (Enter după ultimul număr), ultima citire eșuează și x e prelucrat a doua oară. Forma corectă și mai scurtă:
ifstream f("bac.txt");
int x, s = 0;
while (f >> x)
s = s + x;
9. Șiruri de caractere: dimensiune și citire
Un șir cu „cel mult 100 de caractere” are nevoie de 101 poziții, pentru terminatorul '\0': char s[101];. Dacă textul poate conține spații, cin >> s citește doar primul cuvânt — folosește cin.getline(s, 101);.
O capcană mai subtilă: ștergerea unui caracter cu strcpy(s + i, s + i + 1). Sursa și destinația se suprapun, iar standardul C++ spune că rezultatul e nedefinit în acest caz. Mai sigur e să muți caracterele cu o buclă sau să folosești un șir auxiliar.
10. Subprogramul nu face ce cere enunțul
Dacă enunțul spune „subprogramul returnează…”, rezultatul se întoarce cu return, nu se afișează cu cout. Dacă spune „subprogramul citește…” sau „are parametrii n și x”, respectă exact numele și ordinea parametrilor. Iar dacă parametrul trebuie să fie modificat și „văzut” în afara funcției, îl transmiți prin referință: void f(int n, int &x).
Cum scapi de ele definitiv
Fă-ți o listă cu greșelile de mai sus și, după fiecare problemă rezolvată, verifică-ți codul pe rând, punct cu punct. După câteva săptămâni verificarea devine automată și o faci deja în timp ce scrii. Iar când greșești totuși, notează exemplul concret — greșelile tale personale sunt cele mai valoroase de recapitulat.
De reținut
- ● Inițializează orice sumă (0), produs (1), contor (0) și maxim/minim (cu primul element).
- ● În condiții se scrie
==, nu=; larepetă … până cândcondiția dinwhilese neagă. - ● Împărțirea a doi întregi dă întotdeauna un întreg: pentru medie folosește
s * 1.0 / n. - ● Dacă ai nevoie de valoarea inițială a lui n după ce i-ai luat cifrele, lucrează pe o copie.
- ● Citește din fișier cu
while (f >> x), nu cuwhile (!f.eof()). - ● Un șir de cel mult 100 de caractere se declară
char s[101]și se citește cucin.getlinedacă poate conține spații.