Struktury

Autor podstrony: Krzysztof Zajączkowski

Stronę tą wyświetlono już: 4219 razy

Struktury umożliwiają przechowywanie pod jedną nazwą zmiennej złożonej wielu typów prostych a nawet i egzemplarzy struktur czy też klas, dzięki czemu dużo łatwiej jest grupować takie zmienne w tablicach. Poniżej zamieszczam prosty przykład struktury typu student:

struct student // deklaracja struktury typu student { char Nazwisko[100]; // pole struktury będące 100 elementową tablicą statyczną typu char char Imie[100]; // pole struktury będące 100 elementową tablicą statyczną typu char float MatematykaOcena; // pole struktury typu float float FizykaOcena; // pole struktury typu float }; // ważne, aby nie zapominać o średniku po zamknięciu nawiasów klamrowych

Jak widać, udało się w jednej definicji struktury typu student zamieścić kilka typów prostych oraz typy łańcuchowe, teraz utworzyć należy egzemplarz struktury student w sposób następujący:

student s = {"Kowalski","Leon",5,5}; // tak tworzy się i jednocześnie inicjalizuje się zmienną o nazwie s będącą egzemplarzem klasy typu student cout<<"Nazwisko: "<<s.Nazwisko /*odwołanie się do pola struktury o nazwie Nazwisko */<<" Imie: "<<s.Imie<<"\nOcena koncowa z matematyki: "<<s.MatematykaOcena<<"\nOcena końcowa z fizyki: "<<s.FizykaOcena; // wypisywanie zawartości pól struktury

Powyżej pokazany został przykład odwołania się do elementów struktury typu student za pomocą operatora . (kropki). W podobny sposób deklaruje się tablice statyczne struktur:

student tstudentow[] = {{"Kowalski","Leon",5,5},{"Pietrucha","Mirosław",3,3}}; // inicjowanie statycznej tablicy dwuelementowej wraz z jednoczesnym ustawieniem danych zawartych w polach for(int i = 0; i < sizeof(tstudentow) / sizeof(student) /* określenie rozmiaru tablicy (poprawne tylko dla statycznie utworzonych tablic)*/; i++){ cout<<"Nazwisko: "<<tstudentow[i].Nazwisko /*odwołanie się do pola struktury o nazwie Nazwisko i-tego elementu tablicy*/<<" Imie: "<<tstudentow[i].Imie<<"\nOcena koncowa z matematyki: "<<s.MatematykaOcena<<"\nOcena koncowa z fizyki: "<<tstudentow[i].FizykaOcena; // wypisywanie zawartości pól struktury }

Dynamiczne deklarowanie egzemplarza struktury typu student:

student *lpstudent = new student; strcpy(lpstudent->Nazwisko,"Kowalski"); // kopiowanie ciągu znaków "Kowalski" do pola Nazwisko za pomocą funkcji strcpy. Aby możliwe było korzystanie z tej funkcji trzeba załączyć do projektu plik nagłówkowy string.h strcpy(lpstudent->Imie,"Leon"); lpstudent->MatematykaOcena = 5; // inicjalizowanie pola wskaźnika na strukturę lpstudent->FizykaOcena = 5; cout<<"Nazwisko: "<<lpstudent->Nazwisko /*odwołanie się do pola wskaźnika o nazwie Nazwisko struktury typu student*/<<" Imie: "<<lpstudent->Imie<<"\nOcena koncowa z matematyki: "<<lpstudent->MatematykaOcena<<"\nOcena końcowa z fizyki: "<<lpstudent->FizykaOcena; // wypisywanie zawartości pól struktury if(lpstudent){ // jeżeli lpstudent ma przypisany jakiś adres w pamięci to delete lpstudent; // zwolnij tą pamięć lpstudent = 0; // i przypisz zerowy adres aby dać znać, że wskaźnik już na nic nie wskazuje }

Skoro mamy studenta, to wypadałoby utworzyć strukturę typu grupa opisującą daną grupę studentów danego roku studiów:

