Wska¹niki, tablice dynamiczne jednowymiarowe, staªe

Podobne dokumenty
7.3 Tablice jednowymiarowe dynamiczne

ˆ tablice statyczne (o staªej ilo±ci elementów) ˆ tablice dynamiczne (o zmiennej ilo±ci elementów) 7.1 Tablice jednowymiarowe statyczne

Wska¹niki, tablice dynamiczne wielowymiarowe

1 Klasy. 1.1 Denicja klasy. 1.2 Skªadniki klasy.

Lekcja 9 - LICZBY LOSOWE, ZMIENNE

Lab 9 Podstawy Programowania

P tle. Rozdziaª Wst p. 4.2 P tle P tla for(...);

1. Wprowadzenie do C/C++

1. Wprowadzenie do C/C++

Listy i operacje pytania

Wskaźniki i dynamiczna alokacja pamięci. Spotkanie 4. Wskaźniki. Dynamiczna alokacja pamięci. Przykłady

1 Wska¹niki. 1.1 Wska¹nik typu VOID. Wska¹nik jest obiektem przechowuj cym adres (z pami ci) przypisanej do niego zmiennej.

Wskaźniki. Przemysław Gawroński D-10, p marca Wykład 2. (Wykład 2) Wskaźniki 8 marca / 17

ANALIZA NUMERYCZNA. Grzegorz Szkibiel. Wiosna 2014/15

Lekcja 12 - POMOCNICY

Wskaźniki w C. Anna Gogolińska

Lekcja 9 Liczby losowe, zmienne, staªe

Wskaźniki a tablice Wskaźniki i tablice są ze sobą w języku C++ ściśle związane. Aby się o tym przekonać wykonajmy cwiczenie.

Temat: Dynamiczne przydzielanie i zwalnianie pamięci. Struktura listy operacje wstawiania, wyszukiwania oraz usuwania danych.

Co to jest sterta? Sterta (ang. heap) to obszar pamięci udostępniany przez system operacyjny wszystkim działającym programom (procesom).

Stałe, tablice dynamiczne i wielowymiarowe

1 Bª dy i arytmetyka zmiennopozycyjna

ZASADY PROGRAMOWANIA KOMPUTERÓW

Programowanie w C++ Wykład 5. Katarzyna Grzelak. 26 marca kwietnia K.Grzelak (Wykład 1) Programowanie w C++ 1 / 40

DYNAMICZNE PRZYDZIELANIE PAMIECI

KURS C/C++ WYKŁAD 6. Wskaźniki

> C++ dynamiczna alokacja/rezerwacja/przydział pamięci. Dane: Iwona Polak. Uniwersytet Śląski Instytut Informatyki

wykład II uzupełnienie notatek: dr Jerzy Białkowski Programowanie C/C++ Język C - funkcje, tablice i wskaźniki wykład II dr Jarosław Mederski Spis

Listy Inne przykªady Rozwi zywanie problemów. Listy w Mathematice. Marcin Karcz. Wydziaª Matematyki, Fizyki i Informatyki.

Lab. 02: Algorytm Schrage

x y x y x y x + y x y

wiczenie 1 Podstawy j zyka Java. Instrukcje warunkowe

1 Wskaźniki i zmienne dynamiczne, instrukcja przed zajęciami

Przetwarzanie sygnaªów

Wskaźniki. Programowanie Proceduralne 1

> C++ wskaźniki. Dane: Iwona Polak. Uniwersytet Śląski Instytut Informatyki 26 kwietnia 2017

Programowanie wspóªbie»ne

Lekcja 6 Programowanie - Zaawansowane

Programowanie w C++ Wykład 4. Katarzyna Grzelak. 19 marca K.Grzelak (Wykład 1) Programowanie w C++ 1 / 37

Zestaw 1 ZESTAWY A. a 1 a 2 + a 3 ± a n, gdzie skªadnik a n jest odejmowany, gdy n jest liczb parzyst oraz dodawany w przeciwnym.

JAO - J zyki, Automaty i Obliczenia - Wykªad 1. JAO - J zyki, Automaty i Obliczenia - Wykªad 1

Języki i metodyka programowania. Wskaźniki i tablice.

Wskaźniki. Informatyka

Algorytmy zwiazane z gramatykami bezkontekstowymi

Wskaźnik może wskazywać na jakąś zmienną, strukturę, tablicę a nawet funkcję. Oto podstawowe operatory niezbędne do operowania wskaźnikami:

A = n. 2. Ka»dy podzbiór zbioru sko«czonego jest zbiorem sko«czonym. Dowody tych twierdze«(elementarne, lecz nieco nu» ce) pominiemy.

Vincent Van GOGH: M»czyzna pij cy li»ank kawy. Radosªaw Klimek. J zyk programowania Java

Tablice, funkcje, wskaźniki - wprowadzenie

Rekurencyjne struktury danych

Programowanie i struktury danych

ARYTMETYKA MODULARNA. Grzegorz Szkibiel. Wiosna 2014/15

Język C zajęcia nr 11. Funkcje

Tablice, funkcje - wprowadzenie

Ciaªa i wielomiany. 1 Denicja ciaªa. Ciaªa i wielomiany 1

ARYTMETYKA MODULARNA. Grzegorz Szkibiel. Wiosna 2014/15

JĘZYKI PROGRAMOWANIA Z PROGRAMOWANIEM OBIEKTOWYM. Wykład 6

Lekcja 8 - ANIMACJA. 1 Polecenia. 2 Typy animacji. 3 Pierwsza animacja - Mrugaj ca twarz

Liczby zmiennoprzecinkowe

2 Skªadnia polece«w pliku

Wskaźniki, funkcje i tablice

Lekcja 3 Banki i nowe przedmioty

Programowanie i struktury danych 1 / 44

Przykªadowe tematy z JiMP

Metody dowodzenia twierdze«

WST P DO TEORII INFORMACJI I KODOWANIA. Grzegorz Szkibiel. Wiosna 2013/14

Wstęp do programowania INP001213Wcl rok akademicki 2018/19 semestr zimowy. Wykład 4. Karol Tarnowski A-1 p.

Proste modele o zªo»onej dynamice

Typy danych i formatowanie

Podstawy programowania 1

Rzut oka na zagadnienia zwi zane z projektowaniem list rozkazów

Model obiektu w JavaScript

Kompilowanie programów

ARYTMETYKA MODULARNA. Grzegorz Szkibiel. Wiosna 2014/15

Podstawy programowania skrót z wykładów:

Ukªady równa«liniowych

Wstęp do wskaźników w języku ANSI C

Wst p do informatyki. Systemy liczbowe. Piotr Fulma«ski. 21 pa¹dziernika Wydziaª Matematyki i Informatyki, Uniwersytet Šódzki, Polska

Informatyka I: Instrukcja 4.2

Aplikacje bazodanowe. Laboratorium 1. Dawid Poªap Aplikacje bazodanowe - laboratorium 1 Luty, 22, / 37

WST P DO TEORII INFORMACJI I KODOWANIA. Grzegorz Szkibiel. Wiosna 2013/14

ARYTMETYKA MODULARNA. Grzegorz Szkibiel. Wiosna 2014/15

W dowolnym momencie można zmienić typ wskaźnika.

Wstęp do Programowania, laboratorium 02

6 Przygotował: mgr inż. Maciej Lasota

Metodydowodzenia twierdzeń

19. Obiektowo± 1 Kacze typowanie. 2 Klasy

Stałe, znaki, łańcuchy znaków, wejście i wyjście sformatowane

Relacj binarn okre±lon w zbiorze X nazywamy podzbiór ϱ X X.

Podstawy modelowania w j zyku UML

1. Odcienie szaro±ci. Materiaªy na wiczenia z Wprowadzenia do graki maszynowej dla kierunku Informatyka, rok III, sem. 5, rok akadem.

Wzorce projektowe strukturalne cz. 1

1 Metody iteracyjne rozwi zywania równania f(x)=0

CCNA Subnetting Guide

Lekcja 3 - BANKI I NOWE PRZEDMIOTY

Podziaª pracy. Cz ± II. 1 Tablica sortuj ca. Rozwi zanie

Podstawy informatyki. Informatyka stosowana - studia niestacjonarne. Grzegorz Smyk. Wydział Inżynierii Metali i Informatyki Przemysłowej

Functionalization. Funkcje w C. Marcin Makowski. 30 listopada Zak lad Chemii Teoretycznej UJ

Ekonometria - wykªad 8

Techniki Programowania wskaźniki

Laboratorium nr 9. Temat: Wskaźniki, referencje, dynamiczny przydział pamięci, tablice dynamiczne. Zakres laboratorium:

Transkrypt:

