2015-04-24 32 views
6

Zastanawiam się, kiedy używamy wskaźnika do wskaźnika w C++ i dlaczego musimy wskazać wskaźnik? Wiem, że kiedy wskażemy wskaźnik, oznacza to, że zapisujemy adres pamięci zmiennej w pamięci, ale nie wiem, dlaczego potrzebujemy go? Również widziałem kilka przykładów, które zawsze używać wskaźnik do wskaźnika w tworzeniu Matrix! Ale dlaczego Matrix może potrzebować wskaźnika do wskaźnika?Kiedy używać wskaźnika do wskaźnika w C++?

+0

samych powodów warto wskazać na int, mniej lub bardziej. – immibis

Odpowiedz

1

Jeśli chcesz zmienić wartość zmiennej przekazanej do funkcji jako argument funkcji i zachować zaktualizowaną wartość poza tą funkcją, potrzebujesz wskaźnika (pojedynczy wskaźnik) do tej zmiennej.

void modify(int* p) 
{ 
    *p = 10; 
} 

int main() 
{ 
    int a = 5; 
    modify(&a); 
    cout << a << endl; 
} 

Teraz, gdy chcemy zmienić wartość wskaźnika przekazywane do funkcji jako argumentu funkcji, wymagany wskaźnik do wskaźnika.

W prostych słowach: Użyj **, jeśli chcesz zachować (lub zachować zmianę) Przydzielenie lub przypisanie pamięci nawet poza wywołaniem funkcji. (Tak, przejść do takiej funkcji z podwójnym wskaźnikiem arg.)

To nie może być bardzo dobrym przykładem, ale pokaże podstawowe zastosowanie:

void safe_free(int** p) 
{ 
    free(*p); 
    *p = 0; 
} 

int main() 
{ 
    int* p = (int*)malloc(sizeof(int)); 
    cout << "p:" << p << endl; 
    *p = 42; 
    safe_free(p); 
    cout << "p:" << p << endl; 
} 
+0

Jest to dobry przykład, ponieważ niektóre standardy kodowania zniechęcają do korzystania z niestatycznego odniesienia. – user3528438

+2

Zrobiłbym odwrotność dla przykładu: 'void safe_free (int ** p) {free (* p); * p = 0; } ' – Jarod42

+0

@ Jarod42 Dobry przykład – CreativeMind

1

Widzieliście pewnie int main() przed, widziałeś to:

int main(int argc, char** argv) 

argv jest rzeczywiście podwójny wskaźnik, to nie jest faktycznie podwójny wskaźnik, ale jest to wskaźnik do tablicy wskaźników, każda wskazuje na tablicę znaków odnoszącą się do argumentów linii poleceń.

To nie jest najlepszy przykład, ponieważ prawdopodobnie potrzebujesz bardziej praktycznego przykładu. Będę napisać lepszy przykład i edytować mój post :)

Edit:

Jeśli jesteś zaznajomiony z klas i funkcji wirtualnych, możesz też mieć świadomość, że każda klasa, która posiada funkcję wirtualnego automatycznie otrzymuje Zmienna członka _vftp.

Członek _vftp to wskaźnik do listy wszystkich wskaźników funkcji do funkcji wirtualnych. Jest wstawiany na samym początku struktury. Jeśli utworzono nowy obiekt w następujący sposób:

class myclass 
{ 
public: 
    //void *_vftp; this is where the _vftp member gets inserted automatically 
    virtual void vfunc1(); 
}; 

void myclass::vfunc1() {printf("yay");} 

void main() { 
    myclass *pMyObject = new myclass(); 
} 

Po instancji MojaKlasa The _vftp jest dodawany do struktury obiektu i jest bardzo zmienna pierwszy. Ponieważ pMyObject jest wskaźnikiem do tej struktury w pamięci, * pMyObject ma wartość eqal do _vftp.

Ponieważ _vftp jest wskaźnikiem do tablicy wirtualnych wskaźników funkcyjnych, * _vftp jest równe vfunc1 (wskaźnik funkcji).

To oznacza, że ​​jeśli my dereference pMyObject dwa razy, i nazywają to będziemy nazywać vfunc1():

typedef (void* (__thiscall* fnVFunc1))(void); 
((fnVFunc)**pMyObject)(); 

