Newsgroup: it.comp.lang.c
Titolo: [LONG] Memoria, Puntatori & Co.

Studiando la materia mi sono fatto uno schema che vorrei cercare di esporre 
ed eventualmente fare approvare/smentire/correggere...
Suppongo che:
Preso un int i = 666, avremo:
	[l-value di "i"] = Indirizzo01 = &i;
	[r-value di "i"] = 0x29A = i;
Preso un int *pv, dinamicamente allocato e riempito come vettore di 2 
interi = {11,22}, avremo:
	[l-value di "pv"] = Indirizzo11 = &pv;
	[r-value di "pv"] = Indirizzo12 = pv;
	[r-value di Indirizzo12] = 0x16 = *pv;
	Cioè quando si ha a che fare con un puntatore, questo risiede in
	Indirizzo11 che contiene a sua volta un Indirizzo12 che punta
	finalmente al contenuto di pv[0] = 11 in questo caso.
Ho fatto un programmino (di cui posterò il codice a fine post) il cui 
output è questo (con int i; int Vet[2] = {77,99}; int *pv):
//INIZIO
&i   = 12ff6c; i   = 666; *i = /INESISTENTE/
&Vet = 12ff70; Vet = 12ff70; *Vet = 77
&pv  = 12ff7c; pv  = cccccccc; *pv  = IMPOSSIBILE (punta a niente)
Inizializzo pv = NULL
&pv  = 12ff7c; pv  = 0; *pv  = IMPOSSIBILE (NULL punta a niente)
//  <-  qui alloco dinamicamente *pv e lo inizializzo
Quanti valori? 1
v[0] = 1
Inizio a mostrare
d[0] = 1
&pv  = 12ff7c; pv  = 431fb0; *pv  = 1
&pv  = 12ff7c; pv  = 431fb0; *pv  = -572662307 (Effettuato free(pv))
Press any key to continue
//FINE
I questiti che mi restano sono questi:
	1) Se vale quanto detto, come si spiega che nel caso di Vet,
	inizializzato a Vet[2] = {77,99}, &Vet sia uguale a Vet ma
	resta (ovviamente) *Vet = 77? Secondo una logica che mi
	pareva scontata, *Vet è il contenuto di Vet ma se Vet = &Vet
	allora mi manca un passaggio... come fa lo stesso indirizzo
	a puntare contemporaneamente a se stesso e a *Vet che è 77?
	2) L'indirizzo pv in seguito a dichiarazione int *pv è di natura
	puramente casuale come per gli interi?
// INIZIO CODICE
#include <stdio.h>
#include <stdlib.h>
void creaVett(int **pv,int *dim)
{
	int i;
	printf("Quanti valori? ");
	scanf("%d", dim);
	*pv = (int*) malloc(*dim * sizeof(int));
	for (i=0; i<*dim; i++){
		printf("v[%d] = ",i);
		//scanf("%d",*pv+i);
		scanf("%d",&(*pv)[i]); //alternativa by poochie
	}
}
void mostraVett(int *v,int dim)
{
	int i;
	printf("Inizio a mostrare");
	for (i=0; i<dim; i++)
		printf("\nd[%d] = %d", i, v[i]);
}
int main()
{
	int *pv, num;
	int Vet[2] = {77,99};
	int i=666;
	printf("&i   = %x; i   = %d; *i = /INESISTENTE/\n",&i,i);
	printf("&Vet = %x; Vet = %x; *Vet = %d\n",&Vet,Vet,*Vet);
	printf("&pv  = %x; pv  = %x; *pv  = IMPOSSIBILE (punta a 
niente)\n",&pv,pv);
	printf("Inizializzo pv = NULL\n");
	pv = NULL;
	printf("&pv  = %x; pv  = %x; *pv  = IMPOSSIBILE (NULL punta a 
niente)\n",&pv,pv);
	creaVett(&pv,&num);
	mostraVett(pv,num);
	printf("\n&pv  = %x; pv  = %x; *pv  = %d\n",&pv,pv,*pv);
	free(pv);	
	printf("&pv  = %x; pv  = %x; *pv  = %d (Effettuato 
free(pv))\n",&pv,pv,*pv);
	return 0;
}
//FINE CODICE
Grazie per l'attenzione,
-- 
Poochie ©
Teoricamente la teoria è uguale alla pratica, ma in pratica non lo è...

 puramente casuale come per gli interi?
