Dlaczego warto używać podwójnego wskaźnika? albo po co używać wskaźników do wskaźników?

Kiedy powinien być użyty Podwójny wskaźnik w C? Czy ktoś może wyjaśnić przykładem?

Wiem, że Podwójny wskaźnik jest wskaźnikiem do wskaźnika. Po co mi wskaźnik do wskaźnika?

 186
Author: BЈовић, 2011-04-07

19 answers

Jeśli chcesz mieć listę znaków (słowo), możesz użyć char *word

Jeśli chcesz listę słów (zdanie), możesz użyć char **sentence

Jeśli chcesz listę zdań (monolog), możesz użyć char ***monologue

Jeśli chcesz listę monologów( biografii), możesz użyć char ****biography

Jeśli chcesz listę biografii( bio-bibliotekę), możesz użyć char *****biolibrary

Jeśli chcesz listę bio-bibliotek (a ??lol), możesz użyć char ******lol

... ...

tak, Wiem, że mogą to nie być najlepsze struktury danych

 375
Author: pmg,
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
2011-04-07 12:23:37

Jednym z powodów jest to, że chcesz zmienić wartość wskaźnika przekazanego do funkcji jako argument funkcji, aby to zrobić, potrzebujesz wskaźnika do wskaźnika.

W prostych słowach, Użyj **, gdy chcesz zachować (Lub zachować zmianę) alokacji pamięci lub przydziału nawet poza wywołaniem funkcji. (Tak, przekazać taką funkcję z podwójnym wskaźnikiem arg.)

Może to nie jest dobry przykład, ale pokaże Ci podstawowe użycie:

void allocate(int** p)
{
  *p = (int*)malloc(sizeof(int));
}

int main()
{
  int* p = NULL;
  allocate(&p);
  *p = 42;
  free(p);
}
 146
Author: Asha,
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-06-28 20:29:48

Oto prosta odpowiedź!!!!

  • powiedzmy, że masz wskaźnik, że jego wartością jest adres.
  • Ale teraz chcesz zmienić ten adres.
  • możesz, wykonując pointer1 = pointer2, a pointer1 będzie miał teraz adres pointer2.
  • Ale! jeśli chcesz, aby funkcja zrobiła to za Ciebie i chcesz, aby wynik utrzymywał się po zakończeniu funkcji, musisz wykonać dodatkową pracę, potrzebujesz nowego pointer3 tylko po to, aby wskazać pointer1 i przekazać pointer3 do funkcja.

  • Oto zabawny przykład (spójrz najpierw na wynik poniżej, aby zrozumieć!):

#include <stdio.h>

int main()
{

    int c = 1;
    int d = 2;
    int e = 3;
    int * a = &c;
    int * b = &d;
    int * f = &e;
    int ** pp = &a;  // pointer to pointer 'a'

    printf("\n a's value: %x \n", a);
    printf("\n b's value: %x \n", b);
    printf("\n f's value: %x \n", f);
    printf("\n can we change a?, lets see \n");
    printf("\n a = b \n");
    a = b;
    printf("\n a's value is now: %x, same as 'b'... it seems we can, but can we do it in a function? lets see... \n", a);
    printf("\n cant_change(a, f); \n");
    cant_change(a, f);
    printf("\n a's value is now: %x, Doh! same as 'b'...  that function tricked us. \n", a);

    printf("\n NOW! lets see if a pointer to a pointer solution can help us... remember that 'pp' point to 'a' \n");
     printf("\n change(pp, f); \n");
    change(pp, f);
    printf("\n a's value is now: %x, YEAH! same as 'f'...  that function ROCKS!!!. \n", a);
    return 0;
}

void cant_change(int * x, int * z){
    x = z;
    printf("\n ----> value of 'a' is: %x inside function, same as 'f', BUT will it be the same outside of this function? lets see\n", x);
}

void change(int ** x, int * z){
    *x = z;
    printf("\n ----> value of 'a' is: %x inside function, same as 'f', BUT will it be the same outside of this function? lets see\n", *x);
}
  • a oto wyjście:
 a's value: bf94c204

 b's value: bf94c208 

 f's value: bf94c20c 

 can we change a?, lets see 

 a = b 

 a's value is now: bf94c208, same as 'b'... it seems we can, but can we do it in a function? lets see... 

 cant_change(a, f); 

 ----> value of 'a' is: bf94c20c inside function, same as 'f', BUT will it be the same outside of this function? lets see

 a's value is now: bf94c208, Doh! same as 'b'...  that function tricked us. 

 NOW! lets see if a pointer to a pointer solution can help us... remember that 'pp' point to 'a' 

 change(pp, f); 

 ----> value of 'a' is: bf94c20c inside function, same as 'f', BUT will it be the same outside of this function? lets see

 a's value is now: bf94c20c, YEAH! same as 'f'...  that function ROCKS!!!. 
 59
