Qual è un buon modo per spiegare la necessità di puntare a un puntatore?

6

Capire cos'è un puntatore (un indirizzo), è abbastanza facile e un bambino di undici anni può capirlo. Ma come possiamo esprimere il motivo per cui abbiamo bisogno di un puntatore a un puntatore? qual è un esempio molto pedagogico? Si estende a puntare a un puntatore a un puntatore (e / o avanti)?

Esempio di problema

T[][] does not decay to a T**

Esempio di problema 2

brainfuck command   C equivalent
(Program Start) char array[30000];
                char *ptr=array;
>   ++ptr;
<   --ptr;
+   ++*ptr;
-   --*ptr;
.   putchar(*ptr);
,   *ptr=getchar();
[   while (*ptr) {
]   }
    
posta Niklas Rosencrantz 03.02.2013 - 06:59
fonte

4 risposte

7

Un puntatore ti consente di parlare di alcune informazioni senza specificarle esplicitamente:

  • il valore in posizione 0x007d32f8
  • la casa in 105 West Street

Un puntatore a un puntatore ti consente di parlare della posizione di qualcosa senza specificare esplicitamente tale posizione:

  • l'indirizzo nella posizione 0x012a0052
  • l'indirizzo indicato sul mio biglietto da visita

Un uso pratico e intuitivo dei puntatori ai puntatori è quando vuoi qualche altra funzione o metodo per darti un puntatore a qualche dato. Invece di chiedere i dati a priori (dopotutto potrebbe essere molto grande) puoi invece chiedere semplicemente l'indirizzo dei dati. Puoi dire: ecco l'indirizzo di un puntatore che vorrei che tu cambiasse in modo che punti ai dati che voglio. Per usare l'analogia con l'indirizzo stradale, è come dire al tuo amico:

Scrivi il tuo indirizzo di casa su questo blocco note.

La frase "questo blocco note" specifica la posizione di uno spazio di archiviazione specifico, quindi è come un puntatore. Una volta che l'indirizzo è stato scritto, è come un puntatore a casa del tuo amico.

Un altro esempio comune di puntatore a un puntatore (indicato nel commento di Brian) sono gli array multidimensionali. In C, ad esempio, una stringa è una matrice di caratteri con terminazione nulla e una variabile stringa è solo un puntatore al primo elemento dell'array. Se si desidera creare una serie di stringhe, è necessario creare una serie di puntatori, ognuno dei quali punta a una stringa diversa. Se si desidera una matrice bidimensionale di stringhe, è possibile ripetere il processo e creare una matrice di matrici di stringhe.

Essere in grado di parlare degli indirizzi consente un'espressione più sofisticata, sia nel codice che nel mondo reale.

    
risposta data 04.02.2013 - 18:10
fonte
7

Sometimes called a Handle, Windows and the Mac OS use this structure to allow memory compaction on the heap. The program manages the pointer p, while the operating system manages the pointer *p. Because the OS manages *p, the block pointed to by p (*p) can be moved, and *p can be changed to reflect the move without affecting the program using p. Pointers to pointers are also frequently used in C to handle pointer parameters in functions.

link

    
risposta data 03.02.2013 - 07:22
fonte
4

Se si dispone di un puntatore e si desidera chiamare una funzione che modifica il puntatore, è necessario indicare la funzione in cui è memorizzato il puntatore. Per indicare la funzione in cui è memorizzato, è necessario ottenere l'indirizzo del puntatore, che è un puntatore a un puntatore

int foo(const char **error_message)
{
    if (!bar())
    {
        // The type of error_message is const char ** (the parameter)
        // The type of *error_message is const char * (the caller's msg)
        // The type of **error_message is const char ('N' from "No error")

        // Note here, I have a * before error_message, it changes the callers msg
        // *error_message is the caller's msg variable
        // reading or writing *error_message will read/write msg
        // before this line executes, msg points to the first character of "No error"
        // after this line, msg points first character of "bar failed"
        *error_message = "bar failed";
        return -2;
    }

    return 0;
}

int main()
{
    // make a variable 'msg' and point it to the first character of "No error"
    const char *msg = "No error";

    // Get the address of 'msg' and pass it to foo.
    // '&msg' is a pointer to 'msg' (which happens to be a pointer).
    int status = foo(&msg);

    // foo could have modified msg, since it knew the address of msg
    if (status < 0 && msg != 0)
       printf("%s\n", msg);
}

Nel mio esempio, il chiamante deve passare un puntatore a msg (un puntatore a un puntatore) così foo può impostarlo in modo che punti al messaggio di errore.

L'idea è la stessa di qualsiasi utilizzo di un puntatore. Se si desidera che una parte di codice sia in grado di leggere o scrivere su indirizzi arbitrari, si passa un puntatore. Un puntatore a un puntatore, punta semplicemente a un puntatore.

    
risposta data 03.02.2013 - 08:46
fonte
1

Che cosa significa che un puntatore è un indirizzo? Significa che si riferisce a una posizione di memoria in cui è memorizzato il valore che punta a, in genere una variabile. Quando dici che un puntatore punta a qualcosa , intendi davvero un puntatore che punta a una variabile qualcosa .

Questa variabile può contenere un int, ma può anche contenere un altro puntatore. Quindi, più correttamente, hai un puntatore a una variabile puntatore. Ciò semplifica la spiegazione: è necessario un puntatore a una variabile puntatore per gli stessi motivi per cui è necessario un puntatore a una variabile intera.

Un puntatore a un puntatore non esiste come tipo proprio. Se hai questo:

int **p;

then p ist è ancora un puntatore a livello singolo. Non leggerlo in questo modo:

int (**)p;  // wrong

ma come questo:

(int *) *p;  // correct

perché è un puntatore a un'altra variabile puntatore che contiene un puntatore a una variabile int.

int i = 125;
int *p1 = &i;
int **p2 = &p1;

Address     Value
0x10000000  [0x20000000]  p2 
0x20000000  [0x30000000]  p1
0x30000000  [125]         i

EDIT:

Se trovi ancora questo confuso, non provare a pensare al puntatore all'infinito. Funziona in C semplice, è un comportamento completamente indefinito (e quindi cattivo ) e richiede sizeof(unsigned int) == sizeof(unsigned int *) . Ma poi funziona con qualsiasi quantità di * del supporto del compilatore.

unsigned int **********p;

p = (void *)&p;

printf("%x\n", **********p);
printf("%p\n", (void *)p);
    
risposta data 09.02.2013 - 09:35
fonte

Leggi altre domande sui tag