Jakie są przypadki użycia i zalety wskaźników? [Zamknięte]

10

Często staram się dostrzec zalety wskaźników (z wyjątkiem programowania niskiego poziomu).

Po co używać char * zamiast String lub char [] lub jakie korzyści przynosi arytmetyka wskaźnika.

Jakie są zalety i przypadki użycia wskaźników?

OliverS
źródło
6
To zabrzmi nieco elitarnie, ale IMHO, jeśli musisz zapytać o zalety i wady wskaźników, najprawdopodobniej ich nie potrzebujesz.
Jas
3
Prawdopodobnie! Ale pytanie jest nadal aktualne!
Zolomon,
1
Nie jest to tak naprawdę niezależne od języka, ponieważ nie wszystkie języki programowania mają prawdziwe wskaźniki w znaczeniu C.
David Thornley,

Odpowiedzi:

6

Wskaźniki są niezbędne do dynamicznej lokalizacji pamięci, wielu struktur danych i wydajnej obsługi dużych ilości danych. Bez wskaźników musiałbyś alokować wszystkie dane programu globalnie, w funkcjach lub w ekwiwalencie, i nie miałbyś możliwości ucieczki, gdyby ilość danych przekroczyła pierwotnie dozwoloną wartość. Waham się, by użyć tutaj absolutów, ale o ile wiem, wszystkie współczesne języki komputerowe mają wskaźniki w takiej czy innej formie.

W większości języków, które używają wskaźników, istnieją pewne rodzaje referencji, które są wskaźnikami, i być może pewne rodzaje referencji, które nie są, i nie ma dalszych różnic notacyjnych. Komórka Lisp consjest parą wskaźników, chociaż a fixnumnie jest wskaźnikiem. W Javie zmienna używana dla instancji klasy jest wskaźnikiem, ale intnie jest. Składnia języka tego nie odzwierciedla.

C jest niezwykłe, ponieważ wskaźniki są opcjonalne, jawne i umożliwiają jawną arytmetykę wskaźników. Jest całkowicie możliwe pisanie struct foo bar; struct foo * baz;, a kiedy już przydzielisz pamięć baz, możesz używać obu bari bazreprezentować struct foos. Ponieważ wskaźniki są opcjonalne, przydatne są różnice notacyjne. (Jest to niezbędne w C ++ dla inteligentnych wskaźników, jak podano boost::shared_ptr<foo> bar;, bar.reset()ma jedno znaczenie i bar->reset()prawdopodobnie będzie miało zupełnie inne.)

(Właściwie, wyraźne wskaźniki były często używane w innych językach, gdy pierwotnie opracowywano C, takich jak ^Pascal. C jest starszym językiem niż większość obecnie powszechnie używanych i to pokazuje.)

Jednym z celów projektowych C było napisanie do Unixa, dlatego też musiał on szczegółowo obsługiwać lokalizacje pamięci. (C jest w rzeczywistości jednym z rodziny języków implementacji systemu powszechnych podczas jego projektowania, innym przykładem jest Cybol dla komputerów z danymi kontrolnymi. C jest tym, który stał się wielkim hitem.) Dlatego można bezpośrednio manipulować wskaźnikami C, przypisywanie adresów pamięci i obliczanie nowych. Doprowadziło to również do pewnych decyzji projektowych w C. Macierze C opierają się w dużej mierze na arytmetyce wskaźników, a tablica rozpada się na wskaźnik w bardzo wielu sytuacjach. Przekazywanie zmiennych do funkcji C przez referencję odbywa się za pomocą wskaźnika. Nie było potrzeby używania tablic i przekazywania zmiennych przez referencje w postaci, jaką miały inne współczesne języki, więc C ich nie dostał.

Tak więc odpowiedź jest taka, że ​​w większości języków używasz wskaźników ciągle, nie przypominając sobie o tym. W C i, w mniejszym stopniu, C ++, używasz wskaźników do robienia rzeczy na niskim poziomie lub do osiągania rzeczy na wyższym poziomie, dla których nie ma specjalnego zapisu.

