Pętle w C#

Pętle to struktury programistyczne, które pozwalają na wielokrotne wykonywanie tego samego bloku kodu. Dzięki nim możemy uniknąć powtarzania kodu i efektywnie przetwarzać duże zbiory danych.

Po co nam pętle?

Wyobraź sobie, że chcesz wyświetlić liczby od 1 do 100:

// Bez pętli - bardzo nieefektywne!
Console.WriteLine(1);
Console.WriteLine(2);
Console.WriteLine(3);
// ... i tak dalej do 100 - to byłoby 100 linijek kodu!

Z pętlą możesz to zrobić w kilku liniach:

// Z pętlą - elegancko i efektywnie!
for (int i = 1; i <= 100; i++)
{
    Console.WriteLine(i);
}

Podstawowe pojęcia

  • Iteracja – jedno przejście przez pętlę
  • Warunek pętli – określa, kiedy pętla ma się wykonywać
  • Licznik pętli – zmienna śledząca liczbę iteracji
  • Ciało pętli – kod wykonywany w każdej iteracji

Pętla while – „dopóki”

Pętla while to najprostsza forma pętli. Wykonuje kod dopóki warunek jest prawdziwy.

Składnia pętli while

while (warunek)
{
    // kod do wykonania
    // pamiętaj o zmianie warunku!
}

Jak działa pętla while – krok po kroku

int licznik = 1;

while (licznik <= 5)
{
    Console.WriteLine($"Iteracja numer: {licznik}");
    licznik++; // BARDZO WAŻNE - zwiększ licznik!
}

Console.WriteLine("Koniec pętli");

Przebieg wykonania:

  1. Sprawdź warunek: licznik <= 51 <= 5true
  2. Wykonaj ciało pętli: wyświetl „Iteracja numer: 1”
  3. Zwiększ licznik: licznik++licznik = 2
  4. Sprawdź warunek: 2 <= 5true
  5. Wykonaj ciało pętli: wyświetl „Iteracja numer: 2”
  6. …kontynuuj aż licznik = 6
  7. Sprawdź warunek: 6 <= 5false
  8. Wyjdź z pętli i kontynuuj program

Praktyczne przykłady pętli while

Przykład 1: Odliczanie

int odliczanie = 10;

Console.WriteLine("Start odliczania:");
while (odliczanie > 0)
{
    Console.WriteLine(odliczanie);
    odliczanie--;
}
Console.WriteLine("ZERO! Koniec odliczania!");

// Wynik: 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, ZERO!

Przykład 2: Pobieranie danych od użytkownika

string odpowiedz = "";

Console.WriteLine("Zgaduję Twoją ulubioną liczbę!");

while (odpowiedz != "tak")
{
    Console.Write("Czy Twoja ulubiona liczba to 42? (tak/nie): ");
    odpowiedz = Console.ReadLine().ToLower();
    
    if (odpowiedz == "nie")
    {
        Console.WriteLine("Hmm, spróbuję jeszcze raz...");
    }
    else if (odpowiedz != "tak")
    {
        Console.WriteLine("Proszę odpowiedz 'tak' lub 'nie'");
    }
}

Console.WriteLine("Wiedziałem! 42 to odpowiedź na wszystko!");

Przykład 3: Sumowanie liczb

int suma = 0;
int liczba = 1;

while (liczba <= 10)
{
    suma = suma + liczba;  // lub: suma += liczba;
    Console.WriteLine($"Dodaję {liczba}, suma = {suma}");
    liczba++;
}

Console.WriteLine($"Końcowa suma liczb 1-10: {suma}");
// Wynik: 55

Ważne ostrzeżenie – pętla nieskończona!

int i = 1;

while (i <= 5)
{
    Console.WriteLine($"To jest iteracja {i}");
    // BŁĄD! Brak zwiększenia i - pętla nigdy się nie skończy!
}

// POPRAWKA:
int j = 1;
while (j <= 5)
{
    Console.WriteLine($"To jest iteracja {j}");
    j++; // Zwiększenie licznika - KLUCZOWE!
}

Pętla do-while – „wykonaj, a potem sprawdź”

Pętla do-while to odmiana pętli while, która zawsze wykonuje się przynajmniej raz, bo warunek sprawdzany jest na końcu.

Składnia pętli do-while

do
{
    // kod do wykonania
} while (warunek);

Różnica między while a do-while

// Pętla while - może się wcale nie wykonać
int a = 10;
while (a < 5)  // Warunek od razu false
{
    Console.WriteLine("To się nie wykona");
}

