Grafikus C# – Windows Forms tanfolyam › 13.2 lecke

Windows Forms · 13.2 lecke · hibakeresés

Breakpoint, Step Into, Step Over

A logikai hibát nem jelzi semmi: a program lefut, csak rossz az eredmény. A leghatékonyabb módszer az, hogy megállítod a programot egy gyanús ponton, és soronként végignézed, mit csinál. Ezt a Visual Studio hibakeresője (debugger) teszi lehetővé. A MessageBox-os „kiíratásos” hibakeresés lassú és zajos: a töréspont (breakpoint) és a lépésenkénti futtatás percek alatt megmutatja, hol tér el a program a te elképzelésedtől. Ebben a leckében megtanulod a debug módot, a töréspontokat, a lépések fajtáit (F10, F11, Shift+F11), a feltételes töréspontot és a Windows Forms eseménykezelők hibakeresésének sajátosságait.

  • kb. 100 perc
  • közepes szint
  • debugger
Anime stílusú diák hibavadászként keresi a hibát a kódban

A lecke végére

  • debug módban indítod a programot (F5), és megkülönbözteted a Ctrl+F5-től;
  • töréspontot teszel (és kapcsolsz ki), és érted, hogy a program a sor végrehajtása előtt áll meg;
  • helyesen használod a Step Over (F10), Step Into (F11), Step Out (Shift+F11) és Run to Cursor (Ctrl+F10) parancsot;
  • feltételes töréspontot és hitszámlálós töréspontot állítasz be (ciklusokhoz);
  • tracepointtal naplózol megállás nélkül;
  • Windows Forms eseménykezelőkben is hibát keresel.

Mielőtt elkezded

Ehhez a leckéhez a 13.1 lecke (hibafajták) és az 5. fejezet (események) szükséges. A szükséges eszköz a Visual Studio; az itteni billentyűparancsok az alapértelmezett kiosztásra vonatkoznak.

13.1 Fordítási hibák →

Debug mód és töréspont

ParancsBillentyűMit csinál?
Start DebuggingF5Elindítja a programot a hibakeresővel: a töréspontoknál megáll.
Start Without DebuggingCtrl+F5Hibakereső nélkül indít: a töréspontok hatástalanok.
Toggle BreakpointF9Töréspont be/ki a kurzor sorában (vagy kattintás a bal margóra).
ContinueF5 (megállás közben)Folytatja a futást a következő töréspontig.
Stop DebuggingShift+F5Leállítja a programot.
RestartCtrl+Shift+F5Újraindítja debug módban.
Break AllCtrl+Alt+BreakMegállítja a futó (például lefagyott) programot (11.4 lecke).
Form1.csC#
private void btnSzamol_Click(object sender, EventArgs e)
{
int n = int.Parse(txtN.Text);
int osszeg = OsszegEgeszig(n); // ● töréspont ide (F9): a program EZ a sor végrehajtása ELŐTT megáll
lblEredmeny.Text = "Összeg: " + osszeg;
}
A megállás pillanataA piros pont a margón a töréspont. Amikor a futás odaér, a sor sárgával kiemelődik, a program megáll, és a megjelölt sor még nem hajtódott végre. A Visual Studio megnyitja a hibakereső ablakokat (Locals, Watch, Call Stack: 13.3 lecke).
Hol legyen a töréspont?A gyanús rész előtt: ahol a program még jól viselkedik. Onnan lépésenként követed, és figyeled, hol romlik el. Ne az elromlás sorára tedd, hanem előtte néhány sorral.
Debug és ReleaseA Debug konfiguráció hibakereséshez kell (a Visual Studio felső eszköztára). A Release optimalizált, a lépegetés összekuszálódhat, a változók „eltűnhetnek”. Fejlesztéskor Debug.
Fut a program, de nem áll meg?Nem debug módban indítottad (Ctrl+F5), vagy a töréspont halvány/üres: a kód nem azonos a lefordított változattal (Rebuild), vagy a sor nem fut le (ellenőrizd: tényleg meghívódik az eseménykezelő?).

Jósolj!

Töréspontot teszel a int osszeg = OsszegEgeszig(n); sorra, és a program megáll rajta. Mi az osszeg változó értéke ekkor?

Jóslat ellenőrzése

0 (vagy értelmetlen alapérték): a sor még nem hajtódott végre, a változó csak most fog értéket kapni. A töréspont „a sor előtt” áll meg. Lépj egyet (F10), és az érték megjelenik.

