C/C++

złoŜone typy danych

tablice

struktury

unie

wyliczenia

wskaźniki

C/C++ - ZłoŜone typy danych, wskaźniki Tablice

Tablice są zbiorami elementów tego samego typu. Dostęp do elementów tablicy odbywa się poprzez indeks (adres w tablicy).

Postać deklaracji tablicy jednowymiarowej (wektora) jest następująca: int wektor_liczb[20];

typ elementów

nazwa

rozmiar

tablicy

Indeksowanie tablic zaczyna się od indeksu o wartości 0

C/C++ - ZłoŜone typy danych, wskaźniki Tablice c.d.

Zapis do tablicy i odczyt z tablicy jednowymiarowej

float wektor_liczb[20];

float liczba_rzeczywista;

wektor_liczb[0]=1.34;

liczba_rzeczywista=wektor_liczb[0];

Utworzenie wektora zainicjowanego

char tabl_znakow[10]={’a’,’b’,’c’,’d’};

Tablice jednowymiarowe wykorzystywane są bardzo często do przechowywania znaków (łańcuchów znaków).

C/C++ - ZłoŜone typy danych, wskaźniki Tablice c.d.

Deklaracja tablicy dwuwymiarowej ma postać:

int tablica_liczb[5][10];

typ elementów

nazwa

liczba

liczba

tablicy

wierszy

kolumn

W dostępie do elementu tablicy pierwszy indeks oznacza numer wiersza, a drugi – numer kolumny.

C/C++ - ZłoŜone typy danych, wskaźniki Tablice c.d.

Zapis do tablicy i odczyt z tablicy dwuwymiarowej

const unsigned char N=5,M=10;

float tabl_liczb[N][M];

float liczba_rzeczywista;

tabl_liczb[0][9]=3.33;

liczba_rzeczywista=tabl_liczb[0][9];

W powyŜszym przykładzie operacje dotyczą elementu tablicy połoŜonego w pierwszym wierszu (indeks 0) i ostatniej kolumnie (indeks 9).

W linii deklaracji tablicy rozmiar tablicy musi być znany (lub musi się dać ustalić) w czasie kompilacji.

Utworzenie tablicy zainicjowanej

int tablica[2][3]={{1,2,3},

{4,5,6}};

C/C++ - ZłoŜone typy danych, wskaźniki Tablice - tablice wielowymiarowe

W języku C++ moŜliwe jest deklarowanie tablic o wielu wymiarach.

Postać deklaracji tablicy N-wymiarowej jest następująca: typ nazwa[ wN]...[ w2][ w1]

Deklaracja tablicy trójwymiarowej

short int tabl_liczb[5][10][10];

Uwaga:

W języku C nie jest prowadzona kontrola zakresów, zatem moŜliwe jest wykonywanie operacji na elementach spoza tablicy (na innych danych, a nawet na kodzie). przykład kontr_zakr_tab

Deklarowane do tej pory tablice są tablicami statycznymi. Oznacza to, Ŝe w momencie deklaracji tablicy następuje zarezerwowanie pamięci dla całej tablicy.

WaŜne jest więc aby rozmiar i typ elementów ustalać dokładnie do potrzeb ( nie na wyrost).

C/C++ - ZłoŜone typy danych, wskaźniki Struktury

Struktury są zbiorami elementów (zmiennych) róŜnych typów. Struktura jest złoŜonym typem danych definiowanym przez uŜytkownika. Elementy struktury są nazywane takŜe polami. Po zdefiniowaniu struktury moŜliwe jest deklarowanie zmiennych tego typu.

słowo

Przykład struktury

nazwa struktury

kluczowe

struct osoba {

char nazwisko[20];

char imie[15];

pola

char adres[30];

int

wiek;

};

średnik kończący deklarację struktury

C/C++ - ZłoŜone typy danych, wskaźniki Struktury c.d.

Zmienne typu strukturalnego moŜna deklarować na dwa sposoby. Pierwszy to wymienienie nazw deklarowanych zmiennych za nawiasem klamrowym zamykającym listę pól, a przed średnikiem kończącym deklarację struktury. W tym przypadku moŜna opuścić nazwę struktury.

struct osoba {

char nazwisko[20];

char imie[15];

char adres[30];

int

wiek;

}a,b,c;

zmienne typu osoba

Drugi sposób to deklaracja postaci:

struct osoba d,e,f;

C/C++ - ZłoŜone typy danych, wskaźniki Struktury c.d.

