Jakie są bariery w zrozumieniu wskaźników i co można zrobić, aby je przezwyciężyć? [zamknięte]

Dlaczego wskaźniki są tak głównym czynnikiem zamieszania dla wielu nowych, a nawet starych, studentów na poziomie C lub c++? Czy istnieją jakieś narzędzia lub procesy myślowe, które pomogły Ci zrozumieć, jak wskaźniki działają na poziomie zmiennej, funkcji i poza nim?

Jakie są dobre praktyki, które można zrobić, aby doprowadzić kogoś do poziomu "Ah-hah, mam to", bez zagłębiania się w ogólną koncepcję? Zasadniczo, ćwiczenia jak scenariusze.

 443
Author: David McGraw, 2008-08-08

28 answers

Wskaźniki to pojęcie, które dla wielu może być mylące na początku, w szczególności jeśli chodzi o kopiowanie wartości wskaźników wokół i nadal odwoływanie się do tego samego bloku pamięci.

Odkryłem, że najlepszą analogią jest rozważenie wskaźnika jako kawałka papieru z adresem domu, a blok pamięci, do którego odnosi się jako prawdziwy dom. W ten sposób można łatwo wyjaśnić wszystkie rodzaje operacji.

Dodałem trochę kodu Delphi poniżej, i kilka komentarzy tam, gdzie to stosowne. Wybrałem Delphi, ponieważ mój drugi główny język programowania, C#, nie wykazuje wycieków pamięci w ten sam sposób.

Jeśli chcesz tylko nauczyć się wysokopoziomowej koncepcji wskaźników, powinieneś zignorować części oznaczone jako "układ pamięci" w wyjaśnieniu poniżej. Mają one na celu podać przykłady tego, jak może wyglądać pamięć po operacjach, ale mają one bardziej niskopoziomowy charakter. Aby jednak dokładnie wyjaśnić, jak naprawdę działają przekroczenia bufora, ważne było, aby dodano te diagramy.

zastrzeżenie: dla wszystkich intencji i celów, to wyjaśnienie i przykład pamięci układy są znacznie uproszczone. Jest więcej kosztów i dużo więcej szczegółów, które można by musisz wiedzieć, czy musisz radzić sobie z pamięcią na niskim poziomie. Jednak dla intencje wyjaśniające pamięć i wskaźniki, jest wystarczająco dokładne.


Załóżmy, że Klasa THouse użyta poniżej wygląda tak:

type
    THouse = class
    private
        FName : array[0..9] of Char;
    public
        constructor Create(name: PChar);
    end;

Kiedy zainicjujesz Dom obiekt, nazwa nadana konstruktorowi jest kopiowana do prywatnego pola FName. Nie bez powodu jest ona definiowana jako tablica o stałym rozmiarze.

W pamięci, będą jakieś koszty związane z alokacją domu, zilustruję to poniżej w następujący sposób:

---[ttttNNNNNNNNNN]---
     ^   ^
     |   |
     |   +- the FName array
     |
     +- overhead

Obszar" tttt " jest nadmiarowy, Zazwyczaj będzie tego więcej dla różnych typów środowisk i języków, takich jak 8 lub 12 bajtów. Konieczne jest, aby jakiekolwiek wartości są przechowywane w tym obszarze nigdy nie ulegały zmianie przez cokolwiek innego niż alokator pamięci lub procedury systemu podstawowego, lub ryzykujesz awarię programu.


Przydzielanie pamięci

Zdobądź przedsiębiorcę, który zbuduje twój dom i poda ci adres domu. W przeciwieństwie do świata rzeczywistego, alokacji pamięci nie można powiedzieć, gdzie przydzielić, ale znajdzie odpowiednie miejsce z wystarczającą ilością miejsca i zgłosi adres do przydzielonej pamięci. Innymi słowy, przedsiębiorca wybierze miejsce.
THouse.Create('My house');

Układ pamięci:

---[ttttNNNNNNNNNN]---
    1234My house

Przechowuje zmienną o adresie

Zapisz adres swojego nowego domu na kartce papieru. Ten dokument posłuży jako odniesienie do Twojego domu. Bez tego kawałka papieru jesteś zagubiony i nie możesz znaleźć domu, chyba że już w nim jesteś.

var
    h: THouse;
begin
    h := THouse.Create('My house');
    ...

Układ pamięci:

    h
    v
---[ttttNNNNNNNNNN]---
    1234My house

Kopiuj wartość wskaźnika

Po prostu napisz adres na nowej kartce papieru. Masz teraz dwa kawałki papieru, które doprowadzą cię do tego samego domu, a nie do dwóch oddzielnych domów. Wszelkie próby podążania za adresem z jednego papieru i przestawiania mebli w tym domu sprawią, że wydaje się, że {42]} drugi dom {43]} został zmodyfikowany w ten sam sposób, chyba że można wyraźnie wykryć, że w rzeczywistości jest to tylko jeden dom.

Uwaga jest to zazwyczaj pojęcie, które mam największy problem z wyjaśnieniem ludziom, Dwa wskaźniki nie oznaczają dwóch obiektów lub bloki pamięci.

var
    h1, h2: THouse;
begin
    h1 := THouse.Create('My house');
    h2 := h1; // copies the address, not the house
    ...
    h1
    v
---[ttttNNNNNNNNNN]---
    1234My house
    ^
    h2

Uwolnienie pamięci

Wyburzyć Dom. Możesz później ponownie użyć papieru na nowy adres, jeśli chcesz, lub wyczyścić go, aby zapomnieć adres do domu, który już nie istnieje.

var
    h: THouse;
begin
    h := THouse.Create('My house');
    ...
    h.Free;
    h := nil;
Tutaj najpierw buduję Dom i zdobywam jego adres. Następnie robię coś do domu (użyj go, the ... kod, pozostawiony jako ćwiczenie dla czytelnika), a następnie go uwalniam. Wreszcie wyczyściłem adres z mojego zmienna.

Układ pamięci:

    h                        <--+
    v                           +- before free
