Newsgroup: it.comp.lang.c
Titolo: domanda su array

in genere, se in un programma trovo un array (chesso', int a[10];)
so che e' possibile raggiungere qualunque elemento con un costrutto del
tipo a[contatore] col contatore di tipo int.
tuttavia, leggendo una rivista, ho trovato questo codice:
main()
{
  int i=0;
  printf("%c\n", i["ABC"]);
}
cioe' il contatore e' quello fuori dalle parentesi quadre, mentre l' array
e' la stringa e sta dentro!
tra l' altro il codice funziona perfettamente (mostra A a video) e compila
senza neanche un warning
mi sapete spiegare il funzionamento?
-- 
int c;main(){for(;c["];c++)c["];write(c-~-c,c+++"-- \nZeD\n",c-~-c));}

 mi sapete spiegare il funzionamento?
Dunque, ho molta ruggine che si addensa tra i neuroni, tuttavia la risposta 
che mi viene in mente è la seguente, basata sull'aritmetica dei puntatori:
Per accedere all'elemento i del vettore v il compilatore considera 
l'indirizzo del vettore v e vi somma i (aritmetica dei puntatori, appunto).
Probabilmente la notazione che hai riportato porta invece il compilatore a 
considerare prima i e a sommarvi l'indirizzo del vettore v... e si ottiene 
quindi lo stesso risultato.
-- 
The only difference between a problem and a solution is that people 
understand
the solution.
                -- Charles F. Kettering

 e' la stringa e sta dentro!
array[posizione] --> *(array+posizione).
"ABC" e' un array di 4 elementi, analogo a dichiarare
char * a = "ABC";
Attenzione che "ABC" potrebbe non essere modificabile (ma questo non c'entra 
nulla con l'esempio).
Per maggior chiarezza uso /a/ anziche' "ABC".
a[i] --> *(a+i)
i[a] --> *(i+a)
Come puoi vedere il risultato e' identico in entrambi i casi.
Ottieni risultato analogo usando direttamente "ABC" al posto di /a/.
Se ti interessano questi problemi ti consiglio l'acquisto del Koenig (C 
traps and pitfalls).
-- 
Mox
"Trust the programmer."
"Don't prevent the programmer from doing what needs to be done."
"Keep the language small and simple."
"Provide only one way to do an operation."

mi sapete spiegare il funzionamento?
a[i] = *(a+i) = *(i+a) = i[a]
Tutto qui ;-)
-- 
Andrea Laforgia
www.geocities.com/andrealaforgia
"640kb of memory should be enough for anyone." -- Bill Gates.

 
Per espandere e chiarificare un po' quanto detto negli altri messaggi.
Il tutto si basa su due cose 1) stringhe 2) aritmetica dei puntatori
Punto 1 - stringhe
Nel linguaggio C le stringhe non esistono. Mettiti l'animo in pace e
fattene una ragione :-). Quello che sembra essere una stringa e' in
effetti un array di caratteri; "pippo"  e' un vettore di tipo char che
ha come primo elemento un'intero di un byte di valore 112, come secondo
elemento un'intero di un byte di valore 105 etc fino al sesto elemento
che ha valore 0. Quando usi da qualche parte "pippo" in effetti usi una
costante di tipo vettore di char questo significa che puoi considerarlo
(non e' proprio cosi' ma facciamo finta, e a tutti gli effetti pratici
cambia poco) come un puntatore al vettore, allo stesso modo in cui se
dichiari char v[10] allora v e' un puntatore al vettore o precisamente
al primo elemento del vettore, quindi v == &v[0] e di conseguenza
"pippo" punta alla "p".
Punto 2 - aritmetica dei puntatori 
Nel C quando dichiari il vettore v e l'intero n e scrivi v[n] in effetti
quello che il compilatore fa e' *(v+n) dove v+n e' calcolato usando
l'aritmetica dei puntatori. In pratica questo significa che quando si
somma un intero ad un puntatore l'intero viene moltiplicato per il size
della variabile puntata, cioe' in soldoni i puntatori non si
incrementano per bytes ma per elementi del vettore; v+1 e' il secondo
elemento del vettore v qualsiasi sia il tipo, se e' char rimane v+1 se
e' float diventa v+4 e cosi' via. La sintassi completa e' in effetti
*(v+i*sizeof(*v)) dove v e' il puntatore e i l'intero _non importa
l'ordine nella somma_ quindi rimarra' uguale se scrivo *(i+v) che si
puo' tradurre con i[v] e dato che tutto cio' vale sia per le variabili
che per le costanti 1["pippo"] vale 'i', e da cio' ne consegue anche che
&1["pippo"] vale "ippo"  
 