Chociaż nie jest to prawdziwy stosowanie podwójnych wskaźników jest najlepszym przykładem ich zastosowania. Najczęstsze miejsce dla podwójnych wskaźników stanowi hakowanie i inżynieria wsteczna, w której często trzeba znaleźć wskaźnik w pamięci i zmienić wszystko, co wskazuje.

6

Kiedy stosować wskaźnik do Pointer w C++?

Powiedziałbym, że lepiej jest nigdy nie używać go w C++. Idealnie byłoby, gdybyś używał do używania go z C API lub ze starszymi materiałami, wciąż mając na myśli lub zaprojektowanymi z C API.

Wskaźnik do wskaźnika został prawie przestarzały dzięki funkcjom języka C++ i dołączonej bibliotece standardowej. Masz odniesienia do kiedy chcesz przekazać wskaźnik i edytować oryginalny wskaźnik w funkcji, a dla rzeczy takich jak wskaźnik do tablicy łańcuchów lepiej jest użyć std::vector<std::string>. To samo dotyczy wielowymiarowych macierzy, macierzy i czegokolwiek, C++ ma lepszy sposób radzenia sobie z tymi rzeczami niż tajemnicze wskaźniki do wskaźników.

1

Po prostu potrzebujemy wskaźnika do wskaźnika, gdy chcemy zmienić adres wskazanego wskaźnika. Bardzo dobrym przykładem będzie przypadek połączonej listy, w której wysyłamy wskaźnik do wskaźnika do węzła głównego, gdy próbujemy wstawić wartość na początku. Fragment kodu wklejony poniżej.

int main() 
    { 
     /* Start with the empty list */ 
     struct node* head = NULL; 

     /* Use push() to construct below list 
     1->2->1->3->1 */ 
     push(&head, 1); 
     push(&head, 2); 
     ..... 
     .... 
} 
    /* Given a reference (pointer to pointer) to the head 
     of a list and an int, push a new node on the front 
     of the list. */ 
    void push(struct node** head_ref, int new_data) 
    { 
     /* allocate node */ 
     struct node* new_node = 
       (struct node*) malloc(sizeof(struct node)); 
    ..... 
    ..... 
    } 

Jest to po prostu dlatego, powiedzmy wskaźnik był initialiy wskazujący na lokalizację pamięci 0x100 i chcemy ją zmienić, aby skierować go do innej lokalizacji powiedzieć 0x108. W takim przypadku wskaźnik do wskaźnika jest przekazywany.

1

Zawsze, gdy masz do czynienia z bibliotekami C. Istnieją dwa wspólne odpowiedzi na to samo pytanie w C:

Pierwsze, kiedy tylko chcesz podwójnie indeksowaną tablicę, jak:

int main(int argc, char** argv) 

drugie, kiedy tylko chcesz inną wartość zwracaną przez funkcję. Jest wiele funkcji w libgit2, które robią to, ponieważ chcą zwrócić znaczący typ błędu, a nie tylko null, jak na przykład pierwszy argument w git_branch_create.

Oczywiście można zwrócić dwie rzeczy: struct, ale zwykle są to dwie dodatkowe linie kodu. W rzeczywistości wskaźnik do wskaźnika umożliwia zapisywanie wskaźnika bezpośrednio w strukturze, w której będzie on żyć.

W C++, można by uniknąć bezpośrednio za pomocą wskaźników, gdy istnieją właściwe C++ typy danych, a mój libgit2 przykładem jest uwzględniana przez wyjątków C++ 's, ale ..

nie można nazwać C++ z większości języków wysokiego poziomu, więc jeśli piszesz biblioteki, które chcesz powiedzieć dostępny w Perl, Python i C++, a następnie zapisać go w C

0

Say chcesz instancję obiektu w C++ ...

MyClass * obj = new MyClass(); 

masz w tym celu, ponieważ new zwraca wskaźnik t o przydzielony obiekt w pamięci dynamicznej. Poniższa byłoby źle:

MyClass obj = new MyClass(); // wrong. 'new' returns a pointer. 

Powiedzmy, że chcesz tablicę obiektów ...

MyClass ** objArray = new MyClass*[10]; 
Powiązane problemy