Przejdź do treści
School IT / Przestrzeń do nauki
← C# od podstawLekcja 17 z 58

Pętle for i foreach — powtarzanie z planem

Organizujesz szkolny turniej. Zamiast ręcznie wypisywać numery czterech stanowisk, zlecasz to pętli — a potem zmieniasz jedną liczbę i masz ich czterdzieści.

C# for foreach licznik 45–90 min
CEL LEKCJI

Czego się dziś nauczysz

  • Zapiszesz pętlę for z inicjalizacją, warunkiem i krokiem.
  • Prześledzisz wartości licznika na kartce, zanim uruchomisz program.
  • Ustawisz krok inny niż jeden i policzysz w dół.
  • Przejdziesz po napisie pętlą foreach.
  • Dobierzesz for albo foreach do konkretnego zadania.

Przygotowanie: lekcje 01–16. Przewidywany czas: 45–90 minut z zadaniami. Przykłady wymagają .NET 8 lub nowszego, z włączonymi ImplicitUsings i Nullable.

TEORIA

Trzy części zapisane w jednym nawiasie

Pętla while z poprzedniej lekcji rozrzuca sterowanie licznikiem po trzech miejscach: deklaracja stoi przed pętlą, warunek w nawiasie, zwiększanie gdzieś w ciele. Łatwo o zapomnienie tego ostatniego — i o pętlę bez końca.

for zbiera wszystkie trzy części w jednym nawiasie, rozdzielone średnikami:

Program.cs
for (int numer = 1; numer <= 4; numer++)
{
    Console.WriteLine($"Stanowisko {numer}");
}
CzęśćZapis w przykładzieKiedy się wykonuje
inicjalizacjaint numer = 1raz, przed pierwszym sprawdzeniem warunku
waruneknumer <= 4przed każdym obiegiem, także przed pierwszym
kroknumer++po każdym obiegu, przed ponownym sprawdzeniem warunku

Kolejność jest zawsze ta sama i warto ją umieć wyrecytować: inicjalizacja → warunek → ciało → krok → warunek → ciało → krok → … aż warunek będzie fałszywy.

Ta sama pętla zapisana przez while

Każdą pętlę for da się przepisać na while i odwrotnie — to ten sam mechanizm w innym zapisie. for wybieramy wtedy, gdy z góry wiadomo, ile obiegów ma być; while wtedy, gdy zależy to od danych, których jeszcze nie znamy.

wersja z while
// dokladnie to samo, tylko rozsypane
int numer = 1;
while (numer <= 4)
{
    Console.WriteLine($"Stanowisko {numer}");
    numer++;        // latwo o tym zapomniec
}
TEORIA

Prześledź licznik na kartce

Zanim uruchomisz jakąkolwiek pętlę, przećwicz ją na kartce. Tabelka poniżej pokazuje, co dzieje się przy for (int i = 1; i <= 4; i++).

ObiegWartość i przy sprawdzaniuWarunek i <= 4Co się dzieje
11prawdawykonuje się ciało, potem i rośnie do 2
22prawdaciało, i rośnie do 3
33prawdaciało, i rośnie do 4
44prawdaciało, i rośnie do 5
—5fałszpętla się kończy, program idzie dalej

Zwróć uwagę na ostatni wiersz: po zakończeniu pętli licznik ma wartość o jeden większą od ostatniej użytej w ciele. To nie jest błąd — tak właśnie działa warunek sprawdzany przed obiegiem.

Zero obiegów to poprawny wynik

Warunek sprawdzany jest także przed pierwszym obiegiem. Jeśli od razu jest fałszywy — na przykład w for (int i = 1; i <= 0; i++) — ciało nie wykona się ani razu, a program po prostu pójdzie dalej. Przy liczeniu sumy albo średniej trzeba pamiętać, co program ma wtedy wypisać.

Krok nie musi wynosić jeden

same nagłówki pętli
for (int i = 0; i <= 10; i += 2)      // 0, 2, 4, 6, 8, 10
for (int i = 5; i >= 1; i--)          // 5, 4, 3, 2, 1
for (int i = 1; i <= 100; i *= 2)     // 1, 2, 4, 8, 16, 32, 64

Krok musi pasować do warunku

Zapis for (int i = 5; i <= 1; i--) nie wykona się ani razu, bo 5 nie jest mniejsze od 1. Za to for (int i = 5; i >= 1; i++) nie skończy się nigdy — licznik rośnie, a warunek pozostaje prawdziwy. Przy odliczaniu w dół sprawdź zawsze obie rzeczy naraz: znak warunku i kierunek kroku.

TEORIA

Gdzie żyje licznik

Zmienna zadeklarowana w nawiasie pętli istnieje tylko w tej pętli. Po jej zakończeniu znika.

Program.cs
for (int i = 1; i <= 3; i++)
{
    Console.WriteLine(i);
}

