1. Struktury Podstawowe informacje



Pobieranie 270,25 Kb.
Data15.04.2018
Rozmiar270,25 Kb.

Wykład 9

Struktury, tablice struktur - przykłady programów w C /C++.



Zastosowanie const - przekazywanie stałych parametrów do funkcji przez wartość, wskaźnik i referencję

Dodatek: Unie, pola bitowe
1. Struktury

1.1. Podstawowe informacje


  • Struktury zawierają różne dane definiujące jeden przedmiot, zgromadzone w jednym miejscu

  • Dane przechowywane w strukturze zwane są składowymi

  • W pamięci składowe stanowią spójny blok danych i występują w kolejności wystąpienia w deklaracji typu strukturalnego



Przykład 1

Świat rzeczywisty

ksiązka_1

Autor_1


Tytuł_1

Cena_1



ksiązka_2

Autor_2


Tytuł_2

Cena_2


Program 1





6 zmiennych

char autor_1[8]= ”Autor_1”;

char tytul_1[8]= ”Tytul_1”;

int cena_1= 10;

char autor_2[8]= ”Autor_2”;

char tytul_2[8]= ”Tytul_2”;

int cena_2= 20

Program 2

szablon” książki



struct KSIAZKA

{ char autor[8];



char tytul[8];

int cena;

};


2 zmienne

struct KSIAZKA ksiazka_1=

{”Autor_1”,”Tytul_1”, 10};



KSIAZKA ksiazka_2 =

{”Autor_2”, ”Tytul_2”, 20};



ksiazka_1

A

u

t

o

r

_

1

\0

T

y

t

u

l

_

1

\0

1 0




autor

tytul

cena

ksiazka_2

A

u

t

o

r

_

2

\0

T

y

t

u

l

_

2

\0

2 0




autor

tytul

cena


1.2. Deklaracje struktur
Deklaracja struktury:

  • jest planem, który opisuje budowę struktury

  • zawiera listę deklaracji składowych



Definicje typu strukturalnego

Przykłady

1. Schemat deklaracji opcjonalnie połączonej z definicją zainicjowanej zmiennej strukturalnej zwanej krótko strukturą

struct [nazwa-typu-struktury]

{

deklaracje



składowych struktury

dowolnych typów;

} [nazwa-struktury] = [inicjator],...];



struct KSIAZKA

{

char autor[MAXNAZ];



char tytul[MAXNAZ];

int cena;

};


2. typedef umożliwia nadanie nowej nazwy dla deklarowanego typu

typedef struct [nazwa-typu-struktury]

{

deklaracje



składowych struktury

dowolnych typów;

} nowa_nazwa-typu;



typedef struct KSIAZKA

{

char autor[MAXNAZ];

char tytul[MAXNAZ];

int cena;

} ksiazka;


  1. 3. Definicje struktur
Definicje struktur i tablic typu KSIAZKA
Uwagi

struct KSIAZKA

{char autor[MAXNAZ];

char tytul[MAXNAZ];

int cena;

} k1 = {”Autor_1”, ”Tytul_1”, 100}, k2, tab[10];



deklaracja typu strukturalnego KSIAZKA i definicja struktury k1z zainicjowanymi składowymi oraz niezainicjowanych: struktury k2 i tablicy tab zawierającej 10 struktur

struct KSIAZKA

k1={”Autor_1”, ”Tytul_1”, 100},

k2, tab[10];

ksiazka k3, tab1[10];



definicja struktury k1 z zainicjowanymi składowymi oraz niezainicjowanych: struktur k2, k3, tablic tab1 oraz tab2 zawierających 10 struktur. Do definicji k3 i tab2 użyto nowej nazwy ksiazka

KSIAZKA

k1= {”Autor_1”, ”Tytul_1”, 100},

k2, tab[10];


