Guida al C: parte 2 (Il resto del Pinguino)

Le variabili e le costanti in C

Per variabile si intende una porzione di memoria atta a contenere un determinato dato che potrà poi essere modificato nel corso dell’uso del programma. Essa può essere inizializzata all’atto della sua dichiarazione con un valore di default o può essere dichiarata senza alcun valore. In tal caso il linguaggio non garantisce un valore
iniziale utile. Ad esempio una variabile può essere dichiarata ed inizializzata in due modi diversi. Per doppio passaggio:

// dichiaro
int x;
// inizializzo
x = 14;

o direttamente:

// dichiaro ed inizializzo
int x = 14;

Una costante, invece, è una porzione di memoria che viene dichiarata per contenere un determinato tipo di dato e ne conserva il valore per tutta la durata dell’uso del programma senza mai poterne modificare il valore. Ogni variabile o costante nel C deve essere identificata da un nome al quale si farà poi riferimento nel corso dello svolgimento del programma per leggere o scriverci dati. Il nome delle variabili in C è arbitrario e può
avere lunghezza variabile però il compilatore si interesserà solo delle prime 8 lettere che lo compongono. Quindi anche se a prima vista un dato di nome “variabile1” pare diverso da “variabile2”, il compilatore restituirà errore poichè vedrà due variabili con lo stesso nome ovvero “variabil”. Il C è un linguaggio che basa la sua struttura sui dati. Dati diversi, infatti, equivalgono a cose diverse. Questo tipo di gestione permette di avere un buon uso della memoria perché ad ogni tipo di dato è dedicata la giusta quantità di memoria e in più dà la possibilità di usare o creare strutture ad hoc per le diverse esigenze di sviluppo. Il C gode delle presenza di 6 tipi di dati base:

char
int
long
short
float
double

Il char è il dato adibito alla gestione dei caratteri. Ogni volta che viene dichiarata una variabile di tipo char essa occupa una quantità di memoria pari a 8 bit (1 byte). Il char, nonostante sia effettivamente un tipo di dato numerico, permette la gestione del suo valore come una normale “lettera”. Un array (vettore) di char permette la virtualizzazione di una stringa mentre, in altri linguaggi, esiste ormai un tipo di dato string dedicato. Un esempio di dichiarazione di un dato char inizializzato è:

char carattare = ‘ a’ ;

E’ importante notare come definire il carattere ‘8’, ad esempio, è totalmente diverso dalla definizione di un valore intero 8. Un char che contiene il carattere ‘8’ in realtà avrà al suo intero il valore numerico che, in base alla codifica in uso, equivale a quel determinato carattere mentre una variabile numerica che contiene 8 avrà proprio quel valore preciso in memoria.

L’ int è il tipo adibito a contenere dati numerici di numeri interi o meglio definiti come numeri naturali. Tali numeri, pertanto, devono contenere numeri senza virgole, frazioni, parti immaginarie, etc… un dato di tipo int, all’atto della sua dichiarazione, occupa 16 bit (2 byte). I valori che un int può assumere vanno da -32.768 a +32.767 se si usa il segno (valori positivi o negativi) o va da 0 a 65535 per soli numeri interi. Un esempio di dichiarazione di un dato int inizializzato è:

int numIntero = 14;

Long può essere visto come un particolare int creato appositamente per ovviare al problema di uso di numeri più grandi di quelli che l’ int offre. Esso occupa una quantità di memoria pari a 32 bit (4 byte) ed offre la possibilità di usare valori che vanno da -2.147.483.648 a +2.147.483.647 per numeri con segno o da 0 a 4.294.967.295 per numeri privi del segno. Un esempio di dichiarazione di un dato long inizializzato è:

long numIntLong = 1000000000;

Lo short è un dato molto simile all’int ma che trova limitazioni più restrittive per quanto riguarda il suo valore massimo o minimo. Esso infatti occupa 8 bit (1 byte) e può perciò coprire un range che va da -127 a +128 pe numeri con segno mentre va da 0 a 256 per numeri senza segno.

I float e i double sono particolari tipi di dati che danno la posibilità di rappresentare i numeri in virgola mobile, ovvero i numeri reali. La differenza tra i due tipi di dati sta nella quantità di memoria utilizzata e pertanto nell’accuratezza con cui i numeri possono essere rappresentati. Un float, infatti, richiede una quantità di memoria pari a 32 bit (4 byte) mentre un double richiede 64 bit (8 byte). Un esempio di dichiarazione di un dato float e di un double inizializzato è:

double dblVirgola = 5.023;
float fltVirgola = 7.8;