// Console.WriteLine(i);   // BLAD CS0103: nazwa 'i' nie istnieje w tym kontekscie

Gdy wartość licznika jest potrzebna po zakończeniu pętli, deklarujemy go wcześniej:

Program.cs
int i;
for (i = 1; i <= 3; i++)
{
    Console.WriteLine(i);
}

Console.WriteLine($"Po petli i = {i}");   // Po petli i = 4

Nazwa licznika

Dla zwykłego licznika przyjęło się i, potem j i k przy pętlach zagnieżdżonych. To jeden z nielicznych przypadków, w których jednoliterowa nazwa jest dobrą praktyką — każdy programista wie, co oznacza. Gdy licznik ma znaczenie, na przykład numer stanowiska, lepiej nazwać go numer.

TEORIA

foreach — gdy indeks nie jest potrzebny

Czasem nie chodzi o liczenie, tylko o przejście po wszystkim, co jest w jakimś zbiorze. Wtedy pilnowanie indeksu to niepotrzebna robota — i kolejna okazja do pomyłki.

Program.cs
foreach (char litera in "KOT")
{
    Console.WriteLine(litera);
}

Czytamy to tak: „dla każdej litery w napisie KOT”. Pętla sama pobiera kolejne znaki i sama kończy pracę po ostatnim. Nie ma warunku, nie ma kroku, nie ma szans na wyjście poza zakres.

forforeach
Znasz numer elementutak, to liczniknie
Możesz pominąć co drugitak — krok i += 2nie
Możesz iść od końcataknie
Ryzyko wyjścia poza zakresjestbrak
Typowe użyciegenerowanie liczb, przeglądanie po indeksieprzejście po wszystkich elementach po kolei

Zmiennej iteracyjnej nie zmieniamy

Zapis litera = 'X'; wewnątrz foreach to błąd kompilacji CS1656. Zmienna iteracyjna służy wyłącznie do odczytu bieżącego elementu. Gdy chcesz coś zmieniać, potrzebna jest pętla for i indeks — albo budowanie nowej wartości obok.

Po czym jeszcze da się przejść

Na razie umiemy przejść foreach po napisie, bo napis to ciąg znaków. Prawdziwą siłę ta pętla pokaże przy tablicach z lekcji 23 i kolekcjach z bloku 7 — tam wypisanie wszystkich elementów to jedna linijka.

PRZYKŁAD

Przykład: plan turnieju

Wklej cały przykład do nowego projektu konsolowego jako Program.cs. Zanim uruchomisz — przewidź każdy wiersz wyniku.

Program.cs
Console.WriteLine("PLAN TURNIEJU");
Console.WriteLine(new string('=', 24));

// 1. numery stanowisk
for (int numer = 1; numer <= 4; numer++)
{
    Console.WriteLine($"Stanowisko {numer,2}: wolne");
}

// 2. odliczanie do startu
Console.Write("Start za: ");
for (int sekunda = 5; sekunda >= 1; sekunda--)
{
    Console.Write($"{sekunda}... ");
}
Console.WriteLine("teraz!");

// 3. suma punktow rund - licznik sluzy do liczenia, nie do wypisywania
int suma = 0;
for (int runda = 1; runda <= 5; runda++)
{
    suma += runda * 10;
}
Console.WriteLine($"Punkty do zdobycia: {suma}");

// 4. foreach po napisie - bez indeksu
Console.Write("Haslo rundy: ");
foreach (char litera in "ROBOT")
{
    Console.Write($"[{litera}]");
}
Console.WriteLine();
wynik w konsoli
PLAN TURNIEJU
========================
Stanowisko  1: wolne
Stanowisko  2: wolne
Stanowisko  3: wolne
Stanowisko  4: wolne
Start za: 5... 4... 3... 2... 1... teraz!
Punkty do zdobycia: 150
Haslo rundy: [R][O][B][O][T]

Co dzieje się po kolei

  • Pierwsza pętla generuje numery — nigdzie ich nie przechowujemy, powstają w chwili użycia.
  • Druga liczy w dół: warunek sekunda >= 1 pasuje do kroku sekunda--. Zamiana jednego z nich dałaby zero obiegów albo pętlę bez końca.
  • W trzeciej licznik nie trafia na ekran — służy wyłącznie do obliczeń. Suma 10 + 20 + 30 + 40 + 50 daje 150.
  • Console.Write bez Line nie przechodzi do nowego wiersza — dlatego odliczanie mieści się w jednej linii.
  • Zapis {numer,2} to wyrównanie do dwóch znaków z lekcji 13. Dzięki niemu numery stoją w kolumnie.
  • foreach przechodzi po pięciu znakach napisu ROBOT — litera O pojawia się dwa razy, bo występuje w napisie dwa razy.

Pobierz Program.cs

ELEMENTY WBUDOWANE

Co robi każdy użyty element