Author: Brian Joseph Spinos,
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-02-24 20:15:53

Dodając do odpowiedzi Asha , jeśli użyjesz pojedynczego wskaźnika do poniższego przykładu (np. alloc1 ()), stracisz odniesienie do pamięci przydzielonej wewnątrz funkcji.

void alloc2(int** p) {
   *p = (int*)malloc(sizeof(int));
   **p = 10;
}

void alloc1(int* p) {
   p = (int*)malloc(sizeof(int));
   *p = 10;
}

int main(){
   int *p;
   alloc1(p);
   //printf("%d ",*p);//value is undefined
   alloc2(&p);
   printf("%d ",*p);//will print 10
   free(p);
   return 0;
}

Dzieje się tak dlatego, że w alloc1 Wskaźnik jest przekazywany przez wartość. Tak więc, gdy zostanie on przypisany do wyniku wywołania malloc wewnątrz alloc1, zmiana Nie dotyczy kodu w innym zakresie.

 34
Author: Silviu,
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
2017-05-23 12:34:51

1. Pojęcie Podstawowe -

Gdy zadeklarujesz, co następuje:-

1. char * ch - (zwany wskaźnikiem znaków)
- ch zawiera adres pojedynczego znaku.
- (*ch) spowoduje odwołanie do wartości znaku..

2. char * * ch -
'ch' zawiera adres tablicy wskaźników znakowych. (jak w 1)
'*ch ' zawiera adres pojedynczego znaku. (Zauważ, że różni się od 1, ze względu na różnicę w deklaracja).
(**ch) spowoduje odwołanie do dokładnej wartości znaku..

dodanie większej liczby wskaźników rozszerza wymiar typu danych, od znaku do łańcucha znaków, do tablicy łańcuchów itd... Można powiązać go z matrycą 1d, 2D, 3D..

Tak więc użycie wskaźnika zależy od tego, jak go zadeklarujesz.

Oto prosty kod..

int main()
{
    char **p;
    p = (char **)malloc(100);
    p[0] = (char *)"Apple";      // or write *p, points to location of 'A'
    p[1] = (char *)"Banana";     // or write *(p+1), points to location of 'B'

    cout << *p << endl;          //Prints the first pointer location until it finds '\0'
    cout << **p << endl;         //Prints the exact character which is being pointed
    *p++;                        //Increments for the next string
    cout << *p;
}

2. Kolejne zastosowanie podwójnych wskaźników -
(obejmowałoby to również przejście przez odniesienie)

Załóżmy, że chcesz zaktualizować znak z funkcji. Jeśli spróbujesz: -

void func(char ch)
{
    ch = 'B';
}

int main()
{
    char ptr;
    ptr = 'A';
    printf("%c", ptr);

    func(ptr);
    printf("%c\n", ptr);
}

Wyjściem będzie AA. To nie działa, ponieważ "przekazałeś wartość" do funkcji.

Poprawnym sposobem na to byłoby -

void func( char *ptr)        //Passed by Reference
{
    *ptr = 'B';
}

int main()
{
    char *ptr;
    ptr = (char *)malloc(sizeof(char) * 1);
    *ptr = 'A';
    printf("%c\n", *ptr);

    func(ptr);
    printf("%c\n", *ptr);
}

Teraz rozszerz ten wymóg aktualizacji ciągu znaków zamiast znaku.
W tym celu musisz otrzymać parametr w funkcji jako Podwójny wskaźnik.

void func(char **str)
{
    strcpy(str, "Second");
}

int main()
{
    char **str;
    // printf("%d\n", sizeof(char));
    *str = (char **)malloc(sizeof(char) * 10);          //Can hold 10 character pointers
    int i = 0;
    for(i=0;i<10;i++)
    {
        str = (char *)malloc(sizeof(char) * 1);         //Each pointer can point to a memory of 1 character.
    }

    strcpy(str, "First");
    printf("%s\n", str);
    func(str);
    printf("%s\n", str);
}

