Array Multidimensionali

I giochi sono semplici fintanto che si gestiscono array ad una singola dimensione, si complicano quando sono a più dimensioni. E’ infatti possibile che gli elementi di un array siano a loro volta altre array, si parla in questo caso di array di array.

L’utilizzo di array multidimensionali dovrebbe però essere molto ponderato sopratutto quando il numero di elementi é notevole, perché ogni dichiarazione comporta una relativa assegnazione di memoria, determinando allocazioni che possono rivelarsi di grandi dimensioni.

Array bidimensionali

Un array bidimensionale, definita anche matrice, é un array i cui elementi sono a loro volta altre array e queste dimensioni possono concettualmente rappresentare una tabella, composta da righe e colonne.

Dichiarazione

La dichiarazione di un array bidimensionale avviene in modo analogo all’array monodimensionale, tranne che per il fatto che si aggiunge una ulteriore coppia di parentesi quadre:

//Dichiarazione di array bidimensionale
data_type identificatore[numero_righe][numero_colonne];

Come nel caso di array a dimensione singola, i valori inseriti tra parentesi quadre rappresentano costanti intere.

Inizializzazione

Anche un array multidimensionale può essere inizializzato contestualmente alla sua dichiarazione, osservando però la seguente sintassi:

//Dichiarazione ed inizializzazione di array bidimensionale
data_type identificatore[numero_righe][numero_colonne] = {
    {value_0, value_1,value_2,…,value_n}, /* NB: inserire virgola */
    {value_0, value_1,value_2,…,value_n}
}; /* terminare con ; */

Valgono tutte le regole di inizializzazione già previste per gli array monodimensionali.

Accesso all’array (subscripting)

L’accesso in lettura/scrittura di un array multidimensionale avviene con le medesime modalità delle monodimensionali, eccezion fatta per una coppia di parentesi quadre da aggiungere a suffisso:

//Scrittura
identificatore[indice_riga][indice_colonna] = value;
//Lettura
altra_variabile = identificatore[indice_riga][indice_colonna];

Anche i cicli iterativi sulle variabili multidimensionali non sono poi molto diversi, prevedendo però in questo caso due o più cicli iterativi inclusi l’uno nell’altro.