---[ttttNNNNNNNNNN]---          |
    1234My house             <--+

    h (now points nowhere)   <--+
                                +- after free
----------------------          | (note, memory might still
    xx34My house             <--+  contain some data)

Zwisające wskaźniki

Mówisz przedsiębiorcy, żeby zniszczył dom, ale zapominasz wymazać adres ze swojej kartki. Kiedy później patrzysz na kartkę papieru, zapominasz, że domu już nie ma i idziesz go odwiedzić, z nieudanymi wynikami (patrz również część o nieprawidłowym odwołaniu poniżej).
var
    h: THouse;
begin
    h := THouse.Create('My house');
    ...
    h.Free;
    ... // forgot to clear h here
    h.OpenFrontDoor; // will most likely fail

Używając h Po wywołaniu do .Free might work, ale to tylko szczęście. Najprawdopodobniej nie powiedzie się, w miejscu Klienta, w środku krytycznej operacji.

    h                        <--+
    v                           +- before free
---[ttttNNNNNNNNNN]---          |
    1234My house             <--+

    h                        <--+
    v                           +- after free
----------------------          |
    xx34My house             <--+

Jak widać, h nadal wskazuje na resztki danych w pamięci, ale ponieważ może nie być kompletna, używanie jej jak wcześniej może się nie udać.


Wyciek pamięci

Zgubiłeś kartkę papieru i nie możesz znaleźć domu. Dom nadal gdzieś stoi, a kiedy później chcesz zbudować nowy dom, nie możesz użyj tego miejsca ponownie.
var
    h: THouse;
begin
    h := THouse.Create('My house');
    h := THouse.Create('My house'); // uh-oh, what happened to our first house?
    ...
    h.Free;
    h := nil;

Tutaj nadpisujemy zawartość zmiennej h z adresem nowego domu, ale stary wciąż stoi... gdzieś. Po tym kodzie nie ma możliwości dotarcia do tego domu i zostanie on pozostawiony. Innymi słowy, przydzielona pamięć pozostanie przydzielona do momentu zamknięcia aplikacji, w którym to momencie system operacyjny ją zburzy.

Układ pamięci po pierwszej alokacji:

    h
    v
---[ttttNNNNNNNNNN]---
    1234My house

Układ pamięci po sekundzie przydział:

                       h
                       v
---[ttttNNNNNNNNNN]---[ttttNNNNNNNNNN]
    1234My house       5678My house

Bardziej powszechnym sposobem uzyskania tej metody jest po prostu zapomnienie o uwolnieniu czegoś, zamiast nadpisania go jak wyżej. W terminach Delphi będzie to miało miejsce za pomocą następującej metody:

procedure OpenTheFrontDoorOfANewHouse;
var
    h: THouse;
begin
    h := THouse.Create('My house');
    h.OpenFrontDoor;
    // uh-oh, no .Free here, where does the address go?
end;

Po wykonaniu tej metody nie ma miejsca w naszych zmiennych, że adres do domu istnieje, ale dom nadal tam jest.

Układ pamięci:

    h                        <--+
    v                           +- before losing pointer
---[ttttNNNNNNNNNN]---          |
    1234My house             <--+

    h (now points nowhere)   <--+
                                +- after losing pointer
---[ttttNNNNNNNNNN]---          |
    1234My house             <--+

Jak widać, stare dane pozostają nienaruszone w pamięci i nie będą być ponownie wykorzystane przez alokator pamięci. Alokator śledzi, które obszary pamięci zostały wykorzystane i nie będą ich ponownie używać, chyba że uwolnij go.


Uwolnienie pamięci, ale zachowanie (teraz niepoprawnego) odniesienia

Wyburzyć Dom, wymazać jedną z kartek papieru, ale masz też inną kartkę ze starym adresem na niej, kiedy idziesz na adres, nie znajdziesz domu, ale może znajdziesz coś, co przypomina ruiny jednego.

Być może będziesz nawet znajdź dom, ale nie jest to dom, do którego pierwotnie podałeś adres, a zatem wszelkie próby użycia go tak, jakby należał do ciebie, mogą się nie udać.

Czasami może się nawet okazać, że sąsiedni adres ma dość duży dom ustawiony na nim, który zajmuje trzy adresy( Main Street 1-3), a twój adres idzie do środka domu. Wszelkie próby traktowania tej części dużego 3-adresowego domu jako pojedynczego małego domu również mogą się nie udać strasznie.

var
    h1, h2: THouse;
begin
    h1 := THouse.Create('My house');
    h2 := h1; // copies the address, not the house
    ...
    h1.Free;
    h1 := nil;
    h2.OpenFrontDoor; // uh-oh, what happened to our house?
Tutaj dom został zburzony, przez odniesienie w h1, i chociaż h1 został wyczyszczony, h2 nadal ma Stary, Nieaktualny adres. Dostęp do domu, który już nie stoi, może działać lub nie.

Jest to odmiana wiszącego wskaźnika powyżej. Zobacz jego układ pamięci.


Przekroczenie bufora

Przenosisz więcej rzeczy do domu, niż możesz zmieścić, rozlewając się do domu sąsiadów albo Podwórko. Kiedy właściciel sąsiedniego domu później wróci do domu, znajdzie różne rzeczy, które uzna za własne.

To jest powód, dla którego wybrałem tablicę o stałym rozmiarze. Aby ustawić scenę, Załóżmy, że drugi dom, który przeznaczymy, z jakiegoś powodu zostanie umieszczony przed pierwszy w pamięci. Innymi słowy, drugi dom będzie miał niższą adres niż pierwszy. Są też przydzielane obok siebie.

Tak więc ten kod:

var
    h1, h2: THouse;
begin
    h1 := THouse.Create('My house');
    h2 := THouse.Create('My other house somewhere');
                         ^-----------------------^
                          longer than 10 characters
                         0123456789 <-- 10 characters

Pamięć układ po pierwszej alokacji:

                        h1
                        v
-----------------------[ttttNNNNNNNNNN]
                        5678My house

Układ pamięci po drugiej alokacji:

    h2                  h1
    v                   v
