2010-05-11 9 views
11

Myślę, że dobrze rozumiem odniesienia i wskaźniki. Oto, co ja (myślę) wiem:Zrozumienie wskaźników C++ (kiedy wskazują wskaźnik)

int i = 5; //i is a primitive type, the value is 5, i do not know the address. 
int *ptr; //a pointer to an int. i have no way if knowing the value yet. 
ptr = &i; //now i have an address for the value of i (called ptr) 
*ptr = 10; //Go to the value in ptr, use it to find a location and store 10 there 

Prosimy o komentarz lub poprawienie tych oświadczeń.

Teraz próbuję przeskoczyć do tablic wskaźników. Oto czego nie wiem:

char **char_ptrs = new char *[50]; 
Node **node_ptrs = new Node *[50]; 

moim rozumieniu jest to, że mam 2 tablice wskaźników, jeden zestaw wskaźników do znaków i jeden do węzłów. Więc gdybym chciał ustawić wartości, chciałbym zrobić coś takiego:

char_ptrs[0] = new char[20]; 
node_ptrs[0] = new Node; 

teraz mam wskaźnik w położeniu 0 mojej tablicy, w każdej odpowiedniej tablicy. Jeszcze raz, proszę o komentarz tutaj, jeśli jestem zdezorientowany.

Co robi operator **? Podobnie, co robi postawienie pojedynczego * przy tworzeniu instancji (* [50])? (co dokładnie nazywa się instancją?)

+3

* ptr = 10 to nie "go, pobierz wartość zapisaną w ptr i zmień ją na 10". Powinno to być "Przejdź do wartości w ptr, użyj jej, aby znaleźć inną lokalizację i zapisz tam 10". To jest właśnie kwestia dereferencji wskaźnika. – Uri

+0

@Uri dobrze spełnione. edytowane i aktualizowane. – Stephano

+0

Muszę zauważyć, że ta książka była nieziemsko pomocna w poznawaniu wskaźników w języku C: Zrozumienie i używanie C Wskaźników przez Richarda Reese'a. Poleciłbym to każdemu, kto uczy się C lub C++, ponieważ pojęcia w nim zawarte są nieocenione. – Stephano

Odpowiedz

7

Kilka komentarzy:

*ptr = 10; // Doesn't need to "go get" the value. Just overwrites it. 

także:

char **char_ptrs = new char *[50]; 
Node **node_ptrs = new Node *[50]; 

Łatwiej jest myśleć, że masz dwie tablice. Jednak technicznie (i jeśli chodzi o kompilator), masz dwa wskaźniki. Jeden to wskaźnik do (wskaźnik do znaku), a drugi to wskaźnik do (wskaźnik do węzła).

to łatwo widoczne deklaracji zmiennych, które, nawiasem mówiąc, można najłatwiej czytanych od prawej do lewej:

char **char_ptrs 

Czytanie od prawej do lewej: char_ptrs jest wskaźnikiem do wskaźnika do char

oddanie * obok wskaźnika jest prawidłowo nazywa dereferencing ten wskaźnik. Ponieważ tablice technicznie nie istnieją, operator [] na tablicach jest także operacją dereferencyjną: arr[i] to inny sposób pisania *(arr + i). Aby to właściwie zrozumieć, musisz zapoznać się z pointer arithmetic.

Więcej niż jeden kolejny * s: każdy odznacza wynik wyrażenia, na którym działa. Więc pisząc:

char c = **char_ptrs; 

co się dzieje:

char_ptrs jest wskaźnik do wskaźnika do char. Dereferencje raz (dla prawej *) dostaniesz jego wartość, która jest wskaźnikiem do znaku. Odwołanie tej wartości (dla skrajnej lewej *) daje po kolei swoją wartość, co jest char. Ostatecznie, c zawiera wartość char przechowywaną w pamięci w miejscu wskazanym przez wskaźnik char_ptrs (innymi słowy pierwszy wskaźnik w twojej tablicy).

Odwrotnie, jeśli napiszesz **char_ptrs = 'a';, zmienisz wartość w tej lokalizacji pamięci.

+0

+1 dobrze powiedziane. doskonały link też. – Stephano

+0

Węzeł * tmp = węzeł_ptrs [0]; Czy to prawda? – Stephano

+0

@Stephano: na pewno. – Jon

6

** jest po prostu *, więc wskaźnik do wskaźnika.

Po umieszczeniu obok typu, * łączy lewy, a nie prawy. Mówienie new char *[50] jest w rzeczywistości new char* [50] i tworzy instancję tablicy 50 char*.

2

Instrukcje wykonane w pierwszej części kodu są poprawne.

char **char_ptrs = new char *[50]; 

... oznacza, że ​​masz tablicę 50 char * s.

Twój zaliczenia z

char_ptrs[0] = new char[20]; 
node_ptrs[0] = new Node; 

jest poprawny, jak również.

** oznacza po prostu "wskaźnik do wskaźnika". To nie jest operator.

Kiedy piszesz

new char *[50]; 

... mówisz 'przydzielić pamięci dla 50 char * s'.

+0

Niekiedy składnia jest myląca. Wolę: "char ** char_ptrs = new char * [50];" Aby było to jasne, ale ma to również swoje wady. –

0

Wyjaśnienie pierwszy odcinek:

int i = 5; // i is a primitive type, the value is 5, the address is retrieved via &i. 
int *ptr; // an unassigned pointer to an int 
ptr = &i; // ptr now point to the address of variable i 
*ptr = 10; // access (dereference) the value through ptr and change it to 10 (same as i=10) 

Nie ma operatora ** * tylko operator. Jak powiedzieli inni, ** deklaruje wskaźnik do wskaźnika. Ponieważ deklarujesz tablice wskaźników, a wskaźniki są deklarowane z operatorem *, musisz zadeklarować je jako takie przy przydzielaniu pamięci dla nich za pomocą new. Dlatego masz:

char **char_ptrs = new char *[50]; // allocates memory for 50 contiguous char* (pointers) 
Node **node_ptrs = new Node *[50]; // allocates memory for 50 contiguous Node* (pointers) 

Wskaźniki do wskaźników niekoniecznie muszą zadeklarować tablice. Można równie dobrze mieć regularny wskaźnik wskazywanego przez innego wskaźnika, na przykład:

char i = 'p'; 
char *myptr = &i; 
char **mysecondptr = &myptr; 
3

Jeśli znajdziesz * notacji trudne do odczytania używanie typedef aby uczynić Twój kod łatwy do odczytania.

typedef char*  CharPtr; 
typedef CharPtr* CharPtrPtr; 
// Alternative to the line above 
// typedef char**  CharPtrPtr; 

// When you call new. You get a ptr to the type you are newing. 
// new int returns an intPtr. new char returns a charPtr 
CharPtrPtr char_ptrs = new CharPtr[50]; 

// So new CharPtr returns a CharPtrPtr 
// In this case we return a pointer to contigious 
// chunk of memory large enough to hold 50 CharPtr objects. 
+0

Nie, nie rób tego. Ukrywanie faktu, że coś jest wskaźnikiem, to bardzo słaby styl, IMHO. –

+1

Zgadzam się z Neilem w sprawie ogólnej. Ale Ptr jest w porządku, ponieważ go nie ukrywasz (IMHO). Ale ponieważ jest to nauka excersise po prostu przyzwyczaić się do używania wskaźników działa. Kiedy stajesz się stary i leniwy jak ja, Niel the * jest równie łatwy do odczytania i szybszy do wpisania :-) –

Powiązane problemy