Léptetés: Step Over, Step Into, Step Out

ParancsBillentyűMit csinál?Mikor?
Step OverF10Végrehajtja az aktuális sort egyben (a hívott metódust is), és megáll a következő soron.Ha a hívott metódus jó, nem érdekel belül.
Step IntoF11Ha a sor metódust hív, belép a metódusba, és ott áll meg az első soron.Ha a hívott metódust gyanúsítod.
Step OutShift+F11Végrehajtja a metódus hátralévő részét, és a hívóhoz tér vissza.Ha véletlenül belépett, vagy már megtudtad, amit akartál.
Run to CursorCtrl+F10Odáig fut, ahol a kurzor áll (mintha ideiglenes töréspont lenne).Ciklus kihagyására, hosszabb szakasz átugrására.
Form1.csC#
private int OsszegEgeszig(int n)
{
int osszeg = 0; // ← F11-gyel ide lépsz be a hívásból

for (int i = 1; i < n; i++) // F10-zel soronként: figyeld, mikor áll meg a ciklus!
{
osszeg += i; // itt látod: i = 1, 2, 3, ..., n-1: az n már NEM kerül bele
}

return osszeg; // logikai hiba: i < n helyett i <= n kell
}
F10 vagy F11?A szabály: ha feltételezed, hogy a hívott metódus rendben van, F10; ha ott gyanítod a hibát, F11. Kezdd F10-zel, és ha a hívás eredménye hibás, lépj vissza (újraindítás) és F11-gyel nézd meg belülről.
A .NET kódjába nem lép beAz F11 a saját kódodba lép; a .NET keretrendszer metódusaiba (int.Parse, List.Add) nem, mert a Just My Code beállítás átugorja őket. Ez jó így: nem akarod a keretrendszer belsejét nézni.
A sárga nyílA bal margón a sárga nyíl az aktuális sort mutatja (amelyik következik). Áthúzható (Set Next Statement): így átugorhatsz egy sort, vagy visszaléphetsz. Óvatosan: a változók állapota nem áll vissza, az eredmény félrevezető lehet.
Ciklus kihagyásaEgy 1000 lépéses ciklust nem F10-zel lépegetsz végig: a ciklus után tégy töréspontot, vagy használd a Ctrl+F10-et (Run to Cursor), vagy feltételes töréspontot (következő rész).

Jósolj!

A program a osszeg = Atlagol(lista); soron áll. Az Atlagol metódus hibás. Melyik billentyűt nyomod, ha a metódus belsejét szeretnéd megnézni?

Jóslat ellenőrzése

F11 (Step Into): belép az Atlagol metódusba. Az F10 az egész hívást egyben végrehajtaná, és a következő soron állna meg, a belsejét nem látnád.

Haladó töréspontok: feltétel, számláló, tracepoint

Töréspont jobb klikk → Conditions / Actions (vagy a töréspont feletti beállítások)menü
Conditional Expression:   i == 500                  (csak akkor áll meg, ha igaz)
nev == "Anna"
Hit Count: = 100 / >= 50 / multiple of 10
Actions (tracepoint): Log a message: "i = {i}, osszeg = {osszeg}"
[x] Continue execution (naplóz, de NEM áll meg)
Feltételes töréspontA Conditional Expression csak akkor állítja meg a programot, ha a feltétel igaz: i == 500. Egy ezer lépéses ciklusban nem kell 499-szer továbblépned. A kifejezés szintaxisa C#.
Hit CountA találatok számához köti a megállást: a 100. lefutásnál, vagy minden 10.-nél. Hasznos, ha tudod: a hiba „valamikor később” jelentkezik.
TracepointA töréspont nem állítja meg a programot, hanem kiír egy üzenetet az Output ablakba ({változó} behelyettesítéssel). Ez a Console.WriteLine/MessageBox „kiíratásos” hibakeresés kódmódosítás nélkül, és nem kell utólag törölni.
KezelésA Breakpoints ablak (Debug → Windows → Breakpoints) listázza az összeset: ki-be kapcsolhatod, törölheted. Ne maradjanak elfelejtett töréspontok a kód leadása előtt.

Jósolj!

Egy 10 000 elemű ciklus 7342. lépésében romlik el az eredmény. Hogyan jutsz oda a leggyorsabban?

Jóslat ellenőrzése

Feltételes töréspontot teszel a ciklus testére: i == 7342 (vagy hit count: = 7342). A program addig szalad, és pontosan ott áll meg; onnan F10-zel lépegetsz.