// Pętla do-while - wykona się przynajmniej raz
int b = 10;
do
{
    Console.WriteLine("To się wykona raz, mimo że warunek jest false");
} while (b < 5);  // Warunek sprawdzany na końcu

Praktyczne przykłady do-while

Przykład 1: Menu programu

string wybor;

do
{
    Console.WriteLine("\n=== MENU GŁÓWNE ===");
    Console.WriteLine("1. Opcja pierwsza");
    Console.WriteLine("2. Opcja druga");
    Console.WriteLine("3. Opcja trzecia");
    Console.WriteLine("0. Wyjście");
    Console.Write("Twój wybór: ");
    
    wybor = Console.ReadLine();
    
    switch (wybor)
    {
        case "1":
            Console.WriteLine("Wybrałeś opcję 1");
            break;
        case "2":
            Console.WriteLine("Wybrałeś opcję 2");
            break;
        case "3":
            Console.WriteLine("Wybrałeś opcję 3");
            break;
        case "0":
            Console.WriteLine("Do widzenia!");
            break;
        default:
            Console.WriteLine("Nieprawidłowy wybór, spróbuj ponownie.");
            break;
    }
    
} while (wybor != "0");

Przykład 2: Walidacja danych

int wiek;
bool poprawnyWiek;

do
{
    Console.Write("Podaj swój wiek (1-120): ");
    string input = Console.ReadLine();
    
    poprawnyWiek = int.TryParse(input, out wiek) && wiek >= 1 && wiek <= 120;
    
    if (!poprawnyWiek)
    {
        Console.WriteLine("Nieprawidłowy wiek! Spróbuj ponownie.");
    }
    
} while (!poprawnyWiek);

Console.WriteLine($"Twój wiek: {wiek} lat");

Przykład 3: Gra w zgadywanie liczby

Random random = new Random();
int sekretnaLiczba = random.Next(1, 11); // 1-10
int proba;
int liczbaProb = 0;

Console.WriteLine("Zgadnij liczbę od 1 do 10!");

do
{
    liczbaProb++;
    Console.Write($"Próba {liczbaProb}: ");
    
    while (!int.TryParse(Console.ReadLine(), out proba) || proba < 1 || proba > 10)
    {
        Console.Write("Podaj liczbę od 1 do 10: ");
    }
    
    if (proba < sekretnaLiczba)
    {
        Console.WriteLine("Za mało!");
    }
    else if (proba > sekretnaLiczba)
    {
        Console.WriteLine("Za dużo!");
    }
    else
    {
        Console.WriteLine($"Brawo! Zgadłeś w {liczbaProb} próbach!");
    }
    
} while (proba != sekretnaLiczba);

Pętla for – „od-do z krokiem”

Pętla for to najbardziej strukturalna forma pętli. Idealnie nadaje się gdy z góry wiesz ile razy pętla ma się wykonać.

Składnia pętli for

for (inicjalizacja; warunek; aktualizacja)
{
    // kod do wykonania
}

Anatomia pętli for

for (int i = 1; i <= 5; i++)
{
    Console.WriteLine($"i = {i}");
}

//   │    │      │     │
//   │    │      │     └── Aktualizacja (po każdej iteracji)
//   │    │      └──────── Warunek (sprawdzany przed każdą iteracją)  
//   │    └─────────────── Inicjalizacja (wykonana raz na początku)
//   └──────────────────── Typ i nazwa zmiennej licznika

Jak działa pętla for – szczegółowo

for (int i = 0; i < 3; i++)
{
    Console.WriteLine($"Wartość i: {i}");
}

Krok po kroku:

  1. Inicjalizacja: int i = 0 (wykonane raz na początku)
  2. Sprawdzenie warunku: i < 30 < 3true
  3. Wykonanie ciała: wyświetl „Wartość i: 0”
  4. Aktualizacja: i++i = 1
  5. Sprawdzenie warunku: i < 31 < 3true
  6. Wykonanie ciała: wyświetl „Wartość i: 1”
  7. Aktualizacja: i++i = 2
  8. Sprawdzenie warunku: i < 32 < 3true
  9. Wykonanie ciała: wyświetl „Wartość i: 2”
  10. Aktualizacja: i++i = 3
  11. Sprawdzenie warunku: i < 33 < 3false
  12. Wyjście z pętli

Różne warianty pętli for

1. Klasyczna pętla rosnąca

// Liczby od 1 do 10
for (int i = 1; i <= 10; i++)
{
    Console.Write(i + " ");
}
// Wynik: 1 2 3 4 5 6 7 8 9 10

