-
Notifications
You must be signed in to change notification settings - Fork 0
4. Struktury
Tablice pozwalają przechowywać wiele wartości, ale wszystkie muszą być tego samego typu. Jeżeli chcemy przechowywać dane dotyczące jednego obiektu, ale będące różnych typów, możemy wykorzystać strukturę. I o tym jest dzisiejsza lekcja.
W celu korzystania ze struktury należy zdefiniować jej składowe:
struct [etykieta struktury]{
definicja składowej;
definicja składowej;
...
definicja składowej;
};
Przykładowa definicja struktury reprezentującej punkt na płaszczyźnie 2D będzie prezentować się następująco:
struct PunktXY{
float x;
float y;
};
Definicja struktury określa układ składowych w strukturze. Musimy pamietać, że samo zdefiniowanie struktury nie jest równoznaczne z utworzeniem zmiennej strukturalnej. Zmienne typu strukturalnego są deklarowane analogicznie jak zmienne typów podstawowych, to znaczy za pomocą konstrukcji
struct PunktXY a, b;
Strukturę można inicjalizować, umieszczając po definicji listę wartości początkowych, czyli dla naszego punktu będzie to:
struct PunktXY a = {3.20, 2.00};
Możemy definiować struktury zawierające inne struktury. Przykładowo informacje o trójkącie można przechowywać w strukturze zdefiniowanej następująco
struct triangle {
struct PunktXY A;
struct PunktXY B;
struct PunktXY C;
};
W powyższym przykładzie trzy pola można zastąpić tablicą struktur.
struct trojkat {
struct PunktXY wierzcholki[3];
};
Podobnie można zdefiniować strukturę opisującą wielokąt posługując się wskaźnikiem na pierwszy element tablicy struktur oraz rozmiarem tej tablicy (wyrażającym liczbę wierzchołków).
struct wielokat {
int n;
struct PunktXY * wierzcholki;
};
Aby uzyskać dostęp do elementów składowych struktury korzystamy z operatora .
(kropka), co wygląda następująco nazwaZmiennejStrukturalnej.nazwaSkładowej
.
Ze względu na to, że struktury mogą mieć duży rozmiar, korzystne może być posługiwanie się wskaźnikami na struktury.
Wiąże się to także z odpowiednim przekazywaniem struktur do funkcji (czyli przez wskaźnik). Dostęp do struktur wskazywanych przez wskaźnik uzyskuje się operatorem ->
.
wskaźnikNaStrukturę->nazwaSkładowej
(*wskaźnikNaStrukturę).nazwaSkładowej
Zastosujmy poznane operatory na przykładzie struktury Polynomial przechowującej stopień wielomianu jako liczbę całkowitą oraz wskaźnik na pierwszy element tablicy przechowującej jego współczynniki.
#include <stdio.h>
#include <stdlib.h>
struct Polynomial{
int degree; //stopien wielomianu
double *coefficients; //wskaznik na tablice wspolczynnikow
};
// tworzymy nowa zmienna typu Polynomial z tablica wspolczynnikow o odpowiednim rozmiarze
struct Polynomial * newPolynomial(int n);
// drukujemy wielomian na ekranie
void printPolynomial(struct Polynomial *wielomian);
void deletePolynimial(struct Polynomial ** wielomian_coef);
void setPolynomial(struct Polynomial *, double *);
int main()
{
//deklaracja zmiennych a typu Polynomial
struct Polynomial * a = newPolynomial(5);
//drukowanie na ekranie zawartosci zmiennej - tablica powinna byc wypelniona zerami
printPolynomial(a);
printf("\n");
double tablica[] = {6,3,8,1,2,3};
setPolynomial(a, tablica);
printPolynomial(a);
printf("\n");
//usuwamy wypelniona tablice wspolczynnikow (zwalniamy pamiec)
deletePolynimial(&(a->coefficients));
//zwalniamy pamiec dla wskaznika na strukture Polynomial
free(a);
return 0;
}
// tworzymy nowa zmienna typu Polynomial z tablica wspolczynnikow o odpowiednim rozmiarze
struct Polynomial * newPolynomial(int n){
struct Polynomial *wielomian = malloc(sizeof(struct Polynomial));
// przypisujemy wartosci polom struktury wielomian
wielomian->degree = n;
wielomian->coefficients = malloc((n+1) * sizeof(*(wielomian->coefficients)));//bo potrzebujemy n+1 wspolczynnikow, np dla wielomianu stopnia 2 mamy a,b i c -> ax^2+bx+c (3 wspolczynniki)
int i;
for(i = 0; i <= n; ++i){ // wypelniamy tabele wspolczynnikow zerami
wielomian->coefficients[i] = 0;
}
return wielomian;
};
// drukujemy wielomian na ekranie
void printPolynomial(struct Polynomial *wielomian){
if(wielomian != NULL){//sprawdzamy czy w ogóle nasz wskaznik przekazany jako argument funkcji wskazuje na jakiekolwiek miejsce w pamieci
int i;
printf("f(x) = ");
for(i = wielomian->degree; i > -1; --i){
printf("%+.2lfx^%d", wielomian->coefficients[i], i);
}
} else{
printf("\nWskaznik jest pusty!\n");
}
};
void deletePolynimial(struct Polynomial ** wielomian_coef){
if(wielomian_coef != NULL){
free(wielomian_coef); // zwalniamy pamiec
wielomian_coef = NULL; // ustawiamy wskaznik 'w nicosc'
}
};
void setPolynomial(struct Polynomial * wielomian, double *tab){
int i;
for(i = 0; i <= wielomian->degree; ++i){ // wypelniamy tabele wspolczynnikow
wielomian->coefficients[i] = tab[i];
}
}
typedef
jest słowem kluczowe, które służy do definiowania typów pochodnych.
typedef stara_nazwa nowa_nazwa;
typedef int mojInt;
typedef int* WskNaInt;
typedef struct PunktXY punkt;
punkt a = {3.20, 2.00}; //inicjalizacja struktury PunktXY wykorzystując zdefiniowany typ pochodny
Jak można dostrzec na powyższym przykładzie, słowo kluczowe typedef
pozwala nam uniknąć ciągłej potrzeby wypisywania struct nazwa_struktury nazwa_zmiennej
w przypadku deklaracji zmiennej strukturalnej.
Polem struktury nie może być ta sama struktura, ale może być wskaźnik na taką strukturę. Tego typu struktury nazywamy strukturami cyklicznymi. Przykładem takich struktur są lista (np. jednokierunkowa) oraz drzewo (np. binarne).