Hibakeresés Windows Forms programban

Form1.csC#
// az eseménykezelő a belépési pont: ide tedd a töréspontot, ha a gombnyomás után romlik el valami
private void btnSzamol_Click(object sender, EventArgs e)
{
// ● a gomb megnyomásakor áll meg ITT
string szoveg = txtN.Text;
int n = int.Parse(szoveg);
Szamol(n);
}

// kiíratás az Output ablakba (Debug → Windows → Output): nem zavarja a felületet
System.Diagnostics.Debug.WriteLine("n = " + n); // csak Debug módban fordul bele

// kényszerített megállás a kódból (csak ha a debugger csatlakozik)
if (System.Diagnostics.Debugger.IsAttached) { System.Diagnostics.Debugger.Break(); }
Megállt a program: lefagy az ablak?Amíg a program a töréspontnál áll, a futó ablak „megfagy” (nem válaszol): ez normális, a debugger tartja. A F5 (Continue) folytatja. Ne gondold elromlottnak.
Melyik eseménykezelőbe?Töréspontot a gombhoz tartozó kezelőbe tegyél, nem a Designer.cs-be. Ha nem tudod, melyik esemény fut, tégy töréspontot több kezelőbe: az áll meg, amelyik valóban lefut (és kiderül, melyik nem hívódik: például nincs bekötve).
Debug.WriteLineA Debug.WriteLine az Output ablakba ír, és csak Debug fordításban él: Release-ben eltűnik. Kényelmes folyamatos naplózáshoz (13.7 lecke), tracepoint helyett is jó, ha kódba szánod.
Edit and ContinueMegállított programban sokszor módosíthatod a kódot, és a futás folytatódik az új kóddal (Edit and Continue). Korlátai vannak (nem minden módosítás engedett: új metódus, típus-módosítások): ha nem megy, állítsd le, módosítsd, indítsd újra.

Jósolj!

Töréspontot teszel a btnSzamol_Click első sorára, a programot elindítod, de a gombra kattintva nem áll meg. Mi lehet az ok?

Jóslat ellenőrzése

Három gyakori ok: (1) a gomb Click eseménye nincs bekötve ehhez a kezelőhöz (Properties → Events); (2) Ctrl+F5-tel indítottad; (3) a töréspont üres/halvány (nem azonos a futó kód: Rebuild). A töréspont, amely „nem áll meg”, maga is információ: a kód nem fut le.

📷 Képernyőkép helye

Mit tegyél ide: a Visual Studio megállított programja: a sárga sor, a piros töréspont, a Locals ablak és a Step gombok az eszköztáron.Javasolt fájlnév: winforms-13-2-debug.webp · Alt szöveg: A Visual Studio debug nézete

Hibakeresés: te vagy a hibadetektív

Mi a baj, és hogyan javítod?

Gondold végig az okot, és csak utána nyisd le a megoldást.

1. A töréspont nem működik

Piros pont van, de a program nem áll meg.

Ok és javítás

Ellenőrizd: F5-tel indítottad-e (nem Ctrl+F5), Debug konfiguráció-e, és a sor lefut-e (a kezelő be van-e kötve). Üres pont: Rebuild.

2. Túl sok F10

Egy 5000 elemű ciklust lépegetsz, és percek telnek el.

Ok és javítás

Használj feltételes töréspontot (i == 4999), hit countot, vagy Ctrl+F10 (Run to Cursor) a ciklus utáni sorra.

3. Belépett, ahová nem akartál

Az F11 egy másik, ismeretlen metódusba vitt.

Ok és javítás

Shift+F11 (Step Out) visszavisz a hívóhoz. Máskor F10, ha a hívott metódus nem gyanús.

4. A töréspont a hibás sor után van

A hibás sor már lefutott, mire megáll a program.

Ok és javítás

Tedd a töréspontot a gyanús rész elé, ahol még minden rendben van, és onnan lépkedj.

5. Eltűnt a változó értéke

A hibakereső „optimalizálva” üzenetet ad a változóra.

Ok és javítás

Release konfigurációban dolgozol. Válts Debug konfigurációra, és építsd újra.

6. A felület lefagyott a megálláskor

A program ablaka nem reagál, miközben a töréspontnál állsz.

Ok és javítás

Ez normális: a program meg van állítva. F5 folytatja, Shift+F5 leállítja.

Mini projekt: nyomozó-labor