Rozdziaª 9 Wska¹niki, tablice dynamiczne jednowymiarowe, staªe 9.1 Wst p Czym w C jest wska¹nik? Wska¹nik jest zmienn, która zawiera adres (wskazanie) innej zmiennej lub adres dowolnego obszaru w pami ci komputera, (np. mo»e by to adres obszaru danych lub adres kodu programu). Jak wiemy, poznane dot d zmienne (typów int, double, float, char, void) przechowywane s w pami ci RAM komputera dost pnej dla programu. Przykªadowo, gdy w programie zdeniujemy zmienn typu int i nadamy jej warot± : 5 i n t a = 104; 6 return 0 ; 7 } zmienna ta zostanie umieszczona w komórce pami ci RAM (dost pnej dla naszego programu) pod okre- ±lonym adresem: Dla powy»szego obrazka przykªadowy wska¹nik, który wskazywaªby na zmienn a, przechowywaªby jej adres w pami ci, czyli warto± 6579. 9. Deklarowanie wska¹ników Poniewa» wska¹nik jest zmienn, która mo»e przechowywa jedynie adresy innych zmiennych, jego deklaracja ró»ni si od deklaracji zwykªych zmiennych. Mo»emy zadeklarowa wska¹nik na ka»dy dost pny w j zyku C typ danych, tj. mo»emy w programie zdeniowa : 196

ˆ wska¹nik na zmienn typu int ˆ wska¹nik na zmienn typu float ˆ wska¹nik na zmienn typu double ˆ wska¹nik na zmienn typu char ˆ wska¹nik na zmienn typu void Ogólny schemat deniowania wska¹nika wygl da nast puj co: 1 typ_danych * nazwa_wskaznika ; Je±li zdeniujemy wska¹nik, który wskazuje na zmienn, wówczas wska¹nik ten przechowuje adres tej zmiennej w pami ci. Je±li wska¹nik nie wskazuje na»adn zmienn, wówczas zamiast adresu wska¹nik przechowuje warto± NULL (wska¹nik nie wskazuje na nic). Cz sto w odniesieniu do wska¹ników, które nie wskazuj na nic, stosuje si równie» okre±lenie pusty wska¹nik. Na poni»szym przykªadzie zdeniowano wska¹niki do wszystkich typów danych j zyka C. W przykªadzie poni»ej wska¹niki nie wskazuj na razie na»adne zmienne, przechowuj wi c warto±ci NULL. 5 /* wskaznik na zmienna typu i n t */ 6 i n t * wi = NULL ; 7 8 /* wskaznik na zmienna typu f l o a t */ 9 f l o a t * wf = NULL ; 10 11 /* wskaznik na zmienna typu double */ 1 double * wd = NULL ; 13 14 /* wskaznik na zmienna typu char */ 15 char * wc = NULL ; 16 17 /* wskaznik na zmienna typu void */ 18 void * wv = NULL ; 19 0 return 0 ; 1 } Nale»y zwróci szczególn uwag na deklarowanie wska¹ników. Gdy chcemy zdeniowa kilka wska¹ników, mo»emy to zrobi na spoosby: 5 /* pierwszy wskaznik na zmienna typu i n t */ 6 i n t * wi1 = NULL ; 7 8 /* drugi wskaznik na zmienna typu i n t */ 9 i n t * wi = NULL ; 10 11 return 0 ; 1 } 197

lub: 5 /* dwa wskazniki na zmienna typu i n t */ 6 7 i n t * wi1 = NULL, * wi = NULL ; 8 9 return 0 ; 10 } Przed ka»d zmienn, któr chcemy zadeklarowa jako zmienn wska¹nikow, MUSI pojawi si symbol gwiazdki, gdy si nie pojawi, zmienna ta b dzie zwykª zmienn, a nie zmienn wska¹nikow : 5 i n t *a, b, *c, d, e, *f, *g, *h ; 6 7 i n t * p, r, s ; 8 9 i n t * x, *y, *z ; 10 11 return 0 ; 1 } W powy»szym kodzie wska¹nikami s : d, e, r, s. a, c, f, g, h, p, x, y, z, natomiast zwykªe zmienne to 9.3 Deniowanie wska¹ników Aby wska¹niki mogªy by u»yteczne w programie, musz wskazywa na zmienne. Nale»y pami ta o tym,»e: ˆ wska¹nik typu int * (na przykªad int *wi) mo»e wskazywa tylko na zmienn typu int (na przykªad int i), ˆ wska¹nik typu float * (na przykªad float *wf) mo»e wskazywa tylko na zmienn typu float (na przykªad float f), ˆ wska¹nik typu double * (na przykªad double *wd) mo»e wskazywa tylko na zmienn typu double (na przykªad double di), ˆ wska¹nik typu char * (na przykªad char *wc) mo»e wskazywa tylko na zmienn typu char (na przykªad char c), Poniewa» wska¹nik mo»e przechowywa jedynie adresy, do wska¹nika nale»y wpisa adres zmiennej, na któr dany wska¹nik powinien wskazywa. Aby to uczyni, konieczne jest skorzystanie z operatorów, przeznaczonych dla wska¹ników. Ze wska¹nikami i adresami zwi zane s dwa operatory: ˆ operator adresu (referencji) & zwracaj cy adres zmiennej podanej po prawej stronie tego operatora ˆ operator wyªuskania (dereferencji) * identykuj cy obszar zmiennej wskazywanej przez wska¹nik podany po prawej stronie tego operatora 198

Adres zmiennej pobieramy za pomoc operatora &. W poni»szym przykªadzie wy±wietlamy warto± zmiennej (tak, jak robili±my to do tej pory), oraz jej adres w pami ci - pobieramy go za pomoc operatora & oraz wykorzystujemy %p jako ci g formatuj cy do wy±wietlenia adresu z pami ci RAM w funkcji printf: 5 /* d e k l a r a c j a zwyklej zmiennej */ 6 i n t a = 104; 7 8 /* w y s w i e t l e n i e w a r t o s c i zmiennej */ 9 printf ( "%d\n", a ) ; 10 11 /* w y s w i e t l e n i e adresu zmiennej */ 1 printf ( "%p\n", &a ) ; 13 14 return 0 ; 15 } Aby wska¹nik wskazywaª na zmienn, nale»y go zadeklarowa i przypisa mu adres zmiennej, na któr ma wskazywa. Skoro adres zmiennej mo»emy pobra za pomoc operatora &, mo»emy tak pobrany adres przypisa do wska¹nika, a nast pnie go wy±wietli : 5 /* d e k l a r a c j a zwyklej zmiennej typu i n t */ 6 i n t a = 104; 7 8 /* w y s w i e t l e n i e w a r t o s c i zmiennej */ 9 printf ( "%d\n", a ) ; 10 /* w y s w i e t l e n i e adresu zmiennej */ 11 printf ( "%p\n", &a ) ; 1 13 /* d e k l a r a c j a wskaznika na zmienna typu i n t */ 14 i n t *w ; 15 16 /* pobranie adresu zmiennej a i wpisanie 17 j e j adresu do wskaznika */ 18 w = &a ; 19 0 /* w y s w i e t l e n i e adresu zmiennej za pomoca wskaznika */ 1 printf ( "%p\n", w ) ; 3 return 0 ; 4 } 199

Za pomoc instrukcji int *w = &a; zadeklarowali±my wska¹nik do zmiennej int oraz wpisalismy do niego adres zmiennej a. Teraz we wska¹niku w znajduje si adres zmiennej a w pami ci RAM dost pnej dla programu. Posiadaj c wska¹nik do zmiennej, mo»emy wy±wietli jej adres, jak równie» sam warto± zmiennej. W poni»szym przykªadzie deklarujemy zmienn zm oraz przypisujemy jej warto±. Nast pnie deklarujemy wska¹nik, który wskazuje na t zmienn, i wy±wietlamy adres zmiennej w pami ci, oraz jej warto± korzystaj c ze wska¹nika. Do pobrania warto±ci zmiennej za pomoc wska¹nika, który na ni wskazuje, u»ywamy operatora *. { 4 /* d e k l a r a c j a zwyklej zmiennej typu f l o a t */ 5 f l o a t zm = 5. 6 ; 6 7 /* wskaznik na zmienna typu f l o a t */ 8 f l o a t *w ; 9 10 /* wskaznik w wskazuje na zmienna zm */ 11 w = &zm ; 1 13 /* w y s w i e t l e n i e adresu zmiennej zm za pomoca wskaznika */ 14 printf ( "%p\n", w ) ; 15 16 /* w y s w i e t l e n i e w a r t o s c i zmiennej zm za pomoca wskaznika */ 17 printf ( "%. f \n", *w ) ; 18 19 return 0 ; 0 } 00

