L`aritmetica dei puntatori Solo due operatori aritmetici possono

L’aritmetica dei puntatori
Solo due operatori aritmetici possono essere applicati alle variabili di tipo puntatore: somma e sottrazione.
int *p1,*p2;
int vect[10];
p1 = & vect[0]; // p1 fa riferimento al primo elemento dell’array
p2 = p1 + 3;
// p2 ora fa riferimento ad una cella di memoria che è collocata ad una distanza in Byte
// dalla prima pari a 3 * sizeof(int)
p1
vect[0]
Come interpreto questo simbolo?
vect[1]
(a) il quarto elemento dell’array di nome vect
(b) l’elemento che, all’interno dell’array, si trova tre
celle di memoria (celle di dimensione tale da
contenere una variabile di tipo int) dopo la
prima
vect[2]
p2= p1+3
vect[3]
Tenendo conto che il nome dell’array, vect, risulta automaticamente definito
come il puntatore alla prima cella di memoria dell’array, allora, se
p1 = & vect[0];
p1 e vect hanno lo stesso valore
Allora i seguenti nomi sono equivalenti:
vect[3] / *(p1+3) / p1[3] / *(vect+3)
Solo due operatori aritmetici possono essere applicati alle variabili di tipo puntatore: somma e sottrazione.
int *p1,*p2;
int vect[10];
p1 = & vect[0]; // p1 fa riferimento al primo elemento dell’array
p2 = p1 + 4;
// p2 ora fa riferimento ad una cella di memoria che è collocata ad una distanza in Byte
// dalla prima pari a 4 * sizeof(int)
Come posso ora identificare l’elemento vect[2]?
p1
vect[0]
vect[1]
vect[2]
p2= p1+4
vect[2]
*(p1+2)
vect[3]
p1[2]
*(p2-2)
vect[4]
p2[-2]
// il secondo elemento di un array che inizia da vect
// la cella di memoria che si trova due locazioni dopo
// la cella cui fa riferimento p1
// il secondo elemento di un array che inizia da p1
// la cella di memoria che si trova due locazioni prima
// della cella cui fa riferimento p2
// l’elemento di un array che si trova due posizioni prima
// dell’elemento p2[0]
Tutto questo ci indica che un’area di memoria contenente un
numero arbitrario di variabili può essere gestita tranquillamente
conoscendo l’indirizzo di una di queste variabili e la collocazione
delle altre. Per semplicità è conveniente fare riferimento all’indirizzo
del primo elemento e ricordarsi qual è il numero totale di elementi.
Solo due operatori aritmetici possono essere applicati alle variabili di tipo puntatore: somma e sottrazione.
int *p1,*p2;
int vect[10];
p1 = & vect[0]; // p1 fa riferimento al primo elemento dell’array
p2 = p1 + 4;
// p2 ora fa riferimento ad una cella di memoria che è collocata ad una distanza in Byte
// dalla prima pari a 4 * sizeof(int)
Altri impieghi degli operatori + e – non sono ammessi ...
int *p1,*p2;
int vect[10];
p1=&vect[1];
p2=&vect[4];
p1=p1+p2; // NON ha senso
p1=&vect[1];
p2=&vect[4];
p1=p2-p1; // NON ha senso
p1=&vect[1];
p2=&vect[4];
p2-p1; // questa espressione può avere senso ... cosa rappresenta?
Scriviamo l’algoritmo di ordinamento usando l’aritmetica dei puntatori
#include <stdio.h>
#include <stdlib.h>
#define NUM 50
int main()
{int vet[NUM],i,scambio;
o for(i=0;i<NUM;i++)
o { *(vet+i) =rand()%51;
printf(“Ecco il valore di vet[%d]: %d\n”,i, *(vet + i) );}
o
o
o
o
o
o
o
o
o
o
scambio = 1;
while(scambio) // se scambio vale 1 significa che
{scambio = 0;
// i valori di alcuni elementi sono stati
for(i=0;i<(NUM-1);i++) // scambiati tra loro
{if( *(vet+i) > *(vet + i+1) ) // non è stato incluso il caso =
{scambia(vet + i, vet + i+1 );
scambio=1;}
}
}
o for(i=0;i<NUM;i++)
o {printf(“Ecco il valore di vet[%d]: %d\n”,i, *(vet+i) );}
o return 0;
}
Le righe di codice precedute dal simbolo o
rappresentano istruzioni in cui si ha un
accesso all’area di memoria in cui è
contenuto l’array (ovvero le le NUM variabili
di tipo int).
Visto che un’area di memoria di dimensione
arbitraria si gestisce conoscendo, ad
esempio, l’indirizzo del primo elemento ed il
numero totale di elementi, possiamo
implementare delle funzioni che, ricevendo
tali parametri, eseguano, in modo compatto,
le operazioni svolte da questo codice, in
modo da renderlo più modulare.
Inoltre, tali funzioni ci permetteranno di
visualizzare, inizializzare ed ordinare un
QUALSIASI array di variabili di tipo int.
funzioni.h
#include <stdio.h>
#include <stdlib.h>
void StampaArrayInt(int *,int);
void InitArrayInt(int *, int);
void OrdinaArrayInt(int*, int);
void StampaArrayInt(int *vet,int dim)
{int i;
for(i=0 ;i< dim ; i++)
printf(“indice: %d, valore: %d\n”,i, *(vet+i));
}
void InitArrayInt(int *vet, int dim)
{int i;
for(i=0;i<dim;i++)
*(vet+i) = rand()%51; // qui si può anche usare IntCasuale()
}
void OrdinaArrayInt(int *vet, int dim)
{int i, scambio = 1;
while(scambio)
{scambio = 0;
for(i=0;i<(dim-1);i++)
{if( *(vet+i) > *(vet + i+1) )
{scambia(vet + i, vet + i+1 );
scambio=1;}
}
}
array.c
#include “funzioni.h”
#define NUM 50
int main()
{int vet[NUM];
InitArray(vet,NUM);
StampaArrayInt(vet,NUM);
OrdinaArrayInt(vet,NUM);
StampaArrayInt(vet,NUM);
return 0;
}
Le stringhe
In generale, di un vettore è noto l’inizio (o meglio la collocazione in memoria del primo elemento), ma
nell’array non è contenuta alcuna informazione relativa al numero totale di elementi dell’array stesso.
Le stringhe sono degli array di char che hanno un “terminatore”, ovvero si sa dove iniziano ed anche dove
terminano. Il carattere che fa da terminatore è il carattere con codice ASCII nullo, ‘\0’
array di 14 char
u
n
a
s
t
r
i
n
g
a \0 x
v
g
a \0 x
v
stringa formata da 11 char
array di 14 char
u
n
a \0
s
t
r
i
n
stringa formata da 3 char
La lunghezza di una stringa non coincide con quella dell’array di char che la contiene, per lo meno la lunghezza è
inferiore di un’unità (in quanto deve esserci spazio per il carattere terminatore)
Come inizializzare una stringa?
#include <stdio.h>
#include <string.h>
#define NUM 50
int main()
{char stringa[NUM];
char *indice;
printf(“Inserisci una frase (al max di %d caratteri): ”,NUM-1); // NUM-1 per lasciare spazio al terminatore
scanf(“%s”,stringa);
// stringa rappresenta il puntatore alla locazione di memoria
// in cui si inizierà a copiare i caratteri inseriti
printf(“Il testo inserito: %s\n”,stringa); // allo specificatore di formato %s deve corrispondere il puntatore
// al primo elemento della stringa che deve essere visualizzata
printf(“ Di quanti caratteri e’ composta la stringa?\n”,strlen(stringa)); /* La funzione int strlen(char *)
appartiene
alla libreria standard e permette di determinare di quanti caratteri sia composta
una stringa; la funzione conteggia tutti i caratteri ESCLUSO il terminatore */
indice=stringa;
// stringa è automaticamente definito come il puntatore al primo elemento dell’array, quindi
while(*indice)
// il suo valore NON deve essere modificato
{printf(“Ecco una parte di stringa: %s\n”,indice);
indice=indice+1;}
// per ottenere lo stesso risultato, si può scrivere anche
indice=stringa;
while(indice[0])
printf(“Ecco una parte di stringa: %s\n”,indice++);
return 0;
}
Esercizi proposti
Nel testo che segue, vengono richiamate le funzioni definite nella pagina “Esercizi proposti/2” della scorsa lezione.
(a)
implementare una funzione che riceve come parametro una variabile di tipo char e che restituisce un valore di tipo int; la
funzione deve determinare se il carattere ricevuto corrisponda a quello di una vocale. Se così è la funzione deve restituire il
valore 1, altrimenti 0.
(b)
implementare una funzione che riceve come parametro un puntatore a char e restituisce un valore di tipo intero. La
funzione deve contare il numero di vocali contenute nella stringa cui fa riferimento il puntatore a char che la funzione
riceve come parametro; fatto questo, essa deve restituire un valore pari a tale numero. Per l’implementazione servirsi della
funzione definita al punto precedente.
(c)
implementare una funzione che riceve come parametro una variabile di tipo char e che restituisce un valore di tipo int. Se il
carattere ha codice ASCII 32 (è lo spazio, ‘ ‘), la funzione deve restituire 1, altrimenti 0.
(d)
implementare una funzione che riceve come parametro un puntatore a char e che non restituisce alcun valore: la
funzione deve fare in modo che i caratteri della stringa vengano disposti in ordine alfabetico (senza considerare la
differenza tra lettere maiuscole e minuscole). Per ottenere questo risultato utilizzare la funzione definita al punto (3) come
criterio di ordinamento (permette di decidere se una coppia di caratteri sia disposta o meno secondo l’ordine alfabetico) e
la funzione definita al punto (1) per scambiare i valori di due variabili di tipo char (ovvero di due elementi della stringa)
(e)
Scrivere un programma in cui venga dichiarato un vettore di char formato da NUM elementi (definire la macro NUM);
chiedere all’utente di inserire del testo e salvare tale testo nell’array di char appena definito. Visualizzare i caratteri inseriti
dall’utente. (Facoltativo: svolgere quest’ultimo compito senza usare un indice di tipo intero). Usando la funzione definita al
punto (b) contare quante vocali siano presenti nel testo inserito dall’utente. (Facoltativo: usando la funzione definita al
punto (c), provate a far diventare maiuscole tutte le iniziali delle parole inserite dall’utente). Usando la funzione definita al
punto (d) ordinare i caratteri contenuti nella stringa.
(f)
Facoltativo: vi viene in mente un metodo per invertire l’algoritmo di ordinamento, ovvero per ottenere la stringa originale
a partire da quella ordinata?