Newsgroup: it.comp.os.linux.development
Titolo: [?][PUNTATORI] Matematica dei puntatori su diversi sistemi

Come funziona la matematica dei puntatori su eventuali sistemi in cui gli
elementi sono allocati in memoria (e quindi i valori dei puntatori) in
maniera decrescente?
Per esempio se ho un array aProva e un puntatore pProva:
pProva= &aProva
pProva1= pProva + 1
aProva[0] e pProva restituiscono il primo elemento.
aProva[1] e pProva1 restituiscono il secondo elemento.
pProva1 > pProva restituisce 'true'.
pProva1 - pProva restituisce 1.
Ma sui sistemi con allocazione decrescente della memoria?
Se questi sistemi si comportano diversamente c'è un modo per identificare
che si tratta di quel caso?

 
Posto che non so a cosa ti possa servire una cosa del genere (se dovessi aver bisogno di spostarmi su un'array e verificare dove mi trovo o se un elemento è sito più verso la fine o verso l'inizio rispetto ad un altro, utilizzerei gli indici e in questo modo mi paro il fondoschiena anche da ipotetiche allocazioni sparse, oltre che avere codice più leggibile), ma un modo potrebbe essere:
array di 2 elementi
if (&test[0]>&test[1]) {
	//decrescente
} else {
	//crescente
}
PSK

 pProva1 > pProva restituisce 'true'.
Su cosa sia 'true' o dei dubbi.
Sarebbe molto piu` corretto dire che (pProva1 > pProva)
assume un valore non nullo.

 ...
The C Programming Language, Second Edition
 by Brian W. Kernighan and Dennis M. Ritchie. 
Prentice Hall, Inc., 1988. 
 ISBN 0-13-110362-8 (paperback), 0-13-110370-9 (hardback)


D'accordo.
La domanda del cosa significano era da intendersi "Che senso ha?" "Qual'è la loro utilità?"
LP

 ... o dei dubbi.
Intendi: ho dei dubbi.

 Ma sui sistemi con allocazione decrescente della memoria?
scusate, l'ignoranza, che sistemi sono questi?

 senso ha?" "Qual'è la loro utilità?"
Nel C i vettori ed i puntatori sono equivalenti 
ed interscambiabili.
Ossia posto: 
int *p,*q,*,v[10],i,j,n;
 p = &v;
Allora:      Equivale a:
*(p+i)       v[i]
p[i]         *(p+i)
q = p+i;     q = &(v[i])
p += j;      p = &(v[j])
p > q        j > i
n = p - q;   n = j - i + 1;
Ossia ogni volta che abbia senso usare o risulta utile 
usare una qualsiasi espressione nella seconda colonna 
ha senso e solitamente e` piu' efficiente usare la 
corrispondente espressione della prima colonna.

 n = p - q;   n = j - i + 1;
                           ^ ...
Tipico /off-by-one/ /error/
 

 in C questo è un errore.
