[C] Informazione esempio sui puntatori
Ciao a tutti 
Sono sempre alle prese con lo studio del codice c sul libro Deitel & Deitel, però non mi è ben chiara la differenza nell'utilizzo dell'operatore commerciale & rispetto all'asterisco * nell'ambito dei puntatori.
Prendiamo ad esempio questo codice riguardante l'ordinamento di un vettore utilizzando la bubblesort e la funzione swap.
Quello che non riesco a capire è come mai che nella riga 42
Utilizzo l'operatore & al posto dell'asterisco, e perché nella funzione swap (righe 61 a 63)
Utilizzo l'asterisco!
Se non ho capito male con l'operatore & vado a dire che il puntatore punta ad una determinata variabile, e quindi punta al suo indirizzo in memoria, mentre quando utilizzo l'asterisco allora io richiamo il valore che ha la variabile puntata.
Sul libro dicono che devo procedere in questo modo perché alla funzione swap non è consentito conoscere il nome di array a causa dell'incapsulamento delle informazioni, però non mi è ben chiaro lo stesso quando posso utilizzare la &!
Grazie in anticipo
Buona serata
Ciaoo

Sono sempre alle prese con lo studio del codice c sul libro Deitel & Deitel, però non mi è ben chiara la differenza nell'utilizzo dell'operatore commerciale & rispetto all'asterisco * nell'ambito dei puntatori.
Prendiamo ad esempio questo codice riguardante l'ordinamento di un vettore utilizzando la bubblesort e la funzione swap.
#include <stdio.h> #define SIZE 10 void bubbleSort (int * const array, const int size); int main () { int a[SIZE] = {2,6,4,8,10,12,89,68,45,37}; int i; printf("Elementi originali non ordinati: \n"); for (i=0;i<SIZE;i++) { printf("%4d", a[i]); } bubbleSort (a,SIZE); printf("\nElementi ordinati in modo acendente:\n"); for (i=0;i<SIZE;i++) { printf("%4d", a[i]); } return 0; } void bubbleSort (int * const array, const int size) { void swap (int *element1ptr, int *element2ptr); int pass, j; { for (pass=1;pass<size-1;pass++) { for (j=0;j<size-1;j++) { if (array[j]>array[j+1]) { swap (&array[j], &array[j+1]); } } } } } void swap (int *element1ptr, int *element2ptr) { int hold = *element1ptr; *element1ptr=*element2ptr; *element2ptr=hold; }
Quello che non riesco a capire è come mai che nella riga 42
swap (&array[j], &array[j+1]);
Utilizzo l'operatore & al posto dell'asterisco, e perché nella funzione swap (righe 61 a 63)
void swap (int *element1ptr, int *element2ptr) { int hold = *element1ptr; *element1ptr=*element2ptr; *element2ptr=hold; }
Utilizzo l'asterisco!
Se non ho capito male con l'operatore & vado a dire che il puntatore punta ad una determinata variabile, e quindi punta al suo indirizzo in memoria, mentre quando utilizzo l'asterisco allora io richiamo il valore che ha la variabile puntata.
Sul libro dicono che devo procedere in questo modo perché alla funzione swap non è consentito conoscere il nome di array a causa dell'incapsulamento delle informazioni, però non mi è ben chiaro lo stesso quando posso utilizzare la &!
Grazie in anticipo
Buona serata
Ciaoo

Risposte
L'operatore & richiama l'indirizzo di una variabile. Mentre * richiama il valore che è memorizzato ad un particolare indirizzo. Un puntatore è una variabile che ha come valore l'indirizzo di una variabile. In questo senso i due operatori sono l'uno l'inverso dell'altro.
Considera un hotel che ha 200 stanze. Una variabile è, per esempio, il cognome di una persona che dorme in hotel. Un puntatore è il numero della stanza (nella realtà anche il puntatore occupa una stanza!). L'operatore & è quindi da interpretare come “Il cognome della persona che dorme nella stanza X”. L'operatore * è invece “Il numero della stanza a cui dorme la persona Y”. Un array vedilo come una scolaresca.
Vi sono comunque dei legami tra array e puntatori, tanto che ogni tanto si considerano intercambiabili. In particolare array[j] si può anche scrivere come *(array + j) e &array[j] come array+j.
Considera un hotel che ha 200 stanze. Una variabile è, per esempio, il cognome di una persona che dorme in hotel. Un puntatore è il numero della stanza (nella realtà anche il puntatore occupa una stanza!). L'operatore & è quindi da interpretare come “Il cognome della persona che dorme nella stanza X”. L'operatore * è invece “Il numero della stanza a cui dorme la persona Y”. Un array vedilo come una scolaresca.
Vi sono comunque dei legami tra array e puntatori, tanto che ogni tanto si considerano intercambiabili. In particolare array[j] si può anche scrivere come *(array + j) e &array[j] come array+j.
Ciao!
Grazie mille per la spiegazione
Ora mi torna tutto, quindi nella funzione void swap alla riga 51 utilizzo l'asterisco perché voglio sapere il valore dell'elemento puntato da &array[j].
E' per quello che li utilizza l'asterisco e non la & commerciale, perché prima mi punta al valore della memoria e poi prende il suo contenuto!
Perfetto ora ci sono!
Grazie mille
Ciaoo!
Grazie mille per la spiegazione

Ora mi torna tutto, quindi nella funzione void swap alla riga 51 utilizzo l'asterisco perché voglio sapere il valore dell'elemento puntato da &array[j].
E' per quello che li utilizza l'asterisco e non la & commerciale, perché prima mi punta al valore della memoria e poi prende il suo contenuto!
Perfetto ora ci sono!