Za pomoc wska¹nika mo»emy zmieni warto± zmiennej. Zaªó»my,»e zmienna abc ma warto± pocz tkow równ 51. Deniujemy wska¹nik wsk który na ni wskazuje, wy±wietlamy warto± zmiennej. Nast pnie, u»ywaj c operatora * w odniesieniu do wska¹nika, wpisujemy do zmiennej abc warto± 4096. Operator * pozwala nam, maj c wska¹nik, dosta si do zmiennej i zmieni / wy±wietli jej warto± : { 4 /* zwykla zmienna typu i n t */ 5 i n t abc = 51; 6 7 /* zmienna wskaznikowa, wskaznik na zmienna typu i n t */ 8 i n t * wsk ; 9 10 /* wskaznik wskazuje t e r a z za zmienna abc */ 11 wsk = &abc ; 1 13 /* wyswietlamy wartosc zmiennej */ 14 printf ( "abc = %d\n", abc ) ; 15 16 /* do zmiennej abc za pomoca wskaznika wpisujemy wartosc 4096 */ 17 /* to samo, co abc = 4096, poniewaz wsk wskazuje na abc */ 18 * wsk = 4096; 19 0 /* wyswietlamy wartosc zmiennej j u z zmieniona */ 1 printf ( "abc = %d\n", abc ) ; 3 return 0 ; 4 } Aby przyswoi sobie deniowanie wska¹ników, prosz przeanalizowa poni»sze przykªady: { 4 /* zmienna typu i n t */ 5 i n t a = 4 ; 6 7 /* wskaznik na typ int, n i e wskazuje na n i c */ 8 i n t * wsk = NULL ; 9 10 /* wskaznik wskazuje na zmienna a */ 11 wsk = &a ; 1 13 /* w y s w i e t l e n i e w a r t o s c i zmiennej a za 14 pomoca wskaznika i samej zmiennej */ 15 printf ( "*wsk = %d, a = %d \n\n", * wsk, a ) ; 16 17 /* w y s w i e t l e n i e adresu zmiennej a za 01

18 pomoca wskaznika i samej zmiennej */ 19 printf ( "wsk = %p, &a = %p \n\n", wsk, &a ) ; 0 1 return 0 ; } 5 /* zmienne typu i n t */ 6 i n t a = 4, b = 5 ; 7 8 /* wskaznik na typ int, n i e wskazuje na n i c */ 9 i n t * wsk = NULL ; 10 11 /* wskaznik wskazuje na zmienna a */ 1 wsk = &a ; 13 14 printf ( "*wsk = %d\n", * wsk ) ; 15 16 /* wskaznik wskazuje na zmienna b */ 17 wsk = &b ; 18 19 printf ( "*wsk = %d\n", * wsk ) ; 0 1 return 0 ; } 0

5 /* zmienna typu i n t */ 6 i n t i = 104; 7 /* wskaznik na typ int, n i e wskazuje na n i c */ 8 i n t * wski = NULL ; 9 /* wskaznik wskazuje t e r a z na zmienna i */ 10 wski = &i ; 11 1 printf ( "* wski = %d \ t \ t i = %d \n", * wski, i ) ; 13 printf ( " wski = %p \ t &i = %p \n\n", wski, &i ) ; 14 15 /* zmienna typu f l o a t */ 16 f l o a t f = 1 0. 4 ; 17 /* wskaznik na typ f l o a t, n i e wskazuje na n i c */ 18 f l o a t * wskf = NULL ; 19 /* wskaznik wskazuje t e r a z na zmienna f */ 0 wskf = &f ; 1 printf ( "* wskf = %f \ t f = %f \n", * wskf, f ) ; 3 printf ( " wskf = %p \ t &f = %p \n\n", wskf, &f ) ; 4 5 /* zmienna typu double */ 6 double d = 1. 0 4 ; 7 /* wskaznik na typ double, n i e wskazuje na n i c */ 8 double * wskd = NULL ; 9 /* wskaznik wskazuje t e r a z na zmienna d */ 30 wskd = &d ; 31 3 printf ( "*wskd = %l f \ t d = %l f \n", * wskd, d ) ; 33 printf ( "wskd = %p \ t &d = %p \n\n", wskd, &d ) ; 34 35 /* zmienna typu char */ 36 char c = 'K ' ; 37 /* wskaznik na typ char, n i e wskazuje na n i c */ 38 char * wskc = NULL ; 39 /* wskaznik wskazuje t e r a z na zmienna c */ 40 wskc = &c ; 41 4 printf ( "*wskc = %c \ t \ t c = %c \n", * wskc, c ) ; 43 printf ( "wskc = %p \ t &c = %p \n\n", wskc, &c ) ; 44 45 return 0 ; 46 } Prosz przyjrze si UWA NIE poni»szemu programowi: 03

5 i n t a = 104; 6 7 i n t * wsk = &a ; 8 9 i n t b ; 10 b = a + 1 ; 11 printf ( "%d\n", b ) ; 1 13 b = * wsk + 1 ; 14 printf ( "%d\n", b ) ; 15 16 return 0 ; 17 } Je±li wsk wskazuje na a, wówczas instrukcje b = *wsk + 1 oraz b = a + 1 s równowa»ne, wykonuj TO SAMO. Gdy deniujemy wska¹nik, który wskazuje na zmienn, sam wska¹nik równie» znajduje si w pewnej komórce pami ci. Rozwa»my poni»szy przykªad: Gdy deklarujemy zmienn a zapisywana jest ona (przykªadowo) do komórki pami ci RAM o adresie 0x0000016. Gdy deklarujemy wska¹nik, który wskazuje na zmienn a, jego warto±ci jest adres zmiennej a w pami ci, czyli adres 0x0000016. Jednak, aby wska¹nik byª dost pny i mógª by u»ywany w programie, on równie» musi mie swoje miejsce w pami ci RAM. Dla powy»szego obrazka: wska¹nik wsk1 znajduje si w komórce pami ci RAM o adresie 0x0000014. W j zyku C mo»liwe jest zdeniowanie wska¹nika, kótry b dzie wskazywaª na inny wska¹nik. Poniewa» wska¹nik równie» ma swój wªasny adres w pami ci, mo»emy zdeniowa wska¹nik, który b dzie na niego wskazywaª: 04

Na obrazku powy»ej widzimy zmienn a, na któr wskazuje wska¹nik wsk1, na który wskazuje wska¹nik wsk. Wówczas wsk = 0x0000014, wsk1 = 0x0000016, a = 18 - wska¹nik wsk przechowuje adres w pami ci wska¹nika wsk1, wska¹nik wsk1 przechowuje adres w pami ci zmiennej a. W j zyku C taka konstrukcja b dzie wygl da nast puj co (oczywi±cie adresy b d si ró»ni, powy»sze to tylko przykªad): 5 /* zwykla zmienna typu i n t */ 6 i n t a = 18; 7 8 /* wskaznik na typ int, n i e wskazuje na n i c */ 9 i n t * wsk1 = NULL ; 10 11 /* wskaznik wsk wskazuje na zmienna a */ 1 wsk1 = &a ; 13 14 /* wskaznik na wskaznik na zmienna int, n i e 15 wskazuje na n i c */ 16 i n t ** wsk = NULL ; 17 18 /* wskaznik wsk wskazuje na wskaznik wsk1 */ 19 wsk = &wsk1 ; 0 1 printf ( "Adres zmiennej a : \ t \ t \ t \ t %p \n", &a ) ; printf ( "Wartosc zmiennej a : \ t \ t \ t \ t %d \n\n", a ) ; 3 4 printf ( "Adres wskaznika wsk1 : \ t \ t \ t \ t %p \n", &wsk1 ) ; 5 printf ( "Wskaznik wsk1 wskazuje na adres : \ t \ t %p \n", wsk1 ) ; 6 printf ( " Wartosc pod adresem %p j e s t rowna \ t %d \n\n", wsk1, * wsk1 ) ; 7 8 printf ( "Adres wskaznika wsk : \ t \ t \ t \ t %p \n", &wsk ) ; 9 printf ( "Wskaznik wsk wskazuje na adres : \ t \ t %p \n", wsk ) ; 30 printf ( " Wartosc pod adresem %p j e s t rowna \ t %p \n\n", wsk, * wsk ) ; 31 3 return 0 ; 33 } Po skompilowaniu i uruchomieniu powy»szego programu zobaczymy: 05

Na obrazku / schemacie taki rozkªad adresów mo»na przedstawi nast puj co: Mo»na powiedzie,»e wska¹nik wsk1 wskazuje na zmienn a bezpo±rednio, natomiast wska¹nik wsk wskazuje na zmienn a po±rednio, za pomoc wska¹nika wsk1. Oczywi±cie mo»liwe jest zdeniowanie wska¹nika, który wskazuje na wska¹nik, wskazuj cy na wska¹nik, itd.... Mo»liwe jest równie» pobranie warto±ci zmiennej a za pomoc wska¹nika, który wskazuje na wska¹nik na zmienn a. 5 /* zwykla zmienna typu i n t */ 6 i n t a = 18; 7 8 /* wskaznik na typ int, n i e wskazuje na n i c */ 9 i n t * wsk1 = NULL ; 10 11 /* wskaznik wsk wskazuje na zmienna a */ 1 wsk1 = &a ; 13 14 /* wskaznik na wskaznik na zmienna int, n i e 15 wskazuje na n i c */ 16 i n t ** wsk = NULL ; 17 18 /* wskaznik wsk wskazuje na wskaznik wsk1 */ 19 wsk = &wsk1 ; 0 1 printf ( "Wartosc zmiennej a j e s t rowna : \ t %d \n\n", ** wsk ) ; 3 return 0 ; 4 } 06