struct grupa { char kierunekStudiow[100]; student *tstudent; // wewnątrz struktury jest wskaźnik do struktury typu student (będzie to tablica dynamiczna) unsigned short int nrOfStudents; // to pole będzie przechowywało informację o liczbie studentów w grupie };

Inicjalizacja podstawowa egzemplarza powyższego typu struktury będzie wyglądała następująco:

grupa gr={"Informatyka",0,0};

Do dodawania nowych studentów stwożyć należy sobie taką oto funkcję:

void DodajStudentaDoGrupy(grupa &gr, const char* nazwisko, const char* imie, float matematykaOcena, float fizykaOcena){ if(gr.nrOfStudents > 29) // jeżeli studentów jest już trzydziestu to return ; // nie pozwalaj na dodawanie kolejnych studentów do grupy student *tstudent = new student[gr.nrOfStudents + 1]; // przydzielanie pamięci o 1 większej niż obecna pamięć zawierająca listę studenciaków for(unsigned int i = 0; i < gr.nrOfStudents; i++){ // dla wszystkich elementów tablicy dynamicznej gr. tstudent[i] = gr.tstudent[i]; // kopiuj zawartość danego elementu tablicy gr.tstudent do tablicy tstudent } if(gr.nrOfStudents){ // gdy liczba studentów nie jest równa 0 delete[] gr.tstudent; // zwalniaj pamięć } gr.tstudent = tstudent; // przypisanie wskaźnika tstudent do gr.tstudent strcpy(tstudent[gr.nrOfStudents].Nazwisko, nazwisko); // kopiowanie nazwiska dodawanego studenciaka strcpy(tstudent[gr.nrOfStudents].Imie, imie); // kopiowanie imienia dodawanego studenciaka tstudent[gr.nrOfStudents].MatematykaOcena = matematykaOcena; // przypisanie oceny z matmy tstudent[gr.nrOfStudents].FizykaOcena = fizykaOcena; // przypisanie oceny z fizy gr.nrOfStudents ++; // zwiększenie zmiennej pamiętającej liczbę studenciaków }

W powyższym kodzie pokazane zostało, jak przekazywać odwołania do struktur w funkcjach poprzez referencje. Dodam jeszcze dwie funkcje, które będą pomocne przy wczytywaniu nowych elementów tablicy do tablicy dynamicznej:

void WypiszDaneStudenta(student &s){ // funkcja wypisuje dane danego studenciaka cout<<"Nazwisko: "<<s.Nazwisko<<" Imie: "<<s.Imie<<endl<<"Ocena koncowa z matematyki: "<<s.MatematykaOcena<<"Ocena koncowa z fizyki: "<<s.FizykaOcena; } void WypiszDaneGrupy(grupa &gr){ // funkcja wypisuje dane na temat grupy, oraz wypisuje nazwiska i imienia wszystkich stodenciaków cout<<"Kierunek: "<<gr.kierunekStudiow<<endl<<endl<<"Liczba studentow: "<< gr.nrOfStudents << endl << endl <<"Lista studentow: "<<endl<<endl; for(unsigned int i = 0; i < gr.nrOfStudents; i++){ cout<<"Nazwisko: "<<gr.tstudent[i].Nazwisko<<" Imie: "<<gr.tstudent[i].Imie<<endl; } }

Potrzebna będzie jeszcze funkcja, która przed zamknięciem programu będzie zwalniała przydzieloną dynamicznie pamięć:

void UsunWszystkichStudentow(grupa &gr){ // funkcja zwalnia pamięć if(gr.nrOfStudents){ delete[] gr.tstudent; // zwalnianie przypisanej pamięci gr.tstudents = 0; // przypisanie zerowego adresu gr.nrOfStudents = 0; // zero studenciaków } }

Teraz kod programu umieszczony w głównej funkcji main:

int main(){ grupa gr={"Informatyka",0,0}; // tworzenie grupy pozbawionej studentów DodajStudentaDoGrupy(gr,"Kowalski","Leon",5,5); // dodawanie pierwszego studenta DodajStudentaDoGrupy(gr,"Pietrucha","Mirosław",3,3); // dodawanie drugiego studenta WypiszDaneGrupy(gr); // wypisywanie informacji o grupie i studentach UsunWszystkichStudentow(gr); // zwalnianie pamięci przed wyjściem z programu cout<<"Wcisnij enter, aby zamknac program..."; cin.get(); return 0; }

Powyższy przykład z użyciem tablic dynamicznych nie jest najlepszym rozwiązaniem, dlatego że konieczne jest tutaj przy każdorazowym dodawaniu nowych wartości deklarowanie nowej tablicy dynamicznej, kopiowanie elementów starej do nowej, zwalnianie pamięci, przepisywanie wskaźnika bla, bla, bla ... dużo pracy i łatwo się pomylić a w dodatku komputer też mocno obciążony zostaje zwłaszcza, gdy w grę wchodzą duże ilości danych do przekopiowania. O tym jak rozwiązać ten palący problem postaram się opowiedzieć podczas omawiania tematu dotyczącego tworzenia własnej listy dwukierunkowej.

Propozycje książek