definicja bez słowa struct (C++) struktury k1 z zainicjowanymi składowymi oraz niezainicjowanych: struktury k2 i tablicy tab zawierającej 10 struktur

    1. Wskaźniki do struktur

      Deklaracja nowej nazwy

      Definicje wskaźników na struktury


      typedef struct KSIAZKA * PKsiazka;

      struct KSIAZKA * wsks1, *wskt1;

      ksiazka * wsks2, *wskt2;

      PKsiazka wsks3, wskt3;

      KSIAZKA * wsks4, *wskt4; // C++



    2. Przydzielanie i zwalnianie pamięci

      Przydział pamięci
      Zwalnianie pamięci

      Uwagi

      wsks1 = malloc(sizeof(ksiazka));

      free(wsks1);

      C

      wskt1 = malloc(N * sizeof(ksiazka));

      free(wskt1)

      C

      wsks2 = (ksiazka*) calloc(sizeof(ksiazka));

      free(wsks2);

      C, C++

      wskt2 = (ksiazka*) calloc(N, sizeof(ksiazka));

      free(wskt2);

      C, C++

      wsks3= (PKsiazka)malloc(sizeof(KSIAZKA));

      free(wsks3);

      C, C++

      wskt3 = (PKsiazka)malloc(N*sizeof(KSIAZKA));

      free(wskt3);

      C, C++

      wsks4 = new ksiazka;

      delete wsks4;

      C++

      wskt4 = new ksiazka [N];

      delete [] wskt4;

      C++

    3. Operacje na strukturach

Definicje

Obliczanie adresu

Przypisanie struktur

struct KSIAZKA

k1= {”Autor_1”, Tytul_1”, 100}, k2;






k2 = k1;

PKsiazka wsks1;

wsks1 = & k1;







    1. Dostęp do składowych struktury - operatory wyboru: . i




Bezpośredni operator wyboru .

Pośredni operator wyboru

strcpy (k1.autor, ”Autor_1”);

strcpy (k1.tytul, ”Tytul_1”);

k1.cena = 100;


wsks1= &k1;

wsks2 = (ksiazka*)malloc(sizeof( ksiazka));

strcpy (wsks1autor, ”Autor_1”);

wsks2cena = 100;



wsks1= &k1;

wsks2 = new ksiazka;

strcpy((*wsks1).autor,”Autor_1”);

(*wsks2).cena = 100;







Składowe mogą być dowolnego typu (również typu strukturalnego) oprócz następujących przypadków:


  • składowa nie może być aktualnie deklarowanym typem strukturalnym, a jedynie wskaźnikiem tego typu

  • składowe struktury w C nie mogą być funkcją, lecz wskaźnikiem na funkcję




Nieprawidłowo w C, C++

Prawidłowo w C,C++

struct A

{struct A a;

int b;

};


struct A

{struct A* a;

int b;

};


1.8. Zagnieżdżanie struktur

Deklaracje struktur

Definicje struktur

Odwołania do składowych

1.Deklaracje zagnieżdżonych struktur

struct okno

{ struct punkt

{ int x;

int y;

} lewy;


struct punkt prawy;

};




struct okno okno1; // C, C++
struct punkt srodek1; // C

okno::punkt srodek2; //C++



okno1.lewy.x = 3;

okno1.prawy.x = 5;

srodek1.x = 6;

srodek2.x = 8;


2. Deklaracje niezależnych struktur jako składowych

struct punkt

{

int x;



int y;

};

struct okno

{

struct punkt lewy;

struct punkt prawy;

};




struct okno okno1;
struct punkt srodek1;

punkt srodek2;



okno1.lewy.x = 3;

okno1.prawy.x = 5;

srodek1.x = 6;

srodek2.x = 8;


1.9. Struktury i funkcje

Przykładowe deklaracje i definicje

typedef struct KSIAZKA * PKsiazka;

typedef struct KSIAZKA

{ char autor[8];



char tytul[8];

int cena;

} ksiazka;

ksiazka ksiazka_1, ksiazka_2;

PKsiazka pksiazka_1;




  1. Przekazywanie przez wartość parametru typu struktura
Przekazanie na stos kopii wartości struktury - struktura tylko do czytania

void fun1 (ksiazka k1)

{ cprintf("\r\nAutor:%10c%s\r\n",' ', k1.autor);

cprintf("Tytul:%10c%s\r\n",' ', k1.tytul);

cprintf("Cena:%11c%.2f\r\n",' ', k1.cena);

getch(); }

wywołanie funkcji: fun1(ksiazka_1);
2) Przekazywanie przez referencję parametru typu struktura

Przekazanie na stos referencji (implementowanej przez wskaźnik) do struktury - struktura do czytania i zapisu



void fun2 (ksiazka &k2)