David Thornley
źródło
bardzo ładna odpowiedź
Kate Gregory
1
Akceptuję tę odpowiedź, ponieważ najlepiej opisuje różnicę, której nie mogłem uchwycić między wskaźnikami w C / C ++ a Reference w Javie.
OliverS
Dobrze byłoby dodać krótkie wyjaśnienie, dlaczego Java nie używa wskaźników, aby lepiej wyjaśnić postrzegane „oszustwo” przez Goslinga (głównego twórcę Javy).
Guido Anselmi
10

Złożone struktury danych. Nie możesz zbudować czegoś w rodzaju listy połączonej lub drzewa binarnego bez wskaźników.

Nie ma „zalet” i „wad” wskaźników. Są tylko narzędziem, jak młotek.

zvrba
źródło
5
W Javie nie ma wskaźników. Możliwe jest jednak budowanie połączonej listy i drzewa binarnego. Istnieje różnica między referencjami (jak w Javie) i wskaźnikami (jak w C).
StartClass0830,
7
Nie ma różnicy między odniesieniami a wskaźnikami. Arytmetyka wskaźnika jest specyficzna dla C; istnieją inne języki, które mają wskaźniki, ale nie mają arytmetyki wskaźników (np. Pascal).
zvrba
1
Wskaźniki i referencje nie są synonimami, jak myślisz. Przeczytaj to, aby zobaczyć różnice. stackoverflow.com/questions/57483/…
StartClass0830
4
Aby zająć się pierwszymi dwoma elementami tej listy: referencje Java MOGĄ zostać ponownie przypisane i MOGĄ wskazywać na null. Cechą wyróżniającą wskaźnik jest możliwość pośredniego odniesienia do innego obiektu. Mój test lakmusowy: jeśli możesz zbudować okrągłą strukturę danych (którą możesz zrobić z referencjami Java), jest to wskaźnik. (Należy pamiętać, że nie można budować okrągłej struktury danych z referencjami w C ++.)
zvrba
1
Istnieje różnica między wskaźnikami i odniesieniami. Na przykład C # ma oba . ( blogs.msdn.com/b/ericlippert/archive/2009/02/17/… )
Steven Evers
2
  • Za pomocą wskaźników możesz przydzielać i zwalniać pamięć w czasie wykonywania.
  • I możesz używać dużych struktur danych poza dozwolonym zakresem bez kopiowania.

Odniesienia w C ++, Javie i innych językach tego samego typu są po prostu „bezpiecznymi wskaźnikami”. Te odniesienia są często używane w Javie.

Gulszan
źródło
1
Odnośniki w C ++ NIE są bezpiecznymi wskaźnikami. Odniesienia w C ++ nie mają nic wspólnego ze wskaźnikami. Odniesienia w C ++ to aliasy . Nie można ich przypisać NULLi nie można ich modyfikować po ich utworzeniu.
Billy ONeal,
@Billy: Referencje C ++ są zwykle implementowane za pomocą wskaźników i działają podobnie w niektórych rzeczach, więc ludzie wciąż myślą o nich jako o ograniczonym wskaźniku.
David Thornley,
2

Prawie każdy program komputerowy musi sprawdzać i zmieniać wartości w pamięci (znane jako podglądanie i szturchanie, tym z nas, którzy są wystarczająco starsi). Musisz kontrolować, gdzie w pamięci są te wartości, aby wynik był przewidywalny (aw niektórych przypadkach kolejność jest ważna: ładowanie kodu wykonywalnego jest jednym przykładem). Dlatego musisz mieć typ danych reprezentujący lokalizację w pamięci. Nawet jeśli twoje środowisko programistyczne ukrywa to pod abstrakcją, nadal tam jest.


źródło
2

char*jest kiepskim przykładem wskaźników. Prawdopodobnie lepiej jest używać std::string(lub jakiegoś lepszego typu, który obsługuje specjalność Unicode / Ansi / Multibyte) niż char*. Na prawie każdym innym przykładzie wskaźników ( Employee*, PurchaseOrder*...), jednak istnieje wiele zalet:

  • zasięg większy niż jedna funkcja - przydziel obiekt na stercie i przekaż wskaźnik przez długi czas
  • szybsza funkcja wywołuje duże obiekty, ponieważ nie masz kosztu kopiowania według wartości
  • jeden sposób, aby włączyć funkcję zmiany przekazywanych do niej parametrów
  • oszczędzaj miejsce i czas w kolekcjach kopiując tylko adres zamiast całego obiektu

