1
W
YKŁAD
4 T
ABLICE I WSKAŹNIKI
DR INŻ.
M
AŁGORZATA
J
ANKOWSKA
2
M
.
J
ANKOWSKA –
W
YKŁAD
4 T
ABLICE I WSKAŹNIKI
ARYTMETYKA WSKAŹNIKÓW
Wskaźniki możemy używać jako operandy z następującymi operatorami:
• dodawania (+) i odejmowania (-) liczb całkowitych (możliwe jest również odjęcie od
siebie dwóch wskaźników),
• przypisania (=),
• przypisania wraz dodaniem/odjęciem liczby całkowitej (+=, -=),
• porównania (<, >, <=, >=, ==, !=),
• inkrementacji (++) oraz dekrementacji (--).
W języku C++ istnieje ścisły związek między wskaźnikami a tablicami. Mogą
być one dzięki temu wykorzystywane zamiennie.
Wskaźniki mogą być wykorzystane do wykonania dowolnej operacji, która działa
na indeksach elementów tablicy.
Nazwa tablicy (bez indeksu) jest wskaźnikiem do pierwszego elementu
tablicy.
UWAGI
Arytmetyka operacji na wskaźnikach zawsze bierze pod uwagę rozmiar
wskazywanego typu. Zakłada się, że wskaźnik jest adresem pierwszego
elementu tablicy składającej się z elementów tego właśnie typu.
3
M
.
J
ANKOWSKA –
W
YKŁAD
4 T
ABLICE I WSKAŹNIKI
PRZYKŁAD
/* ... */
int A[6] = {0,1,2,3,4,5};
int * pA = A;
/* ... */
int A[6] = {0,1,2,3,4,5};
int * pA = &A[0];
lub
Deklaracja wskaźnika pA do wartości typu
int połączona z inicjacją adresem
pierwszego elementu tablicy może być
wykonana na dwa równoważne sposoby:
• przy wykorzystaniu nazwy tablicy A –
nazwa tablicy jest adresem pierwszego
elementu tablicy,
• pobierając adres (operator &) pierwszego
elementu tablicy A, czyli elementu A[0];
A[0]
0
A[1]
1
A[2]
2
A[3]
3
A[4]
4
A[5]
5
2000
2004
2008
2012
2016
2020
4
położenie w pamięci
elementy tablicy
2000
pA
zmienna wskaźnikowa pA
wskazuje na element A[0]
tablicy znajdujący się
pod adresem 2000
W języku C/C++ tablica zajmuje ciągły obszar pamięci o rozmiarze, który wystarcza
do przechowania wszystkich jej elementów.
UWAGA 1
4
M
.
J
ANKOWSKA –
W
YKŁAD
4 T
ABLICE I WSKAŹNIKI
Rezultat operacji arytmetycznych wykonywanych na wskaźnikach zależy od
rozmiaru obiektu na który na wskaźnik wskazuje.
Dodanie/odjęcie liczby całkowitej n do/od wskaźnika powoduje przesunięcie go o n
elementów tablicy do przodu/wstecz (tj. w kierunku rosnących/malejących indeksów
lub za tablicę).
Wykonanie wspomnianych operacji dodawania/odejmowania powoduje przesuniecie
wskaźnika o:
n * sizeof(typ-wskazywany)
bajtów.
UWAGA 2 – REZULTAT OPERACJI ARYTMETYCZNYCH
Zmienne wskaźnikowe mogą być od siebie odejmowane.
W przypadku, gdy odejmujemy od siebie zmienne wskaźnikowe wskazujące na
różne elementy tej samej tablicy w wyniku dostaniemy liczbę elementów znajdują-
cych się pomiędzy nimi (a nie liczbę bajtów).
Wynikiem może być oczywiście liczba ujemna!
UWAGA 3 – ODEJMOWANIE ZMIENNYCH WSKAŹNIKOWYCH
5
M
.
J
ANKOWSKA –
W
YKŁAD
4 T
ABLICE I WSKAŹNIKI
PRZYKŁAD – REZULTAT OPERACJI ARYTMETYCZNYCH
/* ... */
int A[6] = {0,1,2,3,4,5};
// Krok 1
int * pA1 = &A[0];
int * pA2 = pA1;
// Krok 2
pA1++;
pA2 += 3;
A[0]
0
A[1]
1
A[2]
2
A[3]
3
A[4]
4
A[5]
5
2000
2004
2008
2012
2016
2020
4
położenie w pamięci
elementy tablicy
zmienne wskaźnikowe
pA1 oraz pA2
wskazują na element A[0]
tablicy znajdujący się
pod adresem 2000
2000
pA1
2000
pA2
KROK 1
6
M
.
J
ANKOWSKA –
W
YKŁAD
4 T
ABLICE I WSKAŹNIKI
PRZYKŁAD – REZULTAT OPERACJI ARYTMETYCZNYCH
/* ... */
int A[6] = {0,1,2,3,4,5};
// Krok 1
int * pA1 = &A[0];
int * pA2 = pA1;
// Krok 2
pA1++;
pA2 += 3;
A[0]
0
A[1]
1
A[2]
2
A[3]
3
A[4]
4
A[5]
5
2000
2004
2008
2012
2016
2020
4
położenie w pamięci
elementy tablicy
zmienna wskaźnikowa pA1
wskazuje na element A[1] tablicy
znajdujący się pod adresem 2004
zmienna wskaźnikowa pA2
wskazuje na element A[3] tablicy
znajdujący się pod adresem 2012
2004
pA1
Wynikiem działania jest wartość 2000 + 4 = 2004;
liczba 2000 zostaje powiększona o rozmiar wskaźnika
(w przypadku liczb typu int rozmiar zazwyczaj wynosi 4).
Wynikiem działania jest wartość 2000 + 3*4 = 2012.
KROK 2
2012
pA2
7
M
.
J
ANKOWSKA –
W
YKŁAD
4 T
ABLICE I WSKAŹNIKI
PRZYKŁAD – ODEJMOWANIE ZMIENNYCH WSKAŹNIKOWYCH
/* ... */
int A[6] = {0,1,2,3,4,5};
int * pA1 = &A[1];
int * pA2 = &A[5];
int x = pA2 – pA1;
A[0]
0
A[1]
1
A[2]
2
A[3]
3
A[4]
4
A[5]
5
2000
2004
2008
2012
2016
2020
4
2020
pA2
2004
pA1
położenie w pamięci
elementy tablicy
zmienna wskaźnikowa pA1
wskazuje na element A[1] tablicy
znajdujący się pod adresem 2004
zmienna wskaźnikowa pA2
wskazuje na element A[5] tablicy
znajdujący się pod adresem 2020
Wynikiem działania nie jest liczba bajtów,
tj. wartość 2020 – 2004 = 16.
Wykonując odejmowanie wskaźników wskazujących na
elementy tej samej tablicy, np. pA2 - pA1 dostaniemy
liczbę elementów znajdujących się pomiędzy nimi;
w danym przypadku x = 4.
8
M
.
J
ANKOWSKA –
W
YKŁAD
4 T
ABLICE I WSKAŹNIKI
ZWIĄZEK MIĘDZY WSKAŹNIKAMI A TABLICAMI
Wiemy już, że istnieje ścisły związek między wskaźnikami i tablicami, gdyż:
• w języku C/C++ tablica zajmuje ciągły obszar pamięci o rozmiarze, który wystarcza
do przechowania wszystkich jej elementów,
• nazwa tablicy (bez indeksu) może być traktowana jako wskaźnik do jej pierwszego
elementu.
Tak więc wskaźniki mogą być wykorzystane do wykonania dowolnej operacji,
działającej na indeksach elementów tablicy.
PRZYKŁAD 1 – DZIAŁANIA NA TABLICY
Z WYKORZYSTANIEM
NOTACJI INDEKSOWEJ
/* ... */
int A[6];
for (int i=0; i<=5; i++)
A[i] = i;
PRZYKŁAD 2 – DZIAŁANIA NA TABLICY
Z WYKORZYSTANIEM
NOTACJI INDEKSOWANIA WSKAŹNIKA
/* ... */
int A[6];
int * pA = A;
for (int i=0; i<=5; i++)
pA[i] = i;
Wskaźnik do pierwszego elementu tablicy (tak samo jak nazwa tablicy) może być
wykorzystany z indeksami poszczególnych elementów. Na przykład wyrażenie pA[3] określa
element o indeksie 3, podobnie jak A[3].
9
M
.
J
ANKOWSKA –
W
YKŁAD
4 T
ABLICE I WSKAŹNIKI
PRZYKŁAD 3 – DZIAŁANIA NA TABLICY
Z WYKORZYSTANIEM
NOTACJI WSKAŹNIK/PRZESUNIĘCIE
(JAKO WSKAŹNIK WYKORZYSTYWANA
JEST NAZWA TABLICY)
/* ... */
int A[6];
for (int i=0; i<=5; i++)
*(A + i) = i;
PRZYKŁAD 4 – DZIAŁANIA NA TABLICY
Z WYKORZYSTANIEM
NOTACJI WSKAŹNIK/PRZESUNIĘCIE
/* ... */
int A[6];
int * pA = A;
for (int i=0; i<=5; i++)
*(pA + i) = i;
Nazwa tablicy jest wskaźnikiem do
jej pierwszego elementu.
Dodając liczbę całkowitą (tzw.
przesunięcie (ang. offset) względem
wskaźnika) do wskaźnika ustalamy,
który element tablicy ma być
referowany (a dokładnie wartość
adresu elementu tablicy, który ma
być referowany)
przy pomocy operatora *.
Zapamiętując adres pierwszego
elementu tablicy w zmiennej
wskaźnikowej pA możemy postępować
podobnie jak w Przykładzie 3.