{ char bufor[8+2];

bufor[0]= 8;

cprintf("\r\nPodaj autora:%3c",' '); strcpy(k2.autor, cgets(bufor));

cprintf("\r\nPodaj tytul:%4c",' '); strcpy(k2.tytul, cgets(bufor));

cprintf("\r\nPodaj cene:%5c",' '); k2.cena=atof(cgets(bufor));

cputs("\r\n");}

wywołanie funkcji: fun2(ksiazka_1);
3) Przekazywanie przez wskaźnik parametru typu struktura

Przekazanie na stos wskaźnika do struktury - struktura do czytania i zapisu

void fun3 (ksiazka *k3)

{ char bufor[8+2];

bufor[0]= 8;

cprintf("\r\nPodaj autora:%3c",' '); strcpy(k3autor, cgets(bufor));

cprintf("\r\nPodaj tytul:%4c",' '); strcpy(k3tytul, cgets(bufor));

cprintf("\r\nPodaj cene:%5c",' '); k3cena=atof(cgets(bufor));

cputs("\r\n"); }

wywołanie funkcji: fun3(&ksiazka_1);

4) Zwracanie wyniku funkcji jako struktury

Przekazanie kopii struktury umieszczonej na stosie funkcji

ksiazka fun4(void)

{ ksiazka k4; char bufor[8+2];

bufor[0]=8;

cprintf("\r\nPodaj autora:%3c",' '); strcpy(k4.autor, cgets(bufor));

cprintf("\r\nPodaj tytul:%4c",' '); strcpy(k4.tytul, cgets(bufor));

cprintf("\r\nPodaj cene:%5c",' '); k4.cena=atof(cgets(bufor));

cputs("\r\n");

return k4;

}

wywołanie funkcji: ksiazka_1= fun4();


5) Zwracanie przez wartość wyniku funkcji jako wskaźnika do struktury
Przekazanie kopii wskaźnika do struktury, która nie może znajdować się na stosie danej funkcji – musi istnieć po zakończeniu funkcji np. na stercie

PKsiazka fun5(void)

{ PKsiazka k5; char bufor[8+2];

bufor[0] = 8;

k5 = new KSIAZKA;

cprintf("\r\nPodaj autora:%3c",' '); strcpy(k5autor, cgets(bufor));

cprintf("\r\nPodaj tytul:%4c",' '); strcpy(k5tytul, cgets(bufor));

cprintf("\r\nPodaj cene:%5c",' '); k5cena=atof(cgets(bufor));

cputs("\r\n");



return k5;

}

wywołanie funkcji: pksiazka_1= fun5();


6) Zwracanie przez wskaźnik wyniku funkcji jako referencji do struktury
Przekazanie kopii referencji do struktury, która nie może znajdować się na stosie danej funkcji – musi istnieć po zakończeniu funkcji

ksiazka& fun6(ksiazka& k6, ksiazka& k7)

{

if (k6.cena <= k7.cena)



return k6;

else return k7;

}

wywołanie funkcji: fun6(ksiazka_1, ksiazka_2).cena *=1.22;



/*zmiana wartości składowej cena w strukturze ksiazka_1 lub ksiazka_2*/

  1. Zastosowanie const - przekazywanie stałych parametrów do funkcji przez wartość, wskaźnik i referencję

Przykłady

Stałe symboliczne

const int ROZMIAR = 5;

zmienna przeznaczona tylko do odczytu

Stała referencyjna

const int& ref_stała = 1;


ref_stała równe 1 w zmiennej tymczasowej

stała tablica

const int stalatab[ROZMIAR] = {1,2,3,4,5};

stalatab[2] = 4;



stała zawartość tablicy

błąd kompilacji

wskaźnik do stałej wartości



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

const int * wsktab1 = zmiennatab;

wsktab1[1] = 5;

zmiennatab[1] = 5;

wsktab1++;

wsktab1 = stalatab;

wsktab1= stalatab+2;




dobrze

błąd kompilacji

dobrze

dobrze

dobrze

dobrze

Zwykły wskaźnik może przechowywać tylko adres danych zmiennych

int *wsktab = zmiennatab;

wsktab = stalatab;




dobrze

błąd kompilacji


stały wskaźnik

int *const wsktab2 = zmiennatab;

wsktab2 = zmiennatab+2;