---[ttttNNNNNNNNNN]----[ttttNNNNNNNNNN]
    1234My other house somewhereouse
                        ^---+--^
                            |
                            +- overwritten

Część, która najczęściej powoduje awarię, polega na nadpisaniu ważnych części przechowywanych danych, które naprawdę nie powinny być losowo zmieniane. Na przykład nie może być problemem, że część nazwy domu h1 została zmieniona, jeśli chodzi o awarię programu, ale nadpisanie narzutu z obiekt najprawdopodobniej ulegnie awarii podczas próby użycia uszkodzonego obiektu, jako will nadpisywanie linków, które są przechowywane do inne obiekty w obiekcie.


Listy połączone

Kiedy podążasz za adresem na kartce papieru, dostajesz się do domu, a w tym domu znajduje się kolejna kartka papieru z nowym adresem, do następnego domu w łańcuchu, i tak dalej.

var
    h1, h2: THouse;
begin
    h1 := THouse.Create('Home');
    h2 := THouse.Create('Cabin');
    h1.NextHouse := h2;

Tutaj tworzymy połączenie z naszego domu do naszej chaty. Możemy podążać za łańcuchem, dopóki dom nie będzie miał odniesienia, co oznacza, że jest ostatni. Aby odwiedzić wszystkie nasze domy, możemy użyć następującego kodu:

var
    h1, h2: THouse;
    h: THouse;
begin
    h1 := THouse.Create('Home');
    h2 := THouse.Create('Cabin');
    h1.NextHouse := h2;
    ...
    h := h1;
    while h <> nil do
    begin
        h.LockAllDoors;
        h.CloseAllWindows;
        h := h.NextHouse;
    end;

