background image

 

 

Wskaźniki

Wskaźniki

background image

 

 

Definiowanie wskaźników

Wskaźnik

 może wskazywać na obiekt 

dowolnego

 typu. 

int

 * w;

    char

 * Wsk_Znak;

    float

 * Wskaz_Real;

Przykłady:

Wskaźnik

 przechowuje 

adres

 obiektu 

wskazanego typu. 

Wskaźnik

  służący  do  pokazywania  obiektów 

jednego  typu  nie  nadaje  się  do  pokazywania 
obiektów innego typu.

background image

 

 

Praca  ze  wskaźnikiem

 Do 

nadania 

wskaźnikowi 

wartości 

początkowej  służy      jednoargumentowy 
operator 

&

 Oblicza  on  adres  obiektu,    który  stoi  po 

prawej stronie operatora przypisania. 

Przykład:

int

 * w;

// definicja wskaźnika do obiektów 
//typu 

int

int

  k  =  10;

                 

//  definicja  i  inicjalizacja 

zwykłego 

                    //obiektu 

typu 

int

        w  = 

&

k;

//  ustawienie  wskaźnika  na 

obiekt 

k

        cout 

<<

  *  w;

//  wypisanie  zawartości 

obiektu 

* w

background image

 

 

Praca  ze  wskaźnikiem

#include <iostream.h>
#include <conio.h>

void main

 ()

{
  int

 zmienna = 8, druga = 4;

  

int

 *wskaznik;

    clrscr ();
    wskaznik = &zmienna;

// ustawienie 

                     // 

wskaźnika na 

zmienna

    cout 

<<

 "

zmienna =

 " 

<<

 zmienna

 

<<

 "

\n a odczytana przez wskaźnik =

 "

 

<<

 * wskaznik 

<<

 

endl

;

cdn

.

background image

 

 

 zmienna = 10;
    cout 

<<

 "

zmienna =

 " 

<<

 zmienna

 

<<

 "

\n a odczytana przez wskaźnik =

 "

 

<<

 * wskaznik 

<<

 

endl

;

    * wskaznik = 200;
    cout 

<<

 "

zmienna =

 " 

<<

 zmienna

 

<<

 "

\n a odczytana przez wskaźnik =

 "

 

<<

 * wskaznik 

<<

 

endl

;

 wskaznik = &druga;
    cout 

<<

 "

zmienna =

 " 

<<

 zmienna

 

<<

 "

\n a odczytana przez wskaźnik =

 "

 

<< 

* wskaznik 

<<

 

endl

;

}

background image

 

 

Uwagi:

Do  danego  obiektu 

można  odnosić  się  na  dwa 

sposoby

:

Operacja odniesienia się 

*

 do danego obiektu 

może być zarówno po prawej, jak i po lewej 
stronie operatora przypisania, np.:

 przez jego 

nazwę

 

 przez 

zorganizowanie wskaźnika

, który 

będzie na ten obiekt pokazywał.

a = 

* Wskaznik

;

*  Wskaznik

  =  100  + 

a;

background image

 

 

Wskaźnik typu

 

void:

Wskaźnik

 jest to adres miejsca w pamięci plus 

informacja o tym, jakiego typu obiekt się 
pokazuje. 

Można  jednak  zdefiniować  wskaźnik  bez  tej 
wiedzy:

void  

 * Wsk;

gdzie

  *  Wsk

  jest  wskaźnikiem  dowolnego 

typu 

void

.

background image

 

 

Przykład

:

int 

 * wi1,  * wi2;

float 

 * wf;

     wi1 = wi2;
          wf  =  wi1;

// 

błąd

     wf = ( 

float

 *) wi1;

void

  * wv;

char

  * wch;

int

     * wi;

float

  * wf;

     wv = wf;
     wv = wch;
     wv = wi;

background image

 

 

Uwagi:

 Wskaźnik  każdego  niestałego  typu  można 

przypisać wskaźnikowi typu 

void

 Wskaźnika  typu 