Dostęp do pola zmiennej typu strukturalnego realizowany jest z wykorzystaniem operatora . (kropki) postaci:

nazwa_zmiennej. nazwa_pola

Przykład

struct { // struktura bez nazwy

int x;

int y;

} a,b;

a.x=7;

a.y=5;

b=a;

//skopiowanie wszystkich pól

Ostatnia instrukcja przypisania pokazuje, Ŝe moŜna przypisać wszystkie pola jednej zmiennej innej zmiennej w jednej instrukcji przypisania.

C/C++ - ZłoŜone typy danych, wskaźniki Struktury c.d.

Z uwagi na to, iŜ struktury są wykorzystywane do opisu obiektów, często są wykorzystywane jako typ elementów tablic.

Deklaracja wektora elementów typu osoba (strukturalnego): struct osoba {

char nazwisko[20];

char imie[15];

char adres[30];

int

wiek;

};

struct osoba lista_osob[30];

lista_osob[6].wiek=21;

lista_osob[29].wiek=lista_osob[6].wiek;

W przedostatnim wierszu następuje przypisanie wartości polu wiek siódmego elementu tablicy, a w ostatnim przypisanie wartości pola wiek siódmego elementu tablicy polu wiek elementu ostatniego.

C/C++ - ZłoŜone typy danych, wskaźniki Struktury - pola bitowe

W języku C istnieje moŜliwość deklarowania struktury której elementy (pola) zajmują określoną liczbę bitów. Takie rozwiązanie umoŜliwia dostęp do pojedynczych bitów. Postać deklaracji struktury pól bitowych jest następująca: nazwa pola bitowego

długość pola w

struct poleb {

bitach

unsigned b1:1;

unsigned b2:1;

elementy

int b3:2;

};

nazwa elementu pola

Dostęp do elementów pola bitowego

struct poleb pb;

pb.b1=0;

Elementy pola bitowego mogą być typu int, signed, unsigned. Jeśli element ma długość 1 bitu to musi być typu unsigned. Długość pola bitowego w systemach 32-bitowych wynosi 32 bity (w 16-bitowych –16 bitów).

C/C++ - ZłoŜone typy danych, wskaźniki Unie

Unia umoŜliwia deklarację zmiennych róŜnych typów współdzielących miejsce w pamięci. Oznacza to, Ŝe ta sama komórka pamięci jest wykorzystywana przez róŜne zmienne zadeklarowane w unii.

Deklaracja unii, jak równieŜ dostęp do elementów unii jest analogiczny do struktury. RóŜnica w deklaracji polega na tym, Ŝe w tym przypadku wykorzystuje się słowo kluczowe union.

Przykład deklaracji

union alfa {

int i;

char c;

}u1,u2;

union alfa u3,u4;

Unia zajmuje tyle miejsca w pamięci ile zajmuje jej najdłuŜsze pole.

C/C++ - ZłoŜone typy danych, wskaźniki Unie c.d.

Dostęp do elementów unii

union alfa {

unsigned int i;

unsigned char c[4];

}u1;

u1.i=25;

cout<<(int)u1.c[0]<<'\n';

cout<<(int)u1.c[1]<<'\n';

cout<<(int)u1.c[2]<<'\n';

cout<<(int)u1.c[3]<<'\n';

PowyŜsza postać unii umoŜliwia dostęp do poszczególnych bajtów liczby całkowitej poprzez tablicę czterech znaków.

przykład

C/C++ - ZłoŜone typy danych, wskaźniki Unie + pola bitowe

struct poleb {

unsigned b0:1;

unsigned b1:1;

W przykładzie mamy pokazany

unsigned b2:1;

sposób dostępu do jednego bajtu jako

unsigned b3:1;

elementu typu unsigned char oraz

unsigned b4:1;

do ka

unsigned b5:1;

Ŝdego z jego bitów z osobna

unsigned b6:1;

(dzięki wykorzystaniu pola

unsigned b7:1;

bitowego).

};

union alfa{

struct poleb p;

unsigned char l;

}u;

u.l=10;

cout<<u.p.b7<<u.p.b6<<u.p.b5<<u.p.b4<<u.p.b3<<u.p.b2<<u.p.b1<<u.p.b0; przykład polabitowe.cpp

C/C++ - ZłoŜone typy danych, wskaźniki Wyliczenia

Typ wyliczeniowy jest zbiorem symbolicznych stałych całkowitych określających wszystkie dopuszczalne wartości jakie moŜe przyjmować zmienna tego typu.

