Gli Array






Per gestire gruppi di variabili di dimensione arbitraria aventi tutte lo stesso tipo è utile ricorrere agli array. Grazie ad essi, infatti, il gruppo di variabili, per quanto numeroso, può essere gestito tramite un unico nome comune ed un indice; l'array perciò si presta naturalmente ad essere inizializzato / modificato / analizzato mediante un ciclo, sia esso while() o for().


// esempio: dichiarazione ed inizializzazione di un array

ricordarsi dell'opzione -lm per la compilazione del codice.

#include <stdio.h>
#include <math.h>
#define MAX 30


int main()
{int quadrati[MAX];
 int i ;

// ciclo di inizializzazione degli elementi del vettore

 for( i = 0; i < MAX ; i++)
  {quadrati[i] = pow(i,2);}

// ciclo di visualizzazione degli elementi del vettore
// all'inizio del ciclo i vale 30

 i --;
 while(i)     // va bene questo ciclo ?
  {printf("l\'elemento che si trova nella posizione %d vale %d",i,quadrati[i]);
    i--; }


// e questo ciclo ?
 for( i = 0 ; i < MAX + 20 ; i++)
  {quadrati[i] = i + 4 /( (double) (i +2));}

 return 0; }

// fine esempio
















La dichiarazione

int quadrati[30]

ndica che ci viene assegnata un'area di memoria avente dimensione pari alla dimensione di 30 variabili di tipo intero. Questo significa che abbiamo diritto di accedere a soli 4 * 30 Byte, non di più. Il compilatore non effettua controlli per sincerarsi di questo, perciò è il programmatore che deve fare attenzione !!

Di norma, accedendo in lettura (ovvero leggendo ciò che ci sta scritto, ad esempio con printf()) ad aree non riservate della memoria non si generano errori in fase di esecuzione.