void

  nie  można  przypisać 

wskaźnikowi “prawdziwemu”. 

 Trzeba  w  takich  przypadkach  posłużyć  się 

operatorem rzutowania:

wf    = (

float

 *) wv;

wi    = (

int

 *) wv;

wch = (

char

 *) wv;

background image

 

 

Podstawowe  zastosowanie  

wskaźników:

wskaźniki  do  tablic

  umożliwiające  ulepszenie 

pracy z tablicami;

funkcje

  zmieniające wartości przesyłanych  do 

nich argumentów;

rezerwacja obszarów pamięci

.

background image

 

 

Wskaźniki do tablic

Nazwa tablicy jest równoważna 
(prawie...)  wskaźnikowi  do  jej 
pierwszego elementu

const int MAX = 20;
int

 *Wsk;//

 definicja wskaźnika na 

obiekty typu 

int

int

 Tab[MAX];

 

Wsk = Tab;

lub

Wsk = &Tab[0];

background image

 

 

Wskaźniki do tablic

int

  *Wsk;

//  definicja  wskaźnika  na 

obiekty typu 

int

int

 Tab[20];

//  definicja tablicy typu 

int

Wsk  = 

&

Tab  [i];

//  ustawienie  wskaźnika  na

  i

-ty 

element 

//tablicy 

Tab

Wsk = 

&

Tab [0];

// inaczej:

Wsk = Tab;

           

Wsk = Wsk + 1;

 

// inaczej:

 Wsk ++;

Wsk += n;

        

// inaczej: 

 Wsk = 

Wsk + n; 

background image

 

 

Dwie poniższe instrukcje są 

równoważne:

Wsk = &Tab[0];

Wsk = Tab;

Dwa poniższe zapisy są także 

równoważne:

Tab + 4 

&Tab [4];

Jeśli  

Wsk = Tab

, to:

Wsk++;

Tab++; // BŁĄD

Nazwa tablicy

 jest 

stałym wskaźnikiem

 do niej 

samej!

Tab[5]             

*(Tab  +  5) //zapisy 

równoważne

background image

 

 

 Wskaźniki 

tablic 

można 

od 

siebie 

odejmować

.  

 Odjęcie  od  siebie  dwóch  wskaźników 

pokazujących  na  różne  elementy  tej  samej 
tablicy  daje  w  wyniku  liczbę  dzielących  je 
elementów tablicy. 

 Liczba ta może być dodatnia lub ujemna. 

 

Wskaźniki można też ze sobą porównywać za 
pomocą operatorów relacji.  

background image

 

 

Przesyłanie tablic do funkcji:

Do funkcji przesyłamy adres tablicy, np.:

void

 fun ( 

int

 tab [ ] );

Odbieramy  tablicę  z  funkcji  na  dwa 
sposoby:

 jako tablicę

 jako wskaźnik

background image

 

 

Wskaźnik do obiektu

 const

Jeśli funkcja otrzymuje adres tablicy, to pracuje 
w  tym  przypadku  na  oryginale  tablicy  i  może 
dowolnie zmieniać wartości jej elementów.

 Jeśli nie chcemy, aby funkcja te wartości 

zmieniała, to należy posłużyć się 

wskaźnikiem do stałego obiektu

 Taki wskaźnik wskazuje na obiekty, ale nie 

pozwala na ich modyfikację. 

background image

 

 

Stałe wskaźniki:

 Dotychczas  mówiliśmy  o  wskaźnikach  do 

obiektów stałych

 Są to wskaźniki, które 

nie mogą zmieniać 

pokazywanego  obiektu

.  Traktują  go  jako 

obiekt stały.

 Sam  obiekt,  na  który  pokazują  nie  musi 

być rzeczywiście stały. 

 Ważne  jest  to,  że  wskaźnik  tak  go 

traktuje.

Są  jeszcze  inne  wskaźniki  z  przydomkiem 

const

, które nazywamy 

wskaźnikami stałymi. 

int

 Dworzec;

int

 * 

