De ce contează?
Programul compilează, rulează — și dă un răspuns greșit. Ce faci? Nu rescrii totul. Nu ghicești. Adaugi câteva cout-uri ca să vezi exact unde calculul deviază față de ce așteptai. Debugging-ul nu e magie: e metodă aplicată pas cu pas, până găsești locul exact unde logica ta și realitatea se despart.
Cele trei tipuri de erori
1. Erori de compilare (Compile Error)
Compilatorul refuză să construiască programul. Cauze frecvente:
int x = 5 // lipseste ;
int y = x + ; // expresie incompleta
if x > 0 { } // lipsesc parantezele de la if
cout << z; // z nedeclaratCe faci: Citești prima eroare din lista compilatorului (nu ultima!), mergi la linia indicată, corectezi.
2. Erori de runtime (Runtime Error)
Programul compilează, dar se oprește cu eroare în timpul rulării:
int a[10];
a[15] = 5; // acces in afara vectorului -- crash
int x = 0;
int y = 5 / x; // impartire la zero -- crashCe faci: Citești mesajul de eroare (segfault, division by zero etc.), identifici linia, verifici condițiile de margine.
3. Erori logice (Wrong Answer)
Programul rulează complet, dar răspunsul e greșit. Cel mai greu tip de depanat.
Ce faci: Urmărire manuală pe un exemplu mic, debug cu cerr pentru a vedea valorile la fiecare pas.
Rezolvă erorile în ordine: mai întâi compile errors (blocante — programul nici nu pornește), apoi runtime errors (crash), la final logic errors (răspuns greșit). Nu poți vedea erorile logice dacă programul nici nu compilează.
Tehnica debug cu cout
Adaugi cout temporare să vezi valorile intermediare:
int suma = 0;
for (int i = 1; i <= n; i++) {
suma += i * i;
cerr << "i=" << i << " suma=" << suma << "\n"; // debug
}
cout << suma << "\n";Folosește cerr în loc de cout pentru debug: mesajele merg la stderr și nu se amestecă cu ieșirea programului (care trebuie să rămână curată pentru judecător).
Când trimiți la concurs, șterge sau comentează toate liniile de debug. cerr ne-șters nu afectează răspunsul la OJI/ONI (stderr e ignorat), dar e o practică bună să cureți codul.
Checklist de debugging
- Citești primul mesaj de eroare, nu ultimul (compilatorul raportează cascade)
- Testezi cu date mici — n=1, n=2, cazul special n=0
- Adaugi cout-uri după fiecare calcul important pentru a identifica unde deviază valoarea
- Urmărești manual pe hârtie algoritmul cu datele de test ce dă greș
- Verifici limitele — variabilele ies din array? Dai cu modulo la 0?
Exemplu: găsirea unui bug
Programul trebuie să calculeze suma pătratelor de la 1 la n. Dă un rezultat prea mare pentru n=3 (așteptăm 1+4+9=14, primim 15).
int suma = 0;
for (int i = 0; i <= n; i++) { // BUG: i porneste de la 0 in loc de 1
suma += i * i;
cerr << "i=" << i << " suma=" << suma << "\n"; // debug
}
cout << suma << "\n";Debug output pentru n=3:
i=0 suma=0
i=1 suma=1
i=2 suma=5
i=3 suma=14
i=... -- bucla nu s-a terminat inca?Citind output-ul: bucla adaugă și 0*0 = 0 (iterația cu i=0), deci suma finală include un termen în plus față de 1²+2²+3². Corectezi i = 0 → i = 1 și bug-ul dispare.
Greșeala 1: Citești ultima linie din erorile de compilare și pierzi timpul depanând o eroare secundară. Prima eroare o cauzează pe a doua, a treia etc. Rezolvi prima, recompilezi.
Greșeala 2: Lași cout-urile de debug în codul final. La concurs nu afectează răspunsul dacă e cerr, dar e cod murdar. Comentează-le sau șterge-le.
Greșeala 3: Testezi numai cu exemplul din enunț. Exemplul e proiectat să funcționeze. Testează cu cazuri suplimentare: n=0, n=1, n maxim, valori negative.
De reținut în 3 idei:
- 3 tipuri de erori: compilare (detectate de compilator), runtime (crash la execuție), logice (răspuns greșit)
- Debug eficient:
cerrpentru valori intermediare + urmărire manuală pe cazuri mici - Prima eroare din compilator e cea reală — rezolv-o, restul pot dispărea