Un array e’ una
struttura di dati costituita da un insieme di variabili dello stesso tipo di dato (intero,
carattere, reale ecc. ), a cui e’ possibile accedere tramite un nome, e referenziare
uno specifico elemento attraverso un indice.
Nel linguaggio C gli elementi di un array sono allocati in MC in celle adiacenti, in cui viene associato l’indirizzo piu’ basso, al primo elemento dell’ array e l’indirizzo piu’ alto all’ultimo elemento dell’array.
Gli array possono essere ad una dimensione (vettori ) , a due dimensioni (matrici) , ad n dimensioni (array multidimensionali).
Se scriviamo la seguente definizione int A[5];
avremo dichiarato un array o vettore A formato da 5
elementi il cui tipo e’ un intero.
In MC viene allocata una sequenza di locazioni intere ( 5 locazioni intere , una dopo l’altra ) come in figura.
|
|
|
|
|
Ogni locazione sara’ tale da poter contenere un valore dell’array.
Ciascuna locazione e’ una variabile uguale ad una variabile
intera, soltanto che queste 5 variabili hanno un NOME COMUNE ( A ) e sono
distinte da un indice che varia da 1 fino a 5.
Nel linguaggio C il primo elemento di un array ha indice 0,
quindi l’indice varia da 0 fino a 4
Per cui avremo A[0], A[1], A[2], A[3], A[4] .
0 |
1 |
2 |
3 |
4 |
A[0] |
A[1] |
A[2] |
A[3] |
A[4] |
Con le variabili con indice si puo' fare tutto quello che
si fa con le variabili normali .
Esempio
A[3] = 7 ; /* assegniamo il valore intero 7 alla
quarta componente dell’ array A */
if (A[3]==7) printf (“\n%d”, A[0]) ;
/* se la quarta componente dell’ array A e’ uguale a 7
allora stampa la prima componente dell’array A */
L’ indice dell’ array puo’ essere gestito scrivendo
espressioni aritmetiche :
A[j] coincide con la componente (j+1)-esima ; se j e’ uguale a
2 e’ la terza componente.
A[J+2] coincide con
A[4] ossia con la quinta componente.
Il vincolo da mantenere e’ che l’indice usato sia tale da
non andare fuori campo.
A[-1] NON ESISTE !
A[5] NON ESISTE !
Gli array non possono essere
assegnati ad array:
Avendo int
x[5],y[5]; …. x=y ; /*e’
scorretta*/
L’ indirizzamento di un elemento
dell'array puo’
avvenire come detto mediante una espressione
int v=2, a=1; …per cui x[v+4-a];
/*equivale all’accesso ad x[5] */
Non c’e’ nessun controllo
sull’effettiva esistenza della componente indirizzata: … x[12] = 9; /* la
tredicesima componente dell’array non esiste ma l’istruzione passa la
compilazione: verra’ posto nella tredicesima locazione intera a partire
dall’inizio dell’array…*/
Nel caso
volessimo ordinare almeno un solo
elemento di un array A costituito da 20
elementi di tipo intero potremmo usare il seguente codice:
#include<stdio.h>
#define N 20
int
main( )
{
int A[N] ; /* dichiarazione dell’ array A di N =20 elementi */
int AUX;
/* dichiarazione della variabile intera AUX di ausilio (appoggio) */
int j;
/* variabile indice per scandire l’ array */
for (j=0; j<=N-2; j++)
if
(A[J] > A[J+1] ) /* confronto fra il j-esimo
ed (j+1) - esimo elemento */
{
AUX= A[j] ;
A[j] = A[j+1] ;
A[j+1]= AUX;
}
for (j=0; j<=N-1; j++)
printf (“\n%d”,A[j]);
return 0;
}
Notiamo che l’ indice dell’ array ( elemento fra le parentesi quadre ) deve essere sempre un intero od una espressione intera.
Una variabile di tipo array si dichiara attraverso la seguente sintassi:
< var_array>::= <tipo><identificatore_var><array> ;
<array>::= < costruttore_array> |
<costruttore_array> <array>
<costruttore array>::= [ <espressione_costante_intera>]
esempio
float negozi [20];
/* abbiamo dichiarato un array chiamato negozi formato da
20 elementi il cui tipo e’ float. */
l’ indice dell'array puo’ spaziare da 0 fino a 19
Con
gli array molte delle operazioni diventano piu’ compatte se eseguite sulle
variabili indicizzate piuttosto che su variabili isolate.
Ad
esempio dovendo leggere dei dati sui negozi basta scrivere :
for
(i=0;i<20;i++)
scanf (“%f”,&negozi[i]);
/*lettura della i-esima variabile*/
Il
linguaggio C permette la loro inizializzazione in fase di dichiarazione.
L’
inizializzazione di un array di dimensione unitaria ha il seguente formato:
tipo
nome_array[dimensione]={lista _di_valori};
La
lista_di_valori e’ una lista di costanti separate da delle virgole. Il tipo di
queste costanti deve essere compatibile con il tipo degli elementi dell’ array.
La prima costante che si incontra nella sequenza lista_di_valori viene assegnata al primo elemento, la seconda costante al secondo elemento e cosi di seguito.
L'inizializzazione di un array in fase di esecuzione si puo' fare utilizzando ad esempio un ciclo di iterazione for.
Inizializzazione
di un array, di nome potenze_di_due, di interi formato da n=11 elementi:
int potenze_di_due[11]={1,2,4,8,16,32,64,128,256,512,1024};
Con
questa inizializzazione abbiamo assegnato all’ elemento dell’array di
indice i-esimo il valore di 2 elevato ad i.
Per cui si avra’ che l’ elemento di indice 0 cioe’ potenze_di_due[0] sara’ inizializzato ad 1 e cosi di seguito fino a potenze_di_due[10] che assumera’ il valore 1024.
Un array a due dimensioni
(detto anche matrice) consiste in pratica in un array di array ad una
dimensione.
La forma generale per dichiarare un array bidimensionale e’
la seguente:
tipo
nome_array[dimensione1][dimensione2]
volendo dichiarare una matrice di nome matrix, di 6 righe
per 4 colonne, i cui elementi siano di tipo intero, scriveremo:
int matrix[6][4];
La matrice come noto e’ una struttura bidimensionale , quindi ci serve un indice i per scandire le righe ed un indice j per scandire le colonne.
Supponendo di voler inizializzare a 0 tutti gli elementi
della matrice matrix, possiamo scrivere:
for (i=0;
i<6; i++)
for (j=0;
j<4; j++)
matrix[i][j]= 0 ;
/*queste istruzioni azzerano una dopo l’ altra la : riga 0 , riga 1, … ,riga 5*/
Notiamo quindi che nel linguaggio C vettori e matrici si
dichiarano usando il costruttore di tipo [ ] , chiamato costruttore array.
Se volessimo
accedere all’ elemento avente coordinate 3, 4 dell’ array di nome matrix
per assegnare il valore intero 55, scriveremmo:
matrix[3][4]=55;
/* tenere presente che tale elemento corrisponde alla 4
riga e 5 colonna della matrice corrispondente */
L’ array di nome matrix e’ cosi’ logicamente rappresentato :
|
Secondo
indice j |
|||
Primo indice i |
0 , 0 |
0 , 1 |
0 , 2 |
0 , 3 |
1 , 0 |
1 , 1 |
1 , 2 |
1 , 3 |
|
2 , 0 |
2 ,1 |
2 , 2 |
2 , 3 |
|
3 , 0 |
3 , 1 |
3 ,2 |
3 , 3 |
|
4 , 0 |
4 , 1 |
4 ,2 |
4 , 3 |
|
5 , 0 |
5 , 1 |
5 ,2 |
5 , 3 |
Il primo indice e’ l’ indice di riga, il secondo indice e’
l’ indice di colonna.
L’ occupazione di memoria di un array bidimensionale si
puo’ ricavare dalla seguente formula,(essendo
sizeof(tipo) un operatore unario che agisce durante la compilazione e che
restituisce il numero di byte che occupa il tipo di dato fra le parentesi tonde)
:
Byte totali occupati =
= (dimensione di i)
X (dimensione j )X ( sizeof(tipo))
Ad esempio la nostra matrice di tipo intero matrix avra’:
Byte totali occupati = 6 X 4 X 2 = 48 byte
In quanto la dimensione del tipo intero in C e’ di 2 byte.
Il
linguaggio C permette la loro inizializzazione in fase di dichiarazione.
L’
inizializzazione di un array di dimensione N=2 ha il seguente formato:
tipo
nome_array[dimensione1][dimensione2]={lista
_di_valori};
La
lista_di_valori e’ una lista di costanti separate da virgole. Il tipo di
queste costanti deve essere compatibile con il tipo degli elementi dell’ array.
La prima costante che si incontra nella sequenza lista_di_valori viene assegnata al primo elemento, la seconda costante al secondo elemento e cosi di seguito.
Con
questa inizializzazione abbiamo assegnato all’ elemento dell’array di
indice i-esimo il valore di 2 elevato ad i.
Per cui si avra’ che l’ elemento di indici 0, 0, cioe’ matrix[0][0] sara’ inizializzato ad 1 e matrix[0][1] assumera' il valore 2 ....matrix[0][2] assumera' il valore 4....cosi di seguito fino a matrix[2][2] che verra' inizializzato al valore 256.
Notiamo che gli elementi sono elencati nello stesso ordine con cui si trovano nella memoria; dal punto di vista logico, pero' ogni gruppo di elementi nelle coppie di parentesi graffe interne rappresenta una riga della matrice.
Per
avere una idea piu’ pratica di quanto detto consideriamo il seguente programma
che carica in un array a due dimensioni i numeri da 1 fino a 20 e li stampa una
riga per volta:
#include<stdio.h>
int main()
{
int matrix[5][4] /* dichiarazione della matrice di nome matrix*/
int i , j ; /* dichiarazione indice di riga ed indice di colonna*/
for (i=0;
i<5; i++)
for (j=0; j<4; j++)
matrix[i][j]=(i*4)+j+1;
/*stampa*/
for (i=0; i<5; i++)
{
for (j=0; j<4; j++)
printf
(“%3d ”,matrix[i][j]) ;
/*%3d significa che riserva 3 cifre per il numero intero*/
printf
(“\n”) ; /* newline va a capo, ad ogni riga della
matrice*/
}
return
0;
}
all’elemento matrix[0][0] viene assegnato il valore 1, a matrix[0][1] viene assegnato il valore 2 e cosi di seguito fino a 20. In pratica avremo la struttura seguente per l’array matrix:
|
0 |
1 |
2 |
3 |
0 |
1 |
2 |
3 |
4 |
1 |
5 |
6 |
7 |
8 |
2 |
9 |
10 |
11 |
12 |
3 |
13 |
14 |
15 |
16 |
4 |
17 |
18 |
19 |
20 |
Una societa’ possiede 15 negozi; dati i guadagni mensili di ciascun negozio (15 input )
1) stampare la media (Media)
2) stampare quali negozi hanno
guadagni inferiori ad 1/3 della media
3) stampare la media dei
guadagni tolto il migliore ed il peggiore (Media2)
4) stampare quali negozi sono
sotto alla Media2
algoritmo
1) leggere i dati e memorizzarli
nel vettore cioe’ nelle componenti dell’ array Negozi[i]
2) calcolare la media (Media)
3) scandire i negozi e stampare
quelli il cui guadagno e’ inferiore ad 1/3 della Media
4) trovare e stampare i/il
negozi/o con il max guadagno (Max)
5) trovare e stampare i/il
negozi/o con il min guadagno (Min )
6) calcolare la Media2 dei
guadagni (detta media ridotta)
7) scandire l’ array con stampa
di indice e valore quando il valore e’ inferiore a Media2
Soluzione
Limitandoci
per ora ai primi 3 punti dell’ algoritmo avremo:
1) Leggere ogni elemento del
vettore
(“scandire” il vettore componente per componente e
assegnare alle componenti i dati letti)
questo si traduce in
for (i=0;
i<15; i++)
{
printf (“\n negozio
%2d : “,i+1);
scanf(“\n%f”,&Negozi[i]);
}
2)
Inizializzazione di Somma_Guadagni a
zero per calcolare la media Media
Sommare (ACCUMULARE) in Somma_Guadagni
tutti i valori dell’ array
Media= Somma_Guadagni/15;
3) Stampa dei negozi pecore nere
Per ogni negozio : se guadagno <Media/3
Stampa indice del negozio e guadagno ossia stampa di i e di
Negozi[i]
Adesso
definiamo due costanti ( valori cristallizzati nel codice ) con uno dei due
metodi consenti dal linguaggio C
#define DIM 15
#define RAGIONE
1/3
Poi
possiamo definire alternativamente
1) float Negozi[DIM];
2) typedef float VETTORE_NEGOZI[DIM]; e poi
VETTORE_NEGOZI Negozi;
/* con questa seconda definizione abbiamo usato la parola
chiave typedef per definire un array di nome VETTORE_NEGOZI formato da 20
componenti di tipo reale.
E poi abbiamo introdotto un nome Negozi che e’ di tipo
VETTORE_NEGOZI.
Questa e’ la definizione dei tipi da parte dell’ utente.
Infatti abbiamo anche per un tipo_array la seguente sintassi:
<tipo_array>::= typedef
<tipo><identificatore><array>
Il
programma completo guadagni.c puo’ essere trovato al seguente link a cui vi
rimando per una analisi completa e dettagliata : GUADAGNI DEI NEGOZI.
Calcolare la matrice C prodotto di due matrici di
interi quadrate A (n x n) e B(n x n) :
C=A*B ?
Esempio
di matrice A ,con elementi generici aij , di dimensioni 3 x 3
A(
3 righe e 3 colonne )
A
a11 |
a12 |
a13 |
a21 |
a22 |
a23 |
a31 |
a32 |
a33 |
Come certamente sara’ noto, il prodotto di due matrici
quadrate (numero di righe uguale al numero di colonne) entrambe di dimensioni n
x n ci fornira’ una matrice una nuova matrice C anche essa di dimensioni n x n,
dove il generico elemento della matrice C detto Cij sara’ dato da:
n Cij = å aik * bkj k=1 con 1 <= (i,j) <= n |
Ricordiamo
che per eseguire il prodotto di due matrici generiche A (m x n ) e B(r x
c) e’ necessario che il numero di
colonne della matrice A coincida con il numero di righe della matrice B ; nel
nostro caso dobbiamo avere n = r ed otterremo una matrice prodotto C (m x c) avente un numero di righe pari
alle righe di A ed un numero di colonne pari alle colonne di B.
Detto
cio’ avremo che per le matrici quadrate il prodotto e’ sempre eseguibile dal
punto di vista algebrico e la formula per calcolarla sara’ la sopradetta.
Adesso scriviamo il programma per calcolare C
sapendo che la dimensione n delle due matrici quadrate A e B e’ pari a 10.
#include<stdio.h>
#define n
10 /* numero di righe e colonne
delle matrici */
int main ( )
{
int A[n][n] ;
int B[n][n];
int C[n][n];
int i, j, k; /* indici per scandire le matrici
*/
/*
lettura matrice A */
printf (“\nInserite gli N= %d elementi
della matrice A\n”, n*n);
for (i=0 ;
i<n ; i++)
for (j=0 ;
j<n ; j++)
scanf (“\n%d”,&A[i][j]);
/*
lettura matrice B */
printf (“\nInserite gli N= %d elementi
della matrice B\n”, n*n);
for (i=0 ;
i<n ; i++)
for (j=0 ; j<n
; j++)
scanf (“%d”,&B[i][j]);
/* Calcolo della matrice prodotto C */
for (i=0 ;
i<n ; i++)
for (j=0 ; j<n ; j++)
{
C[i][j]=0; /* inizializzazione della
matrice prodotto*/
for (k= 0;
k<n ; k++)
C[i][j] = C[i][j] +
A[i][k] * B[k][j];
}
/* Stampa della matrice prodotto */
for (i=0 ;
i<n ; i++){
for (j=0 ; j<n ; j++)
printf (“%6d ”,
C[i][j]);
printf (“\n”); /* Per andare a capo ad
ogni riga */
}
return 0;}
Nella parte destra di una espressione vi possono tranquillamente essere dei puntatori ed e’ possibile assegnare il valore di questi puntatori ad altri puntatori.
Nel linguaggio C si possono usare soltanto due operatori aritmetici sui puntatori: l’addizione + e la sottrazione - .
Se punt1 e’ un puntatore ad interi, l’espressione *punt1 , si puo’ utilizzare come qualsiasi variabile intera.
int k, i=1, *punt1;
punt1 = &k; /*inizializzazione di punt1:ora in punt1 vi e’ l’indirizzo di k*/
punt1 =
i;
/* la locazione associata a k ora contiene 1*/
*punt1 = 25; /* la locazione associata a k ora contiene 25*/
i = *punt1; /*alla variabile i viene assegnato 25*/
Consideriamo la seguente dichiarazione di un puntatore ad un intero:
int *punt1;
Come noto il tipo intero occupa solitamente 2 byte in memoria (2 celle); per cui nel caso il valore corrente del puntatore punt1 e’ 1500 , dopo la seguente espressione
punt1 = punt1 +1 ; il contenuto di punt1 diventa 1502, per poter puntare all’ intero successivo e non alla cella successiva. Idem per il decremento;
punt1 = punt1 +1; equivale a punt1++;
punt1--; avremmo come contenuto di punt1 1498.
Nota: La maggior parte dei computer oggigiorno utilizzano interi di 2 o 4 byte. Alcune macchine piu’ recenti utilizzano interi di 8 byte.
Se fosse stata char *punt1; (tutto semplice poiche’ il carattere occupa 1 byte (1cella) ).
Indirizzo di memoria |
Contenuto della memoria |
variabili |
1498 |
. |
punt1-- |
1499 |
. |
. |
1500 |
. |
punt1 |
1501 |
. |
. |
1502 |
. |
punt1++ |
1503 |
. |
. |
1504 |
. |
. |
1505 |
. |
. |
… |
. |
. |
Uniche operazioni consentite con i puntatori sono : incremento ,decremento e somma e sottrazione di interi.
Importante
ricordare sempre: che gli array nel linguaggio C sono gestiti con un meccanismo
di allocazione statica della memoria mentre con i puntatori si possono utilizzare meccanismi di allocazione
dinamica. Quindi array e puntatori sono dei concetti compenetrati in C; il loro
uso e’ in sostanza intercambiabile.
Il
nome di un array e’ il puntatore all’indirizzo di memoria della prima
componente del vettore .
Se il vettore e’ cosi’ dichiarato: int vector[20];
avremo che vector punta alla locazione
corrispondente all’intero vector[0].
L’aritmetica
dei puntatori e’ diversa da quella delle altre variabili; se un puntatore a
<tipo> riceve un incremento di 1, il valore dell’indirizzo che esso
contiene non viene necessariamente aumentato di 1; verra’ aumentato di una quantita’ di byte uguale alla dimensione
del tipo di locazione puntata;
Tra puntatori ed array esiste come detto una relazione molto stretta derivante dal fatto che gli elementi di un array vengono allocati in memoria in “celle” consecutive. Per capire tale tipo di relazione consideriamo le seguenti istruzioni:
char strin[81] , *punt1;
punt1 = strin;
Per definizione al puntatore punt1 si assegna l’indirizzo del primo elemento dell’array strin (il valore di una variabile strin di tipo array e’ l’indirizzo del suo elemento zero cioe’ &strin[0]). Per cui le due espressioni strin ed &strin[0] sono equivalenti; in altre paraole l'espressione strin==&strin[0] e' vera.
Questo avviene poiche’ , come detto, nel linguaggio C, il nome dell’array senza gli indici, e’ considerato l’indirizzo iniziale dell’array; quindi il nome dell’array e’ un puntatore all’array.
Nel caso volessimo accedere alla componente 30 dell’array strin, possiamo usare una delle due equivalenti espressioni:
strin[29] oppure *(punt1+29) poiche' qualunque variabile di ti po puntatore puo' essere dotata di indici come se fosse stata dichiarata come array.
In generale alla componente i-esima dell’array strin si accede con
strin[i-1] oppure con *(punt1 + i - 1);
inoltre *(punt1 +i) equivale a punt1[i] .
Assegnamento con l'aritmetica dei puntatori: *(punt1+3)=100; assegnamento tramite indice: punt1=strin; punt1[3]=100;
esempio
pa=vector;
|
equivale a
|
pa=&vector[0];
|
vector
|
equivale a
|
&vector[0]
|
*(vector+i)
|
equivale a
|
vector[i]
|
*vector
|
equivale a
|
vector[0]
|
(vector+i)
|
equivale
a
|
&vector[i]
|
Nelle matrici si puo' accedere agli elementi, anche, sia tramite indice che tramite puntatore . esempio: int matrix[5][4]; int *punt1; punt1=matrix; avremo che all'elemento matrix[0][3] si puo' accedere con puntatore con *(punt1+3); in generale a matrix[i][j] corrisponde *(punt1+(i*dimensione_riga)+j).
vediamo un esempio
#include<stdio.h>
int main()
{
static int nome_array[]={4,6,2,44,55,77};
int *punt_array;
char car;
punt_array=nome_array;
/*punt_array punta al primo elemento dell'array nome_array*/
while(*punt_array)
{ printf("%X -> %d\n", punt_array,*punt_array);
++punt_array; /*incrementa punt_array*/
}
scanf("%c",&car);
return
0;}
/* nel ciclo while avremo che finche' l'intero puntato da punt_array non e' 0
viene stampato punt_array e l'intero puntato. Lo specificatore di formato %X
visualizza in esadecimale */
Passaggio di array a funzioni
Il linguaggio C passa un array ad una funzione, sempre per indirizzo, in quanto in fase di compilazione il nome dell'array e' automaticamente associato all'indirizzo del primo dell'elemento.
int nome_funzione( int nome_array[5]); e' un prototipo di funzione con parametro un array di 5 interi.
Nella chiamata della funzione scriveremo nome_funzione(nome_array);
che equivale a nome_funzione(&nome_array[0]);
per cui possiamo sostituire la definizione di un argomento di tipo array con la dichiarazione di un parametro puntatore al tipo_elementi dell'array; ossia il prototipo su scritto diventerebbe:
int nome_funzione( int *vettore);
vettore e' un puntatore ad interi.
Nel linguaggio C gli array ad una dimensione e’ possibile utilizzarli come stringhe di caratteri, ossia array i cui elementi sono di tipo carattere; e' da ricordare bene che l’ultimo carattere dell’array e’ il carattere NULL ( indicato come ‘\0’ e rappresentato in memoria con uno 0 ).
"notare che
questa di utilizzare gli array come stringhe non e' un buon metodo di
programmazione in C"
Se volessimo dichiarare un array di nome strin che contiene
una stringa lunga 5 caratteri si deve usare la seguente dichiarazione:
char strin[6];
ossia dobbiamo tenere conto del fatto che bisogna inserire
una cella per il carattere, di terminazione della stringa, NULL. Quindi sempre la
lunghezza dell’array per le stringhe deve essere superiore di 1 alla lunghezza
della stringa piu’ grossa che si intende rappresentare.
Il linguaggio C
non possiede un tipo di dato stringa , ma consente la dichiarazione
di costanti stringa, come una sequenza di caratteri racchiusa fra virgolette.
Un esempio di costante stringa puo’ essere :
“io sono una stringa”.
La lunghezza di questa costante stringa e’ di 19 caratteri contando
gli spazi bianchi che sono dei caratteri pure essi; quindi per essere contenuta
dentro un array di nome strin necessita che l’array abbia una lunghezza pari a 20 ; 19
caratteri +1 per contenere il carattere di terminazione NULL.
/* Dichiarazione dell'array
strin necessario a contenere tale stringa */
char strin [20];
Il metodo corretto per dichiarare e manipolare le stringhe nei programmi e' attraverso l'uso dei puntatori, come possiamo vedere nel seguente programma che visualizza la stringa "fondamenti di informatica" ed attende con la funzione scanf(), l'inserimento di un carattere.
#include<stdio.h>
int main()
{
char *strin="fondamenti di informatica";
char car;
printf("%s\n",strin);
scanf("%c",&car);
return
0;}
strin e' un puntatore alla stringa "fondamenti di informatica"
*strin contiene solo il primo carattere della stringa ossia il carattere 'f' ;
per accedere ai caratteri successivi al primo e' necessario eseguire una scansione incrementando il puntatore di una opportuna quantita'.
Il programma seguente visualizza la stringa "fondamenti di" in senso verticale:
#include<stdio.h>
void scansione();
int main()
{
char *strin="fondamenti di"
char car;
printf("%s\n",strin);
scansione();
scanf("%c",&car);
return
0;}
void scansione()
{
int i=0;
while(*(strin+i) !=NULL)
{
printf("%c\n", *(strin +i));
i++;
}
}
APRIAMO UNA PARENTESI PER DISCUTERE DELLA FUNZIONE SCANF()
La funzione scanf() puo' leggere dati dalla tastiera convertendo i numeri nella loro rappresentazione interna, piu' opportuna. Essa e' contenuta in stdio.h ed ha il seguente prototipo:
int scanf(char *stringa_di_controllo, elenco_argomenti);
essa restituisce il numero di oggetti a cui vene assegnato un valore ed EOF nel caso di errore.
La stringa_di_controllo determina la modalita' con cui vengono lette le variabili a cui punta l'elenco_ argomenti; la stringa di controllo o di formato e' sempre presente.
L'elenco degli argomenti o parametri, enumera le variabili dove devono essere memorizzati i dati in lettura.
avendo int i,j; scanf("%d",&i); avremo che la scanf() legge un intero e lo assegna alla variabile i.
Tabella dei specificatori di formato di scanf() e printf()
codice | formato |
%c | singolo carattere |
%d | decimale intero |
%i | decimale intero |
%e | formato scientifico |
%E | formato scientifico |
%f | floating point |
%o | ottale |
%s | stringa di caratteri |
%x | esadecimale |
%X | esadecimale |
%p | puntatore (a void) |
%u | intero senza segno |
La funzione scanf() puo' essere usata per leggere una stringa dal flusso di input mediante lo specificatore di formato %s. Pero' la scanf() legge fino a quando incontra un carattere di spazio, teminando la stringa con un carattere nullo, a differenza della funzione gets() che tratta gli spazi come dei caratteri.
Tutte le variabili utilizzate da scanf() devono essere passate per indirizzo; e' chiaro che avendo dichiarato char strin[21]; per memorizzarvi dati letti da input in strin basta scrivere
scanf("%s", strin); non viene richiesto l'operatore & , poiche' strin rappresenta un puntatore come sappiamo.
Fine parentesi
Per manipolare le stringhe esistono delle funzioni di
libreria contenute in "string.h" tipo :
strcpy (s1,s2); la quale copia la stringa s2 nella stringa s1.
il prototipo della strcpy() e':
char *strcpy(char *s1, char *s2);
la stringa puntata da s2 deve terminare con un carattere nullo. La funzione strcpy restituisce un puntatore ad s1.
strlen (s1); che e' una funzione restituisce la lunghezza della stringa puntata da s1;
il prototipo della strlen() e':
size_t strlen(char *s1);
la stringa s1 deve essere terminata da un carattere nullo
che pero' non viene conteggiato.
strcmp (s1,s2) compara, secondo l'ordinamento alfabetico le due stringhe terminate da un carattere nullo;
il prototipo della funzione e:
int strcmp(const char *s1, const char *s2);
restituisce 0 se s1 ed s2 sono uguali, un valore > 0
se s1>s2 , un valore < 0 se s1<s2
N.B. la funzione strcmp() vale falso se le due stringhe
sono uguali, pertanto bisogna usare l’operatore ! (NOT) per invertire la condizione e verificare l’ eguaglianza fra
stringhe;
esempio
Se volessimo verificare se la stringa s1 sia uguale alla
stringa
“io sono una stringa”
scriveremmo :
if ( !strcmp (s1, “io sono una stringa”))
printf (“\n%s”, le due stringhe sono
uguali );
L’ assegnazione
all’ array strin, della stringa “io sono una stringa” , puo’
essere fatta attraverso la seguente istruzione:
strcpy (strin,
“io sono una stringa”);
Queste funzioni sono contenute nel file di libreria del
compilatore string.h . Per cui se volessimo fare uso dentro il nostro programma
di tali funzioni dovremmo includere come file di intestazione la string.h ,
attraverso la seguente direttiva per il preprocessore:
#include<string.h>
Nella
programmazione si possono dichiarare gli array di stringhe attraverso una
matrice di caratteri , in cui con il primo indice i spazia lungo il numero max di stringhe ed il secondo indice j spazia sulla “ lunghezza massima ammissibile
+1” di una stringa.
Questo
lo si fa’ con la seguente dichiarazione:
char
stringhe_caratteri[20][81];
Abbiamo
dichiarato una matrice od array bidimensionale di stringhe avente nome
stringhe_caratteri, precisamente 20 stringhe ognuna formata da un massimo di 80
caratteri. Da notare, che indipendentemente dalla lunghezza delle stringhe di
caratteri che inseriremo nell’array, di nome stringhe_caratteri, la memoria
allocata (riservata) per tale tipo di dato e’ sempre la stessa.
Ossia
con questo tipo di dichiarazione si ha la allocazione statica della memoria.
Infatti si puo’ calcolare a priori la memoria che bisogna riservare per tale
dato.
La
memoria occupata dall’array stringhe_caratteri e’ pari a:
Numero
totale di byte = 20 x 81 x sizeof(char) ;
Siccome
nel linguaggio C un carattere occupa 1 byte avremo che sizeof(char)=1 byte
per cui : Numero totale di byte=20 x 81 x 1 = 1620 byte .