119
Wiesz już, że nie możemy odwołać się pod komórkę pamięci wskazywaną przez wskaźnik NULI-. Po co zatem przypisywać wskaźnikowi 0? Odpowiedź może być zaskakująca: właśnie po to. aby uniknąć błędów! Wydaje się to zabawne, ale większość (jeśli nie wszystkie) funkcje, które zwracają wskaźnik w przypadku błędu zwrócą właśnie NULL, czyli zero. Tutaj rodzi się kok-jua wskazówka: jeśli w danej zmiennej przechowujemy wskaźnik, zwrócony wcześniej przez jakąś funkcję zawsze sprawdzajmy, czy nie jest on równy 0 (NULL). Wtedy mamy pewność, źe funkcja zadziałała poprawnie.
Dokładniej, NULL nie jest słowem kluczowym, lecz stałą (makrem) zadeklarowaną przez dyrektywy preprocesora. Deklaracja taka może być albo wartością 0 albo też wartością 0 zrzutowaną nu void* (((void *)0)), ale też jakimś słowem kluczowym deklarowanym przez kompilator.
Warto zauważyć, że |»ouiimo przypisywania wskaźnikowi zera. nie oznacza to, że wskaźnik NULL jest reprezentowany przez same zerowe bity. Co więcej, wskaźniki NULL różnych typów mogą mieć różną wartość! Z tego powodu poniższy kod jest niepoprawny:
int ••tablica.wskaźników ■ callocOOO, sizeof •tablica.wskaznikow);
Zakłada on, że w reprezentacji wskaźnika NULL występują same zera. Poprawnym zainicjowaniem dynamicznej tablicy wskaźników wartościami NULL jest (|>oinijamy sprawzdanie wartości zwróconej przez ntalloc()):
int **tablica_wskaznikow ■ mallocOOO • sizeof *tablica_wskaznikow); int i ■ 0; while (i<100)
tablica.wskaznikow(i**] ■ 0;
Tak, jak istnieją zwykłe stałe, tak samo możemy mieć stałe wskaźniki jednak są ich dwa rodzaje. Wskaźniki na stałą wartość:
const int *a; /• lub równoważnie •/ int const *a;
oraz stałe wskaźniki:
int • const b;
Pierwszy to wskaźnik, którym nie można zmienić wskazywanej wartości. Drugi to wskaźnik, którego nie można przestawić na inny adres. Dodatkowo, można zadeklarować stały wskaźnik, którym nie można zmienić wartości wskazywanej zmiennej, i również można zrobić to na dwa sposoby:
const int • const c; /• alternatywnie •/ int const • const c;
int i«0;
const int *a-4i;
int • const b-4i;
int const • const c=4i;
•a = 1; /• kompilator zaprotestuje
•b ■ 2; /• ok •/
•c - 3 /• kompilator zaprotestuje
a ■ b; /• ok •/
b ■ a; /• kompilator zaprotestuje c = a; /• kompilator zaprotestuje
•/
•/
•/
■/