Układ pamięci (dodany obok jako link w obiekcie, odnotowany z cztery LLL ' s na poniższym diagramie):

    h1                      h2
    v                       v
---[ttttNNNNNNNNNNLLLL]----[ttttNNNNNNNNNNLLLL]
    1234Home       +        5678Cabin      +
                   |        ^              |
                   +--------+              * (no link)

Co to jest adres pamięci?

Adres pamięci jest w podstawowych terminach tylko liczbą. Jeśli myślisz o pamięci jako duża tablica bajtów, pierwszy bajt ma adres 0, następny adres 1 i tak dalej w górę. Jest to uproszczone, ale dobre wystarczy.

Więc ten układ pamięci:

    h1                 h2
    v                  v
---[ttttNNNNNNNNNN]---[ttttNNNNNNNNNN]
    1234My house       5678My house

Może mieć te dwa adresy (lewy - to adres 0):

  • h1 = 4
  • h2 = 23

Co oznacza, że nasza Powyższa lista może wyglądać tak:

    h1 (=4)                 h2 (=28)
    v                       v
---[ttttNNNNNNNNNNLLLL]----[ttttNNNNNNNNNNLLLL]
    1234Home      0028      5678Cabin     0000
                   |        ^              |
                   +--------+              * (no link)

Typowe jest przechowywanie adresu, który "nigdzie nie wskazuje" jako adresu zerowego.


Co to jest wskaźnik?

Wskaźnik jest tylko zmienną zawierającą adres pamięci. Zazwyczaj można zapytać o program język, aby podać swój numer, ale większość języków programowania i środowisk uruchomieniowych próbuje ukryć fakt, że pod spodem znajduje się liczba, tylko dlatego, że sama liczba nie naprawdę ma dla Ciebie jakieś znaczenie. Najlepiej jest myśleć o wskaźniku jako czarnej skrzynce, tj. tak naprawdę nie wiesz ani nie dbasz o to, jak to jest faktycznie realizowane, tak długo, jak to działa.

 730
Author: Lasse V. Karlsen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-29 08:11:15

W mojej pierwszej klasie Comp Sci wykonaliśmy następujące ćwiczenie. Była to sala wykładowa z około 200 studentami...

Profesor pisze na tablicy: int john;

John wstaje

Profesor pisze: int *sally = &john;

Sally wstaje, wskazuje na Johna

Profesor: int *bill = sally;

Bill wstaje, wskazuje na Johna

Profesor: int sam;

Sam wstaje

Profesor: bill = &sam;

Bill wskazuje teraz na sama.

Myślę, że masz pomysł. Myślę, że spędziliśmy nad tym godzinę, dopóki nie omówiliśmy podstaw przydzielania wskaźników.

 146
Author: Tryke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-21 20:41:01

Analogia, którą uznałem za pomocną w wyjaśnieniu wskaźników, to hiperłącza. Większość ludzi może zrozumieć, że link na stronie internetowej "wskazuje" na inną stronę w Internecie, a jeśli możesz skopiować i wkleić hiperłącze, oba będą wskazywać na tę samą oryginalną stronę internetową. Jeśli pójdziesz i edytować tę oryginalną stronę, a następnie postępuj zgodnie z jednym z tych linków (wskaźniki) otrzymasz tę nową zaktualizowaną stronę.

 122
Author: Wilka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-26 15:56:33

Powodem, dla którego wydaje się, że mylić tak wielu ludzi, jest to, że w większości pochodzą z małym lub żadnym tle w architekturze komputera. Ponieważ wielu nie zdaje się mieć pojęcia, w jaki sposób komputery (maszyna) są faktycznie zaimplementowane-praca w C / C++ wydaje się obca.

Ćwiczenie polega na poproszeniu ich o zaimplementowanie prostej maszyny wirtualnej opartej na kodzie bajtowym (w dowolnym języku, który wybrali, python działa do tego świetnie) z zestawem instrukcji skupionym na operacjach wskaźników (load, store, direct / indirect adresowanie). Następnie poproś ich o napisanie prostych programów dla tego zestawu instrukcji.

Wszystko, co wymaga nieco więcej niż proste dodawanie, będzie wymagało wskaźników i na pewno je dostaną.

 49
Author: JSN,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-08 06:29:59

Dlaczego wskaźniki są tak wiodącym czynnikiem zamieszania dla wielu nowych, a nawet starych studentów na poziomie college ' u w języku C/C++?

Pojęcie symbolu zastępczego dla wartości - zmiennych-odwzorowuje coś, czego uczymy się w szkole-algebrę. Nie ma istniejącej równoległości, którą można narysować bez zrozumienia, jak pamięć jest fizycznie ułożona w komputerze, i nikt nie myśli o tego typu rzeczach, dopóki nie ma do czynienia z rzeczami niskiego poziomu-w C/C++ / bajt poziom łączności.

Czy są jakieś narzędzia lub procesy myślowe, które pomogły Ci zrozumieć, jak wskaźniki działają na poziomie zmiennej, funkcji i poza nim?

Pola adresów. Pamiętam, że kiedy uczyłem się programowania BASIC na mikrokomputery, były tam takie ładne książki z grami i czasami trzeba było wbijać wartości do konkretnych adresów. Mieli zdjęcie kilku pudełek, oznaczonych stopniowo cyframi 0, 1, 2... i wyjaśniono, że tylko jedna mała rzecz (bajt) zmieściła się w tych pudełkach, a było ich dużo - niektóre komputery miały aż 65535! Byli obok siebie i wszyscy mieli adres.

Jakie są dobre praktyki, które można zrobić, aby doprowadzić kogoś do poziomu "Ah-hah, mam to", bez zagłębiania się w ogólną koncepcję? Zasadniczo, ćwiczenia jak scenariusze.

Na wiertło? Twórz strukturę:
struct {
char a;
char b;
char c;
char d;
} mystruct;
mystruct.a = 'r';
mystruct.b = 's';
mystruct.c = 't';
mystruct.d = 'u';

char* my_pointer;
my_pointer = &mystruct.b;
cout << 'Start: my_pointer = ' << *my_pointer << endl;
my_pointer++;
cout << 'After: my_pointer = ' << *my_pointer << endl;
my_pointer = &mystruct.a;
cout << 'Then: my_pointer = ' << *my_pointer << endl;
my_pointer = my_pointer + 3;
cout << 'End: my_pointer = ' << *my_pointer << endl;

Ten sam przykład jak wyżej, z tym że w C:

// Same example as above, except in C:
struct {
    char a;
    char b;
    char c;
    char d;
} mystruct;

mystruct.a = 'r';
mystruct.b = 's';
mystruct.c = 't';
mystruct.d = 'u';

char* my_pointer;
my_pointer = &mystruct.b;

printf("Start: my_pointer = %c\n", *my_pointer);
my_pointer++;
printf("After: my_pointer = %c\n", *my_pointer);
my_pointer = &mystruct.a;
printf("Then: my_pointer = %c\n", *my_pointer);
my_pointer = my_pointer + 3;
printf("End: my_pointer = %c\n", *my_pointer);

Wyjście:

Start: my_pointer = s
After: my_pointer = t
Then: my_pointer = r
End: my_pointer = u

Może to wyjaśnia niektóre podstawy na przykładzie?

 28
Author: Josh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-25 17:04:17

Powodem, dla którego miałem trudności ze zrozumieniem wskazówek, na początku, jest to, że wiele wyjaśnień zawiera wiele bzdur o przechodzeniu przez odniesienie. Wszystko to powoduje zamieszanie. Kiedy używasz parametru wskaźnika, jesteś nadal przekazywany przez wartość; ale wartością jest adres, a nie, powiedzmy, int.

Ktoś już linkował do tego tutoriala, ale mogę podkreślić moment, w którym zacząłem rozumieć wskazówki:

Tutorial o wskaźnikach i Tablice w C: Rozdział 3-Wskaźniki i ciągi

int puts(const char *s);

Na chwilę obecną ignoruj const. parametr przekazany do puts() jest wskaźnikiem, jest wartością wskaźnika (ponieważ wszystkie parametry w C są przekazywane przez wartość), a wartością wskaźnika jest adres, na który wskazuje, lub, po prostu, adres.{[17] } Tak więc kiedy piszemy puts(strA); Jak widzieliśmy, przekazujemy adres strA [0].

W chwili, gdy przeczytałem te słowa, chmury się rozeszły i promień światło słoneczne otuliło mnie wskaźnikowym zrozumieniem.

Nawet jeśli jesteś programistą VB. NET lub C# (tak jak ja) i nigdy nie używasz niebezpiecznego kodu, nadal warto zrozumieć, jak działają wskaźniki, lub nie zrozumiesz, jak działają odniesienia do obiektów. Wtedy pojawi się powszechne, ale błędne przekonanie, że przekazanie odniesienia do obiektu do metody kopiuje obiekt.

 23
Author: Kyralessa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-12 17:07:42

Znalazłem "samouczek Teda Jensena o wskaźnikach i tablicach w C" doskonałym źródłem wiedzy o wskaźnikach. Jest on podzielony na 10 lekcji, począwszy od wyjaśnienia, czym są wskaźniki (i do czego służą), a skończywszy na wskaźnikach funkcji. http://home.netcom.com / ~tjensen/ptr/cpoint.htm

Idąc dalej, Beej ' s Guide to Network Programming uczy Unix sockets API, od którego można zacząć robić naprawdę fajne rzeczy. http://beej.us/guide/bgnet/

 19
Author: Ted Percival,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-11 04:21:07

Złożoność wskaźników wykracza poza to, czego możemy łatwo nauczyć. To, że uczniowie wskazują na siebie nawzajem i używają kartek papieru z adresami domowymi, to świetne narzędzia do nauki. Świetnie sobie radzą wprowadzając podstawowe pojęcia. Rzeczywiście, poznanie podstawowych pojęć jest istotne , aby skutecznie używać wskaźników. Jednak w kodzie produkcyjnym często zdarza się wchodzić w znacznie bardziej złożone scenariusze, niż te proste demonstracje mogą być hermetyzowane.

I ' ve been involved with systemy, w których mieliśmy struktury wskazujące na inne struktury wskazujące na inne struktury. Niektóre z tych struktur zawierały również struktury wbudowane (zamiast wskaźników do dodatkowych struktur). Tutaj wskaźniki stają się naprawdę mylące. Jeśli masz wiele poziomów indrection, a zaczynasz z kodem w ten sposób:

widget->wazzle.fizzle = fazzle.foozle->wazzle;

Bardzo szybko może być mylące (wyobraź sobie o wiele więcej linii i potencjalnie więcej poziomów). Dorzucamy tablice wskaźników, a węzeł do węzła wskaźniki (drzewa, listy linkowane) i jeszcze gorzej. Widziałem, jak niektórzy naprawdę dobrzy Programiści gubią się, gdy zaczęli pracować nad takimi systemami, nawet deweloperzy, którzy naprawdę dobrze rozumieli podstawy.

Złożone struktury wskaźników niekoniecznie wskazują na słabe kodowanie (choć mogą). Kompozycja jest ważnym elementem dobrego programowania obiektowego, a w językach z surowymi wskaźnikami nieuchronnie doprowadzi do wielowarstwowej indirection. Ponadto, systemy często muszą korzystaj z bibliotek innych firm ze strukturami, które nie pasują do siebie pod względem stylu lub techniki. W takich sytuacjach naturalnie pojawi się złożoność (choć z pewnością powinniśmy z nią walczyć jak najwięcej).

Myślę, że najlepszą rzeczą, jaką uczelnie mogą zrobić, aby pomóc uczniom w nauce wskaźników, jest korzystanie z dobrych demonstracji, w połączeniu z projektami, które wymagają użycia wskaźników. Jeden trudny projekt zrobi więcej dla zrozumienia wskaźników niż tysiąc demonstracji. Demonstracje mogą uzyskać płytkie zrozumienie, ale aby dogłębnie zrozumieć wskazówki, musisz naprawdę ich użyć.

 12
Author: Derek Park,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-10 18:09:16

Nie wydaje mi się, aby wskazówki jako koncepcja były szczególnie trudne - większość modeli mentalnych uczniów map do czegoś takiego i kilka szybkich szkiców pudełkowych może pomóc.

Trudność, przynajmniej ta, której doświadczyłem w przeszłości i widziałem, jak inni sobie radzą, polega na tym, że zarządzanie wskaźnikami w C/C++ może być niezauważalnie zawiłe.

 10
Author: Matt Mitchell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-08 06:35:42

Przykład samouczka z dobrym zestawem diagramów bardzo pomaga w zrozumieniu wskaźników.

Joel Spolsky w swoim artykuleGuerrilla Guide to Interviewing podaje kilka dobrych punktów na temat zrozumienia wskaźników:

Z jakiegoś powodu większość ludzi wydaje się urodzić bez części mózgu, która rozumie wskaźniki. Jest to rzecz z predyspozycją, a nie umiejętnością-wymaga skomplikowanej formy podwójnie niepodzielnego myślenia, że niektórzy ludzie po prostu nie mogę.

 10
Author: David,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-20 17:38:38

Pomyślałem, że dodam analogię do tej listy, która okazała się bardzo pomocna przy wyjaśnianiu wskaźników (kiedyś) jako korepetytor Informatyki; najpierw:


Ustaw scenę :

Rozważmy parking z 3 miejscami, miejsca te są ponumerowane:

-------------------
|     |     |     |
|  1  |  2  |  3  |
|     |     |     |

W pewnym sensie jest to jak miejsca pamięci, są one sekwencyjne i przyległe.. coś jak tablica. W tej chwili nie ma w nich samochodów, więc to jak pusta tablica (parking_lot[3] = {0}).


Dodaj dane

Parking nigdy nie pozostaje pusty na długo... gdyby tak było, to byłoby bezcelowe i nikt by ich nie zbudował. Załóżmy więc, że w ciągu dnia parking jest wypełniony 3 samochodami, niebieskim samochodem, czerwonym samochodem i zielonym samochodem:

   1     2     3
-------------------
| o=o | o=o | o=o |
| |B| | |R| | |G| |
| o-o | o-o | o-o |

Wszystkie te samochody są tego samego typu (samochodu), więc jednym ze sposobów myślenia o tym jest to, że nasze samochody są pewnego rodzaju danymi (powiedzmy int), ale mają różne wartości (blue, red, green; to może być kolor enum)


Wpisz wskaźnik

Jeśli zabiorę cię na ten parking i poproszę, żebyś znalazł mi niebieski samochód, wyciągnij jeden palec i użyj go, aby wskazać niebieski samochód w miejscu 1. To tak, jakby wziąć wskaźnik i przypisać go do adresu pamięci (int *finger = parking_lot)

Twój palec (wskaźnik) nie jest odpowiedzią na moje pytanie. Szukam na twój palec nic mi nie mówi, ale jeśli spojrzę, gdzie jesteś palec jest wskazujący na ( dereferując wskaźnik), mogę znaleźć samochód (dane) Szukałem.


Przypisanie wskaźnika

Teraz mogę poprosić Cię o znalezienie czerwonego samochodu, a Ty możesz przekierować palec do nowego samochodu. Teraz twój wskaźnik (ten sam, co poprzednio) pokazuje mi nowe dane (miejsce parkingowe, w którym można znaleźć Czerwony Samochód) tego samego typu (samochód).

Wskaźnik nie zmienił się fizycznie, to nadal Twój palec, tylko dane, które pokazywał zmieniłem się. (adres "miejsca parkingowego")


Podwójne wskaźniki (lub wskaźnik do wskaźnika)

To działa również z więcej niż jednym wskaźnikiem. Mogę zapytać, gdzie jest wskaźnik, który wskazuje na czerwony samochód i możesz użyć drugiej ręki i wskazać palcem na pierwszy palec. (to jest jak int **finger_two = &finger)

Teraz, jeśli chcę wiedzieć, gdzie jest niebieski samochód, mogę podążać w kierunku pierwszego palca do drugiego palca, do samochodu (dane).


Zwisający wskaźnik

Powiedzmy, że czujesz się jak posąg i chcesz trzymać rękę wskazującą na czerwony samochód w nieskończoność. Co jeśli ten czerwony samochód odjedzie?
   1     2     3
-------------------
| o=o |     | o=o |
| |B| |     | |G| |
| o-o |     | o-o |

Twój wskaźnik nadal wskazuje, gdzie był czerwony samochód , ale już nie jest. Powiedzmy, że podjeżdża tam nowy samochód... pomarańczowy samochód. Jeśli zapytam jeszcze raz, "gdzie jest czerwony samochód", nadal tam wskazujesz, ale teraz się mylisz. To nie jest czerwony samochód, pomarańczowy.


Arytmetyka wskaźnika

Ok, więc nadal wskazujesz drugie miejsce parkingowe (obecnie zajęte przez pomarańczowy samochód)

   1     2     3
-------------------
| o=o | o=o | o=o |
| |B| | |O| | |G| |
| o-o | o-o | o-o |
Mam teraz nowe pytanie... Chcę znać kolor samochodu na następnym miejscu parkingowym. Możesz zobaczyć, że wskazujesz na miejsce 2, więc po prostu dodaj 1 i wskazujesz na następne miejsce. (finger+1), teraz, skoro chciałem wiedzieć, jakie są dane, trzeba sprawdzić to miejsce (nie tylko palcem), dzięki czemu można wyróżnić wskaźnik (*(finger+1)), aby zobaczyć, że obecny jest tam zielony samochód (dane w tym miejscu)
 10
Author: Mike,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-05 19:55:49

Myślę, że główną barierą w zrozumieniu wskaźników są źli nauczyciele.

Prawie każdy jest nauczany kłamstw na temat wskaźników: że są one niczym więcej niż adresami pamięci , lub że pozwalają wskazywać dowolne lokalizacje.

I oczywiście, że są one trudne do zrozumienia, niebezpieczne i pół-magiczne.

Nic z tego nie jest prawdą. Wskaźniki są właściwie dość prostymi pojęciami, tak długo, jak trzymasz się tego, co język C++ ma do powiedzenia o nich i nie nasycaj ich atrybutami, które "zwykle" sprawdzają się w praktyce, ale mimo to nie są gwarantowane przez język, a więc nie są częścią rzeczywistej koncepcji wskaźnika.

Próbowałem napisać wyjaśnienie tego kilka miesięcy temu w ten wpis na blogu -- mam nadzieję, że to komuś pomoże.

(zauważ, zanim ktoś zacznie pedantycznie na mnie naciskać, tak, standard C++ mówi, że wskaźniki reprezentują adresy pamięci. Ale nie mówi że "wskaźniki są adresami pamięci i tylko adresami pamięci i mogą być używane lub myślone zamiennie z adresami pamięci". Rozróżnienie jest ważne)

 8
Author: jalf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-17 03:43:58

Problem ze wskaźnikami nie jest pojęciem. Chodzi o wykonanie i język. Dodatkowe zamieszanie powoduje, gdy nauczyciele zakładają, że to pojęcie wskaźników jest trudne, a nie żargon, lub zawiły bałagan C i C++ sprawia, że pojęcie. Tyle wysiłku wkłada się w wyjaśnienie tego pojęcia (jak w przyjętej odpowiedzi na to pytanie) i jest to po prostu zmarnowane na kogoś takiego jak ja, bo już to wszystko rozumiem. To tylko wyjaśnianie niewłaściwej części problemu.

Aby dać ci wyobrażenie o tym, skąd pochodzę, jestem kimś, kto doskonale rozumie wskaźniki i potrafię je kompetentnie wykorzystać w języku asemblera. Ponieważ w języku asemblera nie są one określane jako wskaźniki. Są one określane jako adresy. Jeśli chodzi o programowanie i używanie wskaźników w C, popełniam wiele błędów i bardzo się mylę. Nadal tego nie rozwiązałem. Dam ci przykład.

Gdy api mówi:

int doIt(char *buffer )
//*buffer is a pointer to the buffer

Czego on chce?

Może chcieć:

Liczba reprezentująca adres do bufora

(aby dać to, mam powiedzieć doIt(mybuffer), Czy doIt(*myBuffer)?)

Liczba reprezentująca adres do adresu do bufora

(czy to doIt(&mybuffer) Czy doIt(mybuffer) Czy doIt(*mybuffer)?)

Liczba reprezentująca adres do adresu do adresu do bufora

(może to jest doIt(&mybuffer). a może doIt(&&mybuffer) ? lub nawet doIt(&&&mybuffer))

I tak dalej, i język nie czyni tego tak jasnym, ponieważ obejmuje słowa "pointer" i "reference", które nie mają dla mnie tak dużego znaczenia i jasności jak" X holds the address to Y "I"this function requires an address to y". Odpowiedź dodatkowo zależy od tego, czym jest" mybuffer " na początku i co zamierza z nim zrobić. Język nie obsługuje poziomów zagnieżdżania spotykanych w praktyce. Jak wtedy, gdy muszę przekazać" wskaźnik " do funkcji, która tworzy nowy bufor i modyfikuje wskaźnik, aby wskazywał na nową lokalizację bufora. Czy naprawdę chce wskaźnik, czy wskaźnik do wskaźnika, aby wiedział, gdzie iść, aby zmodyfikować zawartość wskaźnika. Przez większość czasu po prostu muszę odgadnąć, co oznacza "wskaźnik" i większość czasu się mylę, niezależnie od tego, ile doświadczenia mam w zgadywaniu.

"wskaźnik" jest zbyt przeciążony. Czy wskaźnik jest adresem wartości? czy jest to zmienna, która zawiera adres do wartości. Gdy funkcja chce wskaźnika, czy chce adresu, który posiada zmienna wskaźnika, czy też chce adresu do zmiennej wskaźnika? Jestem zdezorientowany.

 7
Author: Breton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-17 00:17:45

Myślę, że to, co sprawia, że pointers trudne do nauczenia jest to, że dopóki pointers jesteś komfortowo z ideą, że "w tym miejscu pamięci jest zestaw bitów, które reprezentują int, podwójne, znak, cokolwiek".

Kiedy po raz pierwszy widzisz wskaźnik, tak naprawdę nie rozumiesz, co jest w tym miejscu pamięci. "Jak to przechowuje adres ?"

Nie zgadzam się z poglądem, że "albo je masz, albo nie".

Stają się łatwiejsze do zrozumienia, gdy zacznij odnajdywać dla nich prawdziwe zastosowania (np. nie przekazywanie dużych struktur do funkcji).

 5
Author: Baltimark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-22 19:19:11

Tak trudno to zrozumieć nie dlatego, że jest to trudne pojęcie, ale dlatego, że składnia jest niespójna.

   int *mypointer;

Najpierw dowiadujemy się, że lewa część tworzenia zmiennej określa jej typ. Deklaracja wskaźnika nie działa tak w C i C++. Zamiast tego mówią, że zmienna wskazuje na typ w lewo. W tym przypadku: *mypointer wskazuje {[5] } na int.

Nie do końca zrozumiałem wskazówki dopóki nie próbowałem ich używać w C# (z unsafe), działają dokładnie tak samo, ale z logiczną i spójną składnią. Wskaźnik jest typem. Tutaj mypointer jest wskaźnikiem do int.

  int* mypointer;

Nawet nie każ mi zaczynać od wskaźników funkcyjnych...

 5
Author: burrrr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-17 16:51:08

Mogłem pracować ze wskaźnikami, gdy znałem tylko C++. Wiedziałem, co robić w niektórych przypadkach, a czego nie robić metodą prób/błędów. Ale to, co dało mi pełne zrozumienie, to język zgromadzenia. Jeśli wykonujesz poważne debugowanie na poziomie instrukcji za pomocą napisanego przez Ciebie programu języka asemblacji, powinieneś być w stanie zrozumieć wiele rzeczy.

 5
Author: toto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-29 02:18:09

Podoba mi się analogia adresu domu, ale zawsze myślałem, że adres jest do samej skrzynki pocztowej. W ten sposób można zwizualizować koncepcję dereferencji wskaźnika (otwarcie skrzynki pocztowej).

Na przykład po powiązanej liście: 1) Zacznij od artykułu z adresem 2) Przejdź do adresu na papierze 3) Otwórz skrzynkę pocztową, aby znaleźć nową kartkę papieru z następnym adresem