Tutto cio' non e' "voluto" ma semplicemente una conseguenza di come il
C, e i compilatori, funzionano. Come discusso anche in un'altro thread 
questo sono cose da evitare quando si programma. Da usare solo per
divertimento o per stupire gli amici.......
SE&O....
Ciao,
      GianPiero

*(v+i*sizeof(*v)) 
Assolutamente sbagliato.


 
Siamo qui per imparare..... ma potresti essere piu' specifico? Perche'
l' espansione di v[i] non e' *(v+i*sizeof(*v))? ovviamente questo vale non
considerando l'aritmetica dei puntatori (a meno che v non si di tipo
char nel qual caso non fa differenza).
Ciao,
      GianPiero

l' espansione di v[i] non e' *(v+i*sizeof(*v))? 
Perché l'espansione di v[i] è *(v+i) NON *(v+i*sizeof(*v)), anche se a
quest'ultima ci aggiungi la postilla che non stai considerando
l'aritmetica dei puntatori.  Se non consideri l'aritmetica dei
puntatori, allora non ha neanche senso scrivere quell'espressione (che
è, appunto, la somma di un puntatore e di uno scalare).
Ben diverso sarebbe spiegare, a chi vuole imparare, che, internamente,
il compilatore traduce l'espressione v[i] nella somma dell'indirizzo
del primo elemento di v e di i moltiplicato la dimensione del singolo
elemento del vettore.


 
Assolutamente inesatto! Questo e' &v[i] ;-). 
Per me ad essere troppo pignoli si peggiora la comprensione. Per me
quello che hai detto e' equivalente a (v+i*sizeof(*v)) se si ignora per
il momento l'aritmetica dei puntatori.  Se proprio vuoi scrivi che
l'indirizzo calcolato e' ((int)v+i*sizeof(*v)), ma non credo che questo
aumenti la comprensione. 
Comunque non c'e' problema, basta capirsi.
Ciao,
      GianPiero

il momento l'aritmetica dei puntatori. 
No, scritto a questo modo, non ha alcun senso.


 
Continui a dirlo ma non spieghi mai il perche'. 
Secondo te questo codice cosa stampa?
main()
{
  char v[10];
  int i=1; 
  v[i]=100;
  printf("Valori: %d %d \n",v[i], *(v+i*sizeof(*v))); 
}
Per me stampa "100 100"
A parte cio' suppongo sarebbe bene piantarla, dubito che agli altri
interessi la nostra diversita' di vedute sul modo di far capire il C.
Ciao,
      GianPiero

 Tutto qui ;-)
eh, insomma... in pratica il significato di livello piu' alto di vettore,
detto cosi', va a farsi friggere! ^^;


 Per me stampa "100 100"
Già, ma prova a sostituire
char v[10];
con
int v[10];
e vedi se il risultato è lo stesso oppure no.
EMG
--
EMAG Software Homepage:     
http://www.emagsoftware.it
The EMG's ZX-Spectrum Page: 
http://www.emagsoftware.it/spectrum
The Best of Spectrum Games: 
http://www.emagsoftware.it/tbosg

 
Ovvio che non e' lo stesso, ma il caso char e' quello in cui
*(v+i*sizeof(*v)) e' uguale sia che si consideri l'aritmetica dei
puntatori o no che e' quello di cui stavo parlando. 
Ciao,
         GianPiero

