1. Greseala off-by-one: indexarea vectorilor
v[n] in loc de v[n-1], sau pornirea buclei de la i=1 in loc de i=0.Consecinta: Undefined behavior — rezultate imprevizibile sau crash la examen.
// GRESIT: i <= n acceseaza v[n] care e out of bounds! for (int i = 0; i <= n; i++) suma += v[i]; // CORECT: ultimul indice valid este n-1 for (int i = 0; i < n; i++) suma += v[i];
#include <iostream> using namespace std; int main() { int v[5] = {10, 20, 30, 40, 50}; int n = 5; cout << "v[0]=" << v[0] << " v[n-1]=" << v[n-1] << endl; int suma = 0; for (int i = 0; i < n; i++) suma += v[i]; cout << "Suma corecta: " << suma << endl; return 0; }
v[0]=10 v[n-1]=50 Suma corecta: 150
Unele probleme BAC declara int v[101] si folosesc indicii 1..n. In acest caz bucla i=1; i<=n e corecta — dar trebuie sa declari tabloul cu dimensiunea n+1 pentru a evita overflow.
2. Confuzia = (atribuire) vs == (comparatie)
if (x = 5) in loc de if (x == 5).Consecinta: Atribuie 5 lui x, testeaza daca 5 != 0 (mereu adevarat), si modifica variabila — bug silentios, greu de depistat!
int x = 3; // GRESIT: atribuie 5 lui x, testeaza 5!=0 (mereu true!) if (x = 5) cout << "gresit"; // CORECT: compara x cu 5 if (x == 5) cout << "corect";
#include <iostream> using namespace std; int main() { int x = 5; if (x == 5) cout << "x este 5 (comparatie corecta)" << endl; return 0; }
x este 5 (comparatie corecta)
Un singur egal = pune valoare (atribuie). Doua egale == compara valorile. In orice conditie (if, while, for) vrei aproape intotdeauna ==.
3. Impartire intreaga vs impartire reala
int, / face impartire intreaga (trunchiaza), chiar daca rezultatul e stocat intr-un double.Consecinta: Pierdere de zecimale — greseala clasica la probleme cu medii sau rapoarte.
#include <iostream> using namespace std; int main() { int a = 7, b = 2; double rez_gresit = a / b; // impartire intreaga: 3 double rez_corect = (double)a / b; // cast inainte de /: 3.5 cout << "7/2 int: " << rez_gresit << endl; cout << "7/2 real: " << rez_corect << endl; return 0; }
7/2 int: 3 7/2 real: 3.5
Daca vrei impartire reala, castureaza CEL PUTIN UN operand inainte de operatie: (double)a / b sau a / (double)b. Alternativ, declara variabilele ca double de la inceput.
4. CMMDC gresit, recursivitate fara caz de baza, terminator sir
a inainte de a calcula restul — rezultat intotdeauna gresit.Greseala recursivitate: Omiterea cazului de baza — stack overflow garantat.
Greseala sir: Confuzia
'\0' (terminator nul) cu spatiu sau cu un caracter de continut.
#include <iostream> using namespace std; // CMMDC CORECT: variabila temporara r salveaza restul // GRESIT ar fi: a=b; b=a%b; (pierde valoarea originala a lui a) int cmmdc(int a, int b) { while (b != 0) { int r = a % b; a = b; b = r; } return a; } // Recursivitate CORECTA: cazul de baza este OBLIGATORIU int factorial(int n) { if (n <= 1) return 1; // fara asta: stack overflow! return n * factorial(n - 1); } // Sir de caractere: '\0' e terminatorul NUL, nu caracter de continut void lungime_sir() { char s[] = "Hello"; int lung = 0; while (s[lung] != '\0') lung++; cout << "Lungime 'Hello': " << lung << endl; } int main() { cout << "CMMDC(12,8) = " << cmmdc(12, 8) << endl; cout << "5! = " << factorial(5) << endl; lungime_sir(); return 0; }
CMMDC(12,8) = 4 5! = 120 Lungime 'Hello': 5
Un sir "Hello" in memorie are 6 bytes: H, e, l, l, o, \0. Numeri pana gasesti \0 si obtii 5 (lungimea corecta). Daca confunzi '\0' cu ' ' (spatiu), bucla continua in memorie nedefinita.
5. Overflow la int: numere mari la examen EXCLUSIV INTENSIV
int pe 32 biti tine maxim 2 147 483 647 (aprox. 2,1 miliarde). Daca produsul sau suma depaseste aceasta limita, apare overflow — un rezultat complet gresit, fara eroare de compilare!
int n = 100000; // GRESIT: n*n = 10^10, depaseste int (max ~2.1*10^9) int p_gresit = n * n; // overflow: valoare incorecta // CORECT: cast la long long INAINTE de inmultire long long p_corect = (long long)n * n; // 10000000000
n*n long long: 10000000000 n*n int overflow: 1410065408
Nota: overflow pentru int este Undefined Behavior in C++. Valoarea 1410065408 este caracteristica pe sisteme two's complement pe 32 biti: 1010 mod 232 reinterpretat ca signed. Nu te baza pe ea.
long long cu cast explicit. Complexitate CMMDC: O(log min(a,b)).
6. Backtracking: omiterea resetarii starii EXCLUSIV INTENSIV
Cea mai frecventa greseala la backtracking: dupa apelul recursiv, candidatii uita sa reseteze starea (f[i] = 0). Rezultat: se genereaza mult mai putine solutii decat cele corecte.
// GRESIT: lipseste resetarea for (int i = 1; i <= n; i++) { if (!f[i]) { v[k] = i; f[i] = 1; perm(k + 1); // LIPSESTE: f[i] = 0; } } // CORECT: resetezi starea dupa revenire (backtrack) for (int i = 1; i <= n; i++) { if (!f[i]) { v[k] = i; f[i] = 1; perm(k + 1); f[i] = 0; // obligatoriu! } }
#include <iostream> using namespace std; int v[10], n = 3, f[10] = {0}; void perm(int k) { if (k > n) { for (int i = 1; i <= n; i++) cout << v[i] << " "; cout << "\n"; return; } for (int i = 1; i <= n; i++) { if (!f[i]) { v[k] = i; f[i] = 1; perm(k + 1); f[i] = 0; // backtrack! } } } int main() { cout << "Permutarile {1,2,3}:\n"; perm(1); return 0; }
Permutarile {1,2,3}:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1