W linearnej liście linearnej ostatnia Skrzynka pocztowa nie ma w sobie nic (koniec listy). W okrągła lista połączona, ostatnia Skrzynka pocztowa ma w sobie adres pierwszej skrzynki pocztowej.

Zauważ, że krok 3 to miejsce, w którym następuje dereferencja i gdzie ulegniesz awarii lub awarii, gdy adres jest nieprawidłowy. Zakładając, że możesz podejść do skrzynki z nieprawidłowym adresem, wyobraź sobie, że jest tam czarna dziura lub coś, co wywraca świat na drugą stronę:)

 4
Author: Christopher Scott,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-16 03:28:13

Myślę, że głównym powodem, dla którego ludzie mają z tym problem, jest to, że generalnie nie jest nauczany w interesujący i angażujący sposób. Chciałbym, aby wykładowca zebrał 10 wolontariuszy z tłumu i dał im po 1 metrowej linijce każdy, kazał im stać w określonej konfiguracji i używać linijek do wskazywania na siebie. Następnie pokaż arytmetykę wskaźnika, przesuwając ludzi wokół (i gdzie wskazują swoje linijki). Byłby to prosty, ale skuteczny (a przede wszystkim niezapomniany) sposób pokazania koncepcje bez zbytniego zagłębiania się w mechanice.