9.4 Operacje arytmetyczne na wska¹nikach Na wska¹nikach mog by wykonywane nast puj ce operacje: 1. przypisania: =. porównania: >, <, >=, <=, ==,!= 3. operacje powi kszania lub pomniejszania wska¹nika (+, -, ++, --, +=, -=) o liczb caªkowit (tylko dla wska¹ników zdeniowanych, czyli wskazuj cych ju» na co±) 4. operacje odejmowania wska¹ników tego samego typu - wyznaczenie odlegªo±ci pomi dzy dwoma adresami w pami ci Poni»ej przeanalizujemy i omówimy ka»d z mo»liwych operacji dost pnych dla wska¹ników. 1. Poniewa» wska¹niki przechowuj adresy, istnieje mo»liwo± przypisania jednej zmiennej adresowej do innej zmiennej adresowej. Oznacza to,»e je±li do jakiego± wska¹nika, np. wska¹nika wsk przypiszemy inny wska¹nik, np. wska¹nik wsk1, b dzie to oznacza, i» od tej pory wska¹nik wsk wskazuje na to samo, na co wskazuje wska¹nik wsk1 (oba wska¹niki przechowuj TEN SAM ADRES): 5 /* zwykla zmienna typu i n t */ 6 i n t a = 51; 7 8 /* wskazniki na zmienne typu i n t */ 9 i n t * wsk1, * wsk ; 10 11 /* wskaznik wsk1 wskazuje na zmienna a */ 1 wsk1 = &a ; 13 14 /* wskaznik wsk wskazuje na to samo, 15 co wskaznik wsk1, c z y l i wskaznik 16 wsk wskazuje t e r a z na zmienna a */ 17 wsk = wsk1 ; 18 19 printf ( "*wsk1 = %d \ t \ t *wsk = %d \n\n", * wsk1, * wsk ) ; 0 printf ( " wsk1 = %p \ t wsk = %p \n\n", wsk1, wsk ) ; 1 return 0 ; 3 } 07

. Dost pne operatory porównania dla wska¹ników pozwalaj nam sprawdzi, czy dwa wska¹niki wskazuj te same zmienne (==), czy wskazuj na inne zmienne (!=), czy zmienna, na któr wskazuje jeden wska¹nik znajduje si w pami ci RAM wcze±niej / pó¹niej ni» inna zmienna, na któr wskazuje inny wska¹nik (>, <, >=, <=). Na poni»szym listingu zostaªy zaprezentowane przykªadowe wykorzystania operatorów porówania dla wska¹ników: 5 /* zwykla zmienna typu i n t */ 6 i n t a = 51; 7 /* zwykla zmienna typu i n t */ 8 i n t b = 51; 9 10 /* wskazniki na zmienne typu i n t */ 11 i n t * wsk1, * wsk ; 1 13 /* wskaznik wsk1 wskazuje na zmienna a */ 14 wsk1 = &a ; 15 16 /* wskaznik wsk wskazuje na zmienna a */ 17 /* to samo mozna uzyskac p i s z a c : wsk = wsk1 */ 18 wsk = &a ; 19 0 /* spr czy oba wskazniki wskazuja na t e sama zmienna */ 1 i f ( wsk1 == wsk ) printf ( "Oba wskazniki wskazuja na t e sama zmienna \n\n" ) ; 3 4 /* t e r a z wskaznik wsk wskazuje na zmienna b */ 5 wsk = &b ; 6 7 /* spr czy oba wskazniki wskazuja na rozne zmienne */ 8 i f ( wsk1!= wsk ) 9 printf ( " Wskazniki wskazuja na rozne zmienne \n\n" ) ; 30 31 i f ( wsk1 < wsk ) 3 printf ( "Zmienna b j e s t d a l e j w pamieci n i z zmienna a \n\n" ) ; 33 i f ( wsk1 <= wsk ) 34 printf ( "Zmienna b j e s t d a l e j w pamieci n i z zmienna a \n\n" ) ; 35 36 printf ( "Sprawdzmy to, porownujac i c h adresy w RAMie: \ n\n" ) ; 37 38 printf ( "wsk1 = %p \ t &a = %p \n", wsk1, &a ) ; 39 printf ( "wsk = %p \ t &b = %p \n", wsk, &b ) ; 40 41 return 0 ; 4 } 08

3. Powi kszenie (pomniejszenie) wska¹nika o warto± N powoduje wyznaczenie adresu przesuni tego o N * sizeof(typ_zmiennej_wskazywanej) bajtów w kierunku rosn cych adresów, tj.: Dla przykªadu powy»ej: deniuj c wska¹nik na typ danych int wiemy, i» int zajmuje 4 bajty w pami ci RAM (mo»emy to sprawdzi za pomoc operatora sizeof(int) pisz c np.: printf("%d\n", sizeof(int));). Na powy»szym obrazku widzimy, iz na pocz tku wska¹nik w przechowywaª adres 36. Je±li zwi kszymy wska¹nik o N=1, czyli wykonamy instrukcj w ++ (lub w = w + 1, albo w += 1), wówczas zwi kszymy adres wska¹nika o 1 * 4 (skoro N = 1, a sizeof(int) = 4) który b dzie przechowywaª wówczas warto± 40 (36 + 1 * 4 = 40). Sytuacja wygl da analogicznie w przypadku pomniejszania warto±ci wska¹nika. 5 /* zwykla zmienna typu i n t */ 6 i n t a = 51; 7 8 /* wskaznik na typ int, n i e wskazuje na n i c */ 9 i n t * wsk = NULL ; 10 11 /* wskaznik wskazuje na zmienna a */ 1 wsk = &a ; 13 14 printf ( " Aktualny adres zapisany we wskazniku : \ t \ t \ t %p \n", wsk ) ; 15 printf ( "Wartosc zmiennej wskazywanej przez wskaznik : \ t \ t %d \n", * wsk ) ; 16 printf ( " Aktualny adres zmiennej a : \ t \ t \ t \ t %p \n\n", &a ) ; 17 18 /* zwiekszamy wskaznik o 1, przesuwamy adresy */ 19 /* t e r a z wskaznik n i e wskazuje juz na zmienna a, 0 t y l k o na inny adres w pamieci */ 1 wsk += 1 ; 3 printf ( " Aktualny adres zapisany we wskazniku : \ t \ t \ t %p \n", wsk ) ; 4 printf ( "Wartosc zmiennej wskazywanej przez wskaznik : \ t \ t %d \n", * wsk ) ; 5 printf ( " Aktualny adres zmiennej a : \ t \ t \ t \ t %p \n\n", &a ) ; 6 7 /* zmniejszamy wskaznik o 1, przesuwamy adresy */ 09

8 /* t e r a z wskaznik wskazuje juz na zmienna a */ 9 wsk = wsk 1 ; 30 31 printf ( " Aktualny adres zapisany we wskazniku : \ t \ t \ t %p \n", wsk ) ; 3 printf ( "Wartosc zmiennej wskazywanej przez wskaznik : \ t \ t %d \n", * wsk ) ; 33 printf ( " Aktualny adres zmiennej a : \ t \ t \ t \ t %p \n\n", &a ) ; 34 35 return 0 ; 36 } 4. Mo»liwe jest równie» sprawdzenie odlegªo±ci w pami ci RAM dwóch zmiennych - wykonujemy to równie» za pomoc wska¹ników, dzi ki którym mamy dost p do adresów zmiennych: 5 /* zwykla zmienna typu i n t */ 6 i n t a = 5. 1 ; 7 8 /* wskazniki na typ int, n i e wskazuja na n i c */ 9 i n t * wsk1 = NULL, * wsk = NULL ; 10 11 /* wskaznik wsk1 wskazuje na zmienna a */ 1 wsk1 = &a ; 13 14 wsk = wsk1 + ; 15 16 printf ( " wsk1 = %p \ t wsk = %p \n\n", wsk1, wsk ) ; 17 printf ( " wsk wsk1 = %d \n", wsk wsk1 ) ; 18 19 return 0 ; 0 } 10

