|
Wyjście Spis treści Wstecz Dalej
Autor artykułu |
©2026 mgr Jerzy Wałaszek
|
Przez pętlę (ang. loop) rozumiemy cykliczne wykonywanie instrukcji. Wygląda to tak:

Komputer wykonuje kolejno instrukcję_1, instrukcję_2, ..., instrukcję_n, po czym wraca i ponownie wykonuje instrukcję_1 i dalsze.
Praktycznie każdy program dla mikrokontrolera będzie zawierał pętlę. Bez niej mikrokontroler szybko wykonałby ciąg instrukcji w programie i co dalej? Zawiesiłby się, czyli przestał działać (w praktyce są stosowane rozwiązania, które usypiają mikrokontroler, gdy nie jest potrzebna jego aktywność dla oszczędzania baterii, a następnie wzbudzają w określonej sytuacji, ale czy nie jest to działanie w pętli?).
Zatem z pętlami będziesz musiał się zaprzyjaźnić. Nie ukrywam, że nie jest to problem łatwy dla początkujących i należy dużo poćwiczyć, aby był z tego pożytek. A zatem zabieramy się do pracy.
Przez pętlę warunkową (ang. conditional loop) rozumiemy pętlę, której wykonanie (tzn. wykonanie zawartych w niej instrukcji) uzależnione jest od spełnienia określonego warunku. Pierwszą pętlą warunkową, którą się zajmiemy, będzie pętla while (dopóki). Składnia tej pętli jest następująca:
while(warunek) instrukcja;
lub z instrukcją blokową:
while(warunek)
{
instrukcja_1;
instrukcja_2;
...
instrukcja_n;
}
|
Działa to w sposób następujący:
Przed wykonaniem każdego obiegu pętli (czyli instrukcji lub bloku instrukcji) komputer zawsze wylicza wartość podanego za while warunku. Jeśli warunek jest prawdziwy (ma wartość różną od zera), to komputer wykonuje instrukcję pętli (lub blok instrukcji), po czym następuje powrót na początek pętli i wszystko się powtarza: znów jest obliczany warunek i jeśli prawdziwy, to następuje kolejny obieg pętli. Jeśli jednak warunek ma wartość 0, to instrukcja pętli (lub blok instrukcji) nie jest wykonywana i następuje wyjście z pętli, tzn. komputer wykonuje dalszą część programu za instrukcją while.
Pętle pozwalają zautomatyzować wiele operacji. Prześledźmy kilka przykładów:
/*
Pętle warunkowe
(C)2016 mgr Jerzy Wałaszek
Data utworzenia: 27.09.2016
*/
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
int main()
{
int a = 0;
setlocale(LC_ALL,"");
while(++a < 10) printf("%d\n",a);
return 0;
}
|
W programie tworzymy jedną zmienną i nadajemy jej
wartość 0. Następnie w pętli while testujemy warunek
Zmień warunek w programie, tak aby były wypisywane liczby od 1 do 9999. Widzisz, jak prosta modyfikacja pętli pozwala rozszerzyć działanie programu!
Pętla typu while sprawdza swój warunek na początku każdego obiegu. Może się zatem zdarzyć, że nie wykona ani jednego obiegu, jeśli już na wejściu warunek będzie fałszywy.
/*
Pętle warunkowe
(C)2016 mgr Jerzy Wałaszek
Data utworzenia: 28.09.2016
*/
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
int main()
{
int a = 3;
setlocale(LC_ALL,"");
printf("START\n");
while(--a > 3) printf("%d\n",a);
printf("STOP\n");
return 0;
}
|
W tym programie warunek
Typowym problemem rozwiązywanym przez pętlę while jest znajdowanie największego wspólnego dzielnika algorytmem Euklidesa. Największym wspólnym dzielnikiem NWD (ang. Greatest Common Divisor GCD) dwóch liczb całkowitych a i b jest jest taka liczba c, która jednocześnie dzieli bez reszty liczbę a i liczbę b oraz nie istnieje liczba większa od c, które posiada tę samą właściwość. Euklides zauważył, że jeśli liczby a i b nie są równe, to liczba c (będąca ich największym wspólnym dzielnikiem) dzieli również ich różnicę:

Skąd to wiadomo?
Spójrz na prawą część równości. Skoro c dzieli
a i dzieli b, to ułamki
Co robił Euklides? Po prostu od większej liczby odejmował mniejszą, aż obie liczby się zrównały. Wtedy dowolna z nich była NWD. Zobaczmy to na przykładzie:
| a | b | działanie |
| 40 | 24 | a ← 40 - 24 = 16 |
| 16 | 24 | b ← 24 - 16 = 8 |
| 16 | 8 | a ← 16 - 8 = 8 |
| 8 | 8 | ← NWD |
Uruchom program:
/*
Pętle warunkowe
(C)2016 mgr Jerzy Wałaszek
Data utworzenia: 28.09.2016
*/
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
int main()
{
int a = 40; // liczba naturalna
int b = 24; // liczba naturalna
setlocale(LC_ALL,"");
printf("NWD(%d,%d) = ", a,b);
while(a != b)
if(a > b) a -= b;
else b -= a;
printf("%d\n",a);
return 0;
}
|
Powyższy program działa wg algorytmu Euklidesa. Na początku pętli sprawdza, czy liczby a i b są różne. Jeśli tak, to od większej z nich odejmuje mniejszą i ponownie sprawdza warunek. Pętla while zostaje przerwana, gdy liczby się zrównają. Wtedy zostaje wypisana wartość NWD.
Gdy liczby
Zobaczmy na przykładzie:
| a | b | działanie |
| 40 | 24 | a ← b; b ← reszta z a / b |
| 24 | 16 | a ← b; b ← reszta z a / b |
| 16 | 8 | a ← b; b ← reszta z a / b |
| 8 | 0 | ← NWD w a |
Korzyść uzyskamy, gdy
| a | b | działanie |
| 2000000000 | 2 | a ← b; b ← reszta z a / b |
| 2 | 0 | ← NWD w a |
Uruchom program:
/*
Pętle warunkowe
(C)2016 mgr Jerzy Wałaszek
Data utworzenia: 28.09.2016
*/
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
int main()
{
int a = 40; // liczba naturalna
int b = 24; // liczba naturalna
int r; // reszta z dzielenia
setlocale(LC_ALL,"");
printf("NWD(%d,%d) = ", a,b);
while(b)
{
r = a % b;
a = b;
b = r;
}
printf("%d\n",a);
return 0;
}
|
Zwróć uwagę na warunek w pętli while. Jest tu sama zmienna
b. Jest to najzupełniej poprawny warunek i czytaj go jako: dopóki
b jest różne od zera. W pętli
komputer wylicza najpierw resztę z dzielenia
a przez
b i
zapamiętuje ją w zmiennej pomocniczej
r. Następnie
przesuwa wartości: do a idzie dzielnik, do b idzie
reszta z dzielenia. Chociaż program wydaje się być
dłuższym od poprzedniego, to jednak działa szybciej dla
dużych różnic pomiędzy
Jeśli warunek w pętli while jest zawsze prawdziwy, to otrzymujemy tzw. pętlę nieskończoną (ang. infinite loop lub endless loop). Pętla tego typu będzie się wykonywała w kółko.
/*
Pętle warunkowe
(C)2016 mgr Jerzy Wałaszek
Data utworzenia: 28.09.2016
*/
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
int main()
{
setlocale(LC_ALL,"");
while(1) printf("Witamy w C ");
return 0;
}
|
Program wypisuje w kółko tekst w pętli nieskończonej.
Zatrzymujesz go kombinacją klawiszy
Z pętli nieskończonej można wyjść poleceniem break (patrz dalej).
Uwaga:
| if(warunek)
instrukcja; while(warunek) instrukcja; |
Różnica jest jednak bardzo istotna:
while wykonuje warunkowo powtarzanie swojej instrukcji, po każdym obiegu pętli następuje powrót do sprawdzania warunku.
Drugą pętlą warunkową jest w języku C pętla
do instrukcja; while(warunek);
lub w wersji blokowej:
do
{
instrukcja_1;
instrukcja_2;
...
instrukcja_n;
} while(warunek);
|
Instrukcja działa w sposób następujący:
Najpierw zostaje wykonana instrukcja (lub instrukcje w bloku). Następnie komputer wylicza wartość warunku. Jeśli jest różna od zera, to ponownie wykonuje instrukcję (lub blok instrukcji) i przechodzi do sprawdzenia warunku. Jeśli wartość warunku jest równa zero, to następuje wyjście z pętli i wykonanie następnej instrukcji w programie.
Uruchom program:
/*
Pętle warunkowe
(C)2016 mgr Jerzy Wałaszek
Data utworzenia: 28.09.2016
*/
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
int main()
{
int i = 1; // liczba naturalna
int s = 0; // suma
int g = 1000; // granica sumowania
setlocale(LC_ALL,"");
do printf("Suma = %4d\n",s += i++); while(s < g);
return 0;
}
|
Program sumuje kolejne liczby naturalne aż do momentu, gdy suma osiągnie lub przekroczy zadaną granicę. Na początku tworzone są trzy zmienne:
| i | – | przechowuje kolejne liczby naturalne, 1,2,... |
| s | – | suma kolejnych liczb naturalnych |
| g | – | granica sumy |
W zmiennej i umieszczamy 1 (pierwsza liczba naturalna). Sumę zerujemy. W g umieszczamy granicę, do której chcemy sumować. Następnie w pętli tworzymy kolejne sumy i wyświetlamy ich wartość. Zwróć uwagę na wyrażenie:
| s += i++ |
Jest to wyrażenie, w którym modyfikacji ulegają dwie zmienne:
W wielu przypadkach pętle while i
Podane wyżej zalecenia nie są ścisłe, ponieważ język C posiada niesamowitą elastyczność. Nie martw się, doświadczenie przyjdzie z czasem.
Musisz zwrócić uwagę na jedną ważną cechę różniącą obie pętle:
Obieg iterowany jest to obieg, który posiada swój numer. Przez iterowanie rozumiemy wykonywanie w programie obiegów numerowanych. Pętla iteracyjna jest pętlą, która numeruje kolejno wykonane obiegi. Numer obiegu przechowywany jest w zmiennej zwanej licznikiem pętli (ang. loop counter). Pętlę iteracyjną można w prosty sposób zbudować przy pomocy pętli warunkowej typu while. Uruchom poniższy program:
/*
Pętle warunkowe
(C)2016 mgr Jerzy Wałaszek
Data utworzenia: 28.09.2016
*/
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
int main()
{
int i = 1; // licznik pętli
setlocale(LC_ALL,"");
while (i <= 20)
{
printf("Obieg nr %2d\n",i);
i++;
}
return 0;
} |
Zwróć uwagę na charakterystyczną budowę tej pętli:
| int i = 1; | – | czynności przygotowawcze, najczęściej inicjalizacja licznika pętli, wykonywane przed pętlą |
| while(i <= 20) | – | sprawdzenie warunku kontynuacji, wykonywane na początku każdego obiegu |
| printf(...) | – | instrukcja wykonywana w każdym obiegu |
| i++ | – | modyfikacja licznika pętli, wykonywana na końcu każdego obiegu |
Ponieważ pętle iteracyjne są bardzo częstym elementem programów w języku C, istnieje instrukcja, która ułatwia ich stosowanie. Jest to instrukcja for o następującej składni:
for(a; b; c) instrukcja;
lub w postaci blokowej:
for(a; b; c)
{
instrukcja_1;
instrukcja_2;
...
instrukcja_n;
}
|
| a | – | czynności przygotowawcze przed pętlą |
| b | – | warunek kontynuacji sprawdzany przed każdym obiegiem |
| c | – | czynności kończące obieg |
Instrukcja for działa następująco:
Najpierw komputer wykonuje operację określoną przez parametr a. Najczęściej jest to przypisanie wartości początkowej zmiennej, która będzie pełniła rolę licznika pętli. Operacja ta jest wykonywana jednokrotnie przed rozpoczęciem pętli. Następnie komputer zaczyna wykonywać obiegi iterowane. Przed każdym obiegiem sprawdzany jest warunek b. Jeśli ma on wartość różną od zera, to obieg zostanie wykonany. Inaczej pętla zakończy działanie. W każdym obiegu jest wykonywana podana instrukcja (lub instrukcje w bloku). Na końcu każdego obiegu wykonywane jest działanie określone parametrem c. Najczęściej jest to operacja modyfikacji licznika pętli, aby w następnym obiegu miał inną wartość.Instrukcja for grupuje w jednym miejscu wszystkie elementy sterujące wykonywaniem pętli iteracyjnej. Poniżej mamy poprzedni program w wersji z pętlą for:
/*
Pętle iteracyjne
(C)2016 mgr Jerzy Wałaszek
Data utworzenia: 28.09.2016
*/
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
int main()
{
int i; // licznik pętli
setlocale(LC_ALL,"");
for(i = 1; i <= 20; i++) printf("Obieg nr %2d\n",i);
return 0;
} |
Jak widzisz, program jest krótszy. Gdy nabierzesz wprawy, to okaże się, że stosowanie pętli for zamiast while zwiększa czytelność programu.
Pobawmy się trochę pętlami iteracyjnymi. Numery obiegów nie muszą być kolejnymi liczbami naturalnymi: licznik pętli możesz modyfikować w dowolny sposób:
/*
Pętle iteracyjne
(C)2016 mgr Jerzy Wałaszek
Data utworzenia: 28.09.2016
*/
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
int main()
{
int i; // licznik pętli
setlocale(LC_ALL,"");
for(i = 0; i <= 20; i += 2)
printf("Obieg nr %2d\n",i);
return 0;
} |
Licznik pętli możesz wykorzystywać do kontrolowania liczby obiegów, które wykona pętla:
/*
Pętle iteracyjne
(C)2016 mgr Jerzy Wałaszek
Data utworzenia: 28.09.2016
*/
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
int main()
{
int i; // licznik pętli
unsigned p = 1; // potęgi 2
setlocale(LC_ALL,"");
for(i = 0; i <= 31; i++)
{
printf("2^%d = %u\n",i,p);
p += p;
}
return 0;
} |
Kolejny program oblicza tzw. liczby Fibonacciego, które powstają w następujący sposób:
| f0 = 0 – pierwsza liczba ciągu
Fibonacciego f1 = 1 – druga liczba ciągu Fibonacciego fi = fi-2 + fi-1 – każda kolejna liczba Fibonacciego powstaje jako suma dwóch poprzednich. |
Oto kilka początkowych liczb Fibonacciego:
| f0 = 0 f1 = 1 f2 = 0 + 1 = 1 f3 = 1 + 1 = 2 f4 = 1 + 2 = 3 f5 = 2 + 3 = 5 f6 = 3 + 5 = 8 f7 = 5 + 8 = 13 f8 = 8 + 13 = 21 f9 = 13 + 21 = 34 f10 = 21 + 34 = 55 ... |
Liczby Fibonacciego dosyć szybko rosną. Stosuje się je w zaawansowanej informatyce do rozwiązywania różnych problemów związanych ze strukturami danych i symulacjami.
Uruchom program:
/*
Pętle iteracyjne
(C)2016 mgr Jerzy Wałaszek
Data utworzenia: 28.09.2016
*/
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
int main()
{
int i; // licznik pętli
int n = 40; // numer ostatniej liczby Fibonacciego
unsigned f,f1,f2; // kolejno obliczane liczby
setlocale(LC_ALL,"");
for(i = 0; i <= n; i++)
{
if(i < 2) f = i; else f = f2 + f1;
printf("f(%d) = %d\n",i,f);
f2 = f1;
f1 = f;
}
return 0;
} |
W programie tworzymy zmienne:
| i | – | zlicza wykonane obiegi pętli iteracyjnej |
| n | – | definiuje numer ostatniego obiegu |
| f | – | i-ta liczba Fibonacciego |
| f1 | – | (i-1) liczba Fibonacciego, czyli liczba poprzednia |
| f2 | – | (i-2) liczba Fibonacciego, czyli liczba poprzednia poprzedniej |
Pętla iteracyjna for wykona
Pętlę for można wykorzystać również jako pętlę warunkową, którą w sumie jest (instrukcja for jest wewnętrznie rozwijana w odpowiednią pętlę while).
Uruchom program:
/*
Pętle warunkowe
(C)2016 mgr Jerzy Wałaszek
Data utworzenia: 28.09.2016
*/
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
int main()
{
int i; // liczby nieparzyste
int g = 1000; // granica sumowania
unsigned s = 0; // suma
setlocale(LC_ALL,"");
for(i = 1; s < g; i += 2)
{
s += i;
printf("suma = %d\n",s);
}
return 0;
} |
Program sumuje kolejne liczby nieparzyste, aż ich suma przekroczy zadaną granicę. Zwróć uwagę, że warunek kontynuacji nie jest związany z wartością licznika pętli. Otrzymujemy zatem normalną pętlę warunkową.
Niepotrzebne elementy w obszarze sterowania pętli for można pominąć, jednak należy zachować średniki. Pominięcie warunku kontynuacji spowoduje, że pętla będzie się wykonywała w nieskończoność (tzn. aż zatrzymamy program kombinacją klawiszy Ctrl+C).
/*
Pętle warunkowe
(C)2016 mgr Jerzy Wałaszek
Data utworzenia: 28.09.2016
*/
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
int main()
{
unsigned i = 0;
setlocale(LC_ALL,"");
for(; ; i++) printf("%10d",i);
return 0;
} |
Jeśli instrukcją powtarzaną w pętli będzie instrukcja pętli, to otrzymamy pętle zagnieżdżone. Przy zagnieżdżaniu pętli iteracyjnych należy stosować osobne zmienne liczników pętli.
Zobaczmy, jak to działa w praktyce.
Uruchom poniższy program:
/*
Pętle zagnieżdżone
(C)2016 mgr Jerzy Wałaszek
Data utworzenia: 29.09.2016
*/
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
int main()
{
int x = 15; // liczba znaków w wierszu
int i; // licznik znaków w wierszu
setlocale(LC_ALL,"");
for(i = 1; i <= x; i++) printf("X");
printf("\n");
return 0;
}
|
Program wypisuje wiersz zbudowany z 15 znaków X:
| XXXXXXXXXXXXXXX |
Zmodyfikujmy nieco ten program dodając pętlę zewnętrzną, która będzie wykonywała 15 razy te dwie instrukcje:
/*
Pętle zagnieżdżone
(C)2016 mgr Jerzy Wałaszek
Data utworzenia: 29.09.2016
*/
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
int main()
{
int x = 15; // liczba znaków w wierszu
int i; // licznik znaków w wierszu
int j; // licznik wierszy
setlocale(LC_ALL,"");
for(j = 1; j <= x; j++)
{
for(i = 1; i <= x; i++) printf("X");
printf("\n");
}
return 0;
}
|
W efekcie otrzymasz kwadrat (raczej prostokąt, ponieważ literki w oknie konsoli są wyższe niż szersze):
| XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX |
Pętla wewnętrzna wykonuje zawsze x obiegów. A gdybyśmy kazali
się jej wykonywać
/*
Pętle zagnieżdżone
(C)2016 mgr Jerzy Wałaszek
Data utworzenia: 29.09.2016
*/
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
int main()
{
int x = 15; // liczba znaków w wierszu
int i; // licznik znaków w wierszu
int j; // licznik wierszy
setlocale(LC_ALL,"");
for(j = 1; j <= x; j++)
{
for(i = 1; i <= j; i++) printf("X");
printf("\n");
}
return 0;
}
|
Drobna zmiana, a wynik inny:
| X XX XXX XXXX XXXXX XXXXXX XXXXXXX XXXXXXXX XXXXXXXXX XXXXXXXXXX XXXXXXXXXXX XXXXXXXXXXXX XXXXXXXXXXXXX XXXXXXXXXXXXXX XXXXXXXXXXXXXXX |
Na pewnym konkursie informatycznym zadanie polegało na napisaniu programu wypisującego w oknie konsoli taką oto figurę:
| XXXXXXXXXXXXXXX XX...........XX X.X.........X.X X..X.......X..X X...X.....X...X X....X...X....X X.....X.X.....X X......X......X X.....X.X.....X X....X...X....X X...X.....X...X X..X.......X..X X.X.........X.X XX...........XX XXXXXXXXXXXXXXX |
Jeden młody, ambitny człowiek bardzo się nad tym trudził i wyprodukował program zawierający mnóstwo różnych pętli.
Tymczasem sprawa jest banalnie prosta pod warunkiem, że dokonamy
pewnego spostrzeżenia. Otóż każdy znak, który pojawia się na wydruku możemy potraktować, jako znak znajdujący się
| kolumny → i | ||||||||||||||||
| w i e r s z e ↓ j |
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | |
| 1 | X | X | X | X | X | X | X | X | X | X | X | X | X | X | X | |
| 2 | X | X | . | . | . | . | . | . | . | . | . | . | . | X | X | |
| 3 | X | . | X | . | . | . | . | . | . | . | . | . | X | . | X | |
| 4 | X | . | . | X | . | . | . | . | . | . | . | X | . | . | X | |
| 5 | X | . | . | . | X | . | . | . | . | . | X | . | . | . | X | |
| 6 | X | . | . | . | . | X | . | . | . | X | . | . | . | . | X | |
| 7 | X | . | . | . | . | . | X | . | X | . | . | . | . | . | X | |
| 8 | X | . | . | . | . | . | . | X | . | . | . | . | . | . | X | |
| 9 | X | . | . | . | . | . | X | . | X | . | . | . | . | . | X | |
| 10 | X | . | . | . | . | X | . | . | . | X | . | . | . | . | X | |
| 11 | X | . | . | . | X | . | . | . | . | . | X | . | . | . | X | |
| 12 | X | . | . | X | . | . | . | . | . | . | . | X | . | . | X | |
| 13 | X | . | X | . | . | . | . | . | . | . | . | . | X | . | X | |
| 14 | X | X | . | . | . | . | . | . | . | . | . | . | . | X | X | |
| 15 | X | X | X | X | X | X | X | X | X | X | X | X | X | X | X | |
Figura zbudowana jest ze znaków
for(j = 1; j <= 15; j++)
{
for(i = 1; i <= 15; i++) printf("X");
printf("\n");
}
|
W takiej postaci mamy szkielet programu, lecz program ten
jeszcze nie produkuje naszej figury, ponieważ bezwarunkowo
drukujemy na każdej pozycji
| XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX XXXXXXXXXXXXXXX |
Przyjrzyjmy się naszej figurze: w wierszach nr 1 i nr 15 są
same
for(j = 1; j <= 15; j++)
{
for(i = 1; i <= 15; i++)
if((j == 1) || (j == 15)) printf("X");
else printf(".");
printf("\n");
}
|
Tak, stosujemy instrukcję warunkową, w której sprawdzamy numer aktualnego wiersza za pomocą wyrażenia logicznego. Jeśli jest to wiersz 1 lub 15, to drukujemy X. Jeśli nie, to drukujemy kropki. Teraz otrzymasz:
| XXXXXXXXXXXXXXX ............... ............... ............... ............... ............... ............... ............... ............... ............... ............... ............... ............... ............... XXXXXXXXXXXXXXX |
Dodajmy boki
for(j = 1; j <= 15; j++)
{
for(i = 1; i <= 15; i++)
if((j == 1) || (j == 15) ||
(i == 1) || (i == 15)) printf("X");
else printf(".");
printf("\n");
}
|
Otrzymasz:
| XXXXXXXXXXXXXXX X.............X X.............X X.............X X.............X X.............X X.............X X.............X X.............X X.............X X.............X X.............X X.............X X.............X XXXXXXXXXXXXXXX |
Dodajmy przekątną. Litery X mają się pojawiać dla
for(j = 1; j <= 15; j++)
{
for(i = 1; i <= 15; i++)
if((j == 1) || (j == 15) ||
(i == 1) || (i == 15) ||
(j == i) ) printf("X");
else printf(".");
printf("\n");
}
|
Otrzymasz:
| XXXXXXXXXXXXXXX XX............X X.X...........X X..X..........X X...X.........X X....X........X X.....X.......X X......X......X X.......X.....X X........X....X X.........X...X X..........X..X X...........X.X X............XX XXXXXXXXXXXXXXX |
I druga przekątna, tutaj musi być spełniony warunek
for(j = 1; j <= 15; j++)
{
for(i = 1; i <= 15; i++)
if((j == 1) || (j == 15) ||
(i == 1) || (i == 15) ||
(j == i) || (j == 16 - i)) printf("X");
else printf(".");
printf("\n");
}
|
I wynik ostateczny:
| XXXXXXXXXXXXXXX XX...........XX X.X.........X.X X..X.......X..X X...X.....X...X X....X...X....X X.....X.X.....X X......X......X X.....X.X.....X X....X...X....X X...X.....X...X X..X.......X..X X.X.........X.X XX...........XX XXXXXXXXXXXXXXX |
Jak widzisz, cały program zmieścił się w dwóch pętlach iteracyjnych. Jako ćwiczenie zmodyfikuj ten program, tak aby rysował figurę o rozmiarze n wierszy na n kolumn (n ma być zmienną).
Jeśli chcesz dalej poćwiczyć, to napisz programy rysujące w ten sposób figury
| X.X.X.X.X.X.X.X. .X.X.X.X.X.X.X.X X.X.X.X.X.X.X.X. .X.X.X.X.X.X.X.X X.X.X.X.X.X.X.X. .X.X.X.X.X.X.X.X X.X.X.X.X.X.X.X. .X.X.X.X.X.X.X.X X.X.X.X.X.X.X.X. .X.X.X.X.X.X.X.X X.X.X.X.X.X.X.X. .X.X.X.X.X.X.X.X X.X.X.X.X.X.X.X. .X.X.X.X.X.X.X.X X.X.X.X.X.X.X.X. .X.X.X.X.X.X.X.X |
| XXXX....XXXX.... XXXX....XXXX.... XXXX....XXXX.... XXXX....XXXX.... ....XXXX....XXXX ....XXXX....XXXX ....XXXX....XXXX ....XXXX....XXXX XXXX....XXXX.... XXXX....XXXX.... XXXX....XXXX.... XXXX....XXXX.... ....XXXX....XXXX ....XXXX....XXXX ....XXXX....XXXX ....XXXX....XXXX |
| XXXX....XXXX.... .XXXX....XXXX... ..XXXX....XXXX.. ...XXXX....XXXX. ....XXXX....XXXX X....XXXX....XXX XX....XXXX....XX XXX....XXXX....X XXXX....XXXX.... .XXXX....XXXX... ..XXXX....XXXX.. ...XXXX....XXXX. ....XXXX....XXXX X....XXXX....XXX XX....XXXX....XX XXX....XXXX....X |
| XXXXXXXXXXXXXXXX .XXXXXXXXXXXXXX. ..XXXXXXXXXXXX.. ...XXXXXXXXXX... ....XXXXXXXX.... .....XXXXXX..... ......XXXX...... .......XX....... .......XX....... ......XXXX...... .....XXXXXX..... ....XXXXXXXX.... ...XXXXXXXXXX... ..XXXXXXXXXXXX.. .XXXXXXXXXXXXXX. XXXXXXXXXXXXXXXX |
| XXXXXXXXXXXXXXXX X..............X X.XXXXXXXXXXXX.X X.X..........X.X X.X.XXXXXXXX.X.X X.X.X......X.X.X X.X.X.XXXX.X.X.X X.X.X.X..X.X.X.X X.X.X.X..X.X.X.X X.X.X.XXXX.X.X.X X.X.X......X.X.X X.X.XXXXXXXX.X.X X.X..........X.X X.XXXXXXXXXXXX.X X..............X XXXXXXXXXXXXXXXX |
Poważniejszym przykładem zastosowania pętli zagnieżdżonych może być wyliczanie liczb pierwszych.
Liczba pierwsza (ang. prime number) jest liczbą naturalną p większą od 1, która dzieli się tylko przez 1 i przez siebie samą (czyli posiada dokładnie dwa różne podzielniki).
Odwracając tę definicję, otrzymamy, że liczba pierwsza jest liczbą naturalną p większą od 1, która nie dzieli się przez żadną z liczb naturalnych z przedziału od 2 do pierwiastka z p (z wyjątkiem liczby 2, która jest jedyną liczbą pierwszą parzystą). Ta druga definicja podaje sposób sprawdzenia, czy dana liczba jest pierwsza, czy złożona: Bierzemy kolejne liczby naturalne: jeśli p jest równe 2, to jest pierwsze, jeśli p jest większe od 2, to próbujemy je dzielić przez kolejne liczby z przedziału od 2 do pierwiastka całkowitego z p. Jeśli żadna z nich nie dzieli p, to mamy liczbę pierwszą. Jeśli którakolwiek dzieli p, to p nie jest liczbą pierwszą. Podzielność badamy sprawdzając resztę z dzielenia. Jeśli jedna liczba dzieli drugą, to reszta wynosi 0.
Uruchom program:
/*
Pętle zagnieżdżone
(C)2016 mgr Jerzy Wałaszek
Data utworzenia: 29.09.2016
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <locale.h>
int main()
{
unsigned p; // liczba pierwsza
unsigned a = 2; // dolna granica poszukiwań liczb pierwszych
unsigned b = 3000; // górna granica poszukiwań liczb pierwszych
unsigned pp; // przechowuje pierwiastek z p
unsigned d; // dzielnik
char test; // do testowania
setlocale(LC_ALL,"");
printf("Wyznaczanie liczb pierwszych w przedziale od %u do u\n",a,b);
for(p = a; p <= b; p++)
{
if(p == 2)
{
printf("%8u",p); // tego nie sprawdzamy
continue;
}
pp = sqrt(p); // do pp pierwiastek całkowity z p
test = 1;
for(d = 2; d <= pp; d++)
if(!(p % d))
{
test = 0; // p nie jest pierwsze
break;
}
if(test) printf("%8u",p);
}
printf("\n");
return 0;
}
|
W programie występują dwie pętle iteracyjne: pierwsza z licznikiem p i druga zagnieżdżona z licznikiem d. Pierwsza pętla w p generuje kolejne liczby naturalne od a do b. Teraz wewnątrz tej pętli sprawdzamy, czy p jest liczbą pierwszą. Najpierw wykonujemy test na 2. Jeśli p jest równe 2, to wyświetlamy p i tutaj pojawia się nowa instrukcja języka C, która jest związana z pętlami: continue. Powoduje ona przejście do następnego obiegu pętli z pominięciem dalszych instrukcji w danym obiegu. Tutaj jest to oczywiste. Jeśli p jest równe 2, to jest liczbą pierwszą i dalsze testy są zbędne – wyświetlamy p i kończymy ten obieg pętli. W następnym obiegu komputer wyznaczy nowe p, tym razem większe od 2, bo równe 3. Dla takich p obliczamy pierwiastek i próbujemy je dzielić w pętli wewnętrznej przez kolejne dzielniki d od 2 do pierwiastka z p. Tutaj jest drugi ciekawy fragment: jak sprawdzić, czy żaden dzielnik d nie dzieli naszej liczby p? Otóż wykorzystujemy zmienną pomocniczą test. Przed rozpoczęciem dzielenia, umieszczamy w niej dowolną wartość różną od 0, np. 1 jest dobre. Następnie uruchamiamy pętlę dzielącą. W każdym obiegu tej pętli sprawdzamy, czy aktualny dzielnik d dzieli p. Robimy to za pomocą instrukcji warunkowej if, która sprawdza, czy reszta z dzielenia p przez d jest równa 0. Jeśli tak, to d dzieli p i liczba p nie jest liczbą pierwszą. Zaznaczamy ten fakt zerując zmienną test i kończymy wykonywanie pętli wewnętrznej za pomocą instrukcji break. Jest to kolejna instrukcja języka C, która jest związana z pętlami. Jej wykonanie powoduje natychmiastowe wyjście z dowolnej pętli (wszelkie instrukcje w pętli umieszczone za break nie zostaną już wykonane). Tutaj też ma to sens, bo jeśli jakiś dzielnik d dzieli p, to p nie jest liczbą pierwszą i dalsze testowanie podzielności nie ma sensu. Po wyjściu z pętli wewnętrznej komputer napotka instrukcję warunkową, która bada stan zmiennej test. Jeśli test zawiera wartość różną od zera, to znaczy, że żaden z dzielników d nie dzielił liczby p. Skoro tak, to p jest pierwsze i wyświetlamy je, po czym pętla zewnętrzna wykonuje następny obieg i wyznacza kolejną liczbę p do testu.
Zapamiętaj:
continue |
– | kończy bieżący obieg pętli i rozpoczyna następny |
break |
– | kończy bieżący obieg i wychodzi z pętli |
Zapraszamy do następnego rozdziału.
![]() |
Zespół Przedmiotowy Chemii-Fizyki-Informatyki w I Liceum Ogólnokształcącym im. Kazimierza Brodzińskiego w Tarnowie ul. Piłsudskiego 4 ©2026 mgr Jerzy Wałaszek |
Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone pod warunkiem podania źródła oraz niepobierania za to pieniędzy.
Pytania proszę przesyłać na adres email:
Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.
Informacje dodatkowe.