W tym przykładzie metoda oczekuje, że Podwójny wskaźnik jako parametr zaktualizuje wartość łańcucha znaków.

 19
Author: Bhavuk Mathur,
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-05-17 13:21:44

Widziałem dziś bardzo dobry przykład z tego posta na blogu , Jak podsumuję poniżej.

Wyobraź sobie, że masz strukturę dla węzłów na połączonej liście, która prawdopodobnie jest

typedef struct node
{
    struct node * next;
    ....
} node;

Teraz chcesz zaimplementować funkcję remove_if, która akceptuje kryterium usuwania rm jako jeden z argumentów i przemieszcza się po linkowanej liście: jeśli wpis spełnia kryterium (coś w rodzaju rm(entry)==true), jego węzeł zostanie usunięty z listy. W końcu remove_if zwraca głowę (która może być różni się od oryginalnej głowicy) połączonej listy.

Możesz napisać

for (node * prev = NULL, * curr = head; curr != NULL; )
{
    node * const next = curr->next;
    if (rm(curr))
    {
        if (prev)  // the node to be removed is not the head
            prev->next = next;
        else       // remove the head
            head = next;
        free(curr);
    }
    else
        prev = curr;
    curr = next;
}

Jako twoja for pętla. Wiadomość jest taka, bez podwójnych wskaźników, musisz utrzymywać zmienną prev, aby ponownie uporządkować wskaźniki i obsłużyć dwa różne przypadki.

Ale z podwójnymi wskaźnikami, można rzeczywiście napisać

// now head is a double pointer
for (node** curr = head; *curr; )
{
    node * entry = *curr;
    if (rm(entry))
    {
        *curr = entry->next;
        free(entry);
    }
    else
        curr = &entry->next;
}

Nie potrzebujesz teraz prev, ponieważ możesz bezpośrednio zmodyfikować to, co prev->next wskazało na .

Żeby było jaśniej, niech postępuj zgodnie z kodem trochę. Podczas usuwania:

  1. if entry == *head: będzie *head (==*curr) = *head->next -- head teraz wskazuje na wskaźnik nowego węzła nagłówka. Można to zrobić poprzez bezpośrednią zmianę zawartości head na nowy wskaźnik.
  2. if entry != *head: podobnie, *curr jest tym, na co prev->next wskazał, a teraz wskazuje na entry->next.

Bez względu na to, w którym przypadku, można ponownie zorganizować wskaźniki w jednolity sposób z podwójnymi wskaźnikami.

 17
Author: ziyuang,
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
2014-08-28 13:00:27

Wskaźniki do wskaźników są również przydatne jako "uchwyty" do pamięci, gdzie chcesz przekazać "uchwyt" między funkcjami do ponownego zlokalizowania pamięci. Oznacza to, że funkcja może zmienić pamięć wskazywaną przez wskaźnik wewnątrz zmiennej handle, a każda funkcja lub obiekt korzystający z tego uchwytu będzie prawidłowo wskazywać na nowo przeniesioną (lub przydzieloną) pamięć. Biblioteki lubią to robić z "nieprzezroczystymi" typami danych, czyli typami danych, których nie trzeba martwić się o to, co robią z pamięci jest skierowany zrobić, po prostu przejść wokół "uchwyt" między funkcjami biblioteki do wykonywania niektórych operacji na tej pamięci ... funkcje biblioteczne mogą przydzielać i dealować pamięć pod maską, bez wyraźnego martwienia się o proces zarządzania pamięcią lub wskazywanie miejsca, w którym znajduje się uchwyt.

Na przykład:

#include <stdlib.h>

typedef unsigned char** handle_type;

//some data_structure that the library functions would work with
typedef struct 
{
    int data_a;
    int data_b;
    int data_c;
} LIB_OBJECT;

handle_type lib_create_handle()
{
    //initialize the handle with some memory that points to and array of 10 LIB_OBJECTs
    handle_type handle = malloc(sizeof(handle_type));
    *handle = malloc(sizeof(LIB_OBJECT) * 10);

    return handle;
}

void lib_func_a(handle_type handle) { /*does something with array of LIB_OBJECTs*/ }

void lib_func_b(handle_type handle)
{
    //does something that takes input LIB_OBJECTs and makes more of them, so has to
    //reallocate memory for the new objects that will be created

    //first re-allocate the memory somewhere else with more slots, but don't destroy the
    //currently allocated slots
    *handle = realloc(*handle, sizeof(LIB_OBJECT) * 20);

    //...do some operation on the new memory and return
}