2. Pętla malejąca

// Odliczanie od 10 do 1
for (int i = 10; i >= 1; i--)
{
    Console.Write(i + " ");
}
// Wynik: 10 9 8 7 6 5 4 3 2 1

3. Pętla z krokiem innym niż 1

// Co druga liczba
for (int i = 0; i <= 20; i += 2)
{
    Console.Write(i + " ");
}
// Wynik: 0 2 4 6 8 10 12 14 16 18 20

// Co trzecia liczba wstecz
for (int i = 30; i >= 0; i -= 3)
{
    Console.Write(i + " ");
}
// Wynik: 30 27 24 21 18 15 12 9 6 3 0

4. Zagnieżdżone pętle for

Console.WriteLine("Tabela mnożenia 3x3:");

for (int wiersz = 1; wiersz <= 3; wiersz++)
{
    for (int kolumna = 1; kolumna <= 3; kolumna++)
    {
        int wynik = wiersz * kolumna;
        Console.Write($"{wynik}\t"); // \t to tabulator
    }
    Console.WriteLine(); // Nowa linia po każdym wierszu
}

/* Wynik:
1    2    3
2    4    6
3    6    9
*/

Przykład 1: Kalkulator silnia

Console.Write("Podaj liczbę do obliczenia silni");
int n = int.Parse(Console.ReadLine());

long faktorial = 1;

for (int i = 1; i <= n; i++)
{
    faktorial *= i;
    Console.WriteLine($"{i}! = {faktorial}");
}

Console.WriteLine($"Końcowy wynik: {n}! = {faktorial}");

// Dla n=5: 5! = 1×2×3×4×5 = 120

Przykład 2: Rysowanie wzorów

Console.Write("Podaj wysokość trójkąta: ");
int wysokosc = int.Parse(Console.ReadLine());

Console.WriteLine("Trójkąt z gwiazdek:");

for (int i = 1; i <= wysokosc; i++)
{
    // Wyświetl spacje (dla centrowania)
    for (int spacje = 1; spacje <= wysokosc - i; spacje++)
    {
        Console.Write(" ");
    }
    
    // Wyświetl gwiazdki
    for (int gwiazdki = 1; gwiazdki <= i; gwiazdki++)
    {
        Console.Write("* ");
    }
    
    Console.WriteLine(); // Nowa linia
}

/* Dla wysokości 4:
   * 
  * * 
 * * * 
* * * * 
*/

Pętla foreach – „dla każdego elementu”

Pętla foreach to specjalna forma pętli przeznaczona do iterowania przez kolekcje (tablice, listy). Jest najwygodniejsza gdy chcemy przejrzeć wszystkie elementy bez potrzeby znania indeksów.

Składnia pętli foreach

foreach (typ nazwaZmiennej in kolekcja)
{
    // kod używający nazwaZmiennej
}

Podstawowe przykłady foreach

Iterowanie przez tablicę liczb

int[] liczby = {10, 20, 30, 40, 50};

// Sposób tradycyjny z for
Console.WriteLine("Używając for:");
for (int i = 0; i < liczby.Length; i++)
{
    Console.WriteLine($"Liczba: {liczby[i]}");
}

// Sposób z foreach - prostszy!
Console.WriteLine("Używając foreach:");
foreach (int liczba in liczby)
{
    Console.WriteLine($"Liczba: {liczba}");
}

Iterowanie przez tablicę stringów

string[] owoce = {"jabłko", "banan", "pomarańcza", "kiwi", "mango"};

Console.WriteLine("Lista owoców:");
foreach (string owoc in owoce)
{
    Console.WriteLine($"- {owoc}");
}

// Możemy też użyć var - kompilator automatycznie rozpozna typ
foreach (var owoc in owoce)
{
    Console.WriteLine($"Owoc: {owoc}, długość nazwy: {owoc.Length}");
}

Zalety i ograniczenia foreach

Zalety:

  • Prostota – nie musisz zarządzać indeksami
  • Bezpieczeństwo – nie ma ryzyka wyjścia poza zakres tablicy
  • Czytelność – kod jest bardziej zrozumiały

Ograniczenia:

  • Brak dostępu do indeksu – nie wiesz na której pozycji jesteś
  • Tylko do odczytu – nie możesz modyfikować elementów tablicy
  • Tylko do przodu – nie możesz iterować wstecz
int[] liczby = {1, 2, 3, 4, 5};

