Bracie @Spark_of_hope traktuj może wskaźnik jako taki skrót do jakiejś danej w pamięci. Skrót ów możesz sobie nastawiać na dowolny typ dla którego go zdefiniowałeś, czyli jak na int to możesz odnosić się do int-ów, albo tablic intów. Jeśli używasz owego skrótu bez *
to zmieniasz wskazanie na co pokazuje wskaźnik - te wszystkie +1, -1 co ci kq demonstrował.
Jeżeli chcesz sięgnąć "do wnętrza" wskaźnika aby zrobić coś z daną, na którą on wskazuje to wtedy używasz *
.
Ot i cała filozofia.
Taka jeszcze dygresja odnośnie dynamicznych tablic:
int *tablica; // tutaj deklarujemy wskaznik wskazujacy typ int o nazwie tablica (jasne) //
tablica = new int [rozmiar]; // a tutaj jest kosmos, nagle z jednego wskaźnika robi sie ich tablica, jak??:/ //
Magia polega na tym, że int *tablica
umie wskazywać na element typu int, natomiast new int[ileśtam] powoduje, że pamięci tworzy się taka struktura leżących zaraz obok siebie intów:
| int1 | int2 | int3 | .... | int ileśtam |
i teraz *tablica
wskazuje na int1. Ponieważ za 1 intem jest drugi to jak do tablica dodasz 1 co w języku C/C++ oznacza "przesuń wskaźnik *tablica
o 1 wielkość elementu dla którego zostałaś zdefiniowana" spowoduje to, że teraz w *tablica
będzie adres inta2. I tak aż do inta ileśtam.
Cyrk zacznie się dziać jak po przesunięciu *tablicy
na inta ileśtam znów dodasz jeden lub więcej, albo kiedy *tablica
wskazuje na inta1 a ty odejmiesz od niej 1 lub więcej.
W takim wypadku nie wiadomo, co znajduje się przed oraz za dynamicznie stworzoną tablicą, i czy masz dostęp do tej pamięci. Stąd sytuacja ta jest oznaczana jako Undefined Behavior.
Jeszcze jedna uwaga - jak tworzysz sobie dynamicznie tablicę to lepiej nie zmieniać wskaźnika który wskazuje na jej początek, bo nietrudno potem "zapomnieć" w programie gdzie się ona znajduje. Dlatego *tablicę
w przykładowym programie lepiej zapisać tak:
int *const tablica = new int [rozmiar];
to gwarantuje, że nie przestawisz sobie przypadkiem wskaźnika *tablica
na coś innego niż początek dynamicznej tablicy.