Arytmetyka wskaźników to fundamentalna cecha języka C, która czyni pracę z pamięcią elastyczną, ale potencjalnie niebezpieczną.
Arytmetyka wskaźników powstała z powodu specyfiki języków niskiego poziomu i jest ukierunkowana na pracę z tablicami oraz bezpośrednią obróbkę danych strukturalnych w pamięci. W C wszystkie wskaźniki "wiedzą" rozmiar typu, na który wskazują.
Wielu deweloperów popełnia błąd, myśląc, że dodanie jednej do wskaźnika zwiększy adres o dokładnie jeden bajt. W rzeczywistości zwiększenie następuje o sizeof(typ). Podczas pracy z różnymi typami danych, szczególnie ze strukturami o różnym rozmiarze, łatwo pomylić się przy przechodzeniu przez pamięć. Ponadto arytmetyka wskaźników nie jest dozwolona z void* — to standardowy błąd.
Wszystkie działania arytmetyczne z wskaźnikami uwzględniają rozmiar odpowiedniego typu, co czyni operacje z tablicami maksymalnie efektywnymi. Na przykład:
#include <stdio.h> int arr[4] = {10, 20, 30, 40}; int *p = arr; printf("%d\n", *(p + 2)); // Wyświetli 30
Tutaj (p + 2) przesuwa wskaźnik o 2 * sizeof(int) bajtów do przodu, a nie po prostu o 2 bajty.
Kluczowe cechy:
Czy można wykonywać operacje inkrementacji/dekrementacji z wskaźnikami na void?
Nie, standard C zabrania arytmetyki z void*. Najpierw należy przekonwertować wskaźnik na konkretny typ, na przykład (char*), a dopiero potem wykonywać arytmetykę.
void *vp = arr; char *cp = (char *)vp; cp++;
Co się stanie, jeśli dodasz do wskaźnika na strukturę lub tablicę wartość przekraczającą rozmiar tablicy?
To spowoduje wyjście poza dozwolony obszar pamięci (niezdefiniowane zachowanie). C nie sprawdza granic tablic — odpowiedzialność leży po stronie programisty.
Czy można dodawać dwa wskaźniki do siebie bezpośrednio?
Nie, dodawanie wskaźników jest zabronione i nie ma sensu. Dozwolone jest jedynie odejmowanie dwóch wskaźników, które należą do tej samej tablicy.
Młody programista, pracując z tablicą int przez wskaźniki, przesuwał wskaźnik o ustaloną liczbę bajtów, zapominając o rozmiarze typu.
Zalety:
Wady:
Doświadczony programista zawsze używa wyrażeń takich jak (ptr + n), ufając kompilatorowi, że odpowiednio przeskaluje przesunięcie według rozmiaru typu.
Zalety:
Wady: