[C] Dubbio puntatori
Buonasera sto approfondendo i puntatori, sto iniziando ad intuire le potenzialità super affascinanti di come posso evitare di sovradimensionare matrici, passare parametri, manipolare strutture dati ed altro.. però leggendo il libro ho trovato due piccoli esempi che mi hanno completamente resettato tutto quello che ho capito sugli indirizzi e operatori.
Il primo esempio, molto chiaro sarebbe: (dentro il main eh)
Dove si vede che: a e *aPtr cioè il contenuto della cella puntata dal puntatore stampano lo stesso risultato in quanto stiamo parlando dello stesso contenuto mentre &a e aPtr stampano l'indirizzo proprio perché "dentro" il puntatore si ha l'indirizzo.
Il problema sta nell'esempio 2 quando spiega il passaggio per riferimento:
Ma se la funzione si aspetta un puntatore, perché non passo un puntatore ma un indirizzo? Cioè ho capito che il puntatore al suo interno ha salvato l'indirizzo di una variabile e di conseguenza punta a quella.. ma quando noi abbiamo una funzione che si aspetta int N gli do un numero int non altro.. spero di essermi spiegato.. probabilmente è una cavolata ma proprio non riesco a trovare un motivo: perché oltre numero non si dichiara un puntatore che punta a numero e passa quello?
Inoltre, da quello che ho capito (ormai ho messo tutto in dubbio
) il linguaggio C non prevede il passaggio per riferimento ma solo per valori..Allora quando noi usiamo i puntatori non è per riferimento (?) ma nemmeno per valore, come lo definiamo? stiamo praticamente raggirando il C?!
Grazie in anticipo per le vostre eventuali e pazienti risposte
Il primo esempio, molto chiaro sarebbe: (dentro il main eh)
int a; int *aPtr; //aPtr e' un puntatore a un intero a=7; aPtr=&a; //imposta aPtr all'indirizzo di a printf ("%p %p", &a, aPtr); printf("%d %d", a, *aPtr); }
Dove si vede che: a e *aPtr cioè il contenuto della cella puntata dal puntatore stampano lo stesso risultato in quanto stiamo parlando dello stesso contenuto mentre &a e aPtr stampano l'indirizzo proprio perché "dentro" il puntatore si ha l'indirizzo.
Il problema sta nell'esempio 2 quando spiega il passaggio per riferimento:
#include <stdio.h> void cubeByReference (int *nPtr); int main(void){ int numero=5; cubeByReference(&numero); } void cubeByReference (int *nPtr){ *nPtr=*nPtr* *nPtr * *nPtr; }
Ma se la funzione si aspetta un puntatore, perché non passo un puntatore ma un indirizzo? Cioè ho capito che il puntatore al suo interno ha salvato l'indirizzo di una variabile e di conseguenza punta a quella.. ma quando noi abbiamo una funzione che si aspetta int N gli do un numero int non altro.. spero di essermi spiegato.. probabilmente è una cavolata ma proprio non riesco a trovare un motivo: perché oltre numero non si dichiara un puntatore che punta a numero e passa quello?
Inoltre, da quello che ho capito (ormai ho messo tutto in dubbio

Grazie in anticipo per le vostre eventuali e pazienti risposte
Risposte
La frase
Il C passa tranquillamente oggetti per riferimento (in realtà non possiede il tipo reference, ma in un certo senso un reference è soltanto un particolare tipo di puntatore). Quando tu passi qualcosa per riferimento, tu stai passando alla funzione l'indirizzo in memoria di quel particolare oggetto. In C questo procedimento richiede una operazione esplicita da parte del programmatore. Questo non è vero invece in altri linguaggi. L'unica eccezione a questo, nel C, è data dagli array che sono sempre passati per riferimento.
Detto questo ogni cosa che viene passata ad una funzione occupa una particolare locazione di memoria locale della funzione e possiede un certo valore. Quindi, in un certo senso, per il C, non vi è alcune differenza tra passare direttamente ad una funzione l'indirizzo di un particolare oggetto oppure passare per valore un puntatore che contiene l'indirizzo di quel particolare oggetto. In entrambi i casi la funzione possiederà un oggetto di tipo puntatore che contiene al suo interno il valore numerico corrispondente all'indirizzo in memoria della variabile in questione. Non so se mi sono spiegato bene. Relativamente a questo aspetto c'è anche quello che passare per puntatore potrebbe non ridurre la memoria utilizzata dalla funzione se il valore a cui punta ha una dimensione inferiore a quella di un puntatore (cosa che in una programma a 64 bite è quasi vera per quasi tutti i tipi primitivi).
"studente-studente":mi fa pensare che [list=1][*:146hlh2q] Tu venga da altri linguaggi, [/*:m:146hlh2q][*:146hlh2q]Tu non comprenda fino in fondo cosa significa passare per riferimento.[/*:m:146hlh2q][/list:o:146hlh2q]
il linguaggio C non prevede il passaggio per riferimento ma solo per valori..Allora quando noi usiamo i puntatori non è per riferimento
Il C passa tranquillamente oggetti per riferimento (in realtà non possiede il tipo reference, ma in un certo senso un reference è soltanto un particolare tipo di puntatore). Quando tu passi qualcosa per riferimento, tu stai passando alla funzione l'indirizzo in memoria di quel particolare oggetto. In C questo procedimento richiede una operazione esplicita da parte del programmatore. Questo non è vero invece in altri linguaggi. L'unica eccezione a questo, nel C, è data dagli array che sono sempre passati per riferimento.
Detto questo ogni cosa che viene passata ad una funzione occupa una particolare locazione di memoria locale della funzione e possiede un certo valore. Quindi, in un certo senso, per il C, non vi è alcune differenza tra passare direttamente ad una funzione l'indirizzo di un particolare oggetto oppure passare per valore un puntatore che contiene l'indirizzo di quel particolare oggetto. In entrambi i casi la funzione possiederà un oggetto di tipo puntatore che contiene al suo interno il valore numerico corrispondente all'indirizzo in memoria della variabile in questione. Non so se mi sono spiegato bene. Relativamente a questo aspetto c'è anche quello che passare per puntatore potrebbe non ridurre la memoria utilizzata dalla funzione se il valore a cui punta ha una dimensione inferiore a quella di un puntatore (cosa che in una programma a 64 bite è quasi vera per quasi tutti i tipi primitivi).
L'argomento viene passato per valore anche quando stai passando un puntatore. Il valore in questo caso non è infatti l'oggetto a cui il puntatore sta puntando, ma il puntatore stesso. Stai insomma copiando un indirizzo. Il risultato è del tutto equivalente al passaggio per riferimento dell'oggetto a cui il puntatore sta puntando (ed è in effetti come viene implementato tale passaggio in altri linguaggi) ma dal punto di vista teorico si tratta pur sempre di un passaggio per valore. Quel puntatore può in effetti essere modificato senza fare mai riferimento al valore a cui il puntatore sta puntando. Considera il seguente esempio:
Restituisce l'indirizzo ad un intero intermedio tra due puntatori a e b. L'intero codice funziona anche se a e b puntano a memoria non valida (anche se in questo caso il comportamento potrebbe non essere del tutto sensato).
int *mid(int *a, int *b) { return a + (b - a)/2; }
Restituisce l'indirizzo ad un intero intermedio tra due puntatori a e b. L'intero codice funziona anche se a e b puntano a memoria non valida (anche se in questo caso il comportamento potrebbe non essere del tutto sensato).
"vict85":
Il C passa tranquillamente oggetti per riferimento (in realtà non possiede il tipo reference, ma in un certo senso un reference è soltanto un particolare tipo di puntatore). Quando tu passi qualcosa per riferimento, tu stai passando alla funzione l'indirizzo in memoria di quel particolare oggetto. In C questo procedimento richiede una operazione esplicita da parte del programmatore.
Sinceramente io avevo capito, esattamente come ha detto apatriarca, che il C prevede il passaggio di parametri solo per valore in modo tale che il programma che chiama la funzione non veda le modifiche fatte al suo interno e che il linguaggio C appiana questa ""mancanza"" passando, sempre per valore, i puntatori alle variabili. E questa cosa mi sembra quello che poi hai cercato di spiegarmi dopo: (giusto?)
"vict85":
Quindi, in un certo senso, per il C, non vi è alcune differenza tra passare direttamente ad una funzione l'indirizzo di un particolare oggetto oppure passare per valore un puntatore che contiene l'indirizzo di quel particolare oggetto. In entrambi i casi la funzione possiederà un oggetto di tipo puntatore che contiene al suo interno il valore numerico corrispondente all'indirizzo in memoria della variabile in questione. Non so se mi sono spiegato bene.
Io e Antonio diciamo la stessa cosa. Passare per riferimento significa che la funzione possiede l'indirizzo della variabile memorizzata in qualche variabile locale alla funzione (o un qualche altro modo per recuperare l'indirizzo). Questo è vero a livello di eseguibile, indipendentemente dal linguaggio utilizzato. I linguaggi in cui si passano oggetti per riferimento ti nascondono questo comportamento. Un'altra differenza tra il C e i linguaggi che permettono il passaggio per riferimento è che il C non ti assicura che l'indirizzo sia valido (né al momento in cui questo viene inviato alla funzione né durante la funzione stessa). Altri linguaggi, invece, ti assicurano che certe cose non possano succedere (il cosa ti viene assicurato dipende dal linguaggio).
Vi ringrazio per i vostri chiarimenti ma, ahimè, ancora non riesco a connettere
:
Perché se mi aspetto un puntatore io passo l'indirizzo?
Ad esempio, perché non faccio così:
Spero di essermi fatto comprendere..
](/datas/uploads/forum/emoji/eusa_wall.gif)
Perché se mi aspetto un puntatore io passo l'indirizzo?
Ad esempio, perché non faccio così:
#include <stdio.h> void cubeByReference (int *nPtr); int main (void) { int numero=5; int *numPtr; //puntatore che puntera' a un valore intero numPtr=№ cubeByReference(*numPtr); } void cubeByReference (int *nPtr){ *nPtr=*nPtr* *nPtr * *nPtr; }
Spero di essermi fatto comprendere..
cubeByReference vuole come argomento qualcosa di tipo int *. Non puoi passargli qualcosa di tipo int senza aspettarti qualche problema.. Per quanto riguarda il codice dentro cubeByReference ci metterei qualche parentesi o userei una variabile temporanea.
Credo di aver capito: la funzione vuole il tipo int* , ovvero vuole una variabile di tipo puntatore a int ma passandogli *numPtr è come se passassi proprio numero visto che è numero l'elemento puntato. Allora passo l'indirizzo dato che la variabile di tipo puntatore a int numPtr=&numero..
Ah finalmente l'ho capito come funziona eheh i puntatori mi confondono, credo di doverci prendere la mano!
Grazie mille per le vostre risposte, buona serata.
Ah finalmente l'ho capito come funziona eheh i puntatori mi confondono, credo di doverci prendere la mano!
Grazie mille per le vostre risposte, buona serata.
Ma se la funzione si aspetta un puntatore, perché non passo un puntatore ma un indirizzo?
In realtà la funzione fun(int*) non si aspetta una variabile puntatore ad int, ma l'indirizzo di memoria di un intero. Così come la funzione fun(int) non si aspetta una variabile int, ma un intero. Poi ovviamente puoi anche passare una variabile che contenga il tipo di dato che la funzione si aspetta, ossia una variabile puntatore a int nel primo caso e una variabile int nel secondo.
Considera la seguente porzione del tuo codice
cubeByReference(*numPtr);
Il programma si aspetta l'indirizzo di memoria di un intero, ma tu gli passi un intero. Secondo me dovresti rivedere la differenza del simbolo * nelle dichiarazioni di una variabile puntatore e come operatore di dereferenziazione.
Prova a lanciare il seguente codice:
#include <iostream> using namespace std; int main() { int n = 5; int* p = &n; cout << n << " - " << &n << endl; cout << *p << " - " << p; }
"Super Squirrel":
In realtà la funzione fun(int*) non si aspetta una variabile puntatore ad int, ma l'indirizzo di memoria di un intero. Così come la funzione fun(int) non si aspetta una variabile int, ma un intero. [...]
Considera la seguente porzione del tuo codice
cubeByReference(*numPtr);
Il programma si aspetta l'indirizzo di memoria di un intero, ma tu gli passi un intero. Secondo me dovresti rivedere la differenza del simbolo * nelle dichiarazioni di una variabile puntatore e come operatore di dereferenziazione.
Buongiorno, ho seguito il tuo consiglio e rivisto un attimino i puntatori.. pensavo di aver capito

Allora quando io scrivo int *Ptr posso dire due cose (uguali): Ptr è una variabile di tipo puntatore ad un intero oppure che il dato che viene puntato da Ptr è un intero.
Se io scrivo che la fun(int*) posso dire che la funzione si aspetta una di quelle due cose.
Perciò quando io faccio
int *Ptr; Ptr=&num
ho che dentro la variabile puntatore ad intero Ptr si trova il puntatore a num, il suo indirizzo.
Quindi a fun(int*) gli passo il Ptr cioè &num.. quindi alla fine l'indirizzo..
"Super Squirrel":
Poi ovviamente puoi anche passare una variabile che contenga il tipo di dato che la funzione si aspetta, ossia una variabile puntatore a int nel primo caso e una variabile int nel secondo.
E allora fun(&num) sarebbe uguale a fun(Ptr) no?
Quindi, in conclusione, cosa ho sbagliato? Ieri sera mi pare di aver detto la stessa cosa di ora (quindi o ancora sbatto la testa al muro oppure ieri ho spiegato male)
In realtà ieri mentre rispondevo al post mi sono dovuto allontanare dal pc per un bel po' e quindi quando ho inviato il messaggio non ero al corrente della tua risposta.
Comunque dal tuo ultimo post mi sembra di capire che tu abbia afferrato il concetto.
Comunque dal tuo ultimo post mi sembra di capire che tu abbia afferrato il concetto.
Figurati, grazie per le vostre risposte!!