Jak już przejdziesz do C i C++ to niektórym wydaje się być trudniej. Nie jestem pewien, czy dzieje się tak dlatego, że w końcu wprowadzają teorię, której właściwie nie pojmują w praktyce, czy dlatego, że manipulacja wskaźnikami jest z natury trudniejsza w tych językach. Nie pamiętam tak dobrze mojego przejścia, ale znałam wskaźniki w Pascalu, a potem przeniosłam się do C i kompletnie się zgubiłam.

 4
Author: Wolfbyte,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-11 13:57:27

Nie sądzę, aby same wskaźniki były mylące. Większość ludzi może zrozumieć tę koncepcję. Teraz, ile wskaźników możesz myśleć lub ile poziomów indrection są wygodne. Nie potrzeba zbyt wielu, by postawić ludzi na krawędzi. Fakt, że mogą one zostać przypadkowo zmienione przez błędy w programie, może również sprawić, że będą one bardzo trudne do debugowania, gdy coś pójdzie nie tak w kodzie.

 2
Author: bruceatk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-10 18:39:07

Myślę, że to może być problem ze składnią. Składnia c / c++ dla wskaźników wydaje się niespójna i bardziej złożona niż musi być.

Jak na ironię, rzecz, która naprawdę pomogła mi zrozumieć wskaźniki, to spotkanie z koncepcją iteratora w standardowej bibliotece szablonów c++ . To ironiczne, ponieważ mogę tylko założyć, że Iteratory zostały pomyślane jako uogólnienie wskaźnika.