void lib_func_c(handle_type handle) { /*does something else to array of LIB_OBJECTs*/ }

void lib_free_handle(handle_type handle) 
{
    free(*handle);
    free(handle); 
}


int main()
{
    //create a "handle" to some memory that the library functions can use
    handle_type my_handle = lib_create_handle();

    //do something with that memory
    lib_func_a(my_handle);

    //do something else with the handle that will make it point somewhere else
    //but that's invisible to us from the standpoint of the calling the function and
    //working with the handle
    lib_func_b(my_handle); 

    //do something with new memory chunk, but you don't have to think about the fact
    //that the memory has moved under the hood ... it's still pointed to by the "handle"
    lib_func_c(my_handle);

    //deallocate the handle
    lib_free_handle(my_handle);

    return 0;
}

Mam nadzieję, że to pomoże,

Jason

 12
Author: Jason,
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
2011-04-07 14:52:24

Łańcuchy są doskonałym przykładem zastosowania podwójnych wskaźników. Sam ciąg znaków jest wskaźnikiem, więc za każdym razem, gdy musisz wskazać na ciąg znaków, będziesz potrzebować podwójnego wskaźnika.

 4
Author: drysdam,
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
2011-04-07 12:13:03

Poniżej znajduje się bardzo prosty przykład C++, który pokazuje, że jeśli chcesz użyć funkcji, aby ustawić wskaźnik, aby wskazywał na obiekt, potrzebujesz wskaźnika do wskaźnika . W przeciwnym razie, wskaźnik będzie powracał do null .

W C++, ale wydaje mi się, że to samo jest w C.)

(również, dla odniesienia: Google("pass by value c++") = " domyślnie argumenty w C++ są przekazywane przez wartość. Gdy argument jest przekazywany przez wartość, wartość argumentu jest kopiowana do parametr funkcji.")

Chcemy więc ustawić wskaźnik b równy łańcuchowi a.

#include <iostream>
#include <string>

void Function_1(std::string* a, std::string* b) {
  b = a;
  std::cout << (b == nullptr);  // False
}

void Function_2(std::string* a, std::string** b) {
  *b = a;
  std::cout << (b == nullptr);  // False
}

int main() {
  std::string a("Hello!");
  std::string* b(nullptr);
  std::cout << (b == nullptr);  // True

  Function_1(&a, b);
  std::cout << (b == nullptr);  // True

  Function_2(&a, &b);
  std::cout << (b == nullptr);  // False
}

// Output: 10100

Co się dzieje na linii Function_1(&a, b);?

  • "wartość" &main::a (adres) jest kopiowana do parametru std::string* Function_1::a. Dlatego Function_1::a jest wskaźnikiem do (tj. adresu pamięci) łańcucha main::a.

  • "wartość" main::b (adres w pamięci) jest kopiowana do parametru std::string* Function_1::b. Dlatego w pamięci są teraz 2 z tych adresów, oba null pointers. W linii b = a; zmienna lokalna {[11] } jest następnie zmieniana na równą Function_1::a (= &main::a), ale zmienna main::b pozostaje niezmieniona. Po wezwaniu do Function_1, main::b nadal jest wskaźnikiem zerowym.

Co się dzieje na linii Function_2(&a, &b);?

  • Traktowanie zmiennej a jest takie samo: w funkcji Function_2::a jest adresem łańcucha main::a.

  • Ale zmienna b jest teraz przekazywana jako wskaźnik do wskaźnika. Na "value" of &main::b (The address of the pointer main::b) jest kopiowane do std::string** Function_2::b. Dlatego w obrębie funkcji Formula_2 dereferowanie tego jako {[25] } spowoduje dostęp i modyfikację main::b. Tak więc linia *b = a; ustawia main::b (adres) równy Function_2::a (=adres main::a), co jest tym, czego chcemy.

Jeśli chcesz użyć funkcji do modyfikacji rzeczy, czy to obiektu, czy adresu (wskaźnika), musisz przekazać wskaźnik do tej rzeczy. the thing that you w rzeczywistości pass in nie może być modyfikowany (w zakresie wywołania), ponieważ została wykonana lokalna kopia.

