A cosa servono i puntatori? [c/c++]
Mi chiedo a cosa servano i puntatori. Per esempio se ho
Avrei potuto scrivere x=0. Ora è chiaro che vengono usati per altre cose... Quali?
int x; int* puntax; *puntax=0;
Avrei potuto scrivere x=0. Ora è chiaro che vengono usati per altre cose... Quali?
Risposte
Ciao,
un possibile utilizzo dei puntatori è quello del passaggio per riferimento anziché per valore.
Per chiarirti le idee prova a guardare (ed eseguire) questo codice:
un possibile utilizzo dei puntatori è quello del passaggio per riferimento anziché per valore.
Per chiarirti le idee prova a guardare (ed eseguire) questo codice:
#include <stdio.h> #include <stdlib.h> void aumenta_num(int num) { num++; } void aumenta_punt(int *punt) { (*punt)++; } int main() { int num; /* alloco un puntatore a intero */ int *punt = malloc(sizeof(int)); /* imposto i valori iniziali */ num = 0; (*punt) = 0; printf("num = %d\n", num); printf("*punt = %d\n", (*punt)); /* questo incremento NON avra' effetto: sto passando * solo una copia del valore */ aumenta_num(num); /* questo invece avra' effetto: sto passando un * riferimento all'area di memoria occupata dall'intero */ aumenta_punt(punt); printf("num = %d\n", num); printf("*punt = %d\n", (*punt)); /* anche questo avra' effetto: con il simbolo & ottengo * il riferimento all'area di memoria */ aumenta_punt(&num); printf("num = %d\n", num); return 0; }

