Strona główna » Kursy » Kurs C++ » Struktury
 

Struktury

Wstęp

Struktury są to złożone typy danych, które znacznie ułatwiają pracę nad zaawansowanym projektem. Bardzo często w programie dochodzi do sytuacji kiedy istnieje potrzeba zwrócenia np. dwóch liczb całkowitych. Jednak używając standardowych bibliotek istnieje możliwość zwrócenia tylko jednej z liczb. Oczywiście możliwe jest zwrócenie tablicy liczb, albo podanie kilku wskaźników gdzie mają być zapisane wyniki. Struktury rozwiązują ten problem, ponieważ można w nich zapisać z jakich zmiennych ma się składać dany typ danych.

Zapis struktury

Szkielet struktury składa się z (1.) słowa kluczowego struct. Następnie w kodzie po przerwie powinna znaleźć się nazwa struktury i należy otworzyć nawias. (2.) Pomiędzy otwartym, a zamkniętym nawiasem należy wstawić wszystkie deklaracje zmiennych, a na koniec (3.) zamknąć nawias i postawić średnik. Jednym z najczęstszych błędów popełnianych przez użytkownika jest nie dodanie na końcu średnika co powoduje błąd kompilacji.

  1. struct [nazwa] {
  2.   ...
  3. };

W trakcie deklarowanie zmiennych należy pamiętać, że nie należy do nich przypisywać żadnej wartości. Jest to spowodowane faktem, że struktura ma za zadanie przechowywać z czego ta struktura jest złożona, ale nie jakie powinna mieć wartości domyślne. W celu przypisania zmiennym określonych wartości domyślnych należałoby stworzyć scpejalną funkcję. Wracając jednak do deklarowania zmiennych przykładowo struktura para, która ma mieć dwa wartości, które będą liczbami całkowitymi będzie wyglądać następująco:

  1. struct para {
  2.   int wartosc1;
  3.   int wartosc2;
  4. };

(1.) Instrukcja rozpoczynająca deklarację struktury para. Zadeklarowanie pola (2.) o nazwie wartosc1 oraz (3.) wartosc2. (4.) Deklarację kończy zamknięcie nawiasu i dopisanie średnika.

Użycie struktury

Deklaracja

Zmienną, która będzie miała typ złożony, taki jak zadeklarowany w strukturze odbywa się w ten sposób jak deklarowanie np. typu int. W przypadku przedstawionej wyżej struktury wystarczy napisać następujący fragment kodu:

  1.   para p;

Edycja danych

W celu zmiany lub ustalenia wstępnych danych w zmiennej p należy odwołać się do konkretnej zmiennej tj. pola. Robi się to zapisując nazwę zmiennej, kropkę i nazwę wybranej zmiennej. Przypisywanie czy zmiana wartości odbywa się tak jak w przypadku normalnego użycia wybranego typu danych.

  1.   p.wartosc1 = 1;
  2.   p.wartosc2 = 2;

W tym przypadku należy pamiętać o kropce, ponieważ jest to odwołanie do konkretnej wartości z zmiennej p. Przy pierwszym ustalaniu wartości warto użyć operatora przypisania =. W przypadku dalszych zmian wartości można zacząć używać skróconych operatorów arytmetycznych jak np. +=. Należy jednak pamiętać, że zadeklarowane zmienne nie posiadają na początku żadnej konkretnej wartości i może być ona całkowicie losowa (w zależności od kompilatora i starej zawartości pamięci).

Wypisywanie danych

W celu wypisania danych nie można bezpośrednio wypisać typu para na konsolę lub na dowolny inny strumień. Jest to spowodowane faktem, że kompilator nie umie wypisywać takiego typu danych. W takim przypadku należy wypisać wszystkie interesujące wartości poprzez odwołanie się do kolejnych pól. W przypadku wypisywania wartości w wielu miejscach kodu przydatne może okazać się stworzenie dodatkowej funkcji, która będzie zajmować się jedynie wypisywaniem danych z podanej zmiennej.

Najprostszym sposobem wypisania zmiennej p na konsole będzie:

  1.   cout << p.wartosc1 << " " << p.wartosc2 << endl;

Zastosowanie

Najprostszym przykładem funkcji, która może wykorzystać struktury dotyczy znajdowania na liście minimum oraz maksimum. W normalnej sytuacji można by zwrócić albo jedno z nich. Oczywiście jak wcześniej zostało wspomniane rozwiązaniem mogłoby się okazać zadeklarowanie dodatkowej dwuelementowej listy. Jednak przy wykorzystaniu struktury kod staje się zdecydowanie prostszy do zrozumienia:

  1. para szukajMinMax(int* l, int n) {
  2.   para p;
  3.   p.wartosc1 = l[0];
  4.   p.wartosc2 = l[0];
  5.   for (int i = 1; i < n; i++) {
  6.     if (l[i] < p.wartosc1) {
  7.       p.wartosc1 = l[i];
  8.     } else if(l[i] > p.wartosc2) {
  9.       p.wartosc2 = l[i];
  10.     }
  11.   }
  12.   return p;
  13. }

(1.) Funkcja przyjmuje dwa argumenty: listę l zawierającą n liczb. Zwracanym typem danych będzie para gdzie pierwszy element (wartosc1) będzie odpowiadał minimalnemu elementowi na liście, a drugi (wartosc2) maksymalnemu. (2. - 3.) Przypuść, że pierwszy element jest zarówna maksymalny i minimalny. (4.) Dla każdego elementu: (5.) sprawdź czy nie jest mniejszy niż aktualne minimum. Jeśli tak to (6.) zmień wartość. (7.) W przeciwnym razie sprawdź czy dany element jest nowym maksimum. (8.) Jeśli tak to zmień odpowiednią wartość. (11.) Na koniec zwróć zmienną p.

Testowanie funkcji

W celu przetestowania powyższej funkcji można skorzystać z poniższej funkcji main(), która najpierw przyjmie liczbę n, która określi ile elementów jest na liście, a następnie na listę zostanie wczytanych n elementów. Na koniec program wypisze na ekran dwie liczby z czego pierwsza to jest minimalna wartość na listę, a druga to maksymalna wartość.

  1. int main () {
  2.   int n;
  3.   cin >> n;
  4.   int* l = new int[n];
  5.   for (int i = 0; i < n; i++)
  6.     cin >> l[i];
  7.   para p = szukajMinMax(l, n);
  8.   cout << p.wartosc1 << " " << p.wartosc2 << endl;
  9.   delete[] l;
  10.   system("pause");
  11.   return 0;
  12. }

Podsumowanie

Lekcja 18 dobiegła końca. Zajrzyj do kodu źródłowego, aby przeanalizować wypisywanie danych jeszcze raz. Następnie spróbuj wykonać zadania, aby utrwalić materiał.

Zadania

Zadanie 1

Napisz program, który wczyta od użytkownika n liczb rzeczywistych. Program powinien wypisać na ekran dwie największe liczby na liście. Wypisywane liczby powinny być posortowane rosnąco. Można założyć, że wczytywana lista nie będzie długości krótszej niż dwa elementy.

Dane na wejściu będą zawierały w pierwszej linijce liczbę dodatnią, całkowitą n, która określi ile będzie elementów, a następnie zostanie podanych n liczb rzeczywistych. Przykładowo:

  1. 10
  2. 9.8 3 7 10.1 54.3 12.6 12.0 9.7 0.8 1.5

Prawidłową odpowiedzią dla podanego przykładu będzie:

  1. 12.6 54.3