foreach (int liczba in liczby)
{
    Console.WriteLine(liczba);
    
    // BŁĄD! Nie możesz modyfikować elementu w foreach
    // liczba = liczba * 2;  // To zmieni tylko lokalną kopię
}

// Jeśli chcesz modyfikować, użyj for:
for (int i = 0; i < liczby.Length; i++)
{
    liczby[i] = liczby[i] * 2; // To zmieni element w tablicy
}

Praktyczne przykłady foreach

Przykład 1: Analiza tekstów

string[] zdania = {
    "To jest pierwsze zdanie.",
    "Drugie zdanie jest dłuższe niż pierwsze.",
    "Trzecie.",
    "Ostatnie zdanie kończy nasz przykład."
};

Console.WriteLine("Analiza zdań:");

int numerZdania = 1;
int calkowitaLiczbaSlów = 0;

foreach (string zdanie in zdania)
{
    string[] slowa = zdanie.Split(' ', '.', ',', '!', '?');
    int liczbaSlowWZdaniu = 0;
    
    foreach (string slowo in slowa)
    {
        if (!string.IsNullOrEmpty(slowo))
        {
            liczbaSlowWZdaniu++;
        }
    }
    
    Console.WriteLine($"Zdanie {numerZdania}: {liczbaSlowWZdaniu} słów");
    calkowitaLiczbaSlów += liczbaSlowWZdaniu;
    numerZdania++;
}

Console.WriteLine($"Łącznie słów: {calkowitaLiczbaSlów}");
double srednia = calkowitaLiczbaSlów / (double)zdania.Length;
Console.WriteLine($"Średnia słów na zdanie: {srednia:F1}");

Przykład 2: Przetwarzanie danych uczniów

string[] uczniowie = {"Anna Kowalska", "Piotr Nowak", "Maria Wiśniewska", "Jan Kowalski"};
int[] oceny = {4, 5, 3, 4};

Console.WriteLine("Lista uczniów z ocenami:");

int indeks = 0;
foreach (string uczen in uczniowie)
{
    string[] imieNazwisko = uczen.Split(' ');
    string imie = imieNazwisko[0];
    string nazwisko = imieNazwisko[1];
    int ocena = oceny[indeks];
    
    string komentarz = ocena switch
    {
        5 => "Bardzo dobrze!",
        4 => "Dobrze",
        3 => "Dostatecznie",
        2 => "Słabo",
        1 => "Bardzo słabo",
        _ => "Nieznana ocena"
    };
    
    Console.WriteLine($"{imie} {nazwisko}: {ocena} - {komentarz}");
    indeks++;
}

Przykład 3: Walidacja danych

string[] adresy = {
    "anna@email.com",
    "piotr@firma.pl", 
    "nieprawidlowy-email",
    "maria@test.org",
    "jan.kowalski@example.com"
};

Console.WriteLine("Sprawdzanie poprawności adresów email:");

int prawidlowe = 0;
int nieprawidlowe = 0;

foreach (string adres in adresy)
{
    // Prosta walidacja - sprawdza czy zawiera @ i .
    bool czyPoprawny = adres.Contains("@") && 
                      adres.Contains(".") && 
                      adres.IndexOf("@") < adres.LastIndexOf(".");
    
    if (czyPoprawny)
    {
        Console.WriteLine($"✓ {adres} - poprawny");
        prawidlowe++;
    }
    else
    {
        Console.WriteLine($"✗ {adres} - niepoprawny");
        nieprawidlowe++;
    }
}

Console.WriteLine($"\nPodsumowanie: {prawidlowe} poprawnych, {nieprawidlowe} niepoprawnych");

Porównanie wszystkich rodzajów pętli

Kiedy użyć której pętli?

Rodzaj pętliKiedy używaćPrzykład zastosowania
whileGdy nie wiesz ile razy pętla się wykonaPobieranie danych od użytkownika do momentu podania prawidłowej wartości
do-whileGdy pętla musi wykonać się przynajmniej razMenu programu, walidacja danych
forGdy z góry wiesz ile iteracjiIterowanie przez tablicę po indeksach, liczenie od 1 do N
foreachGdy chcesz przejść przez wszystkie elementy kolekcjiWyświetlanie zawartości tablicy, przetwarzanie listy

Praktyczne porównanie – to samo zadanie różnymi pętlami

Zadanie: Wyświetl wszystkie elementy tablicy z numerami pozycji.

string[] kolory = {"czerwony", "zielony", "niebieski", "żółty"};