(wyjątkiem jest, jeśli parametr jest referencją, np. std::string& a. Ale zazwyczaj są to const. Ogólnie rzecz biorąc, jeśli wywołujesz f(x), jeśli x jest obiektem, powinieneś być w stanie założyć, że f nie zmieni x. Ale jeśli x jest wskaźnikiem, to należy założyć, że f może zmodyfikować obiekt wskazywany przez x.)

 4
Author: jt117,
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
2017-02-23 01:13:30

Prosty przykład, który prawdopodobnie widziałeś już wiele razy

int main(int argc, char **argv)

W drugim parametrze masz: wskaźnik do wskaźnik do znaku.

Zauważ, że notacja wskaźnika (char* c) i notacja tablicy (char c[]) są wymienne w argumentach funkcji. Więc możesz też napisać char *argv[]. Innymi słowy char *argv[] i {[5] } są wymienne.

To, co powyżej reprezentuje, jest w rzeczywistości tablicą sekwencji znaków (argumentów linii poleceń, które są podawane programowi w startup).

Patrz również ta odpowiedź aby uzyskać więcej szczegółów na temat powyższej sygnatury funkcji.

 4
Author: plats1,
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
2017-09-14 11:15:07

Na przykład, możesz chcieć się upewnić, że po zwolnieniu pamięci czegoś ustawisz wskaźnik NA null.

void safeFree(void** memory) {
    if (*memory) {
        free(*memory);
        *memory = NULL;
    }
}

Gdy wywołujesz tę funkcję, wywołujesz ją z adresem wskaźnika

void* myMemory = someCrazyFunctionThatAllocatesMemory();
safeFree(&myMemory);

Teraz myMemory jest ustawione na NULL i jakakolwiek próba ponownego użycia będzie bardzo błędna.

 3
Author: Jeff Foster,
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
2011-04-07 12:13:22

Na przykład, jeśli chcesz losowego dostępu do danych niezgodnych.

p -> [p0, p1, p2, ...]  
p0 -> data1
p1 -> data2

-- in C

T ** p = (T **) malloc(sizeof(T*) * n);
p[0] = (T*) malloc(sizeof(T));
p[1] = (T*) malloc(sizeof(T));

Przechowujesz wskaźnik p, który wskazuje na tablicę wskaźników. Każdy wskaźnik wskazuje na fragment danych.

Jeśli sizeof(T) jest duży, może nie być możliwe przydzielenie sąsiedniego bloku (np. za pomocą malloc) sizeof(T) * n bajtów.

 2
Author: log0,
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
2011-04-07 12:23:41

Jedną z rzeczy, do których ciągle ich używam, jest to, że mam tablicę obiektów i muszę na nich szukać (wyszukiwanie binarne) według różnych pól.
Zachowam oryginalną tablicę...

int num_objects;
OBJECT *original_array = malloc(sizeof(OBJECT)*num_objects);

Następnie utwórz tablicę posortowanych wskaźników do obiektów.

int compare_object_by_name( const void *v1, const void *v2 ) {
  OBJECT *o1 = *(OBJECT **)v1;
  OBJECT *o2 = *(OBJECT **)v2;
  return (strcmp(o1->name, o2->name);
}

OBJECT **object_ptrs_by_name = malloc(sizeof(OBJECT *)*num_objects);
  int i = 0;
  for( ; i<num_objects; i++)
    object_ptrs_by_name[i] = original_array+i;
  qsort(object_ptrs_by_name, num_objects, sizeof(OBJECT *), compare_object_by_name);

Możesz utworzyć tyle posortowanych tablic wskaźników, ile potrzebujesz, a następnie użyć wyszukiwania binarnego na posortowanej tablicy wskaźników, aby uzyskać dostęp do potrzebnego obiektu według posiadanych danych. Oryginalna tablica obiektów może pozostać nieposortowana, ale każdy tablica wskaźników zostanie posortowana według określonego pola.

 2
Author: DavidMFrey,
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
2011-04-07 13:41:37

Jak powiedział jeden z zastosowań double poinnter jest aktualizacja ciągu tak, że zmiany wprowadzone są odzwierciedlone z powrotem.

#include <iostream>
#include <cstring>  // for using strcpy
using namespace std;

void change(char **temp)
{
   strcpy(temp[0],"new");
   strcpy(temp[1],"value");
}

int main()
{
   char **str;
   str = (char **)malloc(sizeof(char *)*3);
   str[0]=(char *)malloc(10);
   str[1]=(char *)malloc(10);
   strcpy(str[0],"old");
   strcpy(str[1],"name");
   char **temp = str;  // always use the temporary variable
   while(*temp!=NULL)
{
    cout<<*temp<<endl;
    temp++;
}
temp = str;   // making it point it to the original head because we have changed the address in while loop above
change(str);
while(*temp!=NULL)
{
   cout<<*temp<<endl;
   temp++;
}

free(temp);
free(str[0]);
free(str[1]);
free(str);
 2
Author: Abhishek Karigar,
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-06-26 20:33:28

Używałem dziś podwójnych wskaźników, gdy programowałem coś do pracy, więc mogę odpowiedzieć, dlaczego musieliśmy ich używać (po raz pierwszy musiałem użyć podwójnych wskaźników). Mieliśmy do czynienia z kodowaniem w czasie rzeczywistym ramek zawartych w buforach będących członkami niektórych struktur. W enkoderze musieliśmy użyć wskaźnika do jednej z tych struktur. Problem polegał na tym, że nasz wskaźnik był zmieniany, aby wskazać inne struktury z innego wątku. W celu wykorzystania obecnej struktury w enkoderze musiałem użyć podwójnego wskaźnika, aby wskazać wskaźnik, który był modyfikowany w innym wątku. Na początku, przynajmniej dla nas, nie było oczywiste, że musimy przyjąć takie podejście. Wiele adresów zostało wydrukowanych w procesie:)).