9.5 Wska¹nik na staª Wska¹nik na staª, jak sama nazwa wskazuje, pokazuje na staª, której nie mo»emy zmieni. Mo»emy jednak zmieni to, na co wskazuje wska¹nik (adres). Nie mo»emy zmieni warto±ci zmiennej, na któr wskazuje wska¹nik. Istniej dwa sposoby deniowania wska¹ników na staªe: 1 const f l o a t * ptr = &zmienna ; f l o a t const * ptr = &zmienna ; Przykªad 9.5.1. Nie mo»emy zmieni warto±ci, na któr wskazuje wska¹nik, je±li zechcemy to zrobi (linia 5) kompilator poinformuje nas o bª dzie. W poni»szym przykªadzie chcemy zmieni warto± zmiennej j z 666 na 45 - nie powiedzie sie to z wy»ej opisanych powodów: 3 i n t main ( i n t argc, char ** argv ) 5 // deklarujemy i definiujemy zmienna 6 const i n t i = 13, j = 666; 7 printf ( "zmienna = %d\n", i ) ; 8 9 // wskaznik wskazuje na s t a l a i 10 const i n t * ptr1 = &i ; 11 1 // wskaznik wskazuje na s t a l a i 13 i n t const * ptr = &i ; 14 15 printf ( "* ptr1 = %d, * ptr = %d\n", * ptr1, * ptr ) ; 16 17 // wskaznik moze wskazywac na inna s t a l a... 18 ptr = &j ; 19 0 printf ( "* ptr1 = %d, * ptr = %d\n", * ptr1, * ptr ) ; 1 //... a l e n i e mozemy zmienic wartosci, 3 // na ktora wskaznik wskazuje BLAD 4 // tu chcemy zmienic wartosc j z 666 na 45 5 * ptr = 4 5 ; 6 7 return 0 ; 8 } 9.6 Staªy wska¹nik Podobnie jak mo»emy deklarowa zwykªe staªe, tak samo mo»emy mie staªe wska¹niki. Staªy wska¹nik to taki, którego nie mo»na przestawi na inny adres. To wska¹nik, który ZAWSZE wskazuje na to samo 11

(na ten sam adres). Nie mo»emy zmieni adresu przechowywanego przez wska¹nik (wska¹nik zawsze b dzie wskazywaª na to samo, na t sam zmienn ), jednak mo»emy zmieni warto±c zmiennej, na któr ten wska¹nik wskazuje. Istniej dwa sposoby deniowania staªych wska¹ników: 1 i n t * const p = &zmienna ; const i n t * const *p = &zmienna ; Przykªad 9.6.1. Kiedy spróbujemy zmieni adres wska¹nika (kiedy chcemy, aby wskazywaª na inn zmienn ), kompilator zawiadomi nas o bª dzie. 3 i n t main ( i n t argc, char ** argv ) 5 // deklarujemy i definiujemy zmienna 6 i n t i = 13; 7 printf ( "zmienna = %d\n", i ) ; 8 9 // deklarujemy i definiujemy wskaznik, 10 // ktory wskazuje na t e zmienna 11 i n t * wsk = &i ; 1 printf ( "*wsk = %d\n", * wsk ) ; 13 14 // s t a l y wskaznik, wskazuje na zmienna 15 i n t * const p = &i ; 16 // to samo, co powyzej, s t a l y wskaznik 17 const i n t * const *r = &i ; 18 19 i n t j = 987; 0 1 // BLAD wskaznik p wskazuje j u z na zmienna i // wiec n i e moze wskazywac na zmienna j 3 p = &j ; 4 5 // mozemy zmienic wartosc, na ktora 6 // wskazuje wskaznik 7 *p = 1040; 8 printf ( "zmienna = %d\n", i ) ; 9 30 return 0 ; 31 } 9.7 Operator sizeof Zanim nauczymy si tworzy dynamiczne tablice jednowymiarowe, musimy najpierw pozna dziaªanie operatora sizeof. Operator sizeof inaczej nazywany jest operatorem rozmiaru - operator ten dost pny jest w j zyku C i C++. Operatora u»ywamy podobnie jak funkcji, która jako argument pobiera (w naszym przypadku) nazw typu danych, którego rozmiar chcemy pozna, oraz zwraca jego rozmiar w bajtach. Przykªadowe u»ycie operatora zaprezentowano poni»ej: 1

5 i n t rozmiar = s i z e o f ( i n t ) ; 6 printf ( " Int zajmuje %d bajty w pamieci RAM\n", rozmiar ) ; 7 return 0 ; 8 } 9.8 Zwi zek pomi dzy wska¹nikiem a tablic Nale»y zapami ta, i» NAZWA TABLICY JEST WSKA NIKIEM DO PIERWSZEGO JEJ ELEMNETU. Oznacza to,»e mo»emy odnie± si do pierwszego elementu tablicy na dwa sposoby: ˆ za pomoc nazwy tablicy i indeksu o warto±ci 0 ˆ poprzez ten wska¹nik (sam nazw tablicy) W poni»szym kodzie korzystamy z tej wªasno±ci - skoro sama nzwa tablicy jest wska¹nikiem (do jej pierwszego elementu, elementu z pod indeksu 0), musimy do pobrania warto±ci ze wska¹nika u»y symbolu * (tak, jak robili±my to podczas pobierania warto±ci z danego adresu zapisanego we wska¹niku): 5 6 i n t tab [ ] = {104, 56, 384, 4096, 51}; 7 8 // odwolanie s i e za pomoca indeksu 9 printf ( "%d\n", tab [ 0 ] ) ; 10 11 // odwolanie s i e za pomoca wskaznika ( samej nazwy t a b l i c y ) 1 printf ( "%d\n", * tab ) ; 13 14 return 0 ; 15 } St d, tab[0] == *tab. Skoro tab (sama nazwa tablicy) jest wska¹nikiem na jej pierwszy element (czyli na element tab[0]) do wy±wietlenia warto±ci elementu musimy u»y symbolu *, który pozwala nam pobra warto± pod wskazanym adresem. Dlatego te» instrukcja printf("%d ",*tab); pokazuje warto± 13

pierwszego elementu tablicy (je±li tab to adres, wówczas *tab daje nam warto± z pod tego adresu): Mo»emy równie» wy±wietli adres pierwszego elementu tablicy, za pomoc samej jej nazwy (czyli wska¹nika, który przechowuje adres pierwszego jej elementu), lub pobieraj c adres zmiennej z tablicy z pod indeksu 0, u»ywaj c operatora pobrania adresu, &: 5 i n t n = 5 ; 6 i n t i ; 7 8 i n t tab [ ] = {104, 51, 56, 18}; 9 10 printf ( "%p\n", tab ) ; 11 printf ( "%p\n", &tab [ 0 ] ) ; 1 13 return 0 ; 14 } Poniewa» tablica w pami ci jest ci gªym obszarem, w którym kolejne elementy umieszczane s jeden po drugim, znaj c adres pierwszego elementu, mo»emy za pomoc wska¹nika uzyska dost p do jej kolejnych elementów. Pami tamy,»e na wska¹nikach mo»emy wykonywa operacj dodawania warto±ci do zmiennej wska¹nikowej, czyli przesuni cia wska¹nika na inny adres. Warto zauwa»y,»e w przypadku 14

elementów, które zajmuj np. 4 bajty pami ci (liczby typu int), b dziemy przy ka»dym zwi kszeniu wska¹nika przeskakiwa o te cztery bajty,»eby dosta si do nast pnej warto±ci tablicy. W przypadku tablicy typu char przeskok b dzie o jeden bajt - tyle ile zajmuje typ char. Reguªa ta dotyczy ka»dego innego typu. W poni»szym przykªadzie zadeklarowali±my tablic o elementach typu int. Za pomoc wska¹nika wy±iwetlamy adres jej pierwszego elementu. Aby wy±wietli adres kolejnego elementu do wska¹nika musimy doda warto± 1, czyli przesun wska¹nik na kolejny element tablicy: 5 i n t n = 5 ; 6 i n t i ; 7 8 i n t tab [ ] = {104, 51, 56, 18}; 9 10 /* wyswietlamy adres 1 go elementu t a b l i c y, elementu 104 */ 11 printf ( "%p\n", tab ) ; 1 printf ( "%p\n", &tab [ 0 ] ) ; 13 14 /* przesuwamy wskaznik o 1 miejsce, c z y l i dla i n t a 4 bajty, 15 na element nastepny, ktorym j e s t 51 i wyswietlamy 16 adres go elementu t a b l i c y */ 17 printf ( "%p\n", tab+1) ; 18 printf ( "%p\n", &tab [ 1 ] ) ; 19 0 return 0 ; 1 } Poniewa» pod kolejnymi wska¹nikami kryj si elemnety tablicy, istnieje mo»liwo± pobrania ich warto±ci przy u»yciu operatora wyªuskania, czyli *: 15