// 1. PĘTLA FOR - najlepsza do tego zadania
Console.WriteLine("Używając for:");
for (int i = 0; i < kolory.Length; i++)
{
    Console.WriteLine($"{i + 1}. {kolory[i]}");
}

// 2. PĘTLA WHILE - możliwa, ale bardziej skomplikowana  
Console.WriteLine("\nUżywając while:");
int indeks = 0;
while (indeks < kolory.Length)
{
    Console.WriteLine($"{indeks + 1}. {kolory[indeks]}");
    indeks++;
}

// 3. PĘTLA FOREACH - prosta, ale bez numerów pozycji
Console.WriteLine("\nUżywając foreach:");
int licznik = 1;
foreach (string kolor in kolory)
{
    Console.WriteLine($"{licznik}. {kolor}");
    licznik++;
}

Kontrola przepływu pętli

Czasami w trakcie wykonywania pętli chcemy zmienić naturalny przepływ – przerwać pętlę wcześniej lub pominąć część iteracji. Do tego służą instrukcje break i continue.

Instrukcja break – „przerwij pętlę”

Instrukcja break natychmiast kończy wykonywanie pętli i przechodzi do pierwszej instrukcji za pętlą.

Do czego służy break:

  • Przedwczesne zakończenie pętli gdy znajdziemy to czego szukamy
  • Wyjście z pętli gdy nastąpi błąd lub nietypowa sytuacja
  • Optymalizacja – nie ma sensu kontynuować gdy zadanie zostało wykonane

Jak działa break – wizualizacja

for (int i = 1; i <= 10; i++)
{
    Console.WriteLine($"Iteracja: {i}");
    
    if (i == 5)
    {
        Console.WriteLine("Przerywam pętlę!");
        break; // Koniec pętli - przeskoczy do instrukcji za pętlą
    }
    
    Console.WriteLine("Koniec iteracji");
}

Console.WriteLine("To się wykona po break");

Przebieg wykonania:

  • Iteracja 1: wyświetla „Iteracja: 1”, potem „Koniec iteracji”
  • Iteracja 2: wyświetla „Iteracja: 2”, potem „Koniec iteracji”
  • Iteracja 3: wyświetla „Iteracja: 3”, potem „Koniec iteracji”
  • Iteracja 4: wyświetla „Iteracja: 4”, potem „Koniec iteracji”
  • Iteracja 5: wyświetla „Iteracja: 5”, potem „Przerywam pętlę!”, break kończy pętlę
  • Wyświetla „To się wykona po break”

Praktyczne przykłady break

Przykład 1: Wyszukiwanie pierwszego wystąpienia

Console.WriteLine("Szukam pierwszej liczby większej od 50:");

int[] liczby = {10, 25, 35, 60, 45, 80, 15};
int pozycja = -1;

for (int i = 0; i < liczby.Length; i++)
{
    Console.WriteLine($"Sprawdzam pozycję {i}: {liczby[i]}");
    
    if (liczby[i] > 50)
    {
        Console.WriteLine($"Znaleziono! Pierwsza liczba > 50 to: {liczby[i]} na pozycji {i}");
        pozycja = i;
        break; // Nie szukamy dalej - znaleźliśmy pierwszą
    }
}

if (pozycja == -1)
{
    Console.WriteLine("Nie znaleziono liczby większej od 50");
}

Console.WriteLine("Koniec wyszukiwania");

Przykład 2: Walidacja hasła z przerwaniem

Console.WriteLine("Sprawdzanie czy hasło zawiera cyfry:");
string haslo = "MyPassword123";
bool zawieraCyfre = false;

foreach (char znak in haslo)
{
    Console.WriteLine($"Sprawdzam znak: '{znak}'");
    
    if (char.IsDigit(znak))
    {
        Console.WriteLine($"Znaleziono cyfrę: {znak}");
        zawieraCyfre = true;
        break; // Nie sprawdzamy dalszych znaków
    }
}

Console.WriteLine($"Hasło zawiera cyfry: {zawieraCyfre}");

Przykład 3: Menu z wyjściem

while (true) // Pętla nieskończona
{
    Console.WriteLine("\n=== MENU ===");
    Console.WriteLine("1. Opcja A");
    Console.WriteLine("2. Opcja B");
    Console.WriteLine("0. Wyjście");
    Console.Write("Wybór: ");
    
    string wybor = Console.ReadLine();
    
    switch (wybor)
    {
        case "1":
            Console.WriteLine("Wybrałeś opcję A");
            break; // break tylko z switch, nie z pętli while!
        case "2":
            Console.WriteLine("Wybrałeś opcję B");
            break; // break tylko z switch, nie z pętli while!
        case "0":
            Console.WriteLine("Do widzenia!");
            return; // Lub można użyć break dla całej pętli while
        default:
            Console.WriteLine("Nieprawidłowy wybór");
            break; // break tylko z switch, nie z pętli while!
    }
}