Grazie mille

Ciaoo!
Esatto floppyes, hai capito benissimo
!
Peraltro bisogna stare molto attenti al significato di * poiché questo è utilizzato sia unitamente assieme ai tipi "standard" (int, double, float, ecc) per indicare il tipo di una variabile puntatore (int*, double*, float*, ecc) ma anche, come avete giustamente detto, per dereferenziare l'indirizzo di una variabile (di tipo puntatore appunto) recuperandone il valore. Sicuramente avrete visto il diverso comportamento rispetto a quando si agisce nello stack e nell'heap. Questo doppio utilizzo di * in base a dove è posta francamente l'ho sempre criticato proprio perché all'inizio può trarre molto in confusione. Fossi stato nei creatori nel C avrei adottato due diverse simbologie per queste situazioni.
Esattamente, è la cosiddetta aritmetica dei puntatori che, se usata nella maniera corretta, permette di eseguire gli accessi mediante una scrittura più semplice.

Peraltro bisogna stare molto attenti al significato di * poiché questo è utilizzato sia unitamente assieme ai tipi "standard" (int, double, float, ecc) per indicare il tipo di una variabile puntatore (int*, double*, float*, ecc) ma anche, come avete giustamente detto, per dereferenziare l'indirizzo di una variabile (di tipo puntatore appunto) recuperandone il valore. Sicuramente avrete visto il diverso comportamento rispetto a quando si agisce nello stack e nell'heap. Questo doppio utilizzo di * in base a dove è posta francamente l'ho sempre criticato proprio perché all'inizio può trarre molto in confusione. Fossi stato nei creatori nel C avrei adottato due diverse simbologie per queste situazioni.
"vict85":
[...]
Vi sono comunque dei legami tra array e puntatori, tanto che ogni tanto si considerano intercambiabili. In particolare array[j] si può anche scrivere come *(array + j) e &array[j] come array+j.
Esattamente, è la cosiddetta aritmetica dei puntatori che, se usata nella maniera corretta, permette di eseguire gli accessi mediante una scrittura più semplice.
Se tu scrivi
Risulta in questo senso utile far notare il comportamento di const relativo alla dichiarazione di una variabile puntatore.
Che differenze ci sono tra queste cinque dichiarazioni/inizializzazioni?
Per prima cosa
Venendo al resto di ha che usando la frase che ho usato prima si ricava che la prima è “un puntatore costante che punta ad una variabile costante di tipo intero”. Il terzo è un puntatore costante mentre il quarto è un puntatore a un intero costante.
Questo significa che nel primo caso ptr dovrà puntare sempre allo stesso indirizzo e non potrà modificare direttamente il valore da lui puntato — ma può passarlo a qualcos'altro che lo può fare!
Nel terzo caso può modificare il valore da lui puntato ma rimarrà legato ad una particolare variabile per tutta la durata della sua vita.
Nel quarto caso invece può cambiare indirizzo quando vuole ma non può modificare ciò a cui punta (a meno di passarlo a qualcos'altro che può farlo).
---------------------------------------------------------
Per la cronaca penso che Deintel e Deintel, come molti altri, siano rimasti a qualche standard C indietro. Gli ultimi standard permettono di definire variabili dove si vuole, in particolare puoi scrivere
int * ptr, non_ptr;stai creando un puntatore e un intero, non due interi. L'asterisco è legato alla variabile e non al tipo. Quindi a rigore l’asterisco continua a significare “la variabile puntata da ...”. Nel caso specifico di
int * ptr;andrebbe letta come la “la variabile puntata da ptr è un int”.
Risulta in questo senso utile far notare il comportamento di const relativo alla dichiarazione di una variabile puntatore.
Che differenze ci sono tra queste cinque dichiarazioni/inizializzazioni?
int const * const ptr = &i; const int * const ptr = &i; int * const ptr = &i; int const * ptr = &i; const int * ptr = &i;
Per prima cosa
const inte
int constsono la stessa cosa. Quindi riga 1 = riga 2 e riga 4 = riga 5.
Venendo al resto di ha che usando la frase che ho usato prima si ricava che la prima è “un puntatore costante che punta ad una variabile costante di tipo intero”. Il terzo è un puntatore costante mentre il quarto è un puntatore a un intero costante.
Questo significa che nel primo caso ptr dovrà puntare sempre allo stesso indirizzo e non potrà modificare direttamente il valore da lui puntato — ma può passarlo a qualcos'altro che lo può fare!
Nel terzo caso può modificare il valore da lui puntato ma rimarrà legato ad una particolare variabile per tutta la durata della sua vita.
Nel quarto caso invece può cambiare indirizzo quando vuole ma non può modificare ciò a cui punta (a meno di passarlo a qualcos'altro che può farlo).
---------------------------------------------------------
Per la cronaca penso che Deintel e Deintel, come molti altri, siano rimasti a qualche standard C indietro. Gli ultimi standard permettono di definire variabili dove si vuole, in particolare puoi scrivere
for(int i = 0; i != size; ++i)e cose del genere. Io sinceramente trovo sia meglio perché evita il riuso delle variabili e fa comprendere bene lo scopo di ogni variabile.
Ciao!
Scusa il ritardo ma ho letto ora la risposta
Grazie mille adesso mi torna tutto quanto, vedo di fare altri esercizi del genere ma con tutta la spiegazione ora è più chiaro
Grazie
Ciaoo
Scusa il ritardo ma ho letto ora la risposta

Grazie mille adesso mi torna tutto quanto, vedo di fare altri esercizi del genere ma con tutta la spiegazione ora è più chiaro

Grazie
Ciaoo