Czasami po prostu nie widać lasu, dopóki nie nauczysz się ignorować drzewa.

 2
Author: Waylon Flinn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-17 16:23:51

Zamieszanie pochodzi z wielu warstw abstrakcji zmieszanych ze sobą w koncepcji "wskaźnika". Programiści nie mylą się ze zwykłymi referencjami w Javie / Pythonie, ale wskaźniki różnią się tym, że ujawniają cechy podstawowej architektury pamięci.

Dobrą zasadą jest czyste oddzielanie warstw abstrakcji, a wskaźniki tego nie robią.

 2
Author: Joshua Fox,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-04 08:53:22

Sposób, w jaki lubiłem to wyjaśniać, był w kategoriach tablic i indeksów - ludzie mogą nie być zaznajomieni ze wskaźnikami, ale generalnie wiedzą, czym jest indeks.

Więc wyobraź sobie, że RAM jest tablicą (a masz tylko 10 bajtów pamięci RAM):

unsigned char RAM[10] = { 10, 14, 4, 3, 2, 1, 20, 19, 50, 9 };

Wtedy wskaźnik do zmiennej jest tak naprawdę tylko indeksem (pierwszym bajtem) tej zmiennej w pamięci RAM.

Więc jeśli masz wskaźnik / indeks unsigned char index = 2, to wartość jest oczywiście trzecim elementem, czyli liczbą 4. Wskaźnik do wskaźnik to miejsce, w którym bierzesz tę liczbę i używasz jej jako samego indeksu, jak RAM[RAM[index]].