ciao. ho provato a far partire il codice ma non gira. Che librerie devo includere?
Nessuna, e ti assicuro che il codice è corretto. Dove e come lo hai compilato?
Servono per dare la possibilità al programmatore di lavorare con la memoria dinamica (heap) anziché solo ed esclusivamente con quella statica (stack). In tal modo lo "scope", ossia la visibilità, di una variabile non è più legata alla parte di programma (blocco) in cui è presente (locale all'interno di una funzione ad esempio) ed al di fuori della quale cessa automaticamente di esistere ma all'esplicita nascita e morte della stessa (operazioni che possono essere effettuate dall'utente mediante le apposite istruzioni di allocazione/deallocazione).
Gli esempi classici che possono essere fatti sono, oltre a quello proposto da minomic, quello in cui hai una funzione per scambiare il contenuto di due variabili (supponiamo per semplicità intere ma vale in generale). Passando gli argomenti per valore (ergo non utilizzando i puntatori) una volta che termina la funzione si ritornano ad avere i medesimi valori delle stesse e non quelli scambiati.
Spero di esserti stato d'aiuto.
Gli esempi classici che possono essere fatti sono, oltre a quello proposto da minomic, quello in cui hai una funzione per scambiare il contenuto di due variabili (supponiamo per semplicità intere ma vale in generale). Passando gli argomenti per valore (ergo non utilizzando i puntatori) una volta che termina la funzione si ritornano ad avere i medesimi valori delle stesse e non quelli scambiati.
Spero di esserti stato d'aiuto.
mi segna errore alla riga 21 (quella di malloc)
invalid conversion from `void*' to `int*'
Per rispondere alla domanda "a cosa servono i puntatori", ti faccio un esempio in cui prendo spunto in modo abbastanza leggero e spensierato dal lavoro.
Supponi di avere un database dove memorizzi i dati di tanti utenti. Fa' finta che in questi dati ci sia memorizzata anche una via, per esempio la via dove questi utenti risiedono, abitano, lavorano, ... quello che ti pare.
Ad ogni utente corrisponde un vettore/una riga di una tabella con tutte le sue informazioni tra cui questa benedetta via.
Ammettiamo - e non capita di rado - che questa via cambi nome. Per es, supponiamo che Zichichi arrivi a 100 anni[nota]Ho preso a caso il nome di uno scienziato non proprio giovanissimo![/nota] e la via che prima si chiamava "via del sole che tramonta" viene chiamata "via Zichichi".
- Se ogni utente aveva memorizzato "manualmente" come via "via del sole che tramonta", la persona si mette le mani nei capelli e modifica manualmente ogni utente che ha quell'informazione, aggiornandola.
- Se nella riga dedicata ad ogni utente, nel campo che indica la via, c'è un puntatore che punta ad una tabella nelle cui righe sono memorizzate le vie, all'aggiornamento della via (presente nella riga specifica), automaticamente tutti quelli che abitano lì si trovano la via aggiornata perché il puntatore "punta" alla posizione in cui è presente quella via.
Ammetti di avere migliaia di utenti.
Il risultato è che nel primo caso si perde un botto di tempo per cercarli tutti - non so un tubo di query quindi magari qualcuno mi smentisce
- e modificarli uno ad uno. Nel secondo caso basta modificare la posizione originale perché il puntatore punta a quella e fa trovare il dato aggiornato. 
Dimenticavo. Dire tabella o matrice, oppure vettore o riga non cambia granché...
Supponi di avere un database dove memorizzi i dati di tanti utenti. Fa' finta che in questi dati ci sia memorizzata anche una via, per esempio la via dove questi utenti risiedono, abitano, lavorano, ... quello che ti pare.
Ad ogni utente corrisponde un vettore/una riga di una tabella con tutte le sue informazioni tra cui questa benedetta via.
Ammettiamo - e non capita di rado - che questa via cambi nome. Per es, supponiamo che Zichichi arrivi a 100 anni[nota]Ho preso a caso il nome di uno scienziato non proprio giovanissimo![/nota] e la via che prima si chiamava "via del sole che tramonta" viene chiamata "via Zichichi".
- Se ogni utente aveva memorizzato "manualmente" come via "via del sole che tramonta", la persona si mette le mani nei capelli e modifica manualmente ogni utente che ha quell'informazione, aggiornandola.
- Se nella riga dedicata ad ogni utente, nel campo che indica la via, c'è un puntatore che punta ad una tabella nelle cui righe sono memorizzate le vie, all'aggiornamento della via (presente nella riga specifica), automaticamente tutti quelli che abitano lì si trovano la via aggiornata perché il puntatore "punta" alla posizione in cui è presente quella via.
Ammetti di avere migliaia di utenti.
Il risultato è che nel primo caso si perde un botto di tempo per cercarli tutti - non so un tubo di query quindi magari qualcuno mi smentisce


Dimenticavo. Dire tabella o matrice, oppure vettore o riga non cambia granché...

"kobeilprofeta":
mi segna errore alla riga 21 (quella di malloc)
invalid conversion from `void*' to `int*'
Sostituisci la riga con
int *punt = (int *) malloc(sizeof(int));
e non dovrebbe più darti errore.
Rispondendo alla domanda iniziale trovo che l’importanza dei puntatori si traduca nel fatto che, per come è stato pensato il C, ci sono cose che puoi fare solo con loro. Insomma, senza il loro uso non puoi usare una variabile al di fuori del suo scopo, né creare memoria dinamicamente[nota]Nel C ci sono i VLA, nel C++ ci sono smart pointer e i reference che possono sostituire i puntatori in determinate condizioni. Ma a parte i reference direi che gli altri possono essere ignorati da un neofita.[/nota].
In alcuni casi usare i puntatori è più facile di scrivere lo stesso codice usando gli indici. Potenzialmente anche più efficiente ma in realtà qualsiasi compilatore è capace di ridurre a zero il vantaggio di questo tipo di ottimizzazione (insomma è capace di fare questa ottimizzazione da solo).
In alcuni casi usare i puntatori è più facile di scrivere lo stesso codice usando gli indici. Potenzialmente anche più efficiente ma in realtà qualsiasi compilatore è capace di ridurre a zero il vantaggio di questo tipo di ottimizzazione (insomma è capace di fare questa ottimizzazione da solo).
Hai detto bene, Zero87, l'esempio direi che calza a pennello
:


Grazie a tutti per l'aiuto. Rispondo ad uno per volta.
@onlyReferee
Perchè senza i puntatori quando termina la funzione i valori tornano come prima? E che problemi mi puó dare?
@Zero87
Con l'esempio della via non ho capito perchè non posso fare una cosa del genere:
Faccio un vettore di stringhe, diciamo utente[10], dove in ogni posto c'è un dato, esempio utente[1] il nome, utente[2] il cognome, ..., utente [9] la via. Poi faccio if (utente[9]='via sbagliata') {utente[9]='via giusta';}.
Cosa cambierebbe con i puntatori in questo caso?
ps: non considerare che il vettore dovrebbe avere due dimensioni (una per i dati e una per le varie persone, cioè persona i, dato j). In poche parole nel mio esempio considero una sola persona.
@vict85
Al momento non ho il computer, appena posso ti dico. Comunque grazie.
@tutti
Comunque abbiate pazienza se non capisco alcune cose perchè mi mancano dei concetti (esempio memoria statica e dinamica).
@onlyReferee
Perchè senza i puntatori quando termina la funzione i valori tornano come prima? E che problemi mi puó dare?
@Zero87
Con l'esempio della via non ho capito perchè non posso fare una cosa del genere:
Faccio un vettore di stringhe, diciamo utente[10], dove in ogni posto c'è un dato, esempio utente[1] il nome, utente[2] il cognome, ..., utente [9] la via. Poi faccio if (utente[9]='via sbagliata') {utente[9]='via giusta';}.
Cosa cambierebbe con i puntatori in questo caso?
ps: non considerare che il vettore dovrebbe avere due dimensioni (una per i dati e una per le varie persone, cioè persona i, dato j). In poche parole nel mio esempio considero una sola persona.
@vict85
Al momento non ho il computer, appena posso ti dico. Comunque grazie.
@tutti
Comunque abbiate pazienza se non capisco alcune cose perchè mi mancano dei concetti (esempio memoria statica e dinamica).
Supponi di avere un array di char multidimensionale del tipo nomi[N][2][15] che contenga nomi e cognomi di N persone (ho posto 15 come limite della dimensione di nomi e cognomi). Supponi di volerti assicurare che i nomi e i cognomi inizino tutti con una lettera maiuscola. Puoi senz'altro fare il codice:
ma usando i puntatori puoi scrivere
sfruttando il modo in cui un array multidimensionale è memorizzato in memoria.
for(int i=0; i != N; ++i) for(int j=0; j != 2; ++j) { char const c = nomi[i][j][0]; nomi[i][j][0] = toupper(c); }
ma usando i puntatori puoi scrivere
{ char const * const c_end = nomi + N*2*15; for(char * c = nomi; c < c_end; c += 15) *c = toupper(*c); }
sfruttando il modo in cui un array multidimensionale è memorizzato in memoria.
"kobeilprofeta":
Con l'esempio della via non ho capito perchè non posso fare una cosa del genere:
Faccio un vettore di stringhe, diciamo utente[10], dove in ogni posto c'è un dato, esempio utente[1] il nome, utente[2] il cognome, ..., utente [9] la via. Poi faccio if (utente[9]='via sbagliata') {utente[9]='via giusta';}.
Cosa cambierebbe con i puntatori in questo caso?
ps: non considerare che il vettore dovrebbe avere due dimensioni (una per i dati e una per le varie persone, cioè persona i, dato j). In poche parole nel mio esempio considero una sola persona.
Non puoi confrontare stringhe in quel modo e le stringhe sono segnate usando " e non '. Insomma il tuo codice non funziona.
"vict85":
Supponi di avere un array di char multidimensionale del tipo nomi[N][2][15] che contenga nomi e cognomi di N persone (ho posto 15 come limite della dimensione di nomi e cognomi). Supponi di volerti assicurare che i nomi e i cognomi inizino tutti con una lettera maiuscola. Puoi senz'altro fare il codice:
for(int i=0; i != N; ++i) for(int j=0; j != 2; ++j) { char const c = nomi[i][j][0]; nomi[i][j][0] = toupper(c); }
ma usando i puntatori puoi scrivere
{ char const * const c_end = nomi + N*2*15; for(char * c = nomi; c < c_end; c += 15) *c = toupper(*c); }
sfruttando il modo in cui un array multidimensionale è memorizzato in memoria.
Hai usato la fantastica aritmetica dei puntatori, vic85


"kobeilprofeta":
Grazie a tutti per l'aiuto. Rispondo ad uno per volta.
@onlyReferee
Perchè senza i puntatori quando termina la funzione i valori tornano come prima? E che problemi mi puó dare?
[...]
Rispondo giustamente alla parte in cui sono "chiamato in causa"