non e' un errore: ma '&aProva' ha (probabilmente) un tipo diverso da 
quello che ti aspetti.
Se, per esempio, abbiamo l'array:
int aProva[7];
- un riferimento ad aProva (oppure &aProva[0]) ha come tipo: puntatore 
ad int
- un riferimento ad &aProva ha come tipo: puntatore ad array di 7 int
Per spiegarmi meglio, assegniamo i due casi ad un puntatore:
int *p1;
p1 = aProva; /*oppure: p1 = &aProva[0]; */
int (*p2)[7];
p2 = &aProva;
(se, al contrario, tu assegnassi 'p1' ad &aProva, un compilatore ansi-c 
ti dovrebbe avvertire con un messaggio del tipo: 'assignment from 
incompatible pointer type')
Un altro esempio, ma con un array multidimensionale:
int aMatrice[7][4];
int (*p3)[4];
int (*p4)[7][4];
p3 = aMatrice; /*oppure: p3 = &aMatrice[0]; */
p4 = &aMatrice;
cioe':
- p3 e' un 'puntatore ad un array di 4 int'
- p4 e' un puntatore ad array di 7 array di 4 int;
Ciao
-- 
Cybertoldo
Per rispondermi via email, sostituisci moc.liamg con 
gmail.com

 corrispondente espressione della prima colonna.
...ma oggi i compilatori ottimizzano molto bene: in genere ha senso 
usare l'espressione piu' chiara e comprensibile.


 ...
Asolutamnte no!
&aProva non e` un lvalue, otterresti un errore di sintassi.

 ha senso usare l'espressione piu' chiara e comprensibile.
Sono d'accordo. Anzi ti diro` che gia` i compilatori 
degli anni ottanta che non ottimizzavano molto bene 
producevano lo stesso identico codice per i diversi 
costrutti e quindi gia` ieri l'altro era preferibile 
usare codice chiaro e comprensibile.
Pero` i vantaggi dell'usare i puntatori al posto degli 
indici per accedere ai vettori non si limitano alla
compattezza del codice ed alla velocita` ma a questo 
punto si passa alle guerre di religione.

 p4 = &aMatrice;
Scusate, non c'entra niente, ma e` bello che ogni tanto qualcuno mi
ricordi perche` ho abbandonato il C per programmare in Python e PHP. :)
Bye.

 &aProva non e` un lvalue, otterresti un errore di sintassi.
(qui non ti sei fatto sfuggire l'occasione, eh? :) )
scusa, intendevo dire "se, al contrario, tu assegnassi &aProva a 'p1' 
...". Pero' il typo mi pareva evidente, dati anche gli esempi 
(oltretutto nel contesto non aveva neanche senso il contrario).


 dettaglio.
qui sono d'accordo: dovrebbe essere un argomento da it.comp.lang.c


 it.comp.lang.c
Si` mi scuso, anche per aver insistito con questa mia.
Non intendo annoiarvi oltre con un argomento preistorico
riguardante un compilatore che non si usa piu` da anni.
 

 Controllero` domattina.
Non sono riuscito a recuperare una copia del TurboC 
comunque ha ragione Cybertoldo almeno per il primo 
punto.

Ottavio Campana wrote:

----------------------------------------------------------------------------
Inserisco qui chiarimenti/risposte:
- Il linguaggio è il C/C++ .
- Ho scritto eventuali sistemi, la mia conoscienza di sistemi al di fuori
dell'x86 con win o linux è quasi zero.
- Con i puntatori e la loro matematica si possono usare tecniche
interessanti/utili, è naturale che ogni tecnica di programmazione può
essere sostituita da un'altra, ma ognuna ha limiti, pregi e difetti unici.
- E' volutamente stato tralasciato il tipo di dati e il cast di tipi di dati
(la differenze tra ++ e +1 su un puntatore è solo una questione di
casting), visto che in questo caso è un punto trascurabile.
- Il confronto logico ( = > <) dei puntatori in C/C++ ha pienamente senso (è
una tecnica, ognuno è libero di considerarla utile o meno).
- Il senso di allocazione della memoria dipende dal sistema operativo,
l'hardware non dovrebbe essere minimamente determinante.
----------------------------------------------------------------------------
Il mio dubbio è che, in EVENTUALI sistemi, in cui l'indirizzo di memoria dei
vari elementi di un vettore sono decrescenti, per esempio 
pProva = &aProva[0] = indirizzo di memoria 100.000
pProva1 = &aProva[1] = indirizzo di memoria 99.990
la matematica dei puntatori risulti invertita, insomma, in questo caso
pProva + 1 non è più il prossimi elemento ma il precedente elemento (nel mio
esempio è anche oltre il limite iniziale del vettore) e che pProva1 >
pProva non è più vero ma falso.
Il dubbio è basato sul fatto che i puntatori sono strettamente legati agli
indirizzi di memoria dove vengono allocati i vari elementi, e quindi anche
le operazioni e i confronti su puntatori dipendano dal senso di allocazione
della memoria.

 pProva + 1 non è più ...
Questo non ha alcun senso. In C, scrivere aProva[1] è esattamente come 
scrivere *(aProva+1), qualsiasi sia l'architettura soggiacente.
Max

 la matematica dei puntatori risulti invertita, ...
Ammesso e non concesso che un compilatore faccia 
questa strana scelta non vedo perche' la matematica 
dei puntatori debba essere alterata.
I puntatori non sono interi e la loro aritmetica non 
e` l'aritmetica che si insegna alle scuole elementari.
pProva+1 e` la locazione successiva rispetto a pProva
qualunque sia lo schema di memoria, sia esso lineare,
segmentato, paginato, virtuale e cicirinielli vari;
che questo sia 99999, 34, 123858 non ha nessuna 
importanza, ammesso anche che un puntatore si possa
rappresentare con una stringa di cifre (cfr i 
puntatori dell' 8086).
 

 la matematica dei puntatori risulti invertita, ...
Ammesso e non concesso che un compilatore faccia 
questa strana scelta non vedo perche' la matematica 
dei puntatori debba essere alterata.
I puntatori non sono interi e la loro aritmetica non 
e` l'aritmetica che si insegna alle scuole elementari.
pProva+1 e` il puntatore all'elemento successivo 
rispetto a quello puntato da pProva qualunque sia 
lo schema di memoria, sia esso lineare, segmentato,
paginato, virtuale e cicirinielli vari; che la sua 
locazione sia 99999, 34, 123858 non ha nessuna 


 scrivere *(aProva+1)
Vero. E questa equivalenza si puo' notare anche negli "effetti 
collaterali" che produce:
	a[i]
corrisponde a:
	*( (a) + (i) )
oppure, per la proprieta' commutativa, a:
	*( (i) + (a) )
quindi, curiosamente, anche a:
	i[a]
...quindi, nell'esempio sopra, aProva[1] e 1[aProva] daranno lo stesso 
risultato :)


 ...
Hai mai sentito parlare di "gruppo abeliano"?
Evidentemente no, ma nemmeno di logica, di 
algebra di Boole, di ragionamento ed i tante 
altre cose. 


(no comment :-) )
Buon Natale!


 risultato :)
bel giochino, sbagliato ma divertente.

 bel giochino, sbagliato ma divertente.
???
M

 dei vari elementi di un vettore sono decrescenti, per esempio
]zac[
Bene, il dubbio in realtà ha una soluzione semplice e banale.
I vari elementi di una stringa o di un vettore non vengono allocati dal
sistema operativo singolarmente, ma viene allocato un blocco di memoria
(che quindi può essere allocato in senso crescente, discendente, casuale),
poi all'interno del blocco di memoria sono le librerie del C/C++
(compilatore/linker/run-time, ecc.) ad '''allocare''' in senso crescente e
consecutivo i vali elementi.
In questo modo si ottiene che i puntatori contengono l'indirizzo 'reale' in
cui è allocato il vettore/stringa/ecc. e che i suo elementi hanno indirizzi 
sicuramente crescenti e consecutivi, su qualsiasi sistema.

(x-post & f/up su it.comp.lang.c)
Ottavio Campana su it.comp.os.linux.development ha scritto:

Non credo che sia sbagliato.
Non ho indagato molto... ma nel documento dello standard C99 mi sembra 
che non ci sia nulla che vieti questa simmetria riguardo l' array 
subscripting.
Nel 'C99 Rationale' rev. 5.10 del 2003, invece, e' riportata questa frase:
     6.5.2.1
     - The C89 Committee found no reason to disallow the symmetry
     that permits a[i] to be written as i[a].
Quindi parrebbe tutto valido.
PS: ovviamente la questione e' di dubbia utilita'... ma se per 
curiosita' vuoi fare una veloce prova con il tuo compilatore:
     printf("%c\n", 3["ABCDEFG"]);
(dovrebbe stampare "D\n" nello std. output)


 un modo potrebbe essere: array di 2 elementi
]zac[
Il codice che volevo riscrive è un po' complesso, ha una struttura a nodi
con sotto sottonodi e vari elementi e varie necessità di accesso ai vari
elementi.
In sintesi, ho seguito il tuo consiglio e utilizzo un indice numerico è un
vettore di puntatori alla struttura dei vari nodi che consento una facile
navigazione nei nodi (eliminando una serie di riferimenti numerici (che
stavo valutando se sostituirli con puntatori e la matematica dei puntatori)
al nodo padre, al nodo superiore, ecc., che per tenerli aggiornati in casi
di inserimento, eliminazione il codice era divento un casino).