const

 Wsk = & Dworzec;

background image

 

 

Stałe wskaźniki,  a wskaźniki do 

stałych:

Stały  wskaźnik

  to  taki,  który  zawsze 

pokazuje  to  samo.  Nie  można  nim 
poruszać.

Wskaźnik  do  stałego  obiektu

,  to  taki 

wskaźnik,  który  uznaje  pokazywany 
obiekt  za  stały.  Nie  można  go  więc 
modyfikować.

Te dwa typy wskaźników można ze sobą 
łączyć, np.

const float

 * 

const

 Wsk = &a;

background image

 

 

Wskaźnik  zawsze na coś 

pokazuje:

 Jeden z najczęściej popełnianych błędów w 

programach ze wskaźnikami jest 

brak 

początkowego ustawienia wskaźnika

.  

 Przy braku ustawienia następuje 

odczyt z 

przypadkowego miejsca

 w pamięci oraz 

zapis do 

przypadkowego miejsca

void 

fun ()

{
   float

 a;

     

float

  *  x,  *  m:

//  definicja  wskaźników  bez 

inicjalizacji

m = &a;

// ustawienie wskaźnika 

m

 

*x = 20.5;

  //  wskaźnik 

x

 nie jest ustawiony!

// 

tym 

momencie 

możemy 

skasować 

// potrzebną daną

}

background image

 

 

Rezerwacja obszarów pamięci:

 Rezerwowanie 

zwalnianie 

obszarów 

pamięci  jest  wykonywane  za  pomocą   
operatorów 

new

 i 

delete

 Operator 

new

 zajmuje się kreacją, a 

delete

 

unicestwianiem obiektów.

Przykłady

:

char

 * Wsk;

Wsk  = 

new

  char;

//  utworzenie  nowego 

obiektu t.

 

char

 

delete

  Wsk;

//  zlikwidowanie  tego 

obiektu

float

 * w;

w = 

new float

 [10];

delete

 [ ] w;

int

 * Wsk;

        Wsk  = 

new  int

 

( 50 );

background image

 

 

Cechy obiektów stworzonych operatorem

 

new

:

 Obiekty  takie  istnieją  od  momentu,  gdy  je 

stworzyliśmy  operatorem 

new

  do  momentu, 

gdy  je  skasujemy  operatorem 

delete

.  Więc, 

programista decyduje o czasie ich życia.

 Obiekt  tak  utworzony  nie  ma  nazwy.  Można 

nim operować tylko za pomocą wskaźników.

 Obiektów tych nie obowiązują zwykłe zasady o 

zakresie  ważności.  Jeśli  tylko  w  danej  chwili 
jest dostępny choćby jeden wskaźnik, który na 
taki obiekt wskazuje, to mamy dostęp do tego 
obiektu.

 Tylko  statyczne  obiekty  są  inicjalizowane 

wstępnie 

zerami. 

Natomiast 

obiekty 

utworzone  operatorem 

new

  po  utworzeniu 

przechowują wartości przypadkowe.

background image

 

 

Dynamiczna alokacja tablicy:

int

 * Wsk_Tab;

   Wsk_Tab = 

new int

 [ Rozmiar ];

Rozmiar

 jest wyrażeniem typu 

int

 Została  stworzona  nienazwana  tablica 

elementów typu 

int

 Wynikiem  działania  operatora 

new

  jest 

wskaźnik do początku tej tablicy. 

 Operator 

new

 daje swobodę. 

 Tablica  definiowana  jest  dynamicznie, 

w trakcie wykonywania programu, np.:

background image

 

 

cout 

<< 

Ile elementów ma mieć tablica?: 

;

int

 Rozmiar;

cin 

>>

 Rozmiar;

int

 * Wsk_Tab =

 new int

 [ Rozmiar ];

*  Wsk_Tab  =  50;

//  wpisanie  do  zerowego 

elementu

// liczby 

50

Wsk_Tab [0] = 50;

// to samo inaczej

* (Wsk_Tab + 4)  =  100;

