c wyjasniony

Tablica to ułożone kolejno w pamięci zmienne jednego typu. Stosowałeś już tablice nic o tym nie wiedząc. Chodzi o teksty, które przesyłałeś do strumienia. Każdy tekst to nic innego jak tablica - zmienne typu char ustawione kolejno w pamięci. Jeżeli zamiast liczb chciałbyś wczytać z klawiatury jakiś tekst, to powstaje problem: w jakiej zmiennej go przechować? Do tego służy właśnie tablica. Można w niej przechować np. ciąg znaków. Ttworzymy ją tak:

char napis[30];

Taka deklaracja przydziela pamięć na 30 kolejnych bajtów (zmiennych typu char). Nie wiadomo, co znajdowało się wcześniej w tym miejscu pamięci. Dlatego można od razu zainicjować taką tablicę jakimiś wartościami, na przykład kolejnymi znakami napisu. Robi się to tak:

char napis[30] = "jakiś tekst";

Takie przypisanie jest możliwe tylko raz, w deklaracji tablicy. Później już nie będzie to możliwe, o czym nieco dalej. Jak widać, nie trzeba w tablicy zapełnić wszystkich 30 znaków. Można zarezerwować pamięć dla 30 znaków, ale używać raz 10, raz 20, innym razem tylko 1.

Ile znaków może zapisać w tablicy 30-elementowej: 29. Komputer podczas wypisywania łańcucha znaków musi wiedzieć, gdzie łańcuch się kończy. Do oznaczenia końca używa bajtu o wartości 0 (\0). W C++ każdy łańcuch jest zakończony takim znakiem. Nie musisz go umieszczać w tekście, kompilator sam o to zadba. Ze względu na ten znak tablica 30-elementowa może pomieścić tylko 29 znaków - bo na 30 miejscu w tablicy będzie znak kończący.

Mamy już utworzoną i zainicjowaną tablicę. Jak się do tych wartości odwoływać? Ponieważ są ułożone w pamięci sekwencyjnie, możemy się do nich odwoływać poprzez indeksy, czyli ich numery porządkowe. Elementy tablicy są numerowane od 0. Pierwszy element ma numer 0, drugi element ma numer 1, itd.. Np. żeby wypisać na ekranie 5 element tablicy, używamy takiej instrukcji:

cout << napis[4];

co jest równoznaczne z instrukcją:

cout << 'ś';

bo 5 element tej tablicy to właśnie znak ś. Podobnej składni używamy, gdy chcemy zmienić zawartość wybranego elementu tablicy. Na przykład zmiana 1 znaku wygląda tak:

napis[0] = 'J';

Wyświetl cały tekst zawarty w tablicy, a zobaczysz, że odpowiednia litera rzeczywiście się zmieniła. Instrukcja:

cout << napis;

spowoduje teraz wyświetlenie na ekran napisu Jakiś tekst. Spróbuj teraz do 5 elementu tablicy wstawić znak \0 i zobacz, że tym razem wyświetli się tylko część napisu, bo komputer kończy wyświetlanie tekstu, gdy natrafi na znak \0.

Jednak reszta napisu dalej jest w tablicy, nigdzie nie ginie. Wystarczy, że zmienisz 5 element tablicy ponownie na znak spacji.

Podczas odwoływania się do elementów tablicy należy uważać, żeby nie odwoływać się do elementów nieistniejących. Jeśli zarezerwowałeś w pamięci miejsce dla tablicy 30-elementowej, nie możesz odwoływać się do jej 50 elementu, bo spowoduje to błąd dostępu do pamięci.

Przejdźmy teraz do wskaźników. Wskaźnik (ang. pointer) to taka zmienna, która nie przechowuje wartości, lecz jej adres w pamięci lub inaczej: wskazuje miejsce w pamięci, w którym znajduje się zmienna określonego typu. Przypuśćmy, że mamy zmienną liczba typu int. Deklaracja wskaźnika, który będzie wskazywał na ten typ zmiennej, wygląda tak:

int *wskaz;

Gwiazdka oznacza, że wskaz nie jest zmienną typu int, lecz wskaźnikiem do takiej zmiennej. Przy czym nie jest ważne, gdzie gwiazdkę umieścisz: bliżej typu, bliżej nazwy, czy nawet pośrodku między nimi, byle tylko tam była. Nowoutworzony wskaźnik wskazuje w jakieś nieznane miejsce w pamięci. Zanim go użyjemy, należy go ustawić tak, żeby wskazywał tam gdzie chcemy, czyli na naszą zmienną liczba.