5 i n t n = 5 ; 6 i n t i ; 7 8 i n t tab [ ] = {104, 51, 56, 18}; 9 10 /* wyswietlamy wartosc 1 go elementu t a b l i c y, elementu 104 */ 11 printf ( "%d\n", * tab ) ; 1 printf ( "%d\n", tab [ 0 ] ) ; 13 14 /* przesuwamy wskaznik o 1 miejsce, c z y l i dla i n t a 4 bajty, 15 na element nastepny, ktorym j e s t 51 i wyswietlamy 16 wartosc go elementu t a b l i c y */ 17 printf ( "%d\n", *( tab+1) ) ; 18 printf ( "%d\n", tab [ 1 ] ) ; 19 0 return 0 ; 1 } Pisz c ogólnie, dla dowolnej tablicy: wska¹niki tab tab+1 tab+... tab+n-1 dane element pierwszy element drugi element trzeci... element n-1 indeksy 0 1... n-1 Dzi ki temu, i» sama nazwa tablicy jest wska¹nikiem do 1-go jej elementu, mo»emy za pomoc przesuwania wska¹nika wy±wietli wszystkie elementy tablicy: 3 4 i n t main ( ) 5 { 6 i n t tab [ 1 0 ] = {1,,4, 5, 6, 4, 3,, 1, 0 } ; 7 i n t i ; 8 9 f o r ( i=0; i <10; i++) 16

10 printf ( "%d ", *( tab+i ) ) ; 11 1 printf ( "\n" ) ; 13 14 f o r ( i=0; i <10; i++) 15 printf ( "%d ", tab [ i ] ) ; 16 17 return 0 ; 18 } Poni»sze kody pokazuj ró»ne mo»liwe sposoby dost pu do elementów tablicy: ˆ Za pomoc operatora indeksu: 5 i n t tab [ 4 ] ; 6 i n t n = 4 ; 7 i n t i ; 8 9 f o r ( i=0;i<n ; i++) 10 { 11 scanf ( "%d", &tab [ i ] ) ; 1 } 13 14 f o r ( i=0;i<n ; i++) 15 { 16 tab [ i ] *= ; 17 } 18 19 f o r ( i=0;i<n ; i++) 0 { 1 printf ( "%d ", tab [ i ] ) ; } 3 4 return 0 ; 5 } ˆ Za pomoc indeksu i operatora wyªuskania: 5 i n t tab [ 4 ] ; 6 i n t n = 4 ; 7 i n t i ; 17

8 9 f o r ( i=0;i<n ; i++) 10 { 11 scanf ( "%d", ( tab+i ) ) ; 1 } 13 14 f o r ( i=0;i<n ; i++) 15 { 16 *( tab+i ) *= ; 17 /* albo : */ 18 /* *( tab+i ) = * *( tab+i ) */ 19 } 0 1 f o r ( i=0;i<n ; i++) { 3 printf ( "%d ", *( tab+i ) ) ; 4 } 5 6 return 0 ; 7 } ˆ Za pomoc wska¹nika i operatora wyªuskania: 5 i n t tab [ 4 ] ; 6 i n t n = 4 ; 7 i n t i ; 8 i n t * wsk = NULL ; 9 10 f o r ( i=0, wsk=tab ; i<n ; i++, wsk++) 11 { 1 scanf ( "%d", wsk ) ; 13 } 14 15 f o r ( i=0, wsk=tab ; i<n ; i++, wsk++) 16 { 17 * wsk *= ; 18 /* albo : */ 19 /* *wsk = * *wsk */ 0 } 1 f o r ( i=0, wsk=tab ; i<n ; i++, wsk++) 3 { 4 printf ( "%d ", * wsk ) ; 5 } 6 7 return 0 ; 8 } ˆ Za pomoc samych wska¹ników: (&tab[rozmiar] oraz tab+n oznaczaj adres ko«ca tablicy, ostatniego jej elementu, dzi ki czemu wska¹nik nie wyjdzie poza tablic ) 5 i n t tab [ 4 ] ; 6 i n t n = 4 ; 7 i n t i ; 8 i n t * wsk = NULL ; 9 10 f o r ( wsk=tab ; wsk < tab + n ; wsk++) 11 { 18

1 scanf ( "%d", wsk ) ; 13 } 14 15 f o r ( wsk=tab ; wsk < tab + n ; wsk++) 16 { 17 * wsk *= ; 18 /* albo : */ 19 /* *wsk = * *wsk */ 0 } 1 f o r ( wsk=tab ; wsk < tab + n ; wsk++) 3 { 4 printf ( "%d ", * wsk ) ; 5 } 6 7 return 0 ; 8 } 5 i n t tab [ 4 ] ; 6 i n t n = 4 ; 7 i n t i ; 8 i n t * wsk = NULL ; 9 10 f o r ( wsk=tab ; wsk < &tab [ n ] ; wsk++) 11 { 1 scanf ( "%d", wsk ) ; 13 } 14 15 f o r ( wsk=tab ; wsk < &tab [ n ] ; wsk++) 16 { 17 * wsk *= ; 18 /* albo : */ 19 /* *wsk = * *wsk */ 0 } 1 f o r ( wsk=tab ; wsk < &tab [ n ] ; wsk++) 3 { 4 printf ( "%d ", * wsk ) ; 5 } 6 7 return 0 ; 8 } 9.9 Wska¹niki i dynamiczne tablice jednowymiarowe Tablica dynamiczna (ang. dynamic array) jest tworzona w czasie uruchomienia programu. Jej rozmiar mo»e by wyliczany. Co wi cej, gdy przestanie by potrzebna mo»emy j usun z pami ci. Dzi ki tym wªasno±ciom program efektywniej wykorzystuje zasoby pami ciowe komputera. Aby utworzy tablic dynamiczn jednowymiarow liczb caªkowitych o rozmiarze (ilo±ci elementów) równej n, nale»y: 1. Zdeniowa zmienn wska¹nikow, która b dzie przechowywaªa adres pierwszego elementu tablicy. Jest to zwykªa denicja wska¹nika: 1 i n t * wsk ;. Przydzieli obszar pami ci dla tablicy. Nale»y zastosowa nast puj c konstrukcj : 1 i n t * tab = malloc ( n * s i z e o f ( i n t ) ) ; 19

Poniewa» nasza tablica ma przechowywa n elementów, a ka»dy z jej elementów ma by zmienn typu int, nale»y sprawdzi, ile bajtów w pami ci zajmuje int, a nast pni warto± t pomno-»y przez ilo± elementów tablicy - dzi ki temu przydzielimy pami na n elementów typu int - utworzymy tablic n-elementow liczb caªkowitych. 3. Do elementów tak utworzonej tablicy odwoªujemy si poprzez ich indeksy, na przykªad: 1 wsk [ 0 ], wsk [ 1 ], wsk [ ],... ogólnie: wsk[indeks], gdzie indeks - powinien by w zakresie od 0 do liczba_elementów - 1. Kompilator nie sprawdza, czy element o danym indeksie znajduje si faktycznie w tablicy. Nale»y zachowa ostro»no±, aby nie wyj± poza tablic. 4. Gdy tablica dynamiczna przestanie by potrzebna, usuwamy j z pami ci za pomoc instrukcji: 1 free ( wsk ) ; wsk = NULL ; Po tej operacji obszar pami ci zaj ty przez tablic zostaje zwrócony do systemu. Wska¹nik mo»na wykorzysta ponownie do innej tablicy wg powy»szych punktów. Tablicy dynamicznej u»ywamy tak samo jak zwykª tablice statyczn, nie trzeba operowa wska¹nikami (ale mo»na), wska¹niki potrzebne s przy jej deklaracji. 9.9.1 Tworzenie dynamicznej tablicy jednowymiarowej Przeanalizujmy poni»szy przykªad. Zaªó»my,»e chcemy stworzy dynamiczn, jednowymiarow tablic o ilo±ci elementów (rozmiarze) podanym przez u»ytkownika. Aby to zrobi, na pocz tku wczytujemy rozmiar tablicy, nast pnie przydzielamy dla niej pami... : 1 i n t n ; scanf ( "%d", &n ) ; 3 i n t * wski = NULL ; 4 wski = ( i n t *) malloc ( n * s i z e o f ( i n t ) ) ; 9.9. Dost p do elementów dynamicznej tablicy jednowymiarowej... zerujemy tablic, wy±wietlamy jej zawarto± (czyli uzyskujemy dost p do elmentów tablicy): 1 f o r ( i=0; i<n ; i++) wski [ i ] = 0 ; 3 4 f o r ( i=0; i<n ; i++) 5 printf ( "%d ", wski [ i ] ) ; 6 printf ( "\n" ) ; 9.9.3 Usuwanie dynamicznej tablicy jednowymiarowej... i usuwamy przydzielon pami : 1 free ( wski ) ; wski = wski ; 0

9.9.4 Tworzenie, dost p do elementów oraz usuwanie dynamicznej tablicy jednowymiarowej Wszystkie powy»sze operacje, aby mogªy dziaªa jako program, zostaªy zebrane na listingu poni»ej. Zaprezentowany kod: 1. Wczytuje od u»ytkownika ilo± elementów tablicy. Deniuje wska¹niki na typy danych int, float, double, char 3. Korzystaj c ze wska¹ników przydziela pami dla ka»dej tablicy (dla tablicy elementów typu int, float, double, char) 4. Wypeªnia ka»d z tablic 5. Wy±wietla ka»d z tablic 6. Zwalnia pami na ka»d z przydzielonych tablic Podsumowuj c, na poni»szych przykªadach widzimy schematy tworzenia dynamicznych tablic jednowymiarowych o n elementach, dla ka»dego typu danych: 5 i n t i ; 6 7 /* i l o s c elementow t a b l i c y */ 8 i n t n ; 9 /* wczytanie i l o s c i elementow t a b l i c y */ 10 printf ( "Podaj i l o s c elementow t a b l i c y : \ n> " ) ; 11 scanf ( "%d", &n ) ; 1 13 /* wskaznik na zmienna typu i n t */ 14 i n t * wski = NULL ; 15 16 /* p r z y d z i e l e n i e pamieci na n elemenotwa t a b l i c e intow */ 17 wski = ( i n t *) malloc ( n * s i z e o f ( i n t ) ) ; 18 19 /* wyzerowanie t a b l i c y dynamicznej */ 0 f o r ( i=0; i<n ; i++) 1 wski [ i ] = 0 ; 3 /* w y s w i e t l e n i e t a b l i c y */ 4 f o r ( i=0; i<n ; i++) 5 printf ( "%d ", wski [ i ] ) ; 6 printf ( "\n" ) ; 7 8 /* z w o l n i e n i e pamieci p r z y d z i e l o n e j na t a b l i c e */ 9 free ( wski ) ; 30 wski = NULL ; 31 3 return 0 ; 33 } 5 i n t i ; 6 1