Narysowałbym tablicę na liście papieru i po prostu użył jej do pokazania rzeczy takich jak wiele wskaźników wskazujących na tę samą pamięć, arytmetyka wskaźnika, Wskaźnik do wskaźnika i tak dalej.

 2
Author: sashoalm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-22 14:42:08

Nie rozumiem, co jest tak mylące w wskaźnikach. Wskazują na lokalizację w pamięci, czyli przechowuje adres pamięci. W C / C++ możesz określić typ, do którego wskazuje wskaźnik. Na przykład:

int* my_int_pointer;

Mówi, że my_int_pointer zawiera adres do lokalizacji, która zawiera int.

Problem ze wskaźnikami polega na tym, że wskazują one miejsce w pamięci, więc łatwo jest wytropić je w miejscu, w którym nie powinno być. Jako dowód spojrzeć na liczne dziury bezpieczeństwa w Aplikacje C / c++ z przepełnienia bufora (zwiększając wskaźnik poza przydzieloną granicą).

 1
Author: grom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-08 06:28:48

Numer skrzynki pocztowej.

To informacja, która pozwala uzyskać dostęp do czegoś innego.

(a jeśli robisz arytmetykę na numerach skrzynek pocztowych, możesz mieć problem, ponieważ litera trafia do niewłaściwego pudełka. A jeśli ktoś przeniesie się do innego stanu ... bez adresu przekierowania ... wtedy masz zwisający wskaźnik. Z drugiej strony-jeśli poczta przekazuje pocztę, to masz wskaźnik do wskaźnika.)

 1
Author: joel.neely,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-29 18:47:30

Nie jest to zły sposób, aby go zrozumieć, za pomocą iteratorów.. ale szukaj dalej, zobaczysz, że Alexandrescu zacznie na nie narzekać.

Wielu byłych programistów C++ (którzy nigdy nie rozumieli, że Iteratory są nowoczesnym wskaźnikiem przed porzuceniem języka) przeskakuje do C# i nadal wierzy, że mają przyzwoite Iteratory.

Hmm, problem polega na tym, że wszystko, czym są Iteratory, jest całkowicie zgodne z tym, co platformy uruchomieniowe (Java/CLR) próbują osiągnąć: nowy, prosty, każdy jest dev. Co może być dobre, ale powiedzieli to raz w purpurowej Księdze i mówili to jeszcze przed i przed C:

Indirection.

Bardzo potężna koncepcja, ale nigdy tak, jeśli robisz to do końca.. Iteratory są przydatne, ponieważ pomagają w abstrakcji algorytmów, inny przykład. A czas kompilacji to miejsce dla algorytmu, bardzo prostego. Znasz Kod + dane, lub w tym innym języku C#:

IEnumerable + LINQ + Massive Framework = 300Mb runtime instancje typów referencyjnych..

" Le Pointer jest tani."

 1
Author: rama-jka toti,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-17 00:34:27

Niektóre odpowiedzi powyżej twierdziły, że "wskaźniki nie są naprawdę trudne", ale nie poszły na adres bezpośrednio, gdzie " wskaźniki są trudne!"pochodzi z. Kilka lat temu uczyłem studentów pierwszego roku CS (tylko przez rok, ponieważ wyraźnie byłem w tym do bani) i było dla mnie jasne, że pomysł pointera nie jest trudny. Trudno jest zrozumieć Dlaczego i kiedy chcesz mieć wskaźnik .

Myślę, że nie da się rozwikłać tego pytania-dlaczego i kiedy użyć wskaźnika-z Wyjaśnienie szerszych zagadnień inżynierii oprogramowania. Dlaczego każda zmienna powinna a nie być zmienną globalną, i dlaczego należy uwzględnić podobny kod w funkcjach (które, get this, używają wskaźników , aby specjalizować swoje zachowanie w ich miejscu wywołania).

 1
Author: Bernd Jendrissek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-28 16:04:32

Aby nieco bardziej pomieszać sprawy, czasami trzeba pracować z uchwytami zamiast wskaźnikami. Uchwyty są wskaźnikami do wskaźników, dzięki czemu tylny koniec może przenosić rzeczy w pamięci w celu defragmentacji sterty. Jeśli wskaźnik zmienia się w trakcie rutynowych czynności, wyniki są nieprzewidywalne, więc najpierw musisz zablokować uchwyt, aby upewnić się, że nic nie idzie w kierunku miejsca.

Http://arjay.bc.ca/Modula-2/Text/Ch15/Ch15.8.html#15.8.5 mówi o tym trochę bardziej spójnie niż ja. :-)

 0
Author: SarekOfVulcan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-22 18:25:52

Każdy początkujący C / C++ ma ten sam problem i ten problem występuje nie dlatego, że "trudno się nauczyć", ale "kto i jak to jest wyjaśnione". Niektórzy uczniowie zbierają go werbalnie, wizualnie, a najlepszym sposobem na wyjaśnienie tego jest użycie przykładu "pociąg" (pasuje do przykładu werbalnego i wizualnego).

Gdzie "lokomotywa"jest wskaźnikiem, który nie może niczego trzymać, a "wagon" jest tym, co "lokomotywa" próbuje pociągnąć (lub wskazać). Po, można sklasyfikować sam "wagon", czy może pomieścić zwierzęta, rośliny lub ludzi (lub ich mieszankę).

 0
Author: Praveen Kumar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-09 19:26:57