wskaz = &liczba;

Operator & to operator adresu (zwany też operatorem referencji): zwraca adres obiektu, który stoi po jego prawej stronie. Powyższa instrukcja oznacza: do wskaźnika wskaz przypisz adres zmiennej liczba. Od tej chwili wskaz wskazuje na miejsce zmiennej liczba w pamięci.

Po takim przypisaniu obie poniższe instrukcje są równoważne (obie przypiszą do numer wartość zmiennej liczba):

int numer = liczba;

int numer = *wskaz;

Operator * nazywa się operatorem wyłuskania. Zwraca to, na co wskazuje wskaźnik stojący po jego prawej stronie czyli wyłuskuje z pamięci to, na co wskazuje wskaźnik. Jeżeli nie byłoby operatora wyłuskania, to do zmiennej numer trafiłby adres, na który wskazuje wskaźnik, a nie to co się pod tym adresem znajduje.

Wskaźnik możemy w każdej chwili przestawić na inne miejsce w pamięci. Przestawimy go teraz tak, by wskazywał na zmienną numer:

wskaz = &numer;

W C++ tablica i wskaźnik to to samo: nazwa tablicy to nic innego jak wskaźnik na miejsce w pamięci, gdzie ta tablica się zaczyna. Jedyną różnicą jest to, że nazwa tablicy jest wskaźnikiem stałym i dlatego nie można takiego "wskaźnika" przestawić na inne miejsce w pamięci. Z tego powodu niepoprawny jest taki kod:

char napis[50] = "Przykładowy tekst";

napis = "Inny tekst";

bo oznaczałoby to przestawienie "wskaźnika" na inne miejsce w pamięci. Jeżeli zamiast tablicy posłużymy się wskaźnikiem, to taka instrukcja jest poprawna, bo zwykły wskaźnik można przestawiać. Wskaźnik również możemy zadeklarować jako stały. Robi się to tak:

char * const napis = "To jest stały wskaźnik do tekstu";

napis działa identycznie jak nazwa tablicy - nie da się go przestawiać. Sprawiła to klauzula const. Nieraz istnieje potrzeba przestawienia wskaźnika z jednoczesnym zakazem modyfikacji obszaru pamięci, na który on wskazuje. Do tego służy wskaźnik do stałej. Różni się on od wskaźnika stałego tym, że można go przestawiać na inne miejsce pamięci. Deklarujemy go tak:

char const * napis;

Tym razem słówko const (oznaczające stałą) znajduje się za znakiem gwiazdki. Tym razem nie zmienna, ale jej typ jest wartością stałą.

Tablica i wskaźnik mają dużo wspólnego. W C++ to co można zrobić z użyciem tablicy, można też zrobić z użyciem wskaźników i na ogół będzie to działać szybciej. Przykłady odwoływania się do poszczególnych znaków zmiennej wskaźnikowej:

char *wskaz = "ABCDEFGHIJK";

char znak;

znak = *Wskaz; //znak='A'

znak = *(Wskaz+2); //znak='C'

znak = Wskaz[4]; //znak='E'

Wyjaśnienia wymaga użycie nawiasów w drugim odwołaniu do zmiennej wskaz: brak nawiasów kompilator zrozumiałby jako przypisanie do zmiennej znak tego, na co wskazuje wskaz powiększonego o liczbę 2. Operator * ma wyższy priorytet niż operator + i najpierw wartość jest wyciągana z pamięci, a dopiero potem zwiększana o 2.

Można to zapisać prościej, wiedząc że wskaźnik i tablica to to samo. Przykład takiego zapisu jest w trzecim odwołaniu. Poniżej masz zestawienie równoważnych odwołań:

*wskaz; <=> wskaz[0];

*wskaz + 3; <=> wskaz[0] + 3;

*(wskaz+4); <=> wskaz[4];

Spróbuj teraz sam napisać program, który będzie pytał użytkownika o nazwisko, a następnie wyświetli mu, na jaką literę się to nazwisko zaczyna, a na jaką kończy.

Stronaaaaaaa kolejna

REFERENCJE

Teraz o czymś, co jest poniekąd odwrotnością wskaźnika: o referencji. Referencja to zmienna, która "podszywa się" pod inną zmienną. Jest ona szczególnie przydatna przy funkcjach, o czym nieco dalej. Oto przykładowy kod:

int liczba = 10;

int & adr_liczby = liczba;

Pierwszy wiersz jest oczywisty: zwyczajne zadeklarowanie zmiennej z inicjacją. Drugi wiersz to coś nowego. Mamy tu operator adresu (zwany operatorem referencji). To jest właśnie deklaracja specjalnej zmiennej zwanej referencją. Taka deklaracja oznacza, że zmienna adr_liczby jest typu referencyjnego i może "podszywać się" pod zmienną typu int. Zmienną referencyjną musimy od razu zainicjować, inaczej kompilator zgłosi błąd, bo musi wiedzieć, jaką zmienną "udaje" referencja. Przypisujemy referencji adr_liczby zmienną liczba. Co to daje? Sprawdź poniższy kod:

cout << "Oryginalna liczba: " << liczba << endl;

cout << "Jej referencja: " << adr_liczby << endl;

Zmienna referencyjna to jakby druga nazwa dla naszej zmiennej. Jak działa taka referencja? Każda zmienna dla kompilatora to nazwa jakiegoś miejsca w pamięci. Dla kompilatora nazwa zmiennej to odpowiednik jakiegoś adresu w pamięci. Referencja działa tak, jak działa, bo przejmuje adres wewnętrzny każdej zmiennej, którą się jej przypisze. Dla kompilatora wygląda to po prostu jak inna nazwa pewnego miejsca w pamięci, czyli inna nazwa jakiejś zmiennej.

Sprawdźmy, czy rzeczywiście chodzi o tą samą zmienną, tylko pod inną nazwą. Zmienimy wartość jednej z nich i zobaczymy, czy druga też się zmieni:

liczba = 10; cout << "liczba: " << adr_liczby << endl;

adr_liczby = 20; cout << "liczba: " << liczba << endl;

Jak widać zmiana referencji powoduje również zmianę drugiej zmiennej. Gdy program chce coś zrobić z referencją, to wskazuje mu ona zawsze miejsce w pamięci, gdzie przechowywana jest ta druga zmienna. Poniższy kawałek kodu powinien wyjaśnić resztę wątpliwości:

cout << "Adres liczby: " << (&liczba) << endl;

cout << "Adres referencji: " << (&adr_liczby) << endl;

Jak widać, w oby wypadkach chodzi o ten sam adres pamięci.

Spójrzmy na to jeszcze raz od strony kompilatora. Dla niego każda nazwa zmiennej to coś na kształt wskaźnika, bo jest odpowiednikiem jakiegoś adresu w pamięci. Zwykła zmienna ma swoje stałe miejsce. Referencja to jakby "bezdomna" zmienna, która korzysta z cudzych adresów. Natomiast wskaźnik - jak zwykła zmienna - ma stały adres pamięci, ale jest czymś w rodzaju informatora, który może wskazać nam adres innej zmiennej, gdy go o to zapytamy. Referencja i wskaźnik, mimo że wydają się być tym samym, są całkowitymi przeciwieństwami. Dlatego operator & (referencji) i operator * (dereferencji) znoszą się nawzajem. Sprawdź poniższy przykład:

int liczba = 123;

int *wskaznik = &liczba;

cout << (*&liczba) << "\t\t" << liczba << endl;

cout << (&*wskaznik) << "\t\t" << wskaznik << endl;

Deklarujemy zmienną i wskaźnik do niej. W 3 wierszu zawartość nawiasu działa tak: najpierw operator referencji zwraca adres zmiennej, po czym operator dereferencji zwraca to, co jest pod tym adresem, czyli zawartość zmiennej. Oba operatory działają całkowicie odwrotnie, co powoduje, że kasują się nawzajem. Dowodem na to jest 3 wiersz:. najpierw operator dereferencji wyciąga to, co jest pod adresem wskazywanym przez wskaźnik, po czym operator referencji zwraca adres tego czegoś (czyli to, co zawiera zmienna wskaźnikowa). Powinno to już wyjaśnić, czym się różni pojęcie REFERENCJI od pojęcia DEREFERENCJI. W kolejnej części poznasz funkcje i zobaczysz wreszcie, do czego może się przydać referencja.

Stronnnaaa kolejna

Wlasne funkcje