Powinieneś używać podwójnych wskaźników podczas pracy na wskaźnikach, które są zmieniane w innych miejscach Twojej aplikacji. Możesz również znaleźć podwójne wskaźniki jako konieczność, gdy masz do czynienia ze sprzętem, który zwraca i adres do ciebie.

 1
Author: Axenie Ionut,
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
2014-11-11 17:06:43

Dlaczego podwójne wskaźniki?

Celem jest zmiana tego, na co wskazuje studentA, za pomocą funkcji.

#include <stdio.h>
#include <stdlib.h>


typedef struct Person{
    char * name;
} Person; 

/**
 * we need a ponter to a pointer, example: &studentA
 */
void change(Person ** x, Person * y){
    *x = y; // since x is a pointer to a pointer, we access its value: a pointer to a Person struct.
}

void dontChange(Person * x, Person * y){
    x = y;
}

int main()
{

    Person * studentA = (Person *)malloc(sizeof(Person));
    studentA->name = "brian";

    Person * studentB = (Person *)malloc(sizeof(Person));
    studentB->name = "erich";

    /**
     * we could have done the job as simple as this!
     * but we need more work if we want to use a function to do the job!
     */
    // studentA = studentB;

    printf("1. studentA = %s (not changed)\n", studentA->name);

    dontChange(studentA, studentB);
    printf("2. studentA = %s (not changed)\n", studentA->name);

    change(&studentA, studentB);
    printf("3. studentA = %s (changed!)\n", studentA->name);

    return 0;
}

/**
 * OUTPUT:
 * 1. studentA = brian (not changed)
 * 2. studentA = brian (not changed)
 * 3. studentA = erich (changed!)
 */
 1
Author: Brian Joseph Spinos,
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-11-26 23:54:46

Mamy nadzieję, że poniższy przykład wyjaśni niektóre pojęcia dotyczące wskaźników i podwójnych wskaźników , ich różnic i wykorzystania w typowych scenariuszach.

    int* setptr(int *x)
    {
        printf("%u\n",&x);
        x=malloc(sizeof(int));
        *x=1;
        return x;
    }

In the above function setptr we can manipulate x either
1. by taking fn arg as int *x , doing  malloc and setting value of x and return x 
Or
    2. By taking arg as int ** and malloc and then set  **x value to some value.