L'inizializzazione a 0 (zero) delle variabili, avviene solo se sono
globali, altrimenti il contenuto è causale (questo vale per *tutte* le
variabili, siano essere intere o puntatori a chicchessia).

Anno Domini Mon, 16 Feb 2004 08:56:52 +0100, Andrea Laforgia, nobilissimus
apud internautas, scripsit:
[CUT]
Grazie della spiegazione, di base ho capito, mi resta il cruccio però di
cosa sia veramente contenuto nell'r-value di quell'indirizzo di memoria,
dato che in altri casi (come ins eguito ad allocazione dinamica) &pv e pv
contengono indirizzi diversi. Per quelle situazioni comprendo benissimo, è
quando l'indirizzo in se è il medesimo che mi chiedo a cosa ci sia a destra
dell'indirizzo vet o &vet... in mancanza di altri riferimenti suppongo ci
sia il contenuto di *vet ma l'esperto non sono io...!


 contengono indirizzi diversi.
Non è possibile.

 Non è possibile.
Infatti nell'output che avevo postato, con pv puntatore a int, in seguito a
malloc:
	&pv  = 12ff7c; pv  = 431fb0; *pv  = 1
l-values ==>> r-values
12ff7c (&pv) ==>> 431fb0 (pv)
...
431fb0 (pv) ==>> 1 (*pv)


 il suo contenuto.
Non č ciň che normalmente si intende per "l-value" e "r-value".

> Intendo nella memoria, in cui l-value indica la cella di memoria e

:O Ero sicuro fosse cosě... ad ogni modo il mio interrogativo restava sul
contenuto della cella di memoria puntata da &vet...
-- 
Poochie ©
Teoricamente la teoria č uguale alla pratica, ma in pratica non lo č...

 Non ? ci? che normalmente si intende per "l-value" e "r-value".
No, pero` viene usato in ambito  accademico. "l-value indica la cella di
memoria" va interpretato come "l'identificatore di una variabile, quando
usato come l-value, rappresenta la locazione  di memoria in il valore di
quella variabile e` memorizzato".
Luca
-- 
Home: 
http://kronoz.cjb.net
Se il  destino di un uomo  e` annegare, anneghera` anche  in un bicchier
d'acqua.
Proverbio yddish

 contenuto della cella di memoria puntata da &vet...
Non capisco, sinceramente, tutti questi dubbi.
Se io ho un vettore di 2 interi "vet":
indice:      0    1
contenuto: [ A ][ B ]
indirizzo: 0x0A 0x0E
vet[0] = A;
vet[1] = B;
&vet[0] = 0x0A
&vet[1] = 0x0E
&vet = 0x0A (puntatore a vettore di 2 interi)
vet = 0x0A (*vet = vet[0]).

> :O Ero sicuro fosse così... ad ogni modo il mio interrogativo


