Newsgroup: it.comp.lang.c++
Titolo: Array (help)

Salve,
tema: sconfinamento degli indici di un array.
Esempio:
A - Codice sorgente:
1. int main ()
2.     {const int SIZE=4;
3.      float a[ ] = {22.2, 44.4, 66.6};
4.      float x=11.1;
5.      cout << "x = " << x << endl;
6.      a [3] = 88.8;
7.      cout << "x= " << endl;
8.     }
B - Output
9. x = 11.1
10. x = 88.8
Nota: le righie di codice ed output sono state numerate per avere un
riferimento.
Sintesi della spiegazione del testo di commento al codice ed all'output:
     dato che la variabile x (riga 4.) e' dichiarata dopo l'array a (riga
3.) il sistema alloca 4 byte per il float di x contiguamente ai 12 byte dei
3 float di a e quindi e' come se x fosse a [3]. Quando il codice assegna
88.8 ad a [3], che non esiste, modifica il valore di x facendolo diventare
88.8.
Perplessita' personali:
     la lista di inizializzazione ha un valore in meno rispetto al valore
assegnato alla costante simbolica SIZE (anche se cio' e' irrilevante), voce
del resto non riportata tra [] della riga 3. come dimensione dell'array
alternativa ad un intero. Mi pare quindi che la riga 2. non influenzi alcuna
altra parte del codice. Direi che a [3] non esiste proprio perche' una a [3]
non e' mai stata inizializzata, in questo codice, anche se a 3 float e'
stata inizializzata una a [ ].
Il testo mi da', sulla riga 6., il commento: "Errore: indice fuori dei
limiti!". Capisco che, partendo ogni indice di array sempre da 0, a [3] e'
un indice fuori dai limiti perche' richiama un quarto valore, di a [ ],
evidentemente inesistente, ma non mi riesce di capire perche' il compilatore
interpreti la contiguita' di byte come identita' tra le variabili x ed a
[3]. Non capisco cioe' come si ingenera esattamente il meccnismo dello
"slide effect". Qualcuno potrebbe illustrarmelo in dettaglio ed in modo
semplice?
Grazie mille
K

 
A parte il fatto che il comportamento che hai illustrato non mi sembra
molto standard (ad esempio in Dev C++ per ottenere lo stesso risultato
dato dal codice da te postato devo usare a[-1] al posto di a[3]), devi
sapere che l'operatore a[i] serve a far ritornare l'indirizzo che stŕ ad
i*n byte di offset da a[0] (cioč dall'oggetto puntato da a, ovvero il
primo elemento dell'array), dove in questo caso n=4. Il fatto che a[3]
non sia mai stato inizializzato non č quindi importante, mentre č
importante che all'indirizzo di a[3] ci sia un oggetto dello stesso tipo
di a[0].
Ciao,
Cecco

 [3].
Il compilatore non interpreta nulla. Quando dereferenzi un elemento
all'esterno dell'array sei in "undefined behaviour". Potrebbe
interpretare quella riga come sytem("format c:"); e avrebbe ragione.
Quello che di solito succede (ma solo perchè è più comodo da
implementare) è che accede alla memoria avente l'indirizzo che avrebbe
l'elemento se esistesse. Nel tuo caso capita che a quell'indirizzo si
trovi proprio la variabile x. Ma è un caso.
Nota che probabilmete se ricompili il programma con le ottimizzazioni
attivate il comportamento cambia (non è detto, ma è probabile. E se non
cambia, prova a cambiare i float in interi e vedere se si comporta
diversamente compilando debug e release).
--
Andrea Ferro
---------
Brainbench C++ Master. Scored higher than 97% of previous takers
Scores: Overall 4.46, Conceptual 5.0, Problem-Solving 5.0
More info 
http://www.brainbench.com/transcript.jsp?pid=2522556

semplice?
Non scandalizzatevi per questa spiegazione!
Immagina la memoria come una serie di scatoline da un byte una di
fianco all'altra e numerate, se tu scrivi:
mio_tipo a[10];
mio_tipo b;
dici al compilatore di "riservare" (10 * sizeof(mio_tipo)) scatoline
una dopo l'altra, cioè lo spazio necessario per contenere 10 oggetti
mio_tipo (se non lo sai sizeof riporta la dimensione in byte di
mio_tipo) e poi sizeof(mio_tipo) scatoline per b.
Quando poi nel codice tu hai "a[4];" il compilatore non fa altro che
calcolare "a + 4 * sizeof(mio_tipo)", cioè calcola la scatolina che ti
serve come la posizone della scatolina in cui inizia a + lo
spostamento che c'è rispetto a questa prima scatolina.
Se il compilatore trova "a[10];" fa la stessa cosa ma non si preoccupa
se finisce al di fuori dello spazio riservato ad a, questo può portare
a conseguenze disastrose o semplicemente può non accadere niente.
Porbabilmente però b e stata "messa" subito dopo a quindi a[10] si
riferisce alle scatoline subito dopo alla fine di a che in questo caso
corrispondono a b.
-- 
Marco Barisione (ICQ 84277092)

corrispondono a b.
Mi sembra di aver capito che il compilatore alloca gli utlimi valori nelle
prime memorie libere contigue alle ultime memorie occupate e quindi va a
cercare in queste ultime memorie gli ultimi valori della variabile x. Ma
questo era quello che gia' avevo capito, quello che non continuo a capire e'
come, il compilatore, consideri a [3] per scambiarlo con x: lo considera,
sostanzialmente e senza dubbio come x, ma fa cio' perche' considera a [3]
come un array di tre elementi mai inizializzato prima, e quindi come una
variabile inesistente, oppure perche' considera a [3] come il quarto valore
dell'array a [ ], inizializzato a 3 valori soltanto per cui il valore
massiomo di esso e' a [2]? Forse la domanda che sto ponendo e' stupida
perche', comunque si interpreti il significato della variabile a [3], essa
resta inesistente, ma sento ancora nebulosa la questione di quella riga 6.
l' a [3] = 88.8 della quale viene inteso dal compilatore come un x = 88.8 a
prescindere dall'esistenza di un'istruzione del tipo x = a [3].
Ora, riguardando meglio il codice, mi verrebbe da dire che essendo a [3]
stata inizializzata (a [3] = 88.8) ma non dichiarata (float a [3]),
quell'assegnazione del valore 88.8 e' stata fatta a qualcosa (area di
memoria) che non dovrebbe esistere, mentre, a fronte dei dati di output
della riga 10., si puo' constatare che al valore 88.8 esiste eccome, ma e'
stato, evidentemente, assegnato ad un'area di memoria non nominata come
variabile.
Ora viene il bello: per il testo, essendo la prima variabile, le cui celle
di memoria sono contigue a quelle di 88.8, a [ ], 88.8 andrebbe ad accodarsi
a 66.6 senza pero' variare la struttura dell'array che e' stata ben definita
dalla lista di inizializzazione di cui 66.6 e', appunto, l'utimo valore, ed
il compilatore interpreterebbe questo valore accodato ed innominato, come
ulteriore valore di x. Ma dove sta il senso se x era gia' stato dichiarato
come float e contestualmente inizializzato al valore 11.1 nella riga 4.?
Grazie
K


sostanzialmente e senza dubbio come x, [...]
Fa ciò perché per il compilatore a[3] significa la variabile che sta
in "a + sizeof(float) * 3" e il compilatore semplicemente se ne frega
di dove questa variabile sta, semplicemente lui va a scrivere e
leggere in quella posizione di memoria, quindi l'array a rimane
intatto perché modifichi qualcosa al di fuori di esso. Se vuoi
qualcosa di più sicuro devi usare i vector della libreria standard.


in "a + sizeof(float) * 3" e il compilatore semplicemente se ne frega
....
Grazie Marco e grazie anche a Francesco.
Alla prossima
CS
KF