Puntatore di puntatore

di il
25 risposte

Puntatore di puntatore

Buonasera a tutti, sono nuovo nel forum e ho da poco iniziato a studiare il c all'università.
Ho un dubbio riguardo i puntatori.
Se io ho un array bidimensionale (che è un array i cui elementi puntano ad un altro array), il nome dell'array bidimensionale è il puntatore dell'array. Quindi se io ho
int b[][2] = {{1,2}.{3,4}} b è l'indirizzo dell'array che contiene i riferimenti agli altri due array.
Quindi teoricamente b dovrebbe essere un puntatore di un puntatore, giusto?

Se io faccio questa prova:
#include <stdio.h>

int main() {
    void prova(int**);

    int b[][2] = {{1,2}.{3,4}};
    prova(b);
    return 0;
}

void prova(int **a) {
    printf("%d\n", **a);
}

mi crasha. perchè?
se io scambio prova(b) (in main) direttamente con printf("%d\n", **b) mi stampa 1, eppure prova(int**) richiede un puntatore di un puntatore e io glielo dò appunto con b.

Mi date una mano? Vi ringrazio in anticipo

(mi scuso per eventuali cavolate che ho scritto)

25 Risposte

  • Re: Puntatore di puntatore

    No, in questo caso la matrice viene vista come un vettore in cui le varie righe si susseguono in memoria.
    Quindi b è assimilabile ad un semplice puntatore che devi utilizzare per accedere a tutti gli elementi in memoria.
    Del resto, un compilatore moderno, segnalerà il tuo programma come sbagliato perché non potrà passare b come doppio puntatore (non è un doppio puntatore).

    Altra storia è se dichiari b come doppio puntatore che punta ad un vettore di puntatori singoli, allocando dinamicamente lo spazio delle singole righe indipendentemente una dall'altra.
  • Re: Puntatore di puntatore

    Grazie per la risposta. Quindi nell'intestazione di un metodo se devo passargli un array bidimensionale, **a non avrebbe senso giusto?
    Un'altra cosa: ho ancora un dubbio riguardo quest'argomento

    Ho provato ad eseguire questo codice
    #include <stdio.h>
    
    int main() {
    
        int a[][2] = {{1,2}, {3, 4}};
    
        printf("%d\n", a);
        printf("%d\n", *a);
        printf("%d\n", **a);
    
        return 0;
    }
    
    Dunque, il primo printf è giusto che mi stampi un numero che è l'indirizzo dove punta a all'array. Stessa cosa mi fa con *a, e invece **a mi stampa il primo numero dell'array, ossia 1. Ma se a è un puntatore "semplice", e non puntatore di puntatore, non dovrebbe stamparmi già con *a ciò che è contenuto all'inizio dell'array, ossia 1, e con **a mi deve stampare il contenuto della cella di memoria all'indirizzo 1 (e quindi non la posizione 0 dell'array)?
  • Re: Puntatore di puntatore

    Il nome dell'array e il suo puntatore sono la stessa cosa. Se scrivi

    printf("%X %X\n", a, &a);

    otterrai lo stesso indirizzo.

    Quindi il nome NON è un doppio puntatore. Quei risultati che ottieni sono "falsati" dal modo in cui operi (ovvero sempre e solo sul primo elemento).
    Se a fosse un doppio puntatore, avresti modo di ottenere tutti i singoli puntatori ai vari elementi (1, 2, 3, 4) ma questi singoli puntatori non esistono.
    ... se devo passargli un array bidimensionale, **a non avrebbe senso giusto?
    Nel caso in questione no. Solo se usi un vero doppio puntatore, con l'allocazione dinamica, allora dovresti farlo.
  • Re: Puntatore di puntatore

    Quindi a punta al primo elemento dell'array?

    Scusa, ma continuo a fare prove su prove, ma non riesco a trovare un senso logico, perche anche se scrivo printf("%X %X\n", a, *a); mi stampa lo stesso indirizzo, teoricamente *a mi dovrebbe dare il contenuto di ciò a cui la variabile a punta
  • Re: Puntatore di puntatore

    gmgigi ha scritto:


    Quindi a punta al primo elemento dell'array?

    Scusa, ma continuo a fare prove su prove, ma non riesco a trovare un senso logico, perche anche se scrivo printf("%X %X\n", a, *a); mi stampa lo stesso indirizzo, teoricamente *a mi dovrebbe dare il contenuto di ciò a cui la variabile a punta
    C'è questo interessante thread che affronta proprio i dubbi che tu stai avendo :
    http://stackoverflow.com/questions/7351331/please-explain-the-ambiguity-in-pointers-in-c/7351390#7351390

    Inoltre c'è anche questo che affronta la stessa questione:
    http://stackoverflow.com/questions/7586702/is-2d-array-a-double-pointer

    Dacci uno sguardo, penso dopo ti saranno chiare molte più cose

    N.B : la risposta che dovrebbe risolvere tutti i tuoi dubbi è proprio questa data nel primo link che ti ho passato:

    Arrays, when used as arguments to functions, decay into pointers to the first element of the array. [...]. When you call printf("%d\n",*x), you are not feeding an integer value to printf, but rather a pointer to the first sub-array of x. Since that sub-array will also decay to a pointer to the first sub-array's element, you can do **x to dereference that subsequent pointer and get at the first element of the first sub-array of x. This is effectively the same thing as *x[0], which by operator precedence will index into the first sub-array of x, and then dereference the pointer to the first sub-array's element that the first sub-array will decay into.

    Io non avrei saputo spiegarlo meglio
  • Re: Puntatore di puntatore

    Ok grazie, penso di aver capito. Mi rimane forse l'ultimo dubbio. Come faccio a passare un array bidimensionale (tipo int a[][2] = {{1,2}, {3, 4}}) ad una funzione del tipo funzione(int **a) ?

    Gli dovrei dare l'indirizzo del primo elemento? Quindi &a[0][0]?
  • Re: Puntatore di puntatore

    gmgigi ha scritto:


    Ok grazie, penso di aver capito. Mi rimane forse l'ultimo dubbio. Come faccio a passare un array bidimensionale (tipo int a[][2] = {{1,2}, {3, 4}}) ad una funzione del tipo funzione(int **a) ?

    Gli dovrei dare l'indirizzo del primo elemento? Quindi &a[0][0]?
    Dichiara la funzione come prova(int* a); e poi chiama prova(a[0]);. Dentro la funzione prova puoi usare a così:
    
    void prova(int *a){
    
    	for (int i = 0; i < 4; ++i)
    	printf("%d\n", *(a + i));  //oppure a[i]
    }
    Per fare una cosa generica, potresti passare anche la dimensione a prova. Diciamo che in questo modo è come se la tua matrice diventa un'unica riga dove la prima riga è concatenata alla seconda.

    Detto in altri termini:
    //prima di chiamare prova
    a:	
    1 2 //prima riga 
    3 4 //seconda riga
    	
    in questo caso : 
    a[0][1] == 2
    a[1][0] == 3
    				
    //dopo ave chiamato prova la matrice la devi vedere come se fosse stata "linearizzata"
    a: 1 2 3 4
    in questo caso : 
    *(a + 1) == 2 == a[1]
    *(a + 2) == 3 == a[2] 
    
  • Re: Puntatore di puntatore

    Il problema è che nella funzione l'array glielo devo passare con **a, così mi chiede l'esercizio
  • Re: Puntatore di puntatore

    Prepara un doppio puntatore

    int **a;

    e poi usalo per allocare dinamicamente l'array
  • Re: Puntatore di puntatore

    gmgigi ha scritto:


    il problema è che nella funzione l'array glielo devo passare con **a, così mi chiede l'esercizio
    L'esercizio ti specifica come allocare la matrice ?
  • Re: Puntatore di puntatore

    Perfetto funziona grazie, l'ultimissima domanda: mi ricollego a quello che ha scritto CarDeFusco, perchè prima di chiamare prova la matrice è una matrice, quindi io per accedere agli elementi devo fare *(*(a+i)+j) che corrisponde a a[j], mentre dopo la devo considerare "linearizzata"? Perchè se la considero linearizzata prima di passarla alla funzione prova, non funziona quel "giochetto" dei puntatore, ossia *(a+i).

    CarDeFusco ha scritto:


    gmgigi ha scritto:


    il problema è che nella funzione l'array glielo devo passare con **a, così mi chiede l'esercizio


    L'esercizio ti specifica come allocare la matrice ?


    No mi dice che ho solo una matrice di interi a
  • Re: Puntatore di puntatore

    gmgigi ha scritto:


    Perfetto funziona grazie, l'ultimissima domanda: mi ricollego a quello che ha scritto CarDeFusco, perchè prima di chiamare prova la matrice è una matrice, quindi io per accedere agli elementi devo fare *(*(a+i)+j) che corrisponde a a[j], mentre dopo la devo considerare "linearizzata"? Perchè se la considero linearizzata prima di passarla alla funzione prova, non funziona quel "giochetto" dei puntatore, ossia *(a+i).

    CarDeFusco ha scritto:


    gmgigi ha scritto:


    il problema è che nella funzione l'array glielo devo passare con **a, così mi chiede l'esercizio


    L'esercizio ti specifica come allocare la matrice ?


    No mi dice che ho solo una matrice di interi a


    E allora sei libero di dichiararla come vuoi. Come ti suggeriva oregon, allocala dinamicamente. A quel punto puoi usare il doppio puntatore **a.

    Nella funzione puoi usarla come se fosse linearizzata perché nella funzione prova hai dichiarato come parametro un int *a, fuori è un int a[][2], cambia la dichiarazione, e quindi devi interpretarla diversamente.
  • Re: Puntatore di puntatore

    Ok grazie, e per quanto riguarda l'altra domanda?
  • Re: Puntatore di puntatore

    gmgigi ha scritto:


    Ok grazie, e per quanto riguarda l'altra domanda?
    Ho editato la risposta sopra
Devi accedere o registrarti per scrivere nel forum
25 risposte