Instrukcja continue – „pomiń resztę iteracji”

Instrukcja continue pomija pozostałą część bieżącej iteracji i przechodzi bezpośrednio do następnej iteracji pętli.

Do czego służy continue:

  • Pomijanie niepożądanych wartości bez przerywania całej pętli
  • Filtrowanie danych w trakcie przetwarzania
  • Upraszczanie logiki – zamiast zagnieżdżonych if-ów

Jak działa continue – wizualizacja

for (int i = 1; i <= 6; i++)
{
    Console.WriteLine($"Początek iteracji {i}");
    
    if (i == 3 || i == 5)
    {
        Console.WriteLine($"Pomijam iterację {i}");
        continue; // Przeskoczy do następnej iteracji (i++)
    }
    
    Console.WriteLine($"Przetwarzam liczbę: {i}");
    Console.WriteLine($"Koniec iteracji {i}");
}

Console.WriteLine("Koniec pętli");

Przebieg wykonania:

  • i=1: „Początek iteracji 1”, „Przetwarzam liczbę: 1”, „Koniec iteracji 1”
  • i=2: „Początek iteracji 2”, „Przetwarzam liczbę: 2”, „Koniec iteracji 2”
  • i=3: „Początek iteracji 3”, „Pomijam iterację 3”, continue (pomija resztę)
  • i=4: „Początek iteracji 4”, „Przetwarzam liczbę: 4”, „Koniec iteracji 4”
  • i=5: „Początek iteracji 5”, „Pomijam iterację 5”, continue (pomija resztę)
  • i=6: „Początek iteracji 6”, „Przetwarzam liczbę: 6”, „Koniec iteracji 6”
  • „Koniec pętli”

Praktyczne przykłady continue

Przykład 1: Filtrowanie liczb parzystych

Console.WriteLine("Liczby nieparzyste od 1 do 10:");

for (int i = 1; i <= 10; i++)
{
    if (i % 2 == 0) // Jeśli liczba parzysta
    {
        continue; // Pomiń - nie wyświetlaj liczb parzystych
    }
    
    Console.WriteLine(i); // To się wykona tylko dla liczb nieparzystych
}

// Wynik: 1, 3, 5, 7, 9

Przykład 2: Przetwarzanie plików z pomijaniem błędnych

string[] nazwyPlikow = {"dokument.txt", "", "raport.pdf", null, "dane.csv", "   "};

Console.WriteLine("Przetwarzanie plików:");

foreach (string nazwa in nazwyPlikow)
{
    // Pomiń puste lub null nazwy
    if (string.IsNullOrWhiteSpace(nazwa))
    {
        Console.WriteLine("Pomijam pusty wpis");
        continue;
    }
    
    // Pomiń pliki PDF (przykładowo)
    if (nazwa.EndsWith(".pdf"))
    {
        Console.WriteLine($"Pomijam plik PDF: {nazwa}");
        continue;
    }
    
    Console.WriteLine($"✓ Przetwarzam plik: {nazwa}");
    
    // Tutaj byłaby logika przetwarzania pliku
    Console.WriteLine($"  - Rozmiar nazwy: {nazwa.Length} znaków");
    Console.WriteLine($"  - Rozszerzenie: {nazwa.Substring(nazwa.LastIndexOf('.') + 1)}");
}

Console.WriteLine("Zakończono przetwarzanie");

Przykład 3: Pomijanie niewłaściwych danych wejściowych

int[] wyniki = {85, -5, 92, 150, 78, -10, 88, 200, 91};

Console.WriteLine("Analiza wyników (pomijam nieprawidłowe wartości):");

int suma = 0;
int liczbaPoprawnych = 0;

foreach (int wynik in wyniki)
{
    // Pomiń wyniki poza zakresem 0-100
    if (wynik < 0 || wynik > 100)
    {
        Console.WriteLine($"⚠️ Pomijam nieprawidłowy wynik: {wynik}");
        continue;
    }
    
    Console.WriteLine($"✓ Prawidłowy wynik: {wynik}");
    suma += wynik;
    liczbaPoprawnych++;
}