Program często powtarza jakieś czynności wielokrotnie. Na przykład wczytuje jakieś dane ze skomplikowaną kontrola poprawności lub przeprowadza identyczne obliczenia. Jednak umieszczenie kodu pojedynczego wczytania w pętli nie jest możliwe, gdyż musimy wczytywać dane na różnych drogach programu i w dodatku różnie je rozmieszczać na ekranie. Do takich zadań służą w C++ funkcje. Używaliśmy już funkcji, nawet się nad tym nie zastanawiając. Przecież cały program to jedną funkcją, która nazywała się main.

Funkcja to jakby zastąpienie jedną instrukcją wielu instrukcji wykonujących jakieś konkretne zadanie. W naszych przykładach zajmiemy się sprawdzaniem typu znaku. Wpiszemy przed funkcją main coś takiego:

void znak()

{ //Tu jest ciało funkcji, czyli instrukcje, z których funkcja się składa

}

To jest definicja funkcji, czyli określenie, co funkcja ma robić. Przyjrzyjmy się dokładniej tej konstrukcji. Nasza funkcja będzie się nazywać znak. W nawiasach klamrowych, czyli w ciele funkcji, będą się znajdowały wszystkie instrukcje, które chcemy wykonywać przy pomocy tej funkcji. Na początek wyświetlimy wynik prostego działania. Zmienimy nasz kod:

void znak ()

{ cout << "\'A\' jest literą"<< endl;

}

Apostrof jako znak specjalny - podobnie jak znak nowego wiersza - musi być poprzedzony znakiem \. Teraz w funkcji main wywołamy naszą funkcję, czyli wydamy polecenie:

znak ();

a program wyświetli na konsoli komunikat: 'A' jest literą. Spróbuj teraz przenieść kod naszej funkcji za funkcję main. Kompilator wyświetli komunikat o braku naszej funkcji.

Zapowiedź funkcji

Nasz funkcja jest dla kompilatora nowym poleceniem, musi ją więc znać, żeby mógł dobrze wykonać pracę. Początkowo zdefiniowaliśmy całą funkcję przed funkcją main. Gdy kompilator analizuje funkcję main i napotka na wywołanie naszej funkcji kwadrat(), to już ją zna. W drugim przypadku jest inaczej. Kompilator dochodząc do wywołania nie zna jeszcze naszej funkcji kwadrat(). Stąd błąd. Często wygodniej i czytelniej jest definiować swoje funkcje za funkcją main. Jeśli tak robimy to należy jakoś powiadomić kompilator, że mamy zamiar użyć funkcji i będzie się ona nazywać tak a tak. Robimy to umieszczając przed funkcją main zapowiedź naszej funkcji (bez określania jej ciała), a zapisujemy ją tam, gdzie nam odpowiada. Jedynym miejscem, gdzie nie wolno definiować funkcji, jest ciało innej funkcji. Zapowiedź funkcji wygląda następująco:

void znak();

Parametry funkcji

Napisaliśmy funkcję, która wyświetla komunikat. Jaki to ma jedna sens, jeżeli zawsze wyświetli nam tekst 'A' jest literą? My byśmy chcieli, sprawdzał dowolny znak.

Zauważyłeś już, że przy deklaracji funkcji zawsze podajemy parę nawiasów. Służą one do umieszczenia między nimi jakiejś informacji dla funkcji, którą właśnie wywołujemy. Ta informacja nazywa się parametrami funkcji. My chcemy podać funkcji argument do sprawdzenia klasy znaku. Na przykład tak:

znak ('1');

I teraz funkcja powinna wyświetlić komunikat '2' jest cyfrą. Znak powinien być typu char. Musimy powiedzieć kompilatorowi, że nasza funkcja będzie pobierać parametr typu char:

void znak (char zn)

{ if (zn >='A' && zn <='Z') cout << zn << " jest wielką literą" <<endl;

if (zn >='a' && zn <='z') cout << zn << " jest małą literą" <<endl;

if (zn >='0' && zn <='0') cout << zn << " jest cyfrą" <<endl;

}