Evidentemente il mio dubbio non è così tanto comprensibile come mi era
parso, ad ogni modo, riprendendo il tuo esempio:
supponiamo che proseguendo faccia:
vet = (char *) malloc (2*sizeof(char));
vet[0] = 'X';
a quel punto
&vet resta = 0x0A
vet sarà cambiato in = 0xAA
*vet = 'X';
ergo fisicamente accade che
cella di memoria 0x0A =contiene= 0xAA
cella di memoria 0xAA =contiene= 'X'... nella rappresentazione binaria...
il mio dubbio consisteva nel fatto che non riuscivo a comprendere cosa
accadesse a livello di memoria fisica (ammettendo che valga quanto scritto
3 righe fa) quando, alla fine del tuo post:
&vet = 0x0A
vet = 0x0A
=> cella di memoria 0x0A =contiene fisicamente= ??? (il contenuto *vet ?)
Perchè in seguito ad allocazione dinamica questo (&vet) contiene un
indirizzo di memoria (vet) che a sua volta contiene il primo valore
dall'array (*vet), caso ben comprensibile; 
ma qui non comprendo come possa lui (the machine) sapere dove risiede il
char contenuto all'index 0 di vet (primo caso analizzato con "char *vet[2]
= {'A','B'}") perchè mi aspetto che vet mi dica dove risiede il vero
vet[0], ma se l'indirizzo &vet e vet sono numericamente identici allora
dove risiede veramente 'A'? L'unica risposta ammissibile è l'indirizzo di
vet che però mi fa sorgere spontanea la domanda: come fa il computer a
sapere se &vet è il vet[0] effettivo o un indirizzo di memoria dove trovare
vet[0]?
Spero riuscirai a comprendere la tortuosa spiegazione al mio amletico
dilemma... ^_^
-- 
Poochie ©
Teoricamente la teoria è uguale alla pratica, ma in pratica non lo è...

 vet[0] = 'X';
Ti stai ponendo in un'altra condizione.  Io sto parlando di array, di
vettori, tu stai parlando di puntatori.
Array e puntatori, in C, sono due cose BEN distinte.
Nel tuo caso, vet è un puntatore, non un array, quindi
&vet è l'indirizzo della variabile puntatore.
vet contiene l'indirizzo puntato.
Il valore di vet e &vet è diverso.
Nel caso di un array, invece:
int vet[2] = { 77, 99 };
&vet è l'indirizzo dell'array.
vet è il puntatore al primo elemento dell'array, per decadimento.
Il valore di vet e &vet è uguale, il tipo è diverso.

 vet = 0x0A (*vet = vet[0]).
Scusa Andrea non vorrei sbagliare ma, per quel che ne so, &vet e vet non
sono mica lo stesso indirizzo di memoria.
Forse volevi scrivere:
&vet[0] = 0x0A
vet = 0x0A
Oppure:
&vet = altro-indirizzo (puntatore a vettore di 2 interi)
vet = 0x0A (*vet = vet[0])
Marcello

 vet = 0x0A
Nel caso di un array, il valore di &vet[0] è uguale a &vet che a sua
volta è uguale a vet.  Sottolineo: _nel caso di un array_ e _il
valore_, perché _il tipo_ è ben distinto.

 Certo che lo sono, nel caso di un array.
Ecco...
E' proprio quest'ultima cosa che non mi torna.
Sia vet un array di n elementi.
Vet e &vet[0], in memoria, sono la stessa cosa, infatti:
printf("%p", vet);
printf("%p", &vet[0]);
stampano un identico output, ma
printf("%p", vet);
printf "%p", &vet);
stampano due output distinti.
Marcello

 stampano due output distinti.
Ho verificato, se inizializzi il vettore
int vet[2] = { 77, 99 };
sono tutti e 3 uguali.
-- 
Poochie ©
Teoricamente la teoria è uguale alla pratica, ma in pratica non lo è...