SIGNED ed UNSIGNED

Come si è visto, ogni dato ha la possibilità di considerare l’insieme dei suoi valori limitato diversamente in base all’uso che se ne vuole fare. Ad esempio due dati, entrambi int, potranno assumere valori massimi diversi se uno è sempre positivo mentre l’altro assume sia valori positivi che negativi. E’ importante avere in mente tale concetto per poter avere a disposizione sempre il miglior tipo di dato per le nostre esigenze. Di default i dati in C vengon visti come signed e perciò è possibile usare il segno per definire il valore in maniera positiva o negativa. Qualora ci fosse bisogno di definire esplicitamente che un numero non necessita di una rappresentazione negativa allora si può dichiarare la viariabile in questo modo:

unsigned int Numero = 15;

altrimenti è possibile usare la sintassi:

signed int Numero = – 15;

che è equivalente a

int Numero = – 15;

COSTANTI

Il discorso trattato fin ora era studiato per l’uso delle variabili; tuttavia, tutte le regole di cui sopra valgono anche per quanto riguarda il trattamente di dati costanti. Bisogna comunque ricordare che essi mantengono il valore iniziale e perciò quanto detto vale solo all’atto della dichiarazione e mai durante lo svolgimento del programma. Un esempio di dichiarazione di una costante può essere:

const float PIGRECO = 3. 14;

Da notare la presenza della parola chiave const che definisce il dato come costante.

CASTING E CONCLUSIONE

Visto il tipo di gestione dei dati in C, esso viene definito come linguaggio a tipizzazione statica, ovvero dove i tipi di dati vengono definiti all’inizio e mantenuti pressoché
costanti per la durata del software. Tuttavia esiste una pratica definita casting mediante la quale è possibile cambiare il tipo di un dato per poterlo adattare ad una certa circostanza. Il casting si avvale della sintassi del tipo:

variabile1 = ( tipo) variabile2

Ad esempio per ottenere un int da un valore float è possibile seguire il seguente codice di esempio:

float fltNumero = 2. 36;
int intNumero;

intNumero = (int) fltNumero;

In questo modo intNumero assumerà valore 2, ovvero la parte intera del numero float.

Conoscere i dati in C significa essere a conoscenza delle fondamenta di un linguaggio ed è perciò importante studiare bene l’argomento prima di addentrarsi in argomenti più avanzati.

Gambas – Modificare cursore del form

Alle volte, per particolari applicazioni, può essere utile e/o pratico modificare il cursore del mouse per tutta l’area di un determinato form. Questo tipo di pratica la si trova sopratutto nei videogame dove il puntatore de mouse assume le forme consone al tema del videogioco stesso.

Effettuare tale operazione in Gambas è abbastanza semplice e la dinamicità del codice permette di modificare il cursore anche in base agli eventi. Premettendo che molti degli oggetti di Gambas hanno la funzione per scegliere il puntatore, tale metodo è pratico perchè permette di associare un’immagine al cursore e non di scegliere tra un limitato numero di esempi predefiniti.

Analizziamo il codice. Per praticità lo inserirò nella sub di apertura del form ma ovviamente esso potrà essere usato quando e dove serve.



Come si vede inizialmente si dichiara una variabile di tipo immagine di nome pCursor. Essa servirà a contenere l’immagine del nostro puntatore. Nella sub open del form si nota come si sia semplicemente associata un’immagine ala variabile prima dichiarata mediante l’uso di Picture.Load, al quale passeremo l’indirizzo dell’immagine, e si sia istanziato un nuovo puntatore associato a Me.Cursor (dove ME indica il form in cui ci si trova) mediante l’operatore NEW.

Il codice è banale ma l’effetto è sicuramente pratico laddove possa risultare utile allo sviluppatore.

Strutture dati: Array


DEFINIZIONE

Con il termine array si intende un tipo di struttura dati complessa che trae le proprie caratteristiche dalla definizione matematica di vettore.

Un array può essere visto come una serie di celle contigue ognuna delle quali ha il compito di contenere un determinato dato. Ogni cella che compone tale struttura è accessibile mediante una chiave denominata indice. L’’indice è un fattore fondamentale per accedere ai dati interni al vettore e nella maggior parte dei linguaggi di programmazione è di tipo numerico intero. I valori di tali parametro sono spesso contigui e possono partire da 0 o da 1.

Ad esempio, se volessi accedere al primo elemento di un array di nome vettore, il cui primo indice è 0 mi basterà usare la sintassi:

vettore[0]

mentre per accedere al terzo elemento dovrò utilizzare l’’indice 2:

vettore[2]

Bisogna precisare che nei linguaggi compilati, l’’uso degli indici di questa struttura, porta a degli errori se non si trattano in maniera consona questi parametri poiché tali linguaggi non hanno alcun riferimento in memoria della dimensione dei vettori con cui si lavora. Questo è un punto fondamentale poiché, l’’uso scorretto degli indici, può portare ad ottenere di dati errati e quindi potenzialmente pericolosi.

DATI DEGLI ARRAY

La concezione dei tipi di dati degli array varia in base ai diversi linguaggi di programmazione. Nel C, ad esempio, quando si definisce un vettore esso viene inizializzato con un tipo di dato che dovrà essere poi compatibile con i singoli dati in esso contenuti. Questo vuol dire che se all’’atto della definizione di un array lo dichiaro di tipo int, esso potrà contenere solo dati di tipo int. Nel PHP, invece, non importa il tipo di dato che l’’array andrà a contenere poiché il linguaggio è di tipo typeless.
Il prototipo di dichiarazione del lingaggio C è:

tipo nome_array[numero elementi];

pertanto un esempio di definizione può essere:

float vector[5];

Si nota come si sia definito un vettore di 6 elementi tutti di tipo float al quale è possibile accedere subito dopo la sua creazione. Se volessimo, infatti, inizializzare i suoi dati con i primi 6 numeri reali basterà utilizzare la sintassi

nome_array[indice] = dato;

Che nel nostro caso sarà:

vector[0] = 0.0;
vector[1] = 1.0;
vector[2] = 2.0;
vector[3] = 3.0;
vector[4] = 4.0;
vector[5] = 5.0;

DINAMICITÀ

Un array, nella maggior parte dei casi, può subire modifiche durante l’’uso del programma. Basti immaginare, ad esempio, un vettore che deve contenere le macchine parcheggiate in un parcheggio custodito. Ogni indice dell’’array indica un posto numerato e il dato in esso contenuto sarà il modello della macchina. Se un giorno il padrone del parcheggio decide di ampliare lo stabile aggiungendo nuovi posti allora anche l’’array dovrà essere ampliato per contenere nuovi indici. In tal caso basterà ricorrere ai mezzi che ogni linguaggio di programmazione pone a disposizione dello sviluppatore per riallocare la memoria utile a tale fine. Questo evidenzia come, se adeguatamente trattata, l’’array è una struttura dati dinamica. Tale concetto di dinamicità (array allocato dinamicamente) è da separare dal concetto di array dinamico.
Un array si definisce dimanico quando consente di aggiungere e/o rimuovere alcuni elementi. Esso si compone di due zone separate: la prima viene allocata e definita come un comune array mentre la seconda è nascosta ed è dedicata ai futuri allocamenti. Tale sezione può essere utilizzata sino a che la sua memoria non si esaurisce. L’’uso degli array dinamici risulta alle volte troppo dipspendioso sia in termini di spazio che di tempo poiché, una sua riscrittura, può richiedere anche la copia dell’’intero array.

ARRAY MULTIDIMENSIONALI

Sino ad ora abbiamo trattato vettori i cui dati erano accessibili mediante un solo indice. Può accadere, per esigenze di sviluppo, che si abbia bisogno di più indici da trattare. Tali elementi vengono chiamati array multidimensionali. Immaginiamo di voler utilizzare un array che mi indichi se in un determinato punto cartesiano ci sia o no un punto mediante la presenza di un 1 o un 0. I dati di tale vettore potranno essere accessibili mediante l’’uso di due indici: uno che indichi il valore dell’’asse delle ascisse da considerare ed uno quello delle ordinate.

Se, ad esempio, in un piano cartesiano prendiamo in considerazione le coppie di valori (2, 2), (2, 3), (3, 2) e (3, 3) e sappiamo che sono presenti solo due punti nelle coordinate (2, 2) e (3, 3), il nostro array potrà essere consultato accedendo ai dati mediante la sintassi:

nome_array[indice 1][indice 2]

Nel nostro caso sarà:

vettore[2][2] = 1;
vettore[2][3] = 0;
vettore[3][2] = 0;
vettore[3][3] = 1;

E’ facile notare come tale discorso può essere facilmente espanso ad array con un numero maggiore di indici.

CONCLUSIONI

L’array è sicuramente una delle strutture dati più semplice da gestire e da utilizzare. La sua convenienza, in termini tecnici, è da apprezzare per un suo uso basilare. Quando i dati iniziano a diventare eccessivamente numerosi e quando le dimensioni iniziano a crescere e sicuramente molto più pratico puntare ad altre strutture più consone a questi compiti.