Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Richiami
Se T è un htypenamei, la dichiarazione
T *p;
p=&var;
Aritmetica
Aritmetica dei puntatori. Sia
x un array monodimensionale (vettore) di N elementi di
tipo T ;
P , Q espressioni di tipo T *,
k espressione di tipo intero, 0 ≤ k ≤ N − 1.
È noto che
Se P =&x[0], e
l è un’espressione di tipo intero, con 0 ≤ l ≤ N − 1:
P [l] equivale a x[l].
Aritmetica
Vale un meccanismo molto più generale.
Un vettore residente in memoria rappresenta una sorta
di spazio di indirizzi, all’interno del quale è definita
un’aritmetica degli indirizzi (confronti, modifica con
operatori opportuni . . . ).
Se P =&x[k ], e
l è un’espressione di tipo intero, con 0 ≤ k + l ≤ N − 1:
P [l] equivale a x[k + l].
Aritmetica
Se P =&x[0] e Q =&x[k ], risulta P +N >Q.
— Da non dereferenziare mai!
Nella valutazione di un’espressione, se x è il nome di
un array, x viene automaticamente convertito nel
puntatore &x[0]. Non accade il contrario!
Nomi di array e puntatori sono quasi intercambiabili
nelle espressioni.
char nome[]="Pippo", *str;
str=nome; /* Corretto: converte nome[] in un ch
/* come str=&nome[0]; */
nome=str; /* Errore! */
Nei parametri di funzione, T [] è sinonimo di T *.
Ecco perché gli array sono passati per riferimento.
Funzioni di I/O – p.8/36
Aritmetica
int x[]={2,4,6,8,10};
int *p, *q;
p=x; // p=&x[0]
q=x+4; // q=&x[4]
printf( "q-p=%d\n", (q-p) ); // Stampa 4
p++; // ora p=&x[1], come p=p+1;
printf( "%d, %d\n", *p, p[1] ); // Stampa 4, 6
if( p<q ) {...} // Vero!
if( p<(q+7) ) {...} // Indeterminato!
*(p+1)=3; // x[2]=3
*(q+7)=3; // Indeterminato!
Aritmetica
Esempio. Calcolo della norma euclidea di un vettore di n
elementi.
double norm(double *x, int n)
{
int i;
double sum=0.0;
for(i=0; i<n; i++)
sum+=x[i]*x[i];
return sqrt(sum); /* Radice quadrata */
}
...
double z[MAXDIM], modulo;
...
modulo=norm(z,10);
(z[3], . . . , z[9])
basta richiamare
modulo=norm(&z[3],7); oppure
modulo=norm(z+3,7);
Aritmetica
L’aritmetica dei puntatori è diventata rapidamente
popolare in C, perché
consente accessi più veloci agli array (almeno, una
volta);
permette un accesso low-level ma comunque con
una certa astrazione alla memoria.
Attenzione: in questo caso si fa spesso uso di caratteristiche dei puntatori legate
all’implementazione!
Aritmetica
Esempio. Scrivere una funzione
Aritmetica
Implementare una funzione
Aritmetica
void selsort(int *v, int n)
{
int i;
for(i=0; i<n-1; i++) {
scambia(v,i,min_pos(v,i,n-1));
}
}
Aritmetica
Implementare una funzione
Aritmetica
void selsort(int *begin, int *end)
{
for(;begin<end;begin++)
scambia(begin, min_pos(begin,end));
}
void *
Assegnazioni e conversioni
void x; /* Errore! */
void *p; /* Ok, puntatore generico */
int i;
double y;
p=&i; /* Ok */
p=&y; /* Ok */
*p=0.0; /* Errore! */
Assegnazioni e conversioni
int x=0, y, *px, *py;
void *p;
double d, *pa;
px=&x;
py=&y;
pa=px; /* Errore! */
py=px; /* Ok, stesso tipo puntato */
*py+=10; /* x=10 */
p=px; /* Ok, void* a sin.*/
pa=p; /* Ok, void* a destra*/
*pa=3.0; // x=??? dip. implem.
pa=&d;
py=(int *)pa; /* Ok, conversione forzata */
*py=1; /* d=??? dip. implem.*/
Assegnazioni e conversioni
Ad un puntatore con valore NULL non si deve mai
applicare l’operatore * (dereferenziazione).
double *p=NULL;
*p=0.5; // Errore!
NULL è definito in vari header file (stddef.h,stdio.h,
stdlib.h, . . . ).
#include <stdlib.h>
Memoria dinamica
void *malloc(size_t size);
Riserva (alloca) sullo heap un blocco di size byte.
Il tipo size_t è un tipo intero “grande abbastanza”.
Ritorna un puntatore corrispondente all’inizio del blocco
riservato.
Ritorna NULL se l’allocazione non può essere effettuata
(es. out of memory).
Il contenuto iniziale del blocco è indefinito (la memoria è
“sporca”).
N sizeof(T )* byte.
Memoria dinamica
Allocazione dinamica di array.
Se N è un’espressione di tipo intero,
e T un nome di tipo, chiamando
malloc(N *sizeof(T ),
Memoria dinamica
void free(void *p);
Rilascia il blocco di memoria al quale punta p.
Il valore di p deve essere stato ottenuto come risultato
di una malloc(), altrimenti l’effetto della free() è
indefinito.
Le variabili allocate nello heap per mezzo di malloc()
non cessano di esistere all’uscita dal blocco nel quale
sono state allocate.
Perché la memoria corrispondente sia liberata occorre
una free() esplicita (no garbage collection.).
Dopo la free(), l’indirizzo contenuto in p non è più
“affidabile” (e non deve essere dereferenziato).
Memoria dinamica
Esempio.
float *v;
int i, n;