Serwis Edukacyjny w I-LO w Tarnowie ![]() Materiały dla uczniów liceum |
Wyjście Spis treści Wstecz Dalej
Autor artykułu: mgr Jerzy Wałaszek |
©2023 mgr Jerzy Wałaszek |
Jest to nauka o poprawnym rozumowaniu, którą matematyka wykorzystuje do udowadniania swoich twierdzeń. Bez logiki nie byłoby współczesnej nauki.
W logice mamy dwie wartości: prawdę (ang. true) i fałsz (ang. false). Wartości logiczne idealnie nadają się dla komputerów, ponieważ przetwarzany przez nie bit posiada dwa różne stany i łatwo zatem przypisać mu wartość fałszu (0) lub prawdy (1).
Utwórz w Code::Blocks nowy projekt 004 i w edytorze wpisz program, skompiluj i uruchom go:
// Wartości logiczne //------------------ #include <iostream> using namespace std; int main() { setlocale(LC_ALL,""); cout << "FAŁSZ: " << false << endl << "PRAWDA: " << true << endl << endl; return 0; } |
W oknie konsoli zostanie wyświetlony tekst:
FAŁSZ: 0 PRAWDA: 1 |
W języku C++ mamy dwie stałe logiczne: false o wartości 0 i true o wartości 1. W naszym programie kazaliśmy komputerowi wyświetlić w oknie konsoli wartości tych stałych.
Zapamiętaj: W języku C++ każda wartość równa 0 jest traktowana logicznie jako fałsz, a jako prawdę komputer traktuje każdą wartość różną od zera. |
// Wyrażenia logiczne //------------------- #include <iostream> using namespace std; int main() { setlocale(LC_ALL,""); int a; cout << "Podaj wartość a = "; cin >> a; cout << "a > 10? : " << (a > 10) << endl << endl; return 0; } |
W programie tworzymy zmienną całkowitą a, po czym odczytujemy z konsoli liczbę i umieszczamy ją w tej zmiennej. Następnie wyświetlamy wartość wyrażenia (a > 10). W wyrażeniu tym mamy operator porównania >. Jest to operator logiczny, czyli taki, który zwraca w wyniku prawdę (1), jeśli nierówność jest spełniona, lub fałsz (0), jeśli nierówność nie jest spełniona. Zatem, jeśli wprowadzisz np. liczbę 9, nierówność nie będzie spełniona i komputer wypisze:
Podaj wartość a = 9 a > 10? : 0 |
Jeśli wpiszesz np. liczbę 12, komputer wypisze:
Podaj wartość a = 12 a > 10? : 1 |
Operatory porównań w języku C++ są następujące:
Operator | Przykład | Opis |
> | a > b | Zwraca 1, jeśli a jest większe od b, zwraca 0 w przypadku przeciwnym. |
< | a < b | Zwraca 1, jeśli a jest mniejsze od b, zwraca 0 w przypadku przeciwnym. |
== | a==b | Zwraca 1, jeśli a jest równe b, zwraca 0 w przypadku przeciwnym. |
!= | a != b | Zwraca 1, jeśli a jest różne od b, zwraca 0 w przypadku przeciwnym. |
>= | a >= b | Zwraca 1, jeśli a jest większe lub równe b, zwraca 0 w przypadku przeciwnym. |
<= | a <= b | Zwraca 1, jeśli a jest mniejsze lub równe b, zwraca 0 w przypadku przeciwnym. |
W powyższej tabelce a i b mogą być zmiennymi lub dowolnymi wyrażeniami (w języku C++ pojedyncza zmienna też jest wyrażeniem o wartości równej zawartości tej zmiennej), np. a + 5 < b - 11.
W języku C++ istnieje typ logiczny, który oznacza wartość logiczną. Nosi on nazwę bool. Dzięki niemu możemy tworzyć zmienne logiczne, czyli takie, które będą zawierały jedną z dwóch wartości false lub true. Wpisz do edytora program:
// Typ logiczny //------------- #include <iostream> using namespace std; int main() { setlocale(LC_ALL,""); bool a; // Zmienna logiczna 0 lub 1 cout << "Podaj wartość dla a = "; cin >> a; cout << "Teraz zmienna a zawiera: " << a << endl << endl; return 0; } |
Program ten pokazuje ważną cechę języka C++. Gdy informacja jest zapisywana do zmiennej, to zawsze zostaje automatycznie przekształcona na jej typ (jeśli to jest możliwe, jeśli nie, dostaniesz komunikat o błędzie w czasie kompilacji). W programie tworzymy jedną zmienną logiczną a. Następnie odczytujemy liczbę ze strumienia cin do zmiennej a. Co się tutaj dzieje dalej? Ponieważ zmienna a jest zmienną logiczną, to nie może przechowywać wartości innych niż 0 lub 1. Dlatego przy zapisie do zmiennej komputer potraktuje wprowadzoną liczbę jako wartość logiczną. Pamiętasz, że wartość zero w języku C++ jest traktowana jak fałsz, a wartość różna od zera jest traktowana jak prawda? Zatem wprowadzona liczba zostaje przekształcona w wartość logiczną zgodnie z tą regułą. Dlatego przy wprowadzeniu dowolnej liczby różnej od zera komputer wypisze, że zmienna a zawiera 1, czyli prawdę.
Podaj wartość dla a = -1999 Teraz zmienna a zawiera: 1 |
Wersja #1:
if(warunek)instrukcja;
W instrukcji if w tej wersji znajdują się dwa elementy: warunek oraz instrukcja. Komputer oblicza wartość warunku traktowanego jako wyrażenie logiczne (jeśli nie wiesz, co to znaczy, wróć do poprzedniego podrozdziału). Jeśli warunek ma wartość prawdy (jest różny od zera), to komputer wykona instrukcję wewnętrzną w if. Jeśli warunek ma wartość fałszu (zero), instrukcja nie zostanie wykonana (komputer ją pominie) i komputer przejdzie do wykonania kolejnej instrukcji w programie.
Słowo if jest słowem kluczowym języka C++.
Uruchom poniższy program:
// Instrukcja warunkowa //--------------------- #include <iostream> using namespace std; int main() { setlocale(LC_ALL,""); int a, b, x; cout << "Wprowadź dwie liczby całkowite: "; cin >> a >> b; // Odczyt 2 liczb do 2 zmiennych x = a; // Szukamy większej liczby z 2 if(b > x) x = b; cout << endl << "Większa lub równa jest liczba : " << x << endl << endl; return 0; } |
Program odczytuje dwie liczby i wypisuje większą z nich. Zwróć uwagę, w jaki sposób jest to robione. Wykorzystujemy dodatkową zmienną x. Najpierw w x umieszczamy wartość jednej z liczb. Następnie przy pomocy instrukcji if sprawdzamy, czy druga z liczb jest większa od liczby zapamiętanej w zmiennej x. Jeśli tak, to w x umieszczamy drugą liczbę. Jeśli nie, to w x pozostaje pierwsza liczba. W rezultacie po wykonaniu tych operacji zmienna x zawiera większą z dwóch wprowadzonych liczb. Liczbę tę komputer wypisuje przy zakończeniu programu.
Wprowadź dwie liczby całkowite: 1267 1266 Większa lub równa jest liczba : 1267 |
Zwróć uwagę na odczyt ze strumienia cin. Podobnie jak przy zapisie do strumienia cout można odczytywać wiele danych do zmiennych w jednej instrukcji, ale każdą zmienną należy poprzedzać operatorem odczytu >>.
Program można łatwo rozbudować na większą ilość liczb. Poniższy program wyszukuje największą liczbę wśród pięciu wprowadzonych liczb:
// Instrukcja warunkowa //--------------------- #include <iostream> using namespace std; int main() { setlocale(LC_ALL,""); int a, b, c, d, e, x; cout << "Wprowadź pięć liczb całkowitych: "; cin >> a >> b >> c >> d >> e; x = a; // Szukamy większej liczby if(b > x) x = b; if(c > x) x = c; if(d > x) x = d; if(e > x) x = e; cout << endl << "Największą liczbą jest : " << x << endl << endl; return 0; } |
Uwaga: program nie zawiera obsługi błędów użytkownika. Musisz wprowadzać liczby poprawnie, rozdzielając je albo spacjami, albo wciśnięciami klawisza Enter. W przeciwnym razie otrzymasz bezsensowne wyniki. Obsługą błędów zajmiemy się w osobnym rozdziale.
Rozwiążmy następujący problem: sprawdzić, czy dana liczba jest parzysta.
Liczba parzysta jest podzielna przez 2, czyli przy dzieleniu całkowitoliczbowym
przez 2 dostajemy resztę zero. W języku C++ dzielenie całkowitoliczbowe wykonuje
operator /, gdy oba jego argumenty są całkowite. Jednakże nas nie
interesuje wynik dzielenia, lecz reszta z dzielenia. Do obliczania
reszty z dzielenia mamy specjalny operator: %
(czytaj: modulo). Jeśli wynikiem operacji:
Uruchom poniższy program:
// Instrukcja warunkowa //--------------------- #include <iostream> using namespace std; int main() { setlocale(LC_ALL,""); int a; cout << "Badanie parzystości liczby" << endl << "==========================" << endl << endl << "Liczba = "; cin >> a; cout << endl << "Liczba jest "; // Sprawdzamy resztę z dzielenia przez 2 if(a % 2) cout << "nie"; cout << "parzysta" << endl << endl; return 0; } |
Jak działa ten program?
Na początku do zmiennej
całkowitej a odczytujemy liczbę całkowitą, którą wprowadzi użytkownik
przy pomocy klawiatury. Teraz uważaj. Wypisujemy tekst początkowy
"Liczba jest ". Ten fragment tekstu ma się pojawić
zawsze, bez względu na to, czy wprowadzona liczba jest lub nie jest parzysta,
dlatego wypisujemy go przed instrukcją warunkową if. Po wypisaniu tekstu
sprawdzamy naszą liczbę w zmiennej a i tutaj zwróć uwagę na
warunek w instrukcji if. Jest to normalne wyrażenie arytmetyczne:
Badanie parzystości liczby ========================== Liczba = 4 Liczba jest parzysta |
Jeśli natomiast wprowadzimy liczbę nieparzystą, to przed słowem "parzysta" komputer wyświetli słowo "nie":
Badanie parzystości liczby ========================== Liczba = 3 Liczba jest nieparzysta |
Wersja #2:
if(warunek) instrukcja1;
else instrukcja2;
Działanie jest następujące:
Komputer oblicza wartość warunku. Jeśli wynikiem jest prawda, zostaje wykonana instrukcja1. Jeśli wynikiem jest fałsz, zostaje wykonana instrukcja2.
Tę wersję instrukcji if stosujemy tam, gdzie musimy podjąć różne działania zależnie od wybranego warunku.
Słowa if i else są słowami kluczowymi języka C++. Nie można nimi nazywać zmiennych (tzn. nie może w programie występować zmienna o nazwie if, ale możesz zastosować nazwę iF, If lub IF, ponieważ język C++ rozróżnia duże i małe litery w nazwach).
Uruchom poniższy program, który oblicza pierwiastek równania
// Instrukcja warunkowa //--------------------- #include <iostream> using namespace std; int main() { setlocale(LC_ALL,""); cout << "Obliczanie pierwiastka równania liniowego" << endl << "ax + b = c" << endl << endl << "Wprowadź współczynniki:" << endl; double a,b,c; // Używane zmienne fp // Odczytujemy współczynniki równania cout << "a = "; cin >> a; cout << "b = "; cin >> b; cout << "c = "; cin >> c; cout << endl; // Pusty wiersz odstępu // Równanie ma rozwiązanie, jeśli a jest różne od 0 if(a) cout << "x = " << (c - b) / a; else cout << "BRAK ROZWIĄZANIA !!!"; cout << endl << endl; return 0; } |
Równanie ma rozwiązanie:
Ponieważ występuje tu dzielenie przez a, to rozwiązanie istnieje, jeśli a jest różne od zera. Program działa wg następującego algorytmu:
Wejście: współczynniki a, b i c równania
Wyjście: wartość niewiadomej x lub informacja, iż rozwiązania
nie ma.
Lista kroków:
K1: Czytaj współczynniki a, b, c
K2: Jeśli a <> 0, to wypisz (c - b) / a
Inaczej wypisz
"BRAK ROZWIĄZANIA"
K3: Zakończ
Pseudokod:
czytaj a,b,c
jeśli a <> 0, to pisz (c - b) / a
inaczej pisz "BRAK ROZWIĄZANIA"
Nasz program tworzy trzy zmienne typu double (zmiennoprzecinkowe podwójnej precyzji) i odczytuje do nich kolejne współczynniki równania a, b i c. W instrukcji if sprawdzana jest wartość zmiennej a, jeśli jest różna od zera (czyli prawdziwa), to komputer wykona pierwszą instrukcję wewnętrzną, czyli wyliczy wartość pierwiastka i wypisze ją w oknie konsoli. Jeśli zmienna a ma wartość równą zero (z liczbami zmiennoprzecinkowymi należy tu uważać, powiemy o tym dokładnie później), to komputer wykona drugą instrukcję wewnętrzną za else i wypisze tekst "BRAK ROZWIĄZANIA".
#1:
if(warunek) instrukcja;
#2:
if(warunek) instrukcja1;
else instrukcja2;
Wynika z nich, iż warunkowo może być wykonana tylko pojedyncza instrukcja. Byłoby to znaczne utrudnienie, bo co zrobić, jeśli musimy wykonać warunkowo kilka instrukcji? Aby rozwiązać ten problem, w języku C++ mamy tzw. blok (ang. block), czyli grupę instrukcji objętych klamrami { }. Blok jest traktowany jako pojedyncza instrukcja złożona, zatem może zastąpić w programie każdą instrukcję pojedynczą. Dokładnie bloki omówimy w dalszej części kursu, ponieważ posiadają one jeszcze inne własności. Dla wygody bloki będziemy pisać od osobnego wiersza. Zwracajmy jedynie uwagę, aby klamra rozpoczynająca blok { znajdowała się w tej samej kolumnie, co początek instrukcji if, a klamra zamykająca } była w tej samej kolumnie co klamra otwierająca { (są też inne szkoły stawiania klamer, ale ten sposób jest wg mnie najbardziej czytelny i będę go tutaj konsekwentnie stosował). Instrukcje wewnątrz klamerek będą pisane z odstępem 2 lub czterech spacji (dla zwiększenia czytelności). Przy ich zastosowaniu instrukcja warunkowa if wygląda teraz następująco:
#1:
if(warunek)
{
instrukcja_1;
instrukcja_2;
...
instrukcja_n;
}
#2:
if(warunek)
{
instrukcja1_1;
instrukcja1_2;
...
instrukcja1_n;
}
else
{
instrukcja2_1;
instrukcja2_2;
...
instrukcja2_n;
}
Liczba instrukcji w bloku nie jest ograniczona. Zwróć uwagę, iż za blokiem nie umieszcza się średnika (wyjątki dokładnie omówimy), natomiast wewnątrz bloku wszystkie pojedyncze instrukcje muszą normalnie kończyć się średnikiem.
Działanie instrukcji if się nie zmienia. W zależności od warunku wykonywane są instrukcje w odpowiednim bloku (w wersji #1 przy warunku równym false instrukcje w bloku są całkowicie pomijane).
W wielu różnych algorytmach występuje operacja zamiany zawartości dwóch zmiennych. Wymaga ona trzech kroków oraz dodatkowej zmiennej pomocniczej.
Powyższa animacja pokazuje kolejne kroki.
Załóżmy iż mamy dwie zmienne a i b, których zawartość chcemy zamienić miejscami, tzn. w zmiennej a ma się znaleźć to, co jest w zmiennej b, a w zmiennej b ma się znaleźć to, co jest w zmiennej a. Tworzymy dodatkową zmienną pomocniczą x i wykonujemy trzy poniższe kroki:
K01: x ← a
K02: a ← b
K03: b ← x
W kroku 1 wpisujemy do zmiennej x zawartość
zmiennej a. W ten sposób ta zawartość zostaje zabezpieczona.
W kroku 2 do zmiennej a wpisujemy zawartość zmiennej b, mamy zatem
wykonane połowę zadania.
W kroku 3 wpisujemy do zmiennej b zapamiętaną w x poprzednią zawartość
zmiennej a.
Przykład:
Operacja | a | b | x |
Start | 4 | 9 | ? |
x ← a | 4 | 9 | 4 |
a ← b | 9 | 9 | 4 |
b ← x | 9 | 4 | 4 |
Koniec | 9 | 4 | 4 |
Kolejny program porządkuje 2 liczby, tzn. bez względu na kolejność wprowadzenia zawsze wyświetla wprowadzone liczby w porządku: mniejsza, większa.
// Instrukcja warunkowa //--------------------- #include <iostream> #include <iomanip> using namespace std; int main() { setlocale(LC_ALL,""); cout << fixed << setprecision(4); cout << "Porządkowanie dwóch liczb" << endl << "-------------------------" << endl << endl << "Wprowadź dwie dowolne liczby:" << endl; double a,b,x; // Używane zmienne fp // Odczytujemy 2 liczby cin >> a >> b; cout << endl << "Liczby przed porządkowaniem:" << endl << setw(15) << a << setw(15) << b << endl; // Sprawdzamy liczby, jeśli są w złej kolejności, to // zamieniamy je miejscami if(a > b) { x = a; a = b; b = x; } cout << "Liczby po porządkowaniu:" << endl << setw(15) << a << setw(15) << b << endl << endl; return 0; } |
Porządkowanie dwóch liczb ------------------------- Wprowadź dwie dowolne liczby: -1.86 -12.94 Liczby przed porządkowaniem: -1.8600 -12.9400 Liczby po porządkowaniu: -12.9400 -1.8600 |
W wyrażeniach logicznych występują operacje logiczne, podobnie jak w wyrażeniach arytmetycznych występują operacje arytmetyczne (np. dodawanie, mnożenie...). Istnieje specjalny dział matematyki, zwany Algebrą Boole'a. Nazwa ta pochodzi od sławnego matematyka angielskiego George Boole'a, który ją opracował i opisał.
George Boole (1815 - 1864)
W logice istnieją trzy podstawowe operacje logiczne. Opiszemy je tabelkami.
a | !a |
0 | 1 |
1 | 0 |
Negacja jest operacją jednoargumentową. Zwraca wartość logiczną przeciwną do wartości logicznej swojego argumentu. Symbolem operatora negacji w języku C++ jest ! (czytaj: nieprawda, że). Wyrażenie a jest dowolnym wyrażeniem, które zostanie potraktowane jako logiczne (patrz: definicja na początku podrozdziału). Jeśli wyrażenie a będzie prawdziwe (różne od zera), to wynikiem !a będzie 0 (false). Jeśli wyrażenie a będzie fałszywe (równe zero), to wynikiem !a będzie 1 (true).
a | b | a || b |
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 1 |
Alternatywa jest operacją dwuargumentową. Wynikiem alternatywy jest fałsz, jeśli jej oba argumenty są fałszywe. Wynikiem alternatywy jest prawda, jeśli jeden z jej argumentów jest prawdziwy. Alternatywa nazywana jest również sumą logiczną, z uwagi na pewne podobieństwo do operacji dodawania: suma dwóch nieujemnych liczb naturalnych jest: równa 0, gdy obie liczby są równe 0; różna od 0, gdy jedna z liczb jest różna od zera (widzisz podobieństwo?).
Symbolem operatora alternatywy w języku C++ jest || (czytaj: lub). Wyrażenia a i b są dowolnymi wyrażeniami traktowanymi jako logiczne (patrz: definicja na początku podrozdziału).
a | b | a && b |
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
Koniunkcja jest również operacją dwuargumentową. Wynikiem koniunkcji jest prawda tylko wtedy, gdy oba jej argumenty są prawdziwe, a fałsz w każdym innym wypadku. Koniunkcja nazywana jest również iloczynem logicznym z powodu podobieństwa do mnożenia: wynik mnożenia dwóch liczb jest różny od zera, jeśli obie mnożone liczby są różne od zera, a zero w każdym innym wypadku.
Symbolem operatora koniunkcji w języku C++ jest && (czytaj: i). Wyrażenia a i b są dowolnymi wyrażeniami traktowanymi jako logiczne (patrz: definicja na początku podrozdziału).
Operatory logiczne stosujemy, gdy potrzebne są nam złożone warunki, np. chcemy sprawdzić, czy liczba x należy do przedziału domkniętego [a,b] (przedział domknięty [a,b] to taki, do którego należą liczby a i b oraz wszystkie liczby leżące pomiędzy a i b). Aby liczba x wpadała w przedział [a,b] musi jednocześnie spełniać dwa warunki:
Użyjemy zatem koniunkcji. Uruchom program:
// Operatory logiczne //------------------- #include <iostream> using namespace std; int main() { setlocale(LC_ALL,""); cout << "Wprowadź dowolną liczbę: "; double x; cin >> x; cout << endl << "Liczba " << x << " "; if((x >= 1) && (x <= 5)) cout << "należy do przedziału [1,5]."; else cout << "leży poza przedziałem [1,5]."; cout << endl << endl; return 0; } |
Wprowadź dowolną liczbę: 4.675 Liczba 4.675 należy do przedziału [1,5]. |
Wprowadź dowolną liczbę: -1.543 Liczba -1.543 leży poza przedziałem [1,5]. |
Przy pomocy operatorów logicznych można tworzyć wyrażenia logiczne podobnie jak w arytmetyce:
a && b || c
Powyższe wyrażenie jest prawdziwe wtedy, gdy a jest prawdziwe i jest prawdziwe b lub c (albo oba). Fałszywe jest natomiast, gdy a jest fałszywe bez względu na stan b i c, lub jednocześnie b i c są fałszywe bez względu na stan a.
Podobnie jak operatory arytmetyczne również operatory logiczne są wyliczane w określonej kolejności (nazywamy to priorytetem operatora):
Pozwala to analizować wyrażenie logiczne:
a && !b || c
Komputer najpierw wyliczy negację !b (ponieważ ma najwyższy priorytet wśród operatorów logicznych). Następnie wyznaczy koniunkcję a && !b, a na końcu wyznaczy alternatywę z c. Wartość wyrażenia w zależności od wartości logicznych a, b i c wyznacza się np. przy pomocy tabelek prawdy:
a | b | c | x = !b | y = a && x | z = y || c |
0 | 0 | 0 | 1 | 0 | 0 |
0 | 0 | 1 | 1 | 0 | 1 |
0 | 1 | 0 | 0 | 0 | 0 |
0 | 1 | 1 | 0 | 0 | 1 |
1 | 0 | 0 | 1 | 1 | 1 |
1 | 0 | 1 | 1 | 1 | 1 |
1 | 1 | 0 | 0 | 0 | 0 |
1 | 1 | 1 | 0 | 0 | 1 |
Pierwsze trzy kolumny zawierają wszystkie możliwe kombinacje wartości logicznych a, b i c. Kombinacji tych jest osiem (zwróć uwagę na podobieństwo do systemu NBS). W naszym wyrażeniu najpierw wyznaczana będzie negacja !b. Tworzymy zatem kolumnę x o wartościach równych !b. Są to zaprzeczenia wartości z kolumny b. W następnej kolejności wyliczana będzie koniunkcja a i wartości !b, czyli a && x. Kolumnę oznaczymy jako y. Wyliczamy tę kolumnę na podstawie wartości z kolumn a i x (korzystamy z tabelki prawdy koniunkcji). Na koniec na podstawie tabelki alternatywy i kolumn y oraz c wyznaczamy alternatywę y || c.
Jeśli chcemy zmienić kolejność działań, stosujemy nawiasy. Podwyrażenie w nawiasach jest wyznaczane najpierw.
!(a || b) && c
a | b | c | x = a || b | y = !x | z = y && c |
0 | 0 | 0 | 0 | 1 | 0 |
0 | 0 | 1 | 0 | 1 | 1 |
0 | 1 | 0 | 1 | 0 | 0 |
0 | 1 | 1 | 1 | 0 | 0 |
1 | 0 | 0 | 1 | 0 | 0 |
1 | 0 | 1 | 1 | 0 | 0 |
1 | 1 | 0 | 1 | 0 | 0 |
1 | 1 | 1 | 1 | 0 | 0 |
1: Wyznacz przy pomocy tabelek prawdy wartości wyrażeń logicznych i wyciągnij wnioski z wyników:
!a && !b oraz
!(a || b)
!a || !b oraz !(a && b)
2: Napisz program, który wczyta liczbę całkowitą, a następnie sprawdzi, czy jest liczbą nieparzystą leżącą w przedziale domkniętym [1,15]. Program powinien wypisać odpowiedni komunikat.
![]() |
Zespół Przedmiotowy Chemii-Fizyki-Informatyki w I Liceum Ogólnokształcącym im. Kazimierza Brodzińskiego w Tarnowie ul. Piłsudskiego 4 ©2023 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: i-lo@eduinf.waw.pl
Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.
Informacje dodatkowe.