Kapsz négy metódust, mindegyikben egy logikai hiba van (a program lefut, de rossz az eredmény). Töréspont és léptetés segítségével találd meg és javítsd a hibákat:

  1. Új projekt: Windows Forms (Nyomozo), a Form1 legyen txtBemenet, négy gomb (btnOsszeg, btnJegy, btnLegnagyobb, btnAtlag) és lblEredmeny.
  2. Másold be a hibás metódusokat (lent), és kösd be a gombokat: a btnOsszeg az OsszegEgeszigt hívja (txtBemenet egész szám), a btnJegy a Jegy-et (pontszám), a btnLegnagyobb a Legnagyobb-at (számok szóközzel elválasztva), a btnAtlag az Atlag-ot (szintén).
  3. Hipotézis: minden hibához először írd le, mit vársz (például OsszegEgeszig(5) = 15), és mit ad a program.
  4. Töréspont és léptetés: tegyél töréspontot a hívásra, F11-gyel lépj a metódusba, F10-zel soronként haladj; jegyezd fel, melyik sornál tér el a valóság a várakozásodtól, és mit mutat a változó (a Locals ablakot a 13.3 leckében részletezzük, itt az egérmutatóval olvasd le az értéket).
  5. Feltételes töréspont: az OsszegEgeszig(1000) esetén egy feltételes töréspontot (i == 999) használj; a Jegy hibájánál töréspont az adott else if sorra.
  6. Tracepoint: az Atlag ciklusában (osszeg += x) állíts be tracepointot (x = {x}, osszeg = {osszeg}), és olvasd le az Output ablakból a menetet megállás nélkül.
  7. Javítás és ellenőrzés: javítsd a négy hibát, és ellenőrizd az előre felírt példákkal (táblázat: bemenet, várt, kapott).
  8. Nyomozónapló: minden hibához: tünet, hol álltam meg, mit láttam, mi az ok, javítás.
A hibás metódusok (próbáld ki előbb önállóan!)
Form1.cs (HIBÁS metódusok)C#
// 1. 1-től n-ig összeadja a számokat
private int OsszegEgeszig(int n)
{
int osszeg = 0;

for (int i = 1; i < n; i++) { osszeg += i; }

return osszeg;
}

// 2. osztályzat pontszámból: 0-49: 1, 50-64: 2, 65-79: 3, 80-89: 4, 90-100: 5
private string Jegy(int pont)
{
if (pont >= 50) { return "2"; }
else if (pont >= 65) { return "3"; }
else if (pont >= 80) { return "4"; }
else if (pont >= 90) { return "5"; }

return "1";
}

// 3. a legnagyobb szám a tömbben
private int Legnagyobb(int[] tomb)
{
int max = 0;

foreach (int x in tomb) { if (x > max) { max = x; } }

return max;
}

// 4. átlag
private double Atlag(List<int> lista)
{
int osszeg = 0;

foreach (int x in lista) { osszeg += x; }

return osszeg / lista.Count;
}

Tippek (ha elakadsz): az 1. hiba a ciklus határa; a 2. a feltételek sorrendje (az első feltétel minden 50 fölöttit elkap); a 3. a kezdőérték (csupa negatív számnál); a 4. az egész osztás (és üres lista esetén DivideByZeroException).

A javított metódusok
Form1.cs (JAVÍTVA)C#
// 1. a ciklus határa: i <= n
private int OsszegEgeszig(int n)
{
int osszeg = 0;

for (int i = 1; i <= n; i++) { osszeg += i; }

return osszeg;
}

// 2. a legnagyobb küszöbbel kezdjük (vagy fordított sorrend)
private string Jegy(int pont)
{
if (pont >= 90) { return "5"; }
else if (pont >= 80) { return "4"; }
else if (pont >= 65) { return "3"; }
else if (pont >= 50) { return "2"; }

return "1";
}

// 3. a kezdőérték az első elem; üres tömbre kivétel
private int Legnagyobb(int[] tomb)
{
if (tomb == null || tomb.Length == 0) { throw new ArgumentException("A tömb nem lehet üres."); }

int max = tomb[0];

foreach (int x in tomb) { if (x > max) { max = x; } }

return max;
}

// 4. valós osztás, üres lista védelme
private double Atlag(List<int> lista)
{
if (lista.Count == 0) { throw new ArgumentException("Üres listának nincs átlaga."); }

int osszeg = 0;

foreach (int x in lista) { osszeg += x; }

return (double)osszeg / lista.Count;
}
📷 Képernyőkép helye