Note: we cant set any general pointer directly without doing  malloc.Pointer indicates that it is a type of variable which can hold address of any data type.Now either we define a variable and give reference to it or we declare a pointer(int *x=NULL) and allocate some memory to it inside the called function where we pass x or a reference to it .. In either case we need to have address of a memory in the  pointer and in the case pointer initially points  to NULL or it is defined like int *x where it points  to any random address then we need to assign a valid memory address to pointer 

    1. either we need to allocate memory to it by malloc

    int *x=NULL means its address is 0.
    Now we need to either o following
    1.



    void main()
        {
            int *x;
            x=malloc
            *x=some_val;
        }
        Or
        void main()
        {
            int *x
            Fn(x);
        }

        void Fn(int **x)
        {
            *x=malloc;
            **x=5;
        }
        OR
        int * Fn(int *x)
        {
            x=malloc();
            *x=4;
            Return x;
        }


        2. Or we need to point it to a valid memory like a defined variable inside the function where pointer is defined.


        OR
        int main()
        {
            int a;
            int *x=&a;
            Fn(x);
            printf("%d",*x);
        }
        void Fn(int *x)
        {
            *x=2;
        }


     in both cases value pointed by x is changed inside fn

    But suppose if we do like


    int main()
    {
        int *x=NULL;
        printf("%u\n",sizeof(x));
        printf("%u\n",&x);
        x=setptr(x);
        //*x=2;
        printf("%d\n",*x);
        return 0;
    }

/* output
4
1
*/

#include<stdio.h>
void setptr(int *x)
{
    printf("inside setptr\n");
    printf("x=%u\n",x);
    printf("&x=%u\n",&x);
    //x=malloc(sizeof(int));
    *x=1;
    //return x;
}
int main()
{
    int *x=NULL;
    printf("x=%u\n",x);
    printf("&x=%u\n",&x);
    int a;
    x=&a;
    printf("x=%u\n",x);
    printf("&a=%u\n",&a);
    printf("&x=%u\n",&x);
    setptr(x);
    printf("inside main again\n");

    //*x=2;
    printf("x=%u\n",x);
    printf("&x=%u\n",&x);
    printf("*x=%d\n",*x);
    printf("a=%d\n",a);
    return 0;
}
 0
Author: Peter_pk,
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-04-27 01:51:07

Zastosowanie podwójnego wskaźnika, jak pokazał Bhavuk Mathur, wydaje się być błędne. Poniższy przykład jest poprawny

void func(char **str)
{
     strcpy(str[0],"second");
}

int main(){

    char **str;
    str = (char **)malloc(sizeof(char*)*1); // allocate 1 char* or string
    str[0] = (char *)malloc(sizeof(char)*10);      // allocate 10 character
    strcpy(str[0],"first");            // assign the string
    printf("%s\n",*str);
    func(str);            
    printf("%s\n",*str);           
    free(str[0]); 
    free(str);
}
 0
Author: Abhishek Karigar,
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-06-24 15:50:43

Poniższy przykład, który podaję, da wgląd lub intuicję o tym, jak działają podwójne wskaźniki, przejdę przez kroki

1) try to understand the following statements
   char **str ;

   a) str is of type char ** whose value is an address of another pointer.
   b) *str is of type char * whose value is an address of variable or (it is a string itself).
   c) **str is of type char ,gives the value stored, in this case a character.

Poniżej znajduje się kod, do którego możesz odnieść się do powyższych punktów (a, b, c), aby zrozumieć

str = (char **)malloc(sizeof(char *) *2); // here i am assigning the mem for two char *
       str[0]=(char *)"abcdefghij"; // assignin the value
       str[1]=(char *)"xyzlmnopqr"; 

Teraz, aby wypisać wartość tj. ciągi znaków w tablicy, wystarczy spojrzeć na punkt b, W przypadku string wartość jak i adres są takie same, więc nie ma potrzeby odwoływania się do niej ponownie.

cout<<*str<<endl;   // abcdefghij;

Teraz, aby wydrukować następny ciąg, WYJDŹ z jednego dereferencja tzn. (*) od * str do str , a następnie inkrementacja, jak pokazano poniżej

str++;

Teraz Drukuj łańcuch

cout<<*str<<endl;        //xyzlmnopqr

Teraz, aby wydrukować tylko znaki w łańcuchu, patrz punkt c)

cout<<**str<<endl;  // prints the first character i.e "a"

Teraz wydrukować następny znak łańcucha tj." wyjście z 1 operatora dereferencyjnego i zwiększenie go tzn. przechodzenie z * * str do * str i do *str++

*str++;

Teraz wydrukuj znak

cout<<**str<<endl;  // prints the second character i.e "b"

Ponieważ dwie tablice ("abcdefghij"," xylmnopqr") są przechowywane w ciągłym bloku pamięć jeśli to samo zostanie zrobione przy zwiększaniu adresu, wszystkie znaki dwóch łańcuchów zostaną wydrukowane

 0
Author: Abhishek Karigar,
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-06-25 11:40:59