W rzeczywistości wskaźniki są tak ważne, że większość języków, które wydają się ich nie mieć, faktycznie mają je tylko. Typy referencyjne w języku C # i Java są zasadniczo wskaźnikami zamaskowanymi jako obiekty stałe.

Teraz manipulowanie wskaźnikiem ( p++na wskaźniku lub p += delta) to cała „inna historia”. Niektórzy uważają, że jest niebezpieczny, inni uważają, że jest świetny. Ale to jeszcze dalej od twojego pytania.

Kate Gregory
źródło
1

Wskaźniki mogą być szybsze i mogą powodować mniejsze obciążenie, zarówno w strukturach danych, jak i przy utrzymaniu niskiego poziomu wykonania programu. (Proszę zwrócić uwagę na słowo „może”.)

Ogólnie rzecz biorąc, zasada polega na tym, że jeśli przydzieliłeś zasób, albo wykonując własny przydział, albo zlecając coś w Twoim imieniu, Twoim zadaniem jest zwolnienie go po zakończeniu.

Ciężar związany z powyższymi czynnościami polega na przeniesieniu odpowiedzialności na programistę, a nie na wykonywaniu tego przez środowisko wykonawcze. Ma to kilka dodatkowych zalet, ponieważ rzeczy mogą być dłużej przeżywane, przekraczać granice lub być usuwane w dogodniejszych momentach, lub nie muszą nosić ciężaru śmieciarza.

W egzotycznych przypadkach, zwykle z wyjątkami i zakresem, istnieją pewne przypadki brzegowe, które wymagają zachowania ostrożności przy unikaniu kodu czyszczenia. Realistycznie przypadki te można zaprojektować wokół. Przez wiele dziesięcioleci żyliśmy bez kodu zarządzanego.

Często to, co sprawia, że ​​wskaźniki są „trudne”, to po prostu niezrozumienie, co się dzieje na poziomie sprzętowym. To nic innego jak pośrednictwo.

Wskaźniki zapewniają znacznie większy dostęp, co może być bardzo pomocne, sprytne lub konieczne. Możesz wskazać w dowolnym miejscu i traktować to jak coś innego. Jeśli użyjesz swoich boskich mocy na dobre, to bardzo, bardzo dobrze.

Konflikt jest zwykle marnotrawstwem, zapominając o wydaniu czegoś lub zwalniając go więcej niż jeden raz, odwołując się do czegoś po wydaniu lub udoskonalając coś, gdy nigdzie nie wskazujesz. Te rzeczy często powodują spektakularne awarie, a szczerze mówiąc, zwykle wskazują, że masz problem z logiką, a nie wskaźniki są kruche.

Jeśli jesteś solidnym programistą, używanie wskaźników nie powinno być bardziej problematyczne niż jakakolwiek inna struktura danych. Znów nie jest to nauka o rakietach, a ludzie robili to przez dziesięciolecia, nie mrugając nawet okiem. W dzisiejszych czasach uczy się go rzadziej.

Wszystko to powiedziawszy, chyba że potrzebujesz wskaźników, wygoda i egzoityczność spraw, które zapewnia dobry system usuwania śmieci, sprawia, że ​​praca w zarządzanym środowisku jest o wiele przyjemniejsza. Wspaniale jest móc pobrać pamięć, wykorzystać ją i porzucić, wiedząc, że później może zostać odrzucona, jeśli ma to sens. To trochę mniej kodu ze strony kodera, w zamian za środowisko wykonawcze, które wymaga dodatkowego podnoszenia.

Walt Stoneburner
źródło
0

Najlepsza odpowiedź jest zawarta w pytaniu: wskaźniki dotyczą programowania niskiego poziomu. To prawda, że ​​jeśli używasz C, nieużywanie wskaźników jest jak programowanie jedną ręką za plecami, ale odpowiedzią na to jest użycie języka wyższego poziomu.

Larry Coleman
źródło
-1

Wskaźniki zapewniają wgląd w maszynę, która jest wymagana do najbardziej interesującego programowania. Większość współczesnych języków po prostu ukrywa przed Tobą ziarniste fragmenty.

Paul Nathan
źródło