7 /* i l o s c elementow t a b l i c y */ 8 i n t n ; 9 /* wczytanie i l o s c i elementow t a b l i c y */ 10 printf ( "Podaj i l o s c elementow t a b l i c y : \ n> " ) ; 11 scanf ( "%d", &n ) ; 1 13 /* wskaznik na zmienna typu f l o a t */ 14 f l o a t * wsk = NULL ; 15 16 /* p r z y d z i e l e n i e pamieci na n elemenotwa t a b l i c e f l o a t */ 17 wsk = ( f l o a t *) malloc ( n * s i z e o f ( f l o a t ) ) ; 18 19 /* wyzerowanie t a b l i c y dynamicznej */ 0 f o r ( i=0; i<n ; i++) 1 wsk [ i ] = 0 ; 3 /* w y s w i e t l e n i e t a b l i c y */ 4 f o r ( i=0; i<n ; i++) 5 printf ( "%.1 f ", wsk [ i ] ) ; 6 printf ( "\n" ) ; 7 8 /* z w o l n i e n i e pamieci p r z y d z i e l o n e j na t a b l i c e */ 9 free ( wsk ) ; 30 wsk = NULL ; 31 3 return 0 ; 33 } 5 i n t i ; 6 7 /* i l o s c elementow t a b l i c y */ 8 i n t n ; 9 /* wczytanie i l o s c i elementow t a b l i c y */ 10 printf ( "Podaj i l o s c elementow t a b l i c y : \ n> " ) ; 11 scanf ( "%d", &n ) ; 1 13 /* wskaznik na zmienna typu double */ 14 double * wsk = NULL ; 15 16 /* p r z y d z i e l e n i e pamieci na n elemenotwa t a b l i c e double */ 17 wsk = ( double *) malloc ( n * s i z e o f ( double ) ) ; 18 19 /* wyzerowanie t a b l i c y dynamicznej */ 0 f o r ( i=0; i<n ; i++) 1 wsk [ i ] = 0 ; 3 /* w y s w i e t l e n i e t a b l i c y */ 4 f o r ( i=0; i<n ; i++) 5 printf ( "%.1 f ", wsk [ i ] ) ; 6 printf ( "\n" ) ; 7 8 /* z w o l n i e n i e pamieci p r z y d z i e l o n e j na t a b l i c e */ 9 free ( wsk ) ; 30 wsk = NULL ; 31 3 return 0 ; 33 }

5 i n t i ; 6 7 /* i l o s c elementow t a b l i c y */ 8 i n t n ; 9 /* wczytanie i l o s c i elementow t a b l i c y */ 10 printf ( "Podaj i l o s c elementow t a b l i c y : \ n> " ) ; 11 scanf ( "%d", &n ) ; 1 13 /* wskaznik na zmienna typu char */ 14 char * wsk = NULL ; 15 16 /* p r z y d z i e l e n i e pamieci na n elemenotwa t a b l i c e char */ 17 wsk = ( char *) malloc ( n * s i z e o f ( char ) ) ; 18 19 /* wyzerowanie t a b l i c y dynamicznej */ 0 f o r ( i=0; i<n ; i++) 1 wsk [ i ] = ' 0 ' ; 3 /* w y s w i e t l e n i e t a b l i c y */ 4 f o r ( i=0; i<n ; i++) 5 printf ( "%c ", wsk [ i ] ) ; 6 printf ( "\n" ) ; 7 8 /* z w o l n i e n i e pamieci p r z y d z i e l o n e j na t a b l i c e */ 9 free ( wsk ) ; 30 wsk = NULL ; 31 3 return 0 ; 33 } 9.10 Wska¹niki i funkcje Wska¹niki mog by argumentami funkcij. Je±li zechcemy napisa funkcj, która jako argument pobiera wska¹nik na zmienn caªkowit, i nie zwraca nic, jej nagªówek b dzie wygl daª nast puj co: void funkcja(int *wsk); Gdy funkcja pobiera wska¹nik do pierwszego elementu dynamicznie utworzonej jednowymiarowej tablicy (mówimy wówczas,»e funkcja pobiera jako argument dynamiczn tablic ), musimy jako kolejny argument poda ilo± jej elementów. Nagªówek takiej funkcji wygl da wi c nast puj co (funkcja nic nie zwraca): void fun(int *tab, int n);. Funkcja mo»e równie» zwraca wska¹nik (np. do pierwszego elementu utworzonej tablicy). Je±li w funkcji za pomoc wska¹ników tworzymy dynamiczn tablic elementów typu int a nast pnie zwracamy wska¹nik do pierwszego elementu, nagªówek funkcji b dzie wygl da nast puj co: int * fun(); (funkcja nie pobiera argumentów). Nale»y pami ta o tym, i» poniewa» wska¹nik ma dost p do oryginalnej zmiennej (za pomoc jej adresu), je±li do funkcji jako argument przeka»emy wska¹nik, który wskazuje na zmienn, a nast pnie za pomoc wska¹nika w funkcji zmodykujemy t zmienn, zmiana b dzie widoczna równie» po wyj±ciu z funkcji. Ta sama zasada obowi zuje podczas przekazywanie dynamicznych tablic (wska¹nika na pierwszy element tablicy). Prosz przeanalizowa poni»sze przykªady: #i n c l u d e <s t d l i b. h> 3 #i n c l u d e <s t r i n g. h> 4 5 void przypisz ( i n t *w ) 6 { 7 *w = 104; 3

8 } 9 10 i n t main ( ) 11 { 1 i n t a = 5 ; 13 i n t * wsk = &a ; 14 15 printf ( "PRZED FUNKCJA: \ n\n" ) ; 16 printf ( "a = %d *wsk = %d\n", a, * wsk ) ; 17 18 przypisz ( wsk ) ; 19 0 printf ( "\n" ) ; 1 printf ( "PO FUNKCJI: \ n\n" ) ; printf ( "a = %d *wsk = %d\n", a, * wsk ) ; 3 4 return 0 ; 5 } #i n c l u d e <s t d l i b. h> 3 #i n c l u d e <s t r i n g. h> 4 5 void zamien ( i n t * tab, i n t n ) 6 { 7 i n t i ; 8 f o r ( i=0; i<n ; i++) 9 tab [ i ] = 1000; 10 } 11 1 i n t main ( ) 13 { 14 i n t i ; 15 i n t *w = ( i n t *) malloc ( s i z e o f ( i n t ) * 4) ; 16 17 f o r ( i=0; i<4; i++) 18 w [ i ] = i + 1 ; 19 0 printf ( "PRZED FUNKCJA: \ n\n" ) ; 1 f o r ( i=0; i<4; i++) 3 printf ( " tab[%d ] = %d\n", i, w [ i ] ) ; 4 5 zamien ( w, 4) ; 6 7 printf ( "\n" ) ; 8 printf ( "PO FUNKCJI: \ n\n" ) ; 9 f o r ( i=0; i<4; i++) 30 printf ( " tab[%d ] = %d\n", i, w [ i ] ) ; 4

31 3 free ( w ) ; 33 34 return 0 ; 35 } Gdy w funkcji za pomoc wska¹nika utworzymy dynamiczn tablic, mo»emy z funkcji zwróci wska¹nik do pierwszego jej elementu, aby (przykªadowo) w funkcji main mie dost p do tak utworzonej tablicy. Ponizszy kod pokazuje, jak napisa funkcj, która pobiera jako argument ilo± elementów tablicy, nast pnie za pomoc wska¹nika dynamicznie j tworzy (przydziela jej pami ) i zwraca wska¹nik do niej (wska¹nik na dynamiczn tablic / wska¹nik do pierwszego elementu dynamicznej tablicy). Nast pnie w funkcji main wska¹nik zwrócony z funkcji zapisujemy do innego wska¹nika i wykonujemy operacje na tablicy, ostatecznie zwalniaj c przydzielon pami : #i n c l u d e <s t d l i b. h> 3 #i n c l u d e <s t r i n g. h> 4 5 f l o a t * alokuj ( i n t n ) 6 { 7 f l o a t *f = ( f l o a t *) malloc ( s i z e o f ( f l o a t ) * n ) ; 8 return f ; 9 } 10 11 i n t main ( ) 1 { 13 i n t n ; 14 printf ( "Podaj i l o s c elementow t a b l i c y : \ n> " ) ; 15 scanf ( "%d", &n ) ; 16 17 f l o a t * wsk = alokuj ( n ) ; 18 19 i n t i=0; 0 f o r ( i=0; i<n ; i++) 1 { wsk [ i ] = i + 1 ; 3 printf ( "wsk[%d ] = %f \n", i, wsk [ i ] ) ; 4 } 5 6 free ( wsk ) ; 7 wsk = NULL ; 8 9 return 0 ; 30 } 5