if (liczbaPoprawnych > 0)
{
    double srednia = suma / (double)liczbaPoprawnych;
    Console.WriteLine($"\nStatystyki z {liczbaPoprawnych} prawidłowych wyników:");
    Console.WriteLine($"Suma: {suma}");
    Console.WriteLine($"Średnia: {srednia:F2}");
}

Połączenie break i continue w jednej pętli

Console.WriteLine("Analiza ocen - przerywam przy ocenie 1, pomijam ocenę 2:");

int[] oceny = {4, 5, 3, 2, 4, 1, 5}; // Oceny uczniów
int suma = 0;
int liczbaPrzetworzonych = 0;

for (int i = 0; i < oceny.Length; i++)
{
    int ocena = oceny[i];
    Console.WriteLine($"\nSprawdzam ocenę {i + 1}: {ocena}");
    
    if (ocena == 1) // Ocena niedostateczna - przerwij całą analizę
    {
        Console.WriteLine($"❌ Znaleziono ocenę niedostateczną: {ocena}. Przerywam analizę.");
        break; // Koniec pętli
    }
    
    if (ocena == 2) // Ocena dopuszczająca - pomiń w obliczeniach
    {
        Console.WriteLine($"⚠️ Pomijam ocenę dopuszczającą: {ocena} (nie liczy się do średniej)");
        continue; // Przejdź do następnej iteracji
    }
    
    // Ta część wykonuje się tylko dla ocen 3, 4, 5
    suma += ocena;
    liczbaPrzetworzonych++;
    Console.WriteLine($"✓ Przetworzona ocena: {ocena} (suma: {suma})");
}

Console.WriteLine($"\n=== WYNIKI ANALIZY ===");
if (liczbaPrzetworzonych > 0)
{
    double srednia = suma / (double)liczbaPrzetworzonych;
    Console.WriteLine($"Liczba ocen do średniej: {liczbaPrzetworzonych}");
    Console.WriteLine($"Suma ocen: {suma}");
    Console.WriteLine($"Średnia: {srednia:F2}");
}
else
{
    Console.WriteLine("Nie przetworzono żadnych ocen do obliczenia średniej");
}

Różnice między break a continue

Aspektbreakcontinue
DziałanieKończy całą pętlęKończy tylko bieżącą iterację
Co się dzieje dalejPrzechodzi do kodu za pętląPrzechodzi do następnej iteracji
Kiedy używaćGdy znalazłeś to czego szukasz lub wystąpił błądGdy chcesz pominąć niektóre wartości
Wpływ na licznikZatrzymuje licznikLicznik kontynuuje (i++, następny element)

Porównanie na przykładzie:

Console.WriteLine("=== DEMO BREAK ===");
for (int i = 1; i <= 5; i++)
{
    if (i == 3)
    {
        Console.WriteLine("Break na 3 - koniec pętli");
        break;
    }
    Console.WriteLine($"i = {i}");
}
Console.WriteLine("Po pętli z break\n");

Console.WriteLine("=== DEMO CONTINUE ===");
for (int i = 1; i <= 5; i++)
{
    if (i == 3)
    {
        Console.WriteLine("Continue na 3 - pomiń resztę iteracji");
        continue;
    }
    Console.WriteLine($"i = {i}");
}
Console.WriteLine("Po pętli z continue");

/* Wynik:
=== DEMO BREAK ===
i = 1
i = 2
Break na 3 - koniec pętli
Po pętli z break

=== DEMO CONTINUE ===
i = 1
i = 2
Continue na 3 - pomiń resztę iteracji
i = 4
i = 5
Po pętli z continue
*/

Zagnieżdżone pętle – break i continue

Ważne: break i continue działają tylko na najbliższą otaczającą pętlę!

Console.WriteLine("Break w zagnieżdżonych pętlach:");

for (int i = 1; i <= 3; i++)
{
    Console.WriteLine($"Pętla zewnętrzna: i = {i}");
    
    for (int j = 1; j <= 5; j++)
    {
        if (j == 3)
        {
            Console.WriteLine($"  Break w pętli wewnętrznej przy j = {j}");
            break; // Przerywa tylko pętlę wewnętrzną (j)
        }
        Console.WriteLine($"  Pętla wewnętrzna: j = {j}");
    }
    
    Console.WriteLine($"Koniec iteracji i = {i}\n");
}