wsktab2[1] = 5;


dobrze

błąd kompilacji

dobrze

stały wskaźnik do stałej wartości

const int *const wsktab3 = zmiennatab;

wsktab3 = zmiennatab+ 2;

wskatab3[1] = 5;


dobrze

błąd kompilacji

błąd kompilacji

przekazywanie parametrów:

wskaźnik do stałej oraz referencja do stałej



int ile=5;

void Pokaz_dane(const int *tab, const int ile);

void Wstaw_do_tablicy(int *tab, int & ile);

Pokaz_dane(stalatab, 5);

Pokaz_dane(zmiennatab, ile );

Wstaw_do_tablicy(stalatab, ile);

Wstaw_do_tablicy(zmiennatab, ile);

void f_ref (int& ref, const int& st)

f_ref( ile, ROZMIAR) ;

f_ref( ROZMIAR, ile) ;

f_ref (3,4);




dobrze

dobrze

błąd kompilacji

dobrze
dobrze

ostrzeżenie ROZMIAR

ostrzeżenie dla 3

  1. Przykłady programów w C / C++

Przykład 1




#include

#include
#define kbEsc 27

#define kbLeft 75

#define kbRight 77

#define kbUp 72

#define kbDn 80
struct punkt

{int x, y;

};
void przesun(punkt&, int, int);

void wyswietl(const punkt*);

void wspolrzedne(const punkt*, int, int);

void komunikat(const char*, int, int);

void narysuj (const punkt);
void main()

{ punkt p={1, 1};



char opcja;

_setcursortype(_NOCURSOR);

clrscr();

printf("Jesli nacisniesz jeden z klawiszy:\n");

printf(" strzalka w prawo, strzalka w lewo, strzalka w gore, strzalka w dol \n");

printf("k, Esc - Koniec programu\n");

narysuj(p);

wspolrzedne(&p,2,23);



do

{

opcja=getch();



if (opcja==0) opcja=getch();

switch(opcja)

{ case kbLeft : przesun(p,-1,0); break;



case kbRight : przesun(p,1,0); break;

case kbUp : przesun(p,0,-1); break;

case kbDn : przesun(p,0,1); break;

case 'k': case kbEsc :

komunikat("Nacisnales klawisz Esc lub k - koniec programu",2,24); break;

default : komunikat("Nacisnales niewlasciwy klawisz",2,24);

}

narysuj(p);



wspolrzedne(&p,2,23);

}while (opcja!=kbEsc && opcja!='k');

_setcursortype(_NORMALCURSOR);

}
void przesun(punkt& p, int x, int y)

{ if ((p.x + x)>0 && (p.x+x)<=80) p.x+=x;

if ((p.y + y)>0 && (p.y+y)<=17) p.y+=y;

}
void wyswietl(const punkt* p)

{ printf("x=%i, y=%i",p->x, p->y);}
void wspolrzedne(const punkt* p, int x, int y)

{ gotoxy(x,y); wyswietl(p);



while(!kbhit());

}
void komunikat(const char* lan, int x, int y)

{ gotoxy(x,y); printf(lan);

while(!kbhit());

gotoxy(x,y); clreol();

}
void narysuj (const punkt p, int x, int y)

{ window(x,y,80,22); clrscr();

gotoxy(p.x,p.y); puts("*");

window(1,1,80,25);


}

Przykład 2 -Tablica struktur

#include

#include

#include

const int DL=10;

struct OSOBA // definicja typu OSOBA

{int Wzrost;

char Nazwisko[DL];

};

//deklaracje uniwersalnych funkcji we/wy dla struktur typu OSOBA



void Pokaz_dane (OSOBA &Dana);

OSOBA Dane();

// deklaracje pomocniczych funkcji obsługujących menu programu oraz komunikaty

const int POZ=7;

char Menu(const int ile, char *Polecenia[POZ]);

// deklaracje funkcji dla zdefiniowanej statycznej tablicy struktur jako listy nieuporządkowanej



const int N=5;

int Wstaw(OSOBA*tab, OSOBA dane, int ktory, int &ile);

int Usun(OSOBA*tab, int ktory, int &ile);

int Wyswietl(OSOBA*tab, int ile);
// funkcja ogólnego przeznaczenia