Viceversa, accedendo in scrittura ad aree non riservate della memoria (ad esempio con un'assegnazione) si ricevono messaggi d'errore di questo tipo:


segmentation fault        

  si è verificato un errore in <nome_programma>. L'applicazione verrà chiusa













Molto spesso avremo a che fare con gruppi di elementi disposti in ordine arbitrario e quindi non necessariamente ordinati; in questi casi ci farà comodo poter utilizzare una procedura che permetta, a partire da un insieme disordinato di elementi, di ottenere un insieme ordinato in base ad uno specifico criterio di ordinamento.



Fissato il criterio, un metodo semplice (ma lento) da utilizzare per ottenere un insieme ordinato è quello del bubble sort. Questo metodo si basa su una procedura di questo tipo:

supponiamo che a e b siano due elementi consecutivi dell'insieme; allora



if(criterio_di_ordinamento(a,b))
  {non fare nulla} // i valori dei due elementi soddisfano il criterio
else
  {scambia i valori di a e b}









Facciamo un esempio nel caso in cui il criterio di ordinamento sia il seguente: i valori devono essere disposti in ordine crescente. Questo si traduce nella richiesta che se a e b sono due elementi consecutivi dell'insieme, allora deve risultare

a <= b


Fissato il criterio, lo schema di sopra si traduce nel seguente blocco di codice C:

if( a <= b )     // ecco il criterio di ordinamento
  { ; }      // se è verificato non altero nulla
else
  { temp = a;     // scambio i valori delle due variabili nel caso i loro valori non soddisfino il criterio
     a = b;
     b = temp;}










Nel caso degli array, esso diventa il confronto tra due elementi dell'array, uno con indice i e l'altro con indice i + 1

supponiamo che la dichiarazione dell'array sia:

int vettore[40];



allora

if( vettore[ i ] <= vettore[ i + 1 ] )     // ecco il criterio di ordinamento
  { ; }      // se è verificato non altero nulla
else
  { temp = vettore[ i ];  // scambio i valori delle due variabili nel caso i loro valori non soddisfino il criterio
     vettore[ i ] = vettore[ i + 1 ];
     vettore[ i + 1 ] = temp;}












Prepariamo ora un programma in cui:

  1. si inizializzi il generatore di numeri casuali chiedendo all'utente di inserire dei caratteri
  2. vengano generati in modo arbitrario dei numeri interi
  3. i valori di tali interi vengano salvati in un vettore
  4. gli elementi dell'array vengano ordinati in ordine crescente




Se quindi il criterio di ordinamento è "un numero del vettore deve essere più piccolo del numero che lo segue" la procedura da applicare è la seguente:

  1. per ogni elemento del vettore, controlliamo se il suo valore è inferiore a quello dell'elemento successivo
  2. se l'ordine è rispettato possiamo ripetere la procedura con l'elemento successivo all'interno del vettore
  3. se l'ordine non è rispettato, scambiamo i due valori tra di loro e passiamo ad analizzare l'elemento successivo



// inizio del codice

#include "myfun.h"
#define MAX 30

int main()
{int temp,vettore[MAX],i;
  char c1,c2;
  printf("\n inserire due caratteri per inizializzare il generatore di numeri casuali\n");
  printf("\nprimo carattere :");
  c1=mygetchar();
  printf("\nsecondo carattere :");
  c2=mygetchar();
  srand(c1*c1*c2*c2);

  // ciclo for() utile ad inizializzare il vettore

  for(i = 0; i< MAX ; i++)
    {vettore[i] = int_rand(0,500);
      printf("\nil valore nella posizione %d del vettore e\' %d",i,vettore[i]);}


  // effettuiamo ora un ciclo di ordinamento 


for( i = 0; i < (MAX - 1) ; i++)  // mi fermo prima altrimenti "esco" dal vettore
    {if( vettore[i] <= vettore[i+1] )
       {;}
      else
       {temp = vettore[i];
           vettore[i] = vettore[i+1];
           vettore[i+1] = temp;
}
    }
 

 
  // ora stampo il risultato

  for(i = 0; i< MAX ; i++)
    {printf("\nil valore nella posizione %d del vettore e\' %d",i,vettore[i]);}

  return 0;}

// fine del codice
















Siamo sicuri di aver ottenuto un vettore ordinato ?
Prendiamo ad esempio questa sequenza: 5 8 2 7



Se applichiamo il ragionamento di prima otteniamo:

(1) 5 e 8 sono ordinati correttamente, quindi rimangono invariati -> 5 8 2 7

(2) 8 e 2 non sono ordinati correttamente e quindi vengono scambiati -> 5 2 8 7

(3) 8 e 7 non sono ordinati correttamente e quindi vengono scambiati -> 5 2 7 8















A questo punto, però, la sequenza non è ancora ordinata. Questo significa che dobbiamo ripetere la procedura di ordinamento fino a quando non vengono effettuati nuovi scambi (in quanto effettuare uno scambio implica che c'erano degli elementi non ordinati e non è detto che dopo aver effettuato lo scambio l'ordine degli elementi delle coppie adiacenti sia quello corretto)


// inizio del codice

#include "myfun.h"
#define MAX 30

int main()
{int temp,vettore[MAX],i, scambi;
  char c1,c2;
  printf("\n inserire due caratteri per inizializzare il generatore di numeri casuali\n");
  printf("\nprimo carattere :");
  c1=mygetchar();
  printf("\nsecondo carattere :");
  c2=mygetchar();
  srand(c1*c2*c2*c1);


  // ciclo for() utile ad inizializzare il vettore
  for(i = 0; i< MAX; i++)
    {vettore[i] = int_rand(0,500);
      printf("\nil valore nella posizione %d del vettore e\' %d",i,vettore[i]);}




  scambi = 1;

  // effettuiamo ora un ciclo di ordinamento

 while(scambi) // il ciclo continua ad essere eseguito fino a quando non vengono
                            // effettuati ulteriori scambi
 {scambi = 0;

for( i = 0; i< MAX ; i++)  // mi fermo prima altrimenti "esco" dal vettore
    {if( vettore[i] <= vettore[i+1] )
       {;}
      else
       {scambi = 1;
        temp = vettore[i];
          vettore[i] = vettore[i+1];
          vettore[i+1] = temp;
}
    }


 } 
  // ora stampo il risultato

  for(i = 0; i< MAX ; i++)
    {printf("\nil valore nella posizione %d del vettore e\' %d",i,vettore[i]);}

  return 0;}

// fine del codice


















Ora inizializziamo un array di char in un modo un po' particolare ...

Prendiamo un intero a caso: 1667850607 e memorizziamone il valore in un'opprtuna variabile di tipo int


int numero = 1667850607;     // questa variabile è composta da 32 bit ...

32 bit




























che può essere anche visto come un gruppo di 4 insiemi di 8 bit ciascuno ... ovvero 4 char !

8 bit (char)
8 bit (char)
8 bit (char)
8 bit (char)




Cerchiamo di visualizzare i 4 char "contenuti" nell'intero. Per visualizzare il primo in fondo a sinistra che operazioni dobbiamo compiere ? Non dobbiamo fare altro che spostare di 24 posizioni verso destra la rappresentazione binaria dell'intero. Fatto questo calcoliamo la divisione con resto usando l'operatore modulo (% 256) e stampiamo il risultato.





Per spostare la rappresentazione binaria, e fare quindi in modo che gli 8 bit si spostino in fondo a destra, si possono usare due metodi:


(1) come visto in precedenza, dividiamo per la potenza di 2 elevata al numero di posizioni di cui vogliamo spostare la rappresentazione binaria. Nel caso del primo numero, dividiamo per 2^24.


printf("ecco il primo carattere in fondo a sinistra: %c", ((int) ( numero / pow(2,24) )) % 256 );




























(2) metodo più furbo !! Usiamo gli operatori bit a bit
In particolare, usiamo lo shift a destra, un operatore che permette di spostare verso destra la sequenza di bit che compongono la rappresentazione binaria di una variabile.

int numero = 1667850607;
int numero_1 = 0;

numero_1 = numero >> 24; // inserisco nella variabile numero_1 la rappresentazione binaria
                                      // di numero, spostata a destra di 24 posizioni


Naturalmente esiste anche lo shift a sinistra

numero_1 = numero << 24; // inserisco nella variabile numero_1 la rappresentazione binaria
                                      // di numero, spostata a sinistra di 24 posizioni



Usando questo metodo, possiamo rendere il tutto più semplice


printf("ecco il primo carattere in fondo a sinistra: %c", ( numero>>24 ) % 256 );
printf("ecco il secondo carattere da sinistra: %c", ( numero>>16 ) % 256 );
printf("ecco il terzo carattere da sinistra: %c", ( numero>>8 ) % 256 );
printf("ecco il quarto carattere da sinistra: %c", ( numero>>0 ) % 256 ); // non serve lo shift !



Se fate la prova vi deve comparire la sequenza : ciao