Istnieje kilka dobrych odpowiedzi na to pytanie, jedna z nich została przyjęta. I tak mam zamiar odpowiedzieć, aby rozszerzyć praktyczność.
Tak, dobrą praktyką jest inicjowanie wskaźników do wartości NULL, a także ustawianie wskaźników na wartość NULL po tym, jak nie są już potrzebne (tj. Zwolnione).
W obu przypadkach bardzo praktyczna jest możliwość przetestowania wskaźnika przed dereferencją. Powiedzmy, że masz strukturę, która wygląda tak:
struct foo {
int counter;
unsigned char ch;
char *context;
};
następnie napisać aplikację, która spawns kilka wątków, z których wszystkie działają na jednej przydzielonej strukturze Foo (bezpiecznie) dzięki zastosowaniu wzajemnego wykluczania.
Wątek A otrzymuje blokadę foo, licznik inkrementów i sprawdza wartość w pkt.Nie znajduje takiego, więc nie przydziela (ani modyfikuje) kontekstu. Zamiast tego przechowuje wartość w ch, dzięki czemu wątek B może zamiast tego wykonać tę pracę.
Wątek B Widzi, że licznik został zwiększony, odnotowuje wartość w ale nie jest pewien, czy wątek A zrobił cokolwiek z kontekstem. Jeśli kontekst został zainicjowany jako NULL, wątek B nie musi już dbać o to, co robił wątek A, wie, że kontekst jest bezpieczny dla dereferencji (jeśli nie jest NULL) lub alokować (jeśli NULL) bez przecieków.
Wątek B wykonuje swoją pracę, wątek A odczytuje jego kontekst, uwalnia go, a następnie ponownie go inicjalizuje na wartość NULL.
To samo rozumowanie dotyczy zmiennych globalnych, bez użycia wątków. Dobrze jest móc przetestować je w różnych funkcjach przed ich dereferencją (lub próbując je przydzielić, powodując wyciek i niezdefiniowane zachowanie w programie).
Kiedy robi się głupio, oznacza to, że zasięg wskaźnika nie wykracza poza pojedynczą funkcję. Jeśli masz jedną funkcję i nie możesz śledzić wskaźników w niej zawartych, zwykle oznacza to, że funkcja powinna zostać ponownie przeanalizowana. Jednak nie ma nic złego w inicjowaniu wskaźnika w pojedynczej funkcji, choćby po to, aby zachować jednolite nawyki.
Jedyny czas, jaki kiedykolwiek widział „brzydki” przypadek opierając się na zainicjowany wskaźnik (przed i po użyciu) jest mniej więcej tak:
void my_free(void **p)
{
if (*p != NULL) {
free(*p);
*p = NULL;
}
}
Nie tylko dereferencji wskaźnika typu punned Zaskoczony na sztywnych platformach, powyższy kod czyni wolnym() jeszcze bardziej niebezpiecznym, ponieważ rozmówcy będą mieli pewne złudzenie bezpieczeństwa. Nie możesz polegać na praktyce "hurtowej", chyba że masz pewność, że każda operacja jest zgodna.
Prawdopodobnie o wiele więcej informacji, niż faktycznie chciałeś.
Jakie jest twoje pytanie? –
Chyba pyta, czy powinien zainicjować "ciąg" na NULL (lub 0), na "", czy nie zainicjować go w ogóle. tutaj –
konieczna jest pewną ostrożnością, NULL jest _usually_ 0 ale według standardu może być różny: 'makro NULL, zdefiniowanego w którymkolwiek z, , , , , lub , jest zdefiniowane w implementacji Stała wskaźnika pustego C++ w niniejszym standardzie międzynarodowym. Na pewno bym się trzymał NULL, poza tym jest bardziej "zorientowany na typ" i bardziej opisowy w kodzie źródłowym niż 0. –
RedGlyph