Per me stampa "100 100"
Ti consiglio la lettura di un buon manuale del linguaggio, il tuo
codice è errato.


puntatori o no che e' quello di cui stavo parlando. 
Quanto scrivi, te lo ripeto per l'ennesima volta, č assolutamente
illogico ed errato, in C.  La sintassi corretta č:
*(v+i) 
e __NON__ *(v+i*sizeof(*v))
Oltretutto dal tuo messaggio originale, si desume che tu stia parlando
di un tipo generico.  E, in ogni caso, anche se tu stessi parlando del
tipo "char", quanto scrivi rimane illogico ed errato.
Punto e basta.


detto cosi', va a farsi friggere! ^^;
E quale sarebbe "il significato di livello piů alto di vettore" ?


 
Comuinque vorrei farti notare che dire "e' errato" senza spiegare il
perche' e' una pessima abitudine, a qualsiasi livello
Addio,
        GianPiero

perche' e' una pessima abitudine, a qualsiasi livello
Guarda che è per tutto il thread che cerco di spiegarti perché quanto
scrivi errato.  Continui a sostenere che *(v+i*sizeof(*v)) è una forma
valida e questa è, invece, ERRATA.  Tutto ciò che basi su questo tuo
assunto ERRATO è, per forza di cose, ERRATO a sua volta.  
D'altronde, questo è un concetto _basilare_, in programmazione C.


 valida e questa è, invece, ERRATA.
Sicuro che *(v+i*sizeof(*v)) e' un mezzo decisamente errato per spiazzarsi
all'interno di un vettore.
Applicandola a un vettore di tipo int si vanno a fare dei bei danni nelle
altre locazioni di memoria, ma se poi il vettore e' di tipo long int o float
allora le probabilita' di lesioni aggravate sul sistema crescono a
dismisura.
Penso che GianPiero abbia fatto un bel "fritto misto alla piemontese", come
si dice dalle mie parti.
Quando si danno delle spiegazioni occorre essere precisi e non fare esempi a
caso o "tanto per dare un'idea". Il formalismo e la precisione nel C sono
due componenti essenziali.
Peccato che abbia notato solo adesso questo thread, sarei intervenuto gia'
prima...
BYE
GIGI
--------------------------------
Inviato via 
http://usenet.libero.it

 si dice dalle mie parti.
[...]
Ho detto che non proseguo e non proseguo. Ma vorrei chiederti di leggere
TUTTO il thread anche le parti dei miei messaggi che sono state
cancellate senza alcun segnale (altra PESSIMA abitudine) nelle risposte.
Puo' anche darsi che mi sbagli, ma c'e' modo e modo.......
Ciao,
     GianPiero

Puo' anche darsi che mi sbagli, ma c'e' modo e modo.......
Appunto, c'è modo e modo di ammetterlo.


 cancellate senza alcun segnale (altra PESSIMA abitudine) nelle risposte.
Ho letto, ho letto tutto e proprio per questo motivo dico che hai fatto un
po' di pasticci.
All'inizio sembrava che volessi dare una spiegazione completa del problema,
ma poi hai utilizzato termini imprecisi e sopratutto esempi non esaustivi,
tant'e' vero che ti sono stati contestati.
Rischi di danneggiare o confondere chi ha posto il quesito.
Per capire che sei in errore non e' poi cosi' difficile, e' sufficiente
provare a compilare i tuoi esempi e vedere che cosa succede.
Comunque e' abitudine riportare solo la parte necessaria di un messagio
nella successiva risposta. Non e' necessario comporre un romanzo per essere
chiari e esplicativi.
E questo vale per tutti i newsgroup.
Bye


 E quale sarebbe "il significato di livello più alto di vettore" ?