Anno Domini Wed, 18 Feb 2004 09:03:51 +0100, Andrea Laforgia, nobilissimus
apud internautas, scripsit:
[CUT]
Inizio a comprendere... quindi:
Il puntatore e il vettore sono "lontani parenti".
se si ha a che fare con un vettore vet
[cella di meoria di vet] =contiene=  vet[0];
... in successione seguono gli altri elementi dell'array.
&vet č dove risiede vet e vet restituisce lo stesso valore solo perchč il
programma sa che questo valore non reindirizza ma fornisce direttamente il
contenuto di vet[0], perchč abbiamo a che fare un vettore.
se per qualche ragione dovessi ampliare il mio vettore, con malloc vet
diventa un puntatore a vettore. Quindi quanto detto prima scenderebbe di
uno a catena e avremmo
[cella di memoria di vet] =contiene= mem dove inizia il nuovo vet
[mem dove inizia il nuovo vet == contenuto di vet[0]
in tal caso il programma sa che da &vet non deve aspettarsi il contenuto di
un indirizzo di memoria ma l'indirizzo dove reperire vet[0] e da lě i
successivi.
Cosě si potrebbe dire che un puntatore ad array e un array sono parenti che
possono o il primo puntare al secondo, o il secondo trasformarsi nel primo
in certe circostanze (malloc).
Sempre solo se tutto questo č vero dovrebbe conseguirne che in qualche modo
il programma deve tenersi registrato da qualche parte se sa che vet č
ancora vettore (come da dichiarazione) o se č stato trasformato in
puntatore a vettore, perchč nel primo caso si aspetterebbe di poter leggere
un intero (ma anche un byte puro in altre condizioni), nel secondo sa che
non ha a che fare col contenuto di vet[0] ma con dove questo viene
contenuto.
Sperando di essere stato un po' piů illuminato & illuminante del solito,
 
Poochie ©
Teoricamente la teoria č uguale alla pratica, ma in pratica non lo č...

 Teoricamente la teoria è uguale alla pratica, ma in pratica non lo è...
Come non detto, qui correggo un errore concettuale, quindi leggi questo
post, non il precedente.
-- 
Poochie ©
Teoricamente la teoria è uguale alla pratica, ma in pratica non lo è...

 Vet e &vet[0], in memoria, sono la stessa cosa, infatti:
#include <stdio.h>
int main()
{
    int a[2], b[2] = {3, 5};
    a[0] = 3;
    a[1] = 5;
    printf("&a = %p ; a = %p; &a[0] = %p\n", &a, a, &a[0]);
    printf("&b = %p ; b = %p; &b[0] = %p\n", &b, b, &b[0]);
    getchar();
    return 0;
}
/* output:
&a = 0240FF58 ; a = 0240FF58; &a[0] = 0240FF58
&b = 0240FF50 ; b = 0240FF50; &b[0] = 0240FF50
*/

> Ho verificato, se inizializzi il vettore
Non solo se inizializzi il vettore.  Anche per i vettori non
inizializzati č cosě.

 inizializzati è così.
Giusto, l'importante è non "ri-mallocarlo".


> Giusto, l'importante è non "ri-mallocarlo".
I vettori non possono essere "ri-mallocati".

Anno Domini Wed, 18 Feb 2004 17:14:14 +0100, Andrea Laforgia, nobilissimus 
apud internautas, scripsit:
[CUT]
Che stress... leggendo ora che un vettore è "definito come un puntatore 
costante" noto ancora più senso nelle tue premonizioni e cecità nelle mie 
esternazioni... no comment... grazie del supporto!


 costante"
Non è neanche del tutto corretta questa definizione.  In realtà, lo
stesso K&R nella prima edizione lo definiva così.  La definizione più
corretta è l-value non modificabile.

> Che stress... leggendo ora che un vettore è "definito come un

Ha sempre più senso... ottimo!


Andrea Laforgia wrote:

Ehmmm....
Sono un asino.
Passavo il vettore ad una funzione stampa senza risolvere il deferimento.
Marcello

> Passavo il vettore ad una funzione stampa senza risolvere il
deferimento.
Attenzione, quando passi un vettore ad una funzione, il vettore decade
sempre nel puntatore al primo elemento.  Cioè, anche se scrivi:
void funzione(char a[50])
{
     printf("%d\n", sizeof a);
}
equivale a:
void funzione(char *a)
{
     printf("%d\n", sizeof a);
}