9.11 Zadania do wykonania 9.11.1 Wska¹niki Zadanie 0.0 Zadeklaruj zmienn typu caªkowitego, a. Zadeklaruj wska¹nik na zmienn typu caªkowitego, wa. Niech wska¹nik wa wskazuje na zmienn a. Wy±wietl warto± zmiennej a korzystaj c ze zmiennej i ze wska¹nika. Zmie«warto± zmiennej - ponownie wy±wietl warto± zmiennej a korzystaj c ze zmiennej i ze wska¹nika. Do warto±ci wskazywanej przez wska¹nik dodaj warto± 100 (skorzystaj z operatora *). Ponownie wy±wietl warto± zmiennej a korzystaj c ze zmiennej i ze wska¹nika. Zadanie 0.1 Zadeklaruj zmienn typu caªkowitego, a. Zadeklaruj dwa wska¹niki na zmienn typu caªkowitego, wa1 oraz wa. Niech wska¹nik wa1 wskazuje na zmienn a, natomiast wska¹nik wa wskazuje na wska¹nik wa1. Wy±wietl warto± zmiennej a korzystaj c ze zmiennej i z wska¹ników. Zmie«warto± zmiennej - ponownie wy±wietl warto± zmiennej a korzystaj c ze zmiennej i z wska¹ników. Do warto±ci wskazywanej przez wska¹nik wa dodaj warto± 100 (skorzystaj z operatora *). Ponownie wy±wietl warto± zmiennej a korzystaj c ze zmiennej i z wska¹ników. Zadanie 0. Zadeklaruj zmienn typu zmiennoprzecinkowego zm1. Zadeklaruj wska¹nik na zmienn typu zmiennoprzecinkowego, wsk. Niech wska¹nik wsk wskazuje na zmienn zm1. Za pomoc funkcji scanf i przy u»yciu wska¹nika, wczytaj warto± do zmiennej zm1. Wy±wietl warto± zmiennej zm1 korzystaj c ze zmiennej i ze wska¹nika. Zadanie 0.3 Napisz funkcj, która pobiera wska¹nik do zmiennej typu int, a nast pnie wpisuje do zmiennej wskazywanej przez wska¹nik warto± 104. Do funkcji dopisz program, w którym zadeklraujesz zmienn zm1, oraz wska¹nik wsk. Do zmiennej wpisz warto± 56, wy±wietl warto± zmiennej zm1 korzystaj c ze zmiennej i ze wska¹nika. Nast pnie wywoªaj funkcj, przeka» jej wska¹nik wsk, i ponownie wy±wietl warto± zmiennej zm1 korzystaj c ze zmiennej i ze wska¹nika. Zadanie 0.4 Zadeklaruj zmienn typu caªkowitego zm1. Zadeklaruj wska¹nik na zmienn typu caªkowitego, wsk. Niech wska¹nik wskazuje na zmienn. Za pomoc funkcji scanf i przy u»yciu wska¹nika, wczytaj warto± do zmiennej zm1. Zwi ksz warto± zmiennej zm1 korzystaj c ze wska¹nika i operatora ++. Ponownie wy±wietl warto± zmiennej zm1 korzystaj c ze zmiennej i ze wska¹nika. Zwi ksz warto± zmiennej zm1 korzystaj c ze wska¹nika i operatora. Ponownie wy±wietl warto± zmiennej zm1 korzystaj c ze zmiennej i ze wska¹nika. Zadanie 0.5 Zadeklaruj i ustaw warto±ci (ró»ne) dwóm zmiennych typu zmiennoprzecinkowego. Zadeklaruj te» dwa wska¹niki. Pierwszy wska¹nik pow inien wskazywa na pierwsz ze zmiennych. Drugi wska¹nik ustaw tak, by wskazywaª n a pierwszy. Wy±wietl warto± obu wska¹ników oraz warto±ci, na które wskazuj. Nast p nie pod pierwsz ze zmiennych (typu zmiennoprzecinkowego) podstaw drug i ponownie wy±w ietl informacje o wska¹nikach. Na ko«cu pierwszej ze zmiennych wska¹nikowych przypisz warto± 5 i znów wy±wietl informacje o wska¹nikach. Zadanie 1 Napisz funkcj otrzymuj c jako argumenty wska¹niki do dwóch zmiennych typu int, która 6

zamienia ze sob warto±ci wskazywanych zmiennych. Zadanie Napisz funkcj otrzymuj c jako argumenty wska¹niki do dwóch zmiennych typu int, która zamienia ze sob warto±ci wskazywanych zmiennych tylko wtedy gdy wskazywana przez drugi argument zmienna jest mniejsza od zmiennej wskazywanej przez pierwszy argument. Zadanie 3 Napisz funkcj, której argumentami s dwa wska¹niki typu int za± zwracan warto±ci jest suma warto±ci zmiennych wskazywanych przez argumenty. Zadanie 4 Napisz funkcj, której argumentami s i typu int oraz w wska¹nik do int, która przepisuje warto± i do zmiennej wskazywanej przez w. Zadanie 5 Napisz funkcj otrzymuj c jako argumenty wska¹niki do dwóch zmiennych typu int, która zwraca jako warto± mniejsz z liczb wskazywanych przez argumenty. Zadanie 6 Napisz funkcj otrzymuj c jako argumenty wska¹niki do dwóch zmiennych typu int, która zwraca jako warto± wska¹nik na zmienn przechowuj c mniejsz z liczb wskazywanych przez argumenty. Zadanie 7 Napisz funkcj double abs_diff(double *a, double *b), która zwraca warto± bezwzgl dn ró»nicy warto±ci wskazywanych przez parametry wej±ciowe a i b. Zadanie 8 Napisz funkcj, która dostaje jako argumenty dwa wska¹niki na liczby zmiennoprzecinkowe i zwraca jako warto± ten z otrzymanych wska¹ników, który wskazuje na warto± o wi kszej warto±ci bezwzgl dnej. Zadanie 9 Napisz funkcj, która dostaje jako argument wska¹nik na liczb caªkowit i zapisuje do zmiennej wskazywanej przez argument warto± wczytan ze standardowego wej±cia. Zadanie 10 int avg(int a, int b, float *result); Zaimplementuj funkcje avg, tak aby zwracaªa 0, je»eli zmienna result wskazuje na NULL. W przeciwnym przypadku funkcja ma zapisa w zmiennej wskazywanej przez result ±redni arytmetyczn liczb a i b oraz zwróci 1. 9.11. Wska¹niki i tablice Zadanie 11 Napisz bezargumentow funkcj, która rezerwuje pami dla pojedynczej zmiennej typu int i zwraca jako warto± wska¹nik do niej. Zadanie 1 Napisz bezargumentow funkcj, która rezerwuje pami dla pojedyn- czej zmiennej typu double i zwraca jako warto± wska¹nik do niej. Zadanie 13 Napisz funkcj dostaj c w argumencie dodatni liczb caªkowit n i zwracaj c wska¹nik do pierwszego elementu n-elementowej dynamicznej tablicy int-ów. Zadanie 14 Napisz funkcj, która dostaje jako argument tablic int-ów i zwalnia pami zajmowan przez przekazan w argumencie tablic. Zadanie 15 Napisz funkcj, która dostaje jako argument wska¹nik do tablicy int-ów i odwraca kolejno± elementów w tablicy nie korzystaj c z dost pu do elementów tablicy operatorami [ ] oraz (). Zadanie 16 Napisz funkcj int previous(int *a, int *b), która dostaje jako argu- menty wska¹niki do dwóch ró»nych elementów tej samej tablicy i zwraca warto± tego o wcze±niejszym indeksie. Zadanie 17 Napisz funkcj, która jako argument otrzymuje wska¹nik do liczby caªkowitej n, alokuje pami na n-elementow tablic liczb zmiennoprzecinkowych, a nast pnie zwraca jako warto± adres do 7

tak przydzielonego bloku pami ci. Zadanie 18 Napisz funkcj, która jako argument otrzymuje wska¹nik do liczby caªkowitej n, alokuje pami na n-elementow tablic liczb zmiennoprzecinkowych, a nast pnie zwraca jako warto± adres do tak przydzielonego bloku pami ci. W funkcji main wczytaj od u»ytkownika rozmiar tablicy (n), wywoªaj funkcj przekazuj c jej podane n, a nast pnie wypeªnij utworzon tablic zerami i j wy±wietl, kolejno zwolnij przydzielon dla niej pami. 8