//Ciclo iterativo per array multidimensionale
//Loop esterno
for (int i = 0; i < lunghezza_riga; i++) {
    //Loop interno
    for (int y = 0; y < lunghezza_colonna; y++) {
        printf(“qualcosa %d”, array[i][y];
    }
}

Array

Un array, noto anche come vettore é una struttura di dati che contiene un insieme di variabili definite elementi.

Dichiarazione di un array

La dichiarazione di un array avviene attraverso la sintassi seguente:

[data_type] identificatore[numero di elementi];

Un ulteriore modo ampiamente utilizzato per la dichiarazione di un array é il seguente:

//utilizzo #define per sostituire “SIZE” con la dimensione dell’array

#define SIZE 10
int main(void){
    int a [SIZE] //dichiaro l’array inserendo nel subscript il valore “SIZE”
}

Al momento della dichiarazione viene riservata una congrua quantità di spazio in memoria dimensionata al contenimento dei dati. Il valore iniziale degli elementi dell’array prima che questi vengano inizializzati può dipendere dai dati preesistenti nelle stesse posizioni di memoria. Non deve quindi stupire se un array non inizializzata contenga già dei dati.

Inizializzazione di un array

Un array può essere anche inizializzata contestualmente alla sua dichiarazione. La sintassi é la seguente:

identificatore[numero_di_elementi} = {valore 0, valore 1, valore 2, …..valore N};

A questo proposito é necessario ricordare alcune regole:

  • Se il numero di elementi inizializzati è inferiore al numero di elementi dell’array, i restanti elementi vengono inizializzati a 0;
  • Se il numero degli elementi eccede la dimensione dell’array il compilatore restituisce un warning;
  • Se si cerca di inizializzare un array vuota si avrà allo stesso modo un warning;
  • E’ possibile omettere il [numero_di_elementi] se é presente una lista di inizializzatori;

L’assegnazione dei valori all’indice dell’array avviene in modo sequenziale, ma a partire dagli ultimi standard del linguaggio C è possibile stabilire in modo specifico quali elementi inizializzare secondo la loro posizione, detta anche indice.

identificatore[numero_di_elementi] = {[indice] = value, ….,[indice_n] = value};

Inizializzazione mista

E’ interessante esaminare il comportamento di un inizializzazione di tipo misto, perché spiega il comportamento del compilatore in casi simili. Come anzidetto l’inizializzazione di un array avviene in modo sequenziale, ma se impostiamo anche l’indice ad uno dei valori da inserire, l’inizializzazione sequenziale riprenderà dall’indice successivo a quello inserito, fino al termine della lunghezza dell’array, lasciando gli elementi “saltati” a 0. Se viene inizializzato due volte lo stesso elemento, questo assume il valore della seconda inizializzazione, che sovrascrive al prima.

Accesso all’array (subscripting)

L’accesso ad un array avviene con la seguente sintassi:

//Scrittura
identificatore[indice] = valore;
//Lettura
variabile = identificatore[indice];

E’ bene notare che il valore di indice può anche non essere direttamente indicato ma può essere il risultato di operazione tra variabili.

Variabili e costanti

Le variabili

Una variabile rappresenta uno spazio di memoria dove vengono memorizzati dei valori.

Nel linguaggio C le variabili devono essere prima dichiarate e poi inizializzate. La dichiarazione è una statement attraverso la quale si indica al compilatore di predisporre e riservare spazio in memoria per contenere il dato specificato, attraverso l’uso di un identificatore di riferimento a quella porzione di memoria. E’ possibile anche dichiarare più variabili allo stesso tempo:

int number, temp, index, max, min;

Nello standard C89 le variabili dovevano essere tutte dichiarate nella parte iniziale di un blocco di codice, sebbene lo standard C99 abbia superato questa prassi.

Dichiarazione

La dichiarazione di una variabile si compone di una dichiarazione di tipo e di un’ assegnazione di nome (o identificatore). La dichiarazione di tipo comporta l’utilizzo di una delle keyword riservate del linguaggio ed indica al compilatore il tipo di dato che la variabile deve contenere, mentre l’assegnazione del nome o identificatore é piuttosto libera, sebbene vi siano accorgimenti e convenzioni stilistiche che é buona pratica rispettare, allo scopo di rendere maggiormente comprensibile il nostro lavoro a coloro che dovranno leggerlo dopo di noi. Ciò detto, nel dichiarare una variabile bisogna evitare:

  • di farla iniziare con un numero (es: int 3variabile)
  • di farla iniziare con __ (underscore), utilizzati per i nomi dei tipi della libreria standard
  • che essa inizi con una lettera maiuscola (non é un errore, ma é una convenzione largamente utilizzata)
  • il nome della variabile non può contenere spazi

Inizializzazione

L’inizializzazione é la procedura attraverso la quale si attribuisce un valore alla variabile e avviene attraverso l’operatore di assegnamento (=) . E’ possibile dichiarare ed inizializzare più variabili allo stesso tempo, come nell’esempio seguente:

int var1 = 99, var4 = 150;

L’assegnazione diretta del valore ad una variabile prende il nome di “letterale”, in quanto, l’assegnazione di un valore alla valore alla variabile può avvenire anche dinamicamente, attraverso l’uso di una funzione, ad esempio.

double db = sqrt(44.44);

Le costanti

Una costante é uno spazio di memoria a sola lettura, cioè un valore che una volta assegnato non più essere alterato.

Una costante può essere inizializzata attraverso la keyword const. L’utilizzo di una costante comporta la sua inizializzazione contestualmente alla sua dichiarazione.

const float var1 = 9,99; → Corretto
short const var2 = 20; → Accettato
const int var 3;
var3 = 50; → Errore

La direttiva #define per le costanti

Una costante può anche essere dichiarata ed inizializzata con la direttiva #define che indica al preprocessore di sostituire tutte le occorrenze in cui compare il suo identificatore in fase di compilazione. In questo caso l’identificatore deve essere scritto in maiuscolo.

#define CIAO “Ciao a tutti” /*dichiarazione di costante di tipo stringa*/;
#define PIGRECO 3.14159 /*dichiarazione di costante di tipo numerico*/;

Tipi di dato fondamentali

La dichiarazione delle variabili e delle costanti implica la loro tipizzazione, ossia l’esplicita dichiarazione del tipo di dato che devono contenere allo scopo di riservare ad essi un adeguata quantità di memoria per contenerli. In C questi tipi di dato sono rappresentati dalla tabella seguente:

charintlong_Bool
doubleshortunsigned_Complex
floatsignedvoid_Imaginary

Specificatori di formato

Le funzioni printf e scanf comportano l’utilizzo di alcuni simboli detti “specificatori di formato” necessari a far comprendere al calcolatore il tipo di dato da inserire o da stampare a video. Tipicamente sono caratterizzati da un segnaposto e specificatori di conversione. Per praticità li elenchiamo nella tabella seguente:

%Segnaposto generico%oIntero ottale
%dIntero Decimale%cCarattere singolo
%fVirgola mobile%pVariabili puntatore
%sStringa%%Carattere percentuale
%xIntero esadecimale\nNuova linea

Specificatori di tipo

Anche il tipo di variabile può essere specificato nell’uso della funzione printf, indicando, sulla base della tabella precedente, gli opportuni simboli relativi al tipo:


DecimaleOttaleEsadecimale
Short%hd%ho%hx
Long%ld%lo%lx
Long Long%lld%llo%llx

Per i valori unsigned si inserisce u al termine dello specificatore, omettendo la d in caso di valore intero (int):

printf(“unsigned int: %u”, nome_variabile)