int Numer(char*);
//przykładowa aplikacja wykorzystująca listę nieuporządkowaną reprezentowaną przez statyczną //tablicę struktur (tablist1.cpp)
char *Polecenia[POZ]={"Tablica OSOBA tab[N] - obsluga typu lista",

" Nacisnij:",

" 1 - aby wstawic element do listy osob",

" 2 - aby usunac element z listy osob",

" 3 - aby wyswietlic liste osob, ",

" 4 - aby usunac liste osob",

" Esc - aby zakonczyc prace."};
char *Stan[]=

{"Tablica pelna",

" Wstawiono poprawnie",

" Zly numer do wstawienia",

" Tablica pusta",

" Usunieto poprawie",

" Zly numer do usuwania",

" Wyswietlono poprawnie"};



void main(void)

{int ile=0, który, stan;

OSOBA tab[N];

char Co;



do

{Co = Menu(POZ,Polecenia);

switch(Co)

{case '1' : OSOBA pom=Dane();

ktory=Integer("\nPodaj indeks: ");

stan= Wstaw(tab, pom, ktory, ile);

printf("%s\n", Stan[stan]); break;

case '2' : ktory=Integer("\nPodaj indeks: ");

stan= Usun(tab, ktory, ile);

printf("\n%s\n", Stan[stan]); break;

case '3' : stan= Wyswietl(tab, ile);

printf("\n%s\n", Stan[stan]); break;



case '4' : ile=0; break;

case 27 : printf("%s\n","\nKoniec programu"); break;

default : printf("%s\n","\nZla opcja");

}

getch();



}while (Co !=27);

}

int Integer(char* s)

{ int ktory;

printf("\n\n%s", s);

scanf("%d", &ktory);

return ktory; }
//definicje uniwersalnych funkcji we/wy dla struktur typu OSOBA

OSOBA Dane()

{char bufor[DL+2];

OSOBA Nowy;

bufor[0]=DL;

Nowy.Wzrost=Integer("\nwzrost: ");

printf("\nnazwisko: ");

strcpy(Nowy.Nazwisko, cgets(bufor));

return Nowy;

}

void Pokaz_dane(OSOBA &Dana)



{ printf("\nWzrost: %d\n", Dana.Wzrost);

printf("Nazwisko: %s\n", Dana.Nazwisko);

printf("Nacisnij dowolny klawisz...\n");

getch();}

// definicje pomocniczych funkcji obsługujących menu programu

char Menu(const int ile, char *Polecenia[])