// wpisanie do elementu 

o indeksie 

4

// wartości 100

Wsk_Tab [4] = 100;

// to samo inaczej

delete

 

Wsk_Tab;

// 

zlikwidowanie 

wykreowanej

// tablicy 

background image

 

 

Sposoby  ustawienia  

wskaźników:

 Wskaźnik  można  ustawić  tak,  aby 

pokazywał na jakiś obiekt, wstawiając do 
niego adres wybranego obiektu:

Wsk = & Obiekt;

 Wskaźnik  można  również  ustawić  na  to 

samo, na co pokazuje już inny wskaźnik. 
Jest  to  zwykła  operacja  przypisania 
wskaźników:

Wsk = Nowy_Wsk;

cdn.

background image

 

 

 Wskaźnik  ustawia  się 

na  początek  tablicy

 

podstawiając  do  niego  jej  adres.    W  zapisie 
jest niepotrzebny operator 

&

:

Wsk = Tablica

 Wskaźnik  może  także  pokazywać  na  funkcję. 

Nazwa  funkcji  jest  także  jej  adresem,  zatem  i 
tu zbędny jest operator 

&

:

Wsk = Funkcja;

 Operator 

new

 zwraca adres nowoutworzonego 

obiektu.  Taki  adres  wpisujemy  do  wskaźnika. 
Od  tej  pory  wskaźnik  pokazuje  na  ten  nowy 
obiekt:

float

 * Wsk;

Wsk = 

new float

;

 Jeśli wskaźnik 

ma pokazywać na ciąg znaków

można go ustawić w taki sposób:

Wsk =  Programowanie komputerów ;

background image

 

 

Tablice  wskaźników:

Elementami tablic mogą być wskaźniki

, czyli 

adresy różnych miejsc w pamięci, np.: 

float

 * Wsk_Flo [10];

lub

float

 * (Wsk_Flo [10]);

char

 * Wsk_Lan [ 3];

char

  *  Wsk_Lan  [3]  =  {  Matematyka

Fizyka

Progr. Komputerów};

char

 * Wsk = { abcde };

background image

 

 

Przykład 1: 

Obliczyć wartości dwóch 

następujących całek:

3

2

2

dx

x

dx

x

1

0

2

sin

 wykorzystując metodę 

Simpsona

.

background image

 

 

Przybliżony wzór na obliczenie całki 
ma następującą postać:

b

a

dx

x

f

I

)

(

3

/

))

(

...

)

(

)

(

(

2

))

(

...

)

(

)

(

(

4

)

(

)

(

2

4

2

1

3

1

0

m

m

m

x

f

x

f

x

f

x

f

x

f

x

f

x

f

x

f

h

I

gdzi
e:

m

a

b

h

- długość 
podprzedziału

m    

-

 

jest parzystą liczbą 

podprzedziałów

.

background image

 

 

f(x) = 3*x*x

0

5

10

15

20

25

30

-2

-1

,5

-1

-0

,5

0

0

,5

1

1

,5

2

2

,5

3

x

y

background image

 

 

#include <conio.h>
#include <iostream.h>

void main

 ()

{

 

int

 a = 1;

 

int

 

*

Adr;

 

int

 

&

r_a = a;

 Adr = 

&

a;

 clrscr();
 cout 

<<

 

*

Adr 

<<

 

endl

;

 cout 

<<

 

&

r_a 

<<

 

endl

;

 cout 

<<

 

&

<<

 

endl

;

 cout 

<<

 Adr 

<<

 

endl

;

 cout 

<<

 a 

<<

 

endl

;

 cout 

<<

 r_a 

<<

 

endl

;

 r_a = 2;
 Adr = 

&

r_a;

 

cout 

<<

 Adr 

<<

 

endl

;

 cout 

<<

 

*

Adr 

<<

 

endl

;

}

Wskaźnik  a  referencja

1

0x8fa0fff4

0x8fa0fff4

0x8fa0fff4

1

1

0x8fa0fff4

2


Document Outline