/* Wynik:
Pętla zewnętrzna: i = 1
  Pętla wewnętrzna: j = 1
  Pętla wewnętrzna: j = 2
  Break w pętli wewnętrznej przy j = 3
Koniec iteracji i = 1

Pętla zewnętrzna: i = 2
  Pętla wewnętrzna: j = 1
  Pętla wewnętrzna: j = 2
  Break w pętli wewnętrznej przy j = 3
Koniec iteracji i = 2

Pętla zewnętrzna: i = 3
  Pętla wewnętrzna: j = 1
  Pętla wewnętrzna: j = 2
  Break w pętli wewnętrznej przy j = 3
Koniec iteracji i = 3
*/

Kiedy NIE używać break i continue

1. Gdy można użyć prostszego warunku

// ❌ Niepotrzebnie skomplikowane z continue
for (int i = 1; i <= 10; i++)
{
    if (i % 2 == 0)
    {
        continue;
    }
    Console.WriteLine(i);
}

// ✅ Prostsze bez continue
for (int i = 1; i <= 10; i++)
{
    if (i % 2 == 1) // lub (i % 2 != 0)
    {
        Console.WriteLine(i);
    }
}

2. Gdy break można zastąpić lepszym warunkiem pętli

// ❌ Niejasny warunek z break
for (int i = 0; i < 100; i++)
{
    if (i > 10)
    {
        break;
    }
    Console.WriteLine(i);
}

// ✅ Jaśniejszy warunek pętli
for (int i = 0; i <= 10; i++)
{
    Console.WriteLine(i);
}

Najczęstsze błędy z break i continue

1. Break w switch vs break w pętli

for (int i = 1; i <= 5; i++)
{
    switch (i)
    {
        case 3:
            Console.WriteLine("Znaleziono 3");
            break; // To przerywa tylko switch, NIE pętlę for!
        default:
            Console.WriteLine($"Liczba: {i}");
            break;
    }
}
// Pętla for będzie działać dalej po switch

Niepotrzebne używanie w foreach

string[] imiona = {"Anna", "Piotr", "Maria"};

// Często niepotrzebne - foreach i tak przejdzie przez wszystkie elementy
foreach (string imie in imiona)
{
    Console.WriteLine(imie);
    // continue tutaj nie ma sensu - i tak przejdzie do następnego elementu
}

Podsumowanie break i continue

Break używamy gdy:

  • Szukamy pierwszego wystąpienia czegoś
  • Chcemy przerwać pętlę przy błędzie
  • Znaleźliśmy wynik i nie ma sensu szukać dalej
  • Implementujemy menu z opcją wyjścia

Continue używamy gdy:

  • Chcemy pominąć nieprawidłowe dane
  • Filtrujemy elementy w trakcie przetwarzania
  • Chcemy uprościć zagnieżdżone warunki if
  • Pomijamy puste lub null wartości

Pamiętaj:

  • break = koniec całej pętli
  • continue = koniec bieżącej iteracji, przejdź do następnej
  • Działają tylko na najbliższą otaczającą pętlę
  • Używaj rozważnie – czasem prostszy warunek jest lepszy

Najczęstsze błędy z pętlami

1. Pętla nieskończona

// BŁĄD! Pętla nieskończona
int i = 0;
while (i < 10)
{
    Console.WriteLine(i);
    // Brak zwiększenia i - pętla nigdy się nie skończy!
}

// POPRAWKA:
int j = 0;
while (j < 10)
{
    Console.WriteLine(j);
    j++; // Pamiętaj o zmianie warunku!
}

2. Błąd off-by-one (o jeden za dużo/mało)

int[] tablica = {10, 20, 30, 40, 50}; // Indeksy: 0, 1, 2, 3, 4

// BŁĄD! Wyjście poza zakres tablicy
for (int i = 0; i <= tablica.Length; i++) // <= zamiast <
{
    Console.WriteLine(tablica[i]); // Błąd przy i=5!
}

// POPRAWKA:
for (int i = 0; i < tablica.Length; i++) // < zamiast <=
{
    Console.WriteLine(tablica[i]);
}

3. Modyfikowanie kolekcji w foreach

int[] liczby = {1, 2, 3, 4, 5};

// BŁĄD! Próba modyfikowania w foreach
foreach (int liczba in liczby)
{
    liczba = liczba * 2; // To nie zmieni elementu w tablicy!
}

// POPRAWKA: Użyj for do modyfikacji
for (int i = 0; i < liczby.Length; i++)
{
    liczby[i] = liczby[i] * 2; // To rzeczywiście zmieni element
}

4. Niewłaściwy warunek w while

Console.Write("Podaj liczbę dodatnią: ");
int liczba = int.Parse(Console.ReadLine());

// BŁĄD! Warunek może być spełniony od początku
while (liczba < 0)
{
}