Typ wyliczeniowy definiuje się za pomocą słowa kluczowego enum.

Przykład wyliczenia

enum nazwa_samochodu{audi,bmw,fiat,ford,toyota}bryka;

słowo

nazwa typu

zbiór dopuszczalnych

deklaracja

kluczowe

stałych symbolicznych

zmiennej

PowyŜsza deklaracja spowoduje, Ŝe stałym ze zbioru wartości typu nazwa_samochodu przypisane zostaną kolejne liczby całkowite od 0 do 4. Wartości przypisywane stałym moŜna ustalać na etapie definiowania typu. Na przykład definicja postaci:

enum miara{sztuka=1,tuzin=12,kopa=60,gros=144};

spowoduje nadanie wartości określonych w liście wyliczenia.

C/C++ - ZłoŜone typy danych, wskaźniki Wyliczenia - operacje na elementach typu wyliczeniowego

enum nazwa_samochodu{audi,bmw,fiat,ford,toyota};

enum nazwa_samochodu bryka;

bryka=toyota;

cout<<bryka;

// wyświetlenie na konsoli

W powyŜszym przykładzie został zdefiniowany typ wyliczeniowy nazwa_samochodu, zadeklarowana został zmienna bryka tego typu.

Następnie nadano jej wartość toyota. W sytuacji kiedy chcemy wyświetlić wartość zmiennej auto na ekran zostanie wyprowadzona wartość liczbowa tej stałej, czyli 4. Wartości symbolicznych moŜna uŜywać bez ograniczeń w wyraŜeniach oraz blokach warunków. przykład wyliczenia.cpp

C/C++ - ZłoŜone typy danych, wskaźniki Wskaźniki

Wskaźnik jest zmienną słuŜącą do przechowywania adresu (zmiennej dowolnego typu, funkcji, kolejnego wskaźnika).

Wskaźnik wskazuje adres zmiennej typu określonego na etapie deklaracji.

Wskaźniki w języku C mają następujące zastosowania:

•

umoŜliwiają funkcjom modyfikację przekazywanych parametrów,

•

umoŜliwiają korzystanie z mechanizmu dynamicznego przydziału pamięci,

•

umoŜliwiają korzystanie z dynamicznych struktur danych.

Omówione zostaną wskaźniki do zmiennych, tablic, struktur,wskaźników.

C/C++ - ZłoŜone typy danych, wskaźniki Wskaźnik do zmiennej

Postać przykładowej deklaracji wskaźnika jest następująca: int *wsk_do_int;

typ wskazywanego

elementu (bazowy)

nazwa zmiennej

gwiazdka

wskaźnikowej

Zadeklarowana zmienna wskaźnikowa moŜe przechowywać adresy zmiennych typu int, mówimy, Ŝe wskazuje na element typu int.

Oprócz operatora gwiazdki *, w operacjach wskaźnikowych wykorzystywany jest operator & . SłuŜy on do uzyskiwania adresu zmiennej.

Zapis &x oznacza adres w pamięci zmiennej x.

Operator * poza deklaracją wskaźnika słuŜy do określenia wartości znajdującej pod adresem, który wskaźnik wskazuje. Instrukcja x=*wsk_do_int ;

realizuje przypisanie zmiennej x wartości spod adresu wsk_do_int.

C/C++ - ZłoŜone typy danych, wskaźniki

Wskaźnik do zmiennej

Przykład

int i,j,*wsk_do_int;

i=3;

wsk_do_int=&i;

j=*wsk_do_int;

cout<<i<<'\n'<<j<<'\n'<<wsk_do_int<<'\n';

C/C++ - ZłoŜone typy danych, wskaźniki

Wskaźnik do zmiennej – arytmetyka wskaźnikowa

Na wskaźnikach moŜna wykonywać operacje dodawania i odejmowania oraz moŜna je porównywać.

Operacja dodania do wskaźnika wartości jeden oznacza, Ŝe będzie on teraz wskazywać nie na kolejny bajt w pamięci lecz na adres większy o tyle, ile bajtów zajmuje typ bazowy wskaźnika.

Przykład

int i,*wsk_do_int;

wsk_do_int=&i;

cout<<wsk_do_int<<'\n';

cout<<wsk_do_int+1<<'\n';

C/C++ - ZłoŜone typy danych, wskaźniki Wskaźnik do tablicy

Wskaźnik do tablicy zawiera adres pierwszego jej elementu.