Jak widać, podaliśmy w nawiasach parametr wraz z typem (możesz podać w razie potrzeby wiele parametrów oddzielonych przecinkami). Przypomina to deklarowanie zmiennych. Parametry nie są niczym innym, jak zmiennymi jakiegoś typu, które przekazujemy do funkcji. Kompilator widząc taki kod zarezerwuje wewnątrz funkcji zmienną typu char i nazwie ją zn. Zmienna taka będzie wyłącznie własnością funkcji. Podobnie jak inne zmienne zadeklarowanymi wewnątrz funkcji. Na takie zmienne mówimy, że są lokalne dla funkcji. Gdy funkcja się zakończy, program automatycznie usunie te zmienne z pamięci. Zmienna lokalna ma jeszcze jedną zaletę: na jej nazwę nie ma wpływu to, czy gdzieś poza funkcją jest już zmienna o takiej samej nazwie. Dla funkcji ważniejsze są zmienne, które są jej własnością. Jeśli poza funkcją istnieje zmienna o nazwie identycznej jak zmienna lokalna, to zostanie przasłonięta przez zmienną lokalną.

Zapowiedź naszej funkcji można zapisać na 2 sposoby. Podając nagłówek funkcji, wraz z listą parametrów lub podając jedynie typy parametrów.

void znak(char zn);

void znak(char);

Wartość zwracana z funkcji

Funkcja testuje parametr i wyświetla komunikat, ale my chcielibyśmy jeszcze ją mieć w programie, aby użyć do dalszych działań. Do zakończenia działania funkcji służy instrukcja return. Gdy wykonamy testy i wyświetlimy komunikat, użyjemy return by wyjść z funkcji. return pozwala również przy wychodzeniu z funkcji zwrócić do programu jakieś dane.

int znak(char zn)

{ int retwar = 4;

if (zn >='A' && zn <='Z')

{ cout << zn << " jest wielką literą" <<endl;

retwar = 0;

}

if (zn >='a' && zn <='z')

{ cout << zn << " jest małą literą" <<endl;

retwar = 1;

}

if (zn >='0' && zn <='0')

{ cout << zn << " jest cyfrą" <<endl;

retwar = 2;

}

zn+=10; //wykonaliśmy zwiększenie parametru o 10

return (retwar)

}

Tera zmieniliśmy w nagłówku funkcji typ void na typ int. Co to znaczy? Poprzednio funkcja nie zwracała żadnej wartości do kodu, który ją wywołał. Czyli typ wartości zwracanej przez funkcję był void (żaden). Teraz funkcja zwraca wartość całkowitą, czyli typ wartości zwracanej jest int. Do zwracania wartości służy instrukcja return. W naszym przykładzie zwracamy kod typu podanego parametru. Co nam to daje? Możemy teraz wywołać funkcję w taki sposób:

if (znak (x)<2) cout << "To jest litera\n";

else cout << "To nie jest litera\n";

Jeżeli funkcja zwróci wartość < 2, to wykona się pierwszy wiersz. W przeciwnym razie - drugi. Zapowiedź funkcji będzie teraz wyglądała tak:

int znak(char);

W tym zapisie widać, co wchodzi do funkcji, a co z niej wychodzi. Wartością zwracana przez funkcję może być zmienną dowolnego typu, oprócz tablicy. Można to obejść, zwracając wskaźnik do tablicy. Podobnie z przekazywaniem parametrów do funkcji.

Przekazywanie parametrów przez wartość

Sprawdźmy poniższe użycie naszej funkcji:

void main()

{ char x = 'X';

cout << znak (x) << endl;

cout << "x=" << x<< endl;

}

Wszystko działa poprawnie, ale zwróć uwagę, że zmienna x ma nadal taką samą wartość. Przy przekazywaniu parametrów do funkcji, program tylko kopiuje ich wartości i przypisuje je do zmiennych liczba lokalnych wewnątrz funkcji. Takie przekazywanie parametru nazywa się przekazywaniem przez wartość. Wewnątrz funkcji pracujemy więc na kopii zmiennej podanej jako parametr, nie modyfikując oryginału. W podobny sposób zwracany jest wynik. Funkcja kopiuje wartość zwracaną do tymczasowego obiektu, którego nie widać. Po wyświetleniu jego wartości obiekt zostaje zlikwidowany. Ale my byśmy woleli pozostawić ten wynik przy życiu. Co więc zrobić, żeby funkcja znak zapisała wynik bezpośrednio w parametrze?

Przekazywanie parametrów przez referencję

I właśnie tutaj przychodzi nam z pomocą referencja. Jak pamiętasz, referencja to jakby inna nazwa zmiennej. Jeśli parametr funkcji będzie przyjmowany jako referencja, to tak jakbyśmy posłali do funkcji zmienną, a nie jej kopię. Wewnątrz funkcji będziemy używać już nie kopii, ale samej zmiennej, tylko będzie ona mieć inną nazwę dzięki referencji. Po takiej zmianie:

int znak(char &zn)

{ int retwar = 4;

if (zn >='A' && zn <='Z')

{ cout << zn << " jest wielką literą" <<endl;

retwar = 0;

}

if (zn >='a' && zn <='z')

{ cout << zn << " jest małą literą" <<endl;

retwar = 1;

}

if (zn >='0' && zn <='0')

{ cout << zn << " jest cyfrą" <<endl;

retwar = 2;

}

zn+=10; //wykonaliśmy zwiększenie parametru o 10

return (retwar)

}

funkcja będzie modyfikować wartość oryginału, a nie kopii jak poprzednio. Dzięki temu zmienna x będzie teraz powiększona o 10. I to dzięki jednemu dodatkowemu znaczkowi. Również funkcja może wynik poprzez referencję. Wtedy nagłówek funkcji wygląda tak:

int &znak(char &zn)

W naszym przypadku nic by to nie zmieniło. Czasami jednak taki sposób zwracania wartości jest przydatny. Trzeba uważać, żeby nie zwracać referencji czegoś, co już nie będzie istniało poza funkcją: na przykład jej zmiennych lokalnych.

Przekazywanie parametrów przez wskaźnik

Trzeci sposób przekazywania parametrów do funkcji lub zwracania wartości polega na użyciu wskaźników. Pamiętasz, że parametrem funkcji nie może być tablica? Teraz poznasz sposób, w jaki można tablicę wrzucić do funkcji. Dajmy na to, że masz taką tablicę znaków:

char napis[] = "Tablica przekazana jako parametr";

Jak można by ją przekazać do funkcji, która służy do wyświetlania tekstu? Przy okazji wskaźników mówiliśmy, że nazwa tablicy jest wskaźnikiem do jej pierwszego elementu. Jeśli dałoby się przekazać do funkcji taki wskaźnik, to problem będzie rozwiązany. Oto jak należy to zrobić:

void wyswietl(char * text) { cout << text << endl; }

Teraz już możemy posłać do funkcji tablicę, wiedząc, że jej nazwa jest adresem jej pierwszego elementu:

wyswietl(napis);

W podobny sposób możemy wyświetlić tekst zaczynając od innej litery. Wystarczy, że poślemy wskaźnik na inny element tablicy, jak w poniższej instrukcji:

wyswietl(&napis[8]);

Spowoduje to wyświetlenie tylko przekazana jako parametr. Zauważ, że odwoływanie się do parametru poprzez jego wskaźnik również pozwala na modyfikowanie oryginału. Podobnie jak referencję, funkcja może także zwracać wskaźnik. I tutaj też trzeba uważać, żeby nie zwracać wskaźnika do obiektów, które przestaną istnieć po opuszczeniu funkcji.

http://www.elektronik.lodz.pl/wbrzo/index.php?l1=03&l2=10&l3=06


Wyszukiwarka

Podobne podstrony:
wyjaśnij pojęcie cyklu i trendu wzrostu gospodarczego (3 str, Ekonomia, ekonomia
Syzyfowe prace - wyjaśnienie tytułu, Przydatne do szkoły, rozprawki
EFEKT GREJPFRUTA WYJAŚNIONY, NAUKA, WIEDZA
Podać jakiś wzór i wyjaśnić symbole
LIST DO ROMEA OD OJCA LAURENTEGO W KTÓRYM ZAKONNIK WYJAŚNIA SWÓJ PODSTĘP
21 Wyjaśnij pojęcia rozpiętość produktu, linia produktowa, głębokość i zawartość produktu
MB pojecia wyjasnienie
3 wyjaśn i modyf 21 07
Metateza - wyjaśnienie pojecia, Poetyka
Wyjaśnij na czym polega tzw. kwestia homerycka, P-Ż
Wyjaśnienie poszkodowanego, BHP, Wypadki
Dlaczego zło, filozoficzno teologiczna próba wyjaśnienia zła
INFORMACJA WYJAŚNIAJĄCA wypełnienie wniosku
Wyjaśnienie żydowskich nazwisk
OŚWIECENIE WYJAŚNIENIE
WYJAŚNIENIE POJĘĆ HUMANIZM I REFORMACJA
Wyjaśnienie3
27 Wyjaśnić znaczenie odchylenia linii pionu w rozwiązywaniu podstawowych zadań geodezyjnych
wyjaśnienie i mod "

więcej podobnych podstron