Mit tegyél ide: a nyomozónapló egy sora és a debug nézet a Jegy metódus else if során.Javasolt fájlnév: winforms-13-2-nyomozo.webp · Alt szöveg: A nyomozó-labor

Három önálló gyakorlófeladat

Egyszerre csak egyet csinálj: tervezd meg, írd meg, futtasd, ellenőrizd, és csak utána nyisd ki a megoldást.

1. Tracepoint-napló

Egy ciklus 100-szor fut. Naplózd minden 10. lépés értékeit a kód módosítása nélkül.

Egy lehetséges megoldás

Tracepoint a ciklus testén: Hit Count: multiple of 10, Log a message: i = {i}, osszeg = {osszeg}, Continue execution bejelölve. Az eredmény az Output ablakban.

2. Hol hibás?

Egy program három metódust hív egymás után; a végeredmény rossz. Hogyan találod meg a hibásat kevés lépésből?

Egy lehetséges megoldás

Felezős keresés: töréspont a második metódus hívása elé; a bemenete helyes? Ha igen, a hiba a második vagy harmadik; ha nem, az első. Mindig a „még helyes” és a „már hibás” pont közé teszel töréspontot.

3. Saját hiba

Szúrj be egy logikai hibát egy korábbi programodba, és kérd meg valakit, hogy debuggerrel keresse meg.

Egy lehetséges megoldás

Jó, ha a hiba ritka feltételnél jelentkezik (negatív szám, üres lista, határérték), így a keresőnek feltételes töréspontra vagy tesztadat-gondolkodásra van szüksége.

Gyakorlótár: 6 további feladat

Három szinten gyakorolhatsz: alap, közepes és kihívás. Csak a próbálkozás után nyisd le a megoldást.

Alap szint

1. F5 vagy Ctrl+F5?

Melyik áll meg a töréspontnál?

Megoldás megnyitása

Az F5 (debug módban indít); a Ctrl+F5 hibakereső nélkül.

2. Mikor áll meg?

A sor előtt vagy után áll meg a program a töréspontnál?

Megoldás megnyitása

A sor előtt: a megjelölt sor még nem hajtódott végre.

Közepes szint

3. F10 vagy F11?

Mikor melyiket?

Megoldás megnyitása

F10: ha a hívott metódust nem gyanítod; F11: ha belül akarsz nézni. Shift+F11: kilépés a metódusból.

4. Töréspont ciklusban

Hogyan állítod meg a programot a ciklus 250. lépésén?

Megoldás megnyitása

Feltételes töréspont (i == 249), vagy Hit Count (= 250).

Kihívás szint

5. Tracepoint vagy MessageBox?

Miért jobb a tracepoint?

Megoldás megnyitása

Nem módosítja a kódot (nem kell utólag törölni), nem zavarja a felületet, nem állítja meg a programot, és sok adatot gyűjt.

6. A debug mellékhatása

Miért viselkedhet másképp a program debuggerrel, mint nélküle?

Megoldás megnyitása

Az időzítés megváltozik (megállás közben telik az idő: időzítők, időtúllépések), és a Debug és Release fordítás különbözik. Időfüggő hibákat naplózással (13.7 lecke) érdemes keresni.

Gyors önellenőrzés

Válaszolj fejben, és csak utána nyisd le a választ.

1. Mi a töréspont?

Egy sor, ahol a program megáll a futás közben, hogy megvizsgálhasd.

2. Mi a Step Over?

Végrehajtja a sort (a hívott metódust is) egyben, és a következőn áll meg (F10).

3. Mi a Step Into?

Belép a hívott metódusba (F11).

4. Mi a Step Out?

Kilép a metódusból a hívóhoz (Shift+F11).

5. Mire jó a feltételes töréspont?

Csak adott feltételnél áll meg (például egy ciklus egy adott lépésén).

6. Mi a tracepoint?

Töréspont, amely megállás nélkül üzenetet naplóz az Output ablakba.

7. Hol legyen a töréspont?

A gyanús rész előtt, ahol még minden rendben van.

Mit tudsz már?

  • Debug módban indítasz, és töréspontot teszel a megfelelő helyre.
  • Helyesen választod a Step Over, Step Into és Step Out parancsot.
  • Feltételes töréspontot és tracepointot használsz.
  • Windows Forms eseménykezelőkben is lépésenként követed a futást.

Következő lecke: Locals, Watch és Call Stack

A megállított program belsejének vizsgálata: a változók értékei, saját kifejezések figyelése és a hívási lánc.