Ponownie poruszę zagadnienie na temat relacji pomiędzy tablicą a wskaźnikiem w języku C i C++. Wątek ten jest albo wymagany, albo poboczny w zależności od tego, w jakim języku piszecie (albo chcecie pisać) na co dzień. Zakładając, że przeczytaliście wprowadzenie do wskaźników, mogę Was poprowadzić za rękę dalej i zaprezentować Wam jak wygląda notacja wskaźnikowa do identyfikowania odpowiedniego elementu do tablicy. Dzisiaj jedynie Was wprowadzę do tematu, a już jutro pokażę Wam zapisy dla tablicy dwuwymiarowej. Wtedy będzie się działo! Na razie, przeanalizujemy tablicę jednowymiarową. Zapraszam!

NOTACJA WSKAŹNIKOWA DLA ARGUMENTÓW TABLICY

Zdecydowana większość obecnie wykorzystywanych języków programowania obsługuje wszystkim znany zapis "dostawania się" do konkretnego argumentu tablicy za pomocą nawiasów kwadratowych ([]). Wprowadzając w środek nich indeks w postaci dodatniej liczby całkowitej (tylko Python obsługuje ujemne wartości) uzyskujemy dostęp do konkretnej wartości. C i C++ wspiera również trudniejszą notację zwaną czasami "notacja wskaźnikowa". Polega ona na "przesuwaniu" adresu wskazującego początek tablicy dodając do niej liczbę całkowitą oraz "dereferencji" wskaźnika po tym przesuniętym adresie celem uzyskania lub modyfikacji wartości. Jeden z moich artykułów pokazywał jak wygląda ten zapis. Przydaje się on wówczas gdy "zapominamy" o zapisie tablicowym przerzucając się w całości na wskaźniki. Przypominam, że notacja wskaźnikowa nie posiada żadnego liczbowego "indeksu", tak jak ma to miejsce przy bardziej znanym zapisie. Spróbujmy teraz te teoretyczne fakty przerzucić na "programistyczny" język.

TŁUMACZENIE NA JĘZYK KOMPUTEROWY

Za przykład podam taką oto tablicę "numbers" noszącą powiedzmy, cztery argumenty typu "liczba całkowita". Wiemy, że w większości znanych języków będzie to wyglądać tak:

int[4] numbers;

W C i C++, nawiasy kwadratowe mają miejsce po nazwie tablicy. A teraz zobaczmy jak to wygląda jako notacja wskaźnikowa. O tym też pisałem wcześniej jednak szybko podsumuję. Tablica w językach C i C++ to tak naprawdę wskaźnik, zatem sama nazwa tablicy spełnia następującą równość:

numbers = &numbers[0]

Znak "ampersandu" przedstawia adres obiektu. Jak nie wierzycie, podstawcie sobie oba zapisy pod "printf" ze specyfikatorem "%p". Do lewej strony równania możemy dorzucić stałą liczbę całkowitą. Przypuśćmy, że wpisaliśmy "numbers + 1". Co to oznacza dla prawej strony równości?

numbers + 1 = &numbers[1]

Czyli "przesunęliśmy" adres startu naszej tablicy o jeden argument do przodu (+4 bajty typu "int", pod warunkiem, że to system 32-bitowy) i w ten sposób uzyskaliśmy adres drugiego argumentu tablicy "numbers" pod indeksem 1 (przypominam, że w tablicy argumenty są liczone od zera!). Pamiętajcie, aby się nie rozpędzić i akurat w naszym przypadku nie dać plus 4 lub więcej. Wówczas "wychodzimy" poza tablicę i dopuszczamy się naruszenia ochrony pamięci. Notacja wskaźnikowa nie wyłapie przekroczenia zakresu tablicy. Możemy bez przeszkód "wyłuskać" wskaźnik i z adresu "wyciągnąć" wartość liczbową. Zatem zakładając, że pierwszy argument posiada wartość 32, prawdziwa jest poniższa równość:

*numbers = numbers[0] = 32

Sprawa się komplikuje gdy chcemy "wyłuskać" konkretny indeks tablicy. Możecie pomyśleć, że to działa identycznie jak powyżej, natomiast muszę Was rozczarować:

*numbers + 1 = numbers[0] + 1 = 32 + 1 = 33

Widzicie? Operator dereferencji ma pierwszeństwo przy wykonywaniu więc komputer najpierw dostanie się do adresu, "wyjmie" liczbę, a dopiero wtedy doda do niej jedynkę. Gdy chcemy, aby stało się po Waszej myśli, musimy osadzić wyrażenie w nawias w taki oto sposób (załóżmy, że druga liczba to 55):

*(numbers + 1) = numbers[1] = 55

Notacja wskaźnikowa jest równie "czuła" na nawiasy jak matematyka. Jeśli chcemy sprawnie się tutaj poruszać, musimy odróżniać jeden zapis od drugiego. Nie muszę dodawać, że ostatni przykład również stanowi zagrożenie w przypadku przekroczenia rozmiaru tablicy.


Dzięki za uwagę i skupienie. Nie smućcie się jeśli macie problem ze zrozumieniem. Ja miałem tak samo jednak na szczęście to już jest za mną. Jutro napiszę jak wygląda notacja wskaźnikowa dla tablicy 2D!