un oggetto composto da piu' elementi dello stesso tipo, e ad ogni singolo
elemento e' associato un valore dell' indice dell' array stesso
poi, diciamo, la sintassi "usuale" e'
tipo a[n]
con tipo il tipo dei singoli elementi
a l' identificatore dell' oggetto
e n il valore dell' indice
questo e' il significato di livello piu' alto
che poi in realta significhi *(a+n) e' ad un livello inferiore di
significato (non meno importante, solo di livello piu' vicino alla
macchina. giusto per capirsi)
da qui, se un dato (i) NON e' un array di qualcosa, non _avrebbe_ senso
fare i[n], e men che meno se n e' un array!
sara' un errore della mia forma mentis su come leggo (e scrivo) il codice
c, ma scrivendo printf("%c", 1["ABC"]); mi sembra di giocare a dama con le
regole degli scacchi


VENGO IN PACE!!!  :-)))
In C, char pippo[10] viene "interpretato" dal compilatore come una LISTA 
di elementi di tipo char, una cosa tipo
struct ecco_come_viene_interpretata
{
   char elemento_Nesimo_di_pippo;
   void *puntatore_al_prossimo_elemento_di_pippo
};
Il discorso del *(v+i*sizeof(*v)) , "in italiano" lo 
capisco come la dimensione del mio void*...
Se crei un'array di stringhe, l'offset in memoria è 1
Se crei un'array di float, l'offset in memoria è 4 (?)
Essendo (non ragionando in codice macchina) le aree di memoria contigue, 
il "i*sizeof(*v)" vuol dire "caro compilatore, se devi prendere il prossimo 
elemento di v, salta 1 byte, e non 4 perchè stai considerando un char che 
per stare in memoria ha bisogno di un byte, e non 4 visto che non è 
un float"...
Non mi sbranate per quello che ho scritto... :-)))
Ciao!

 elemento di v, salta 1 byte,
No, vorrebbe dire "se devi prendere l'elemento i-esimo salta un numero
di bytes pari ad i moltiplicato per la dimensione del tipo dell'array".


 EMG
   Ciao!

 
Si, la regola e' di escludere le parti non importanti, ma di SEGNALARLO!
e comunque i miei messaggi non erano cosi' lunghi da richiedere tagli e
a volte i tagli modificavano il senso del discorso.
Comunque per me qui voi siete troppo seri. Sembra diventati un raccolta
di professoroni inamidati e studenti che cercano qualcuno che gli faccia
il compitino. Non fa per me. Quindi questa (con vostra grande
soddisfazione) sara' la mia ultima apparizione e it.comp.lang.c sparira'
dal mio newsrc.
Addio e non divertitevi troppo.
G.  

 soddisfazione) sara' la mia ultima apparizione
E' gia' la terza volta che lo dici, eppure non demordi.


fare i[n], e men che meno se n e' un array!
Parti da un fondamento sbagliato: assumi che il significato di "array"
cambi a seconda della notazione usata.  In realtà non è così.  Il C
prevede diverse notazioni che però assumono lo _stesso_ significato.


dal mio newsrc.
Stammi bene e non lurkare troppo ;-)


un float"...
???


 prevede diverse notazioni che però assumono lo _stesso_ significato.
amen
cio' non toglie che n[a] non mi piaccia assolutamente e anzi mi crei dei
problemi, a livello di comprensione! ^^;
-- 
char c;main(){for(;c["];c++)c["];write(c-~-c,c+++"-- \nZeD\n",c-~-c));}

problemi, a livello di comprensione! ^^;
Il che è un altro problema, tu chiedevi se e come funziona la cosa e
ti è stato abbondantemente risposto.  Se vuoi sapere la verità,
neanche io uso mai 3[a] se posso usare a[3], perché questo favorisce
la leggibilità del codice.  In C si è voluto semplicemente mantenere
una compatibilità tra a[i] e *(a+i) per cui, per coerenza, *(i+a) lo
si è fatto corrispondere a i[a].  Questa è stata una caratteristica
_voluta_ non _dovuta_, che tu sei libero di utilizzare o meno.