Deklaracja wskaźnika do tablicy jest taka sama jak do zmiennej. Aby wskaźnik mógł być wykorzystany do operacji na tablicy, typ bazowy wskaźnika musi być taki sam jak typ elementów w tablicy.

RóŜnica w operowaniu na tablicach w porównaniu ze zmiennymi innych typów polega na dodatkowej moŜliwości uzyskiwaniu adresu pierwszego elementu tablicy jednowymiarowej.

W celu uzyskania adresu pierwszego elementu tablicy moŜna skorzystać z operatora & w następujący sposób:

wsk=&tab[0];

lub w sposób charakterystyczny dla tablic:

wsk=tab;

tzn. podając nazwę tablicy.

C/C++ - ZłoŜone typy danych, wskaźniki

Wskaźnik do tablicy c.d.

Odwołanie do elementu tablicy z wykorzystaniem wskaźnika zostało przedstawione w sekwencji poniŜej.

char lan[3]={'a','b','c'},*wsk;

wsk=lan;

cout<<*(wsk+2);

Wyświetlony zostanie ostatni element tablicy znaków.

W języku C moŜliwe jest zapamiętanie stałej w postaci łańcucha znaków z wykorzystaniem wskaźnika do typu char:

char *str="werw3erwerwerwerwe”;

cout<<str;

przykład

C/C++ - ZłoŜone typy danych, wskaźniki

Wskaźnik do tablicy c.d.

W przypadku kiedy odwołujemy się przy pomocy wskaźnika do tablicy dwuwymiarowej to konieczne jest ustalenie połoŜenia elementu tablicy w pamięci w stosunku do elementu [0][0] (przesunięcia).

const int N=5,M=6;

int i,j,tab[N][M],*wsk;

wsk=&tab[0][0]; //pozyskanie adresu tablicy

i=4,j=5;

tab[i][j]=44;

cout<<*(wsk+(i*M+j));//wyświetlenie elementu i,j

przykład

C/C++ - ZłoŜone typy danych, wskaźniki Wskaźnik do struktury

Wskaźniki do struktur deklarujemy tak jak wskaźniki do typu prostego. RównieŜ sposób uzyskania adresu zmiennej typu strukturalnego jest standardowy z wykorzystaniem operatora pobierania adresu &.

Sposób dostępu do pola struktury odbywa się z wykorzystaniem operatora ->

C/C++ - ZłoŜone typy danych, wskaźniki

Wskaźnik do struktury c.d.

Przykład 1

struct osoba {

char nazwisko[20];

char imie[15];

int

wiek;

};

struct osoba a,*wsk;

wsk=&a; // pobranie adresu zmiennej a

wsk->wiek=21;// ustawienie pola wiek poprzez wskaźnik cout<<a.wiek;

przyklad

C/C++ - ZłoŜone typy danych, wskaźniki

Wskaźnik do struktury c.d.

Przykład 2

Dostęp do pola struktury będącego elementem tablicy przez wskaźnik.

struct osoba {

char nazwisko[20];

char imie[15];

int

wiek;

}klasa[30];

struct osoba *wsk;

wsk=klasa;

(wsk+10)->wiek=21;

cout<<klasa[10].wiek;

przykład

C/C++ - ZłoŜone typy danych, wskaźniki Wskaźniki do wskaźników

W C++ moŜliwe jest korzystanie z wielokrotnego adresowania pośredniego.

MoŜliwa jest zatem sytuacja, Ŝe wskaźnik zawiera nie adres zmiennej lecz adres komórki pamięci w której znajduje się adres docelowego elementu.

int x,*p,**q; // deklaracja zmiennej, wskaźnika i wskaźnika do

// wskaźnika

x=123;

p=&x; // pobranie adresu zmiennej

q=&p; // pobranie adresu wskaźnika

cout<<x; //wyświetlenie zmiennej x

cout<<*p; // wyświetlenie zawartości spod adresu zmiennej x cout<<**q; // wyświetlenie zawartości spod adresu przechowywanego

//w komórce wskazywanej przez wskaźnik q

przykład

C/C++ - ZłoŜone typy danych, wskaźniki Wskaźniki – typowe błędy

1. UŜycie niezainicjalizowanego wskaźnika do zapisu

int x,*p;

x=123;

*p=x; // zapis pod nieokreślony adres

2. Przypisanie wskaźnikowi wartości zmiennej (int, char) zamiast jej adresu int x,*p;

x=123;

p=x;

cout<<*p // wyprowadzenie wartości spod

//adresu 123

przykład