{clrscr();



for (int i=0; iprintf("\n%s", Polecenia[i]);

return getch();}

//definicje funkcji obsługujących tablice struktur


int Wstaw(OSOBA* tab, OSOBA dane, int ktory,int &ile)

{

if (ile==N) return 0; //tablica pełna



if ( ktory<0 || ktory>ile) return 2; //zły indeks

for (int i= ile; i> ktory; i--) //założenia: 0<=ile

tab[i]= tab[i-1];

tab[ktory]=dane;

ile++;

return 1;



}
int Usun(OSOBA* tab, int ktory, int &ile)

{

if (ile==0) return 3; //tablica pusta



if (ktory<0 || ktory>= ile) return 5; //zły indeks

for (int i= ktory; i//założenia: 0

tab[i]= tab[i+1];

ile--;


return 4; //usunięto poprawnie

}
int Wyswietl(OSOBA* tab, int ile)

{

if (ile==0) return 3; //tablica pusta

for (int i=0; i

Pokaz_dane(tab[i]); //wykonaj czynność na elementach tablicy



return 6; //wyświetlono poprawnie tablice

}


  1. Dodatek

  1. Unie

Unię można uznać za strukturę, w której wszystkie składowe są umieszczone z przesunięciem zerowym względem jej początku. Rozmiar unii jest równy rozmiarowi największej składowej. W danej chwili unia może zawierać co najwyżej jedną ze swoich składowych. W przeciwieństwie do struktury unię można inicjować wartością nadaną pierwszej składowej unii. Składowymi unii w języku C mogą być wskaźniki na funkcje (traktowane tak, jak inne składowe). W C++ składowymi funkcji są również funkcje (metody), dostępne niezależnie od innych składowych.
Deklaracja:

union [identyfikator-typu-unii]

{ deklaracje składowych dowolnych typów;

} [identyfikator-unii] = [inicjator],...];

Przykład



#include

#include

void f1() {cputs("\r\n f1");}

void f2(char *s) {cputs(s);}
static union //globalna unia anonimowa - należy użyć słowa static

{ double Z; int X; //dostęp jak do zwykłych zmiennych globalnych

}; //umieszczonych w jednym miejscu w pamięci
void main()

{ union A

{ double z; int x;

void (*a) ();

void (*b) (char *s);

};

union //unia anonimowa - dostęp do składowych jak do zwykłych zmiennych

{ double z; int x; //lokalnych funkcji, umieszczonych w jednym miejscu pamięci

};

A aa = {1}; //zmienna o rozmiarze sizeof (double) o wartości aa.z=1.0; aa.x= 0;



z = 1; //zmienna o rozmiarze sizeof (double) o wartości z=1.0; x= 0;

Z = 1; //zmienna o rozmiarze sizeof (double) o wartości Z=1.0; X= 0

aa.a = f1; //zmienna aa.z= 1.00000000000016; aa.x = 709

aa.a(); //napis na ekranie: f1

aa.b = f2; //zmienna aa.z= 1.00000051567638; aa.x= 719



// aa.a(); niedozwolona operacja: pod adresem funkcji f2 byłaby

//wywołana funkcja o nagłówku składowej void (* a)();

aa.b("\r\n A.b");} //napis na ekranie: A.b



  1. Pola bitowe

W obrębie deklarowanej struktury, unii oraz klasy mogą wystąpić tzw. pola bitowe, czyli składowe całkowite o rozmiarze wyrażonym w bitach. Rozmieszczenie pól bitowych zależy od implementacji (np. od prawej do lewej lub od lewej do prawej).

Składowe te mogą być zdefiniowane jako: signed lub unsigned int. Rozmiar jednego pola bitowego nie może przekraczać 16 bitów. Dla pól ze znakiem 1 na najstarszym bicie jest bitem znaku (np. 101 jest równe 5 dla unsigned int lub -3 dla signed int).

Pole bez nazwy nie jest składową, nie może być inicjowane oraz nie ma do niego dostępu, lecz może służyć do wyrównania następnego pola bitowego do granicy jednostki przydziału (np. pole bez nazwy o rozmiarze 0) lub do konkretnego położenia w ramach jednostki przydziału (pole bez nazwy o konkretnej wartości).


Przykład

struct Status

{ unsigned int a: 5;

signed int: 0; //pole bez nazwy i rozmiaru wyrównujące następne pole

signed int b: 3; //b do nowego bajtu - bit o numerze 8

unsigned int: 3; //pole bez nazwy, o rozmiarze 3, ustalające położenie

unsigned int c: 2; //następnego pola c

};


15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

c




b










a

1

1










1

0

1










1

0

1

1

0

3










-3










22


3. Porównanie języków C/C++ (wersja nieobiektowa)


  • Język C jest podzbiorem języka C++

  • Język C++ rozwinął się z C (K&R78).

  • Język C++ zawiera większość zmian wyszczególnionych w standardzie ANSI C.

  • Programy napisane w ANSI C, K&R C i C++ są narażone na zmienne wartościowanie wyrażeń.

  • Różnice znaczeń w programach napisanych w ANSI C i C++




Problem

Znaczenie w:

Uwagi

języku C

języku C++

A

stała typu int

stała typu char

różnice rozmiarów typów


enum w {A, B} a;

sizeof(a)



sizeof(int)

nie musi być równe sizeof(int)

j.w.

double x;

void f (void)

{struct x {int a;};



sizeof(x);

}



sizeof(x)

jest równe



sizeof(double)


sizeof(x)

jest równe



sizeof(int)

nazwa struktury zadeklarowana w zasięgu wewnętrznym

void f();

funkcja może przyjąć dowolną liczbę parametrów dowolnego typu

funkcja bez- argumentowa

void f(void) w obu językach oznacza deklarację funkcji bezargumentowej

const

łączność zewnętrzna

łączność wewnętrzna

w obu językach

extern const

łącznosc zewnętrzna

static const

łączność wewnętrzna




Autor: Zofia Kruczkiewicz,p325 C3 Wykład 9 Języki programowania i metody programowania C2




©operacji.org 2017
wyślij wiadomość

    Strona główna