ElementZwracaDziałanie i ograniczenia
for (start; warunek; krok)—Pętla z licznikiem. Każdą z trzech części można pominąć; for (;;) to pętla nieskończona.
foreach (typ x in zrodlo)—Przechodzi po wszystkich elementach po kolei. Zmiennej x nie wolno przypisać nowej wartości.
i++ / i--wartość sprzed zmianyZwiększa lub zmniejsza o jeden. W kroku pętli wynik nie jest wykorzystywany, więc i++ i ++i działają tam tak samo.
i += 2nowa wartośćKrok o dowolną wartość. Działa też dla mnożenia: i *= 2.
Console.Write(x)voidWypisuje bez przejścia do nowego wiersza — przydatne, gdy pętla ma budować jedną linię.
new string(znak, n)stringNapis z n powtórzeń znaku. Wygodna linia oddzielająca bez pętli.
{x,2} w interpolacjitekstWyrównanie do szerokości 2 znaków (lekcja 13). Liczba ujemna wyrównuje do lewej.
CZĘSTE BŁĘDY

Zanim utkniesz

ZapisProblem
for (int i = 1; i <= 4; i++);Średnik zaraz po nawiasie staje się ciałem pętli. Pętla wykonuje się cztery razy, nie robiąc nic, a blok w klamrach — raz. Kompilator nie protestuje.
for (int i = 1; i < 4; i++)Trzy obiegi, nie cztery. Przy starcie od 1 granicę zapisujemy przez <=, przy starcie od 0 — przez <.
for (int i = 5; i >= 1; i++)Pętla bez końca — krok oddala się od warunku. Przerwij program klawiszami Ctrl+C.
Użycie i po zakończeniu pętliCS0103 — licznik zadeklarowany w nawiasie już nie istnieje. Zadeklaruj go wcześniej, jeśli ma przetrwać.
litera = 'X'; w foreachCS1656 — zmiennej iteracyjnej nie wolno zmieniać.
Zmiana licznika wewnątrz ciała forKompiluje się, ale pętla przestaje być przewidywalna. Licznikiem steruje wyłącznie krok w nagłówku.
ZADANIA

Zadania

ZAD 1Odliczanie★☆☆

Wypisz liczby od 5 do 1, każdą w osobnym wierszu, a pod nimi napis START. Użyj pętli for liczącej w dół. Wynik ma mieć sześć wierszy.

ZAD 2Suma i średnia★☆☆

Policz pętlą for sumę liczb od 1 do 10 i wypisz ją razem ze średnią z dwoma miejscami po przecinku. Nie wpisuj gotowego wyniku. Sprawdź program także dla górnej granicy równej 0 i zapisz, co wtedy wypisuje.

ZAD 3Litery w nawiasach★☆☆

Przejdź pętlą foreach po napisie ROBOT i wypisz każdą literę w osobnym wierszu, otoczoną nawiasami kwadratowymi. Potem zapisz to samo pętlą for po indeksach i porównaj oba zapisy.

ZAD 4Tabliczka jednej liczby★★☆

Wczytaj liczbę od użytkownika i wypisz jej tabliczkę mnożenia od 1 do 10 w postaci 7 x 3 = 21. Wyrównaj kolumny tak, żeby znaki równości stały jeden pod drugim.

ZAD 5Co drugi i co trzeci★★☆

Wypisz w jednym wierszu liczby od 1 do 30 podzielne przez 3, a w drugim — wszystkie parzyste z tego zakresu. Użyj dwóch pętli o różnym kroku, bez sprawdzania reszty z dzielenia.

ZAD 6Choinka z gwiazdek★★★

Wypisz choinkę o wysokości wczytanej od użytkownika: w wierszu numer i ma stać 2·i − 1 gwiazdek, poprzedzonych spacjami tak, żeby całość była symetryczna. Sprawdź program dla wysokości 1, 5 i 0. Podpowiedź: liczbę spacji da się wyliczyć z numeru wiersza i wysokości, a napis z powtórzeń zbudujesz przez new string.

PODSUMOWANIE

Co trzeba zapamiętać

  • for zbiera w jednym nawiasie inicjalizację, warunek i krok — w tej kolejności.
  • Warunek sprawdzany jest przed każdym obiegiem, także przed pierwszym: pętla może wykonać się zero razy.
  • Po zakończeniu pętli licznik ma wartość o jeden dalszą niż ostatnia użyta w ciele.
  • Krok musi zbliżać licznik do granicy z warunku — inaczej dostajesz zero obiegów albo pętlę bez końca.
  • Licznik zadeklarowany w nawiasie istnieje tylko wewnątrz pętli.
  • foreach przechodzi po wszystkich elementach bez indeksu; zmiennej iteracyjnej nie wolno zmieniać.

Dokumentacja: Microsoft Learn — temat tej lekcji.

Postęp zapisuje się w tej przeglądarce.