Linguaggio C per MSX – lezione 5

da | Gen 3, 2024 | Linguaggio C | 0 commenti

Linguaggio C per MSX

Rubrica a cura di Nicola Brogelli (Parte 5)

Array e Puntatori

Array

Gli array sono sequenze di variabili dello stesso tipo che vengono memorizzare consecutivamente nella memoria ed alle quali è possibile accedere usando uno stesso nome (identificatore) a cui viene aggiunto un indice. L’uso principale di array è archiviare e organizzare un gran numero di elementi simili in una singola “struttura dati” , rendendone più facile la gestire e manipolazione.

Un “oggetto” di tipo array è una n-upla di elementi ordinati dello stesso tipo, ai quali è possibile accedere mediante il loro indice. Gli elementi di un array di dimensione n sono compresi in un intervallo che va da 0 a n – 1.

type identifier [constant-expressio]

La definizione sopra illustrata, rappresenta la dichiarazione di un array monodimensionale (vedremmo in seguito gli array a più dimensioni). Possiamo vedere come l’array ha un tipo ben definito il quale descrive gli elementi che l’array può contenere, un identificatore che è il nome dell’array e un valore numerico maggiore di zero che definisce la sua dimensione. Un array può essere inizializzato contestualmente alla sua dichiarazione elencando all’interno delle parentesi graffe i valori separati da virgole. Oppure può essere dichiarato e successivamente inizializzato.

Nell’esempio successivo non è necessario dare una dimensione all’array in quanto è inizializzato in modo esplicito (contestualmente alla dichiarazione inizializziamo l’array con i valori riportati tra parentesi graffe).

int numeri[] = {1,2,3,4,5};

Sugli array non sono definite operazioni aritmetiche e di confronto ne possono essere restituiti da una funzione, l’unica operazione definita è la selezione con indice (gli array posso essere utilizzati come argomento di una funzione, vedremmo alcuni esempi nella prossima dispensa).

Le istruzioni che seguono dichiarano che numeri è un array di interi con dimensione 5, e successivamente si assegna il valore 7 all’elemento numero quattro dell’array.

int numeri[5];
numeri[3] = 7;

Dobbiamo fare molta attenzione perché il linguaggio non e effettua nessun controllo sui valori degli indici, l’esempio seguente non darebbe nessun errore in fase di compilazione, ma potrebbe generare problemi a tempo di esecuzione. Andremmo infatti a scrivere il valore 7 in una zona di memoria di cui non conosciamo il significato.

int numeri[5];
numeri[5] = 7;

Array e Puntatori

Questo è un argomento un po’ più complesso, ma cercherò di descriverlo nel modo più semplice possibile. Il nome di un array (nel caso precedente era numeri) è anche l’indirizzo di memoria in cui si trova il primo elemento dell’array stesso. Pertanto possiamo dire che se numeri[n] è un array allora &numeri[0] e numeri rappresentano in modo analogo il suo indirizzo. Nella porzione di codice qui sotto le due stampe riporteranno lo stesso indirizzo di memoria.

int numeri[] = {1,2,3,5,6};
printf(“\n stampo numeri: %d”, numeri);
printf(“\n stampo &numeri[0]: %d”, &numeri[0]);

Se al nome dell’array viene sommato un valore intero i, il risultato sarà un indirizzo di memoria dato dall’indirizzo di base dell’array più un offset dato da i. Nell’esempio seguente entrambe le stampe restituiranno lo stesso indirizzo di memoria (la differenza sostanziale con l’esempio precedente risale nell’offset i).

int numeri[] = {1,2,3,5,6};
int i = 2; // i deve essere un numero compreso tra 0 e 4
printf(“\n stampo numeri: %d”, numeri + i);
printf(“\n stampo &numeri[i]: %d”, &numeri[i]);

Mentre *numeri e numeri[0] rappresentano allo stesso modo il primo elemento dell’array (valore). Quindi entrambe le stampe mostrate nella porzione di codice daranno lo stesso risultato.

int numeri[] = {1,2,3,5,6};
printf(“\n stampo *numeri: %d”, *numeri); // stamperà 1
printf(“\n stampo numeri[0]: %d”, numeri[]); // stamperà 1

Come per gli indirizzi, anche in nell’esempio di codice riportato qui sotto, per ottenere il valore di un i-esimo elemento dell’array, abbiamo sommato a numeri l’offset i. Entrambe le stampe restituiranno lo stesso risultato.

int numeri[] = {1,2,3,5,6};
int i = 2; // i deve essere un numero compreso tra 0 e 4
printf(“\n stampo *(numeri + i): %d”, *(numeri + i)); // stamperà 3
printf(“\n stampo numeri[i]: %d”, numeri[i]); // stamperà 3

Quindi riassumendo, il primo elemento di un array numeri[n] si riferisce mediante l’espressione *numeri, l’i-esimo elemento dell’array si riferisce con l’espressione *(numeri + i). Ma più in generale se ind è un indirizzo e ogni riferimento a ind[i] può essere espresso nella forma *(ind + i).

Aritmetica e Puntatori

Vediamo di dare un ulteriore approfondimento all’aritmetica dei puntatori che abbiamo accennato negli esempi precedenti. Utilizzando l’aritmetica dei puntatori potremmo accedere come visto in precedenza ai vari elementi dell’array. Incrementando un puntatore si incrementa l’indirizzo di memoria contenuto nel puntatore facendo si che punti all’elemento successivo. Per far ciò il C conosce il tipo di dato puntato e incrementa l’indirizzo in base alla sua dimensione. Quindi supponiamo che pi sia un puntatore ad un array di interi con l’istruzione pi++ il valore di pi viene incrementato della dimensione del tipo int (generalmente 2 byte). Allo stesso modo se pf punta a un array di float, pf++ incrementerà il suo valore della dimensione di tipo float (generalmente 4 byte). Questo vale anche per incrementi superiori all’unità. Se ad esempio aggiungiamo un valore n a un puntatore, il C incrementa di del numero di byte necessari per raggiungere il nuovo indirizzo di memoria. Quindi:

pi +=4

incrementerà il contenuto di pi di 8 byte (assumendo sempre che un int sia 2 byte).
Tutto il ragionamento fatto fino a qui vale allo stesso modo per il decremento che viene effettuato tramite gli operatori — o -= .

L’ultima operazione prevista a la differenziazione tra due puntatori che puntano a due differenti elementi dello stesso array, questo permette di sapere quanto distino l’uno dall’altro.
Quindi se pi1 e pi2 sono due puntatori ad un medesimo array di interi , l’espressione pi1 – pi2 fornisce la distanza tra loro due.

Sono validi anche tutti gli operatori relazionali come ==, !=, >, < ecc.. purché entrambi i puntatori puntino allo stesso array.

0 commenti

Invia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Linguaggio C per MSX – lezione 6

Linguaggio C per MSX – lezione 6

Linguaggio C per MSX Rubrica a cura di Nicola Brogelli (Parte 6) Array e Puntatori Array Multidimensionali             Fino ad ora abbiamo considerato array monodimensionali, i quali richiedevano un solo indice per l’individuazione di un elemento. Il C permette di...

Linguaggio C per MSX – lezione 3

Linguaggio C per MSX – lezione 3

Linguaggio C per MSX Rubrica a cura di Nicola Brogelli (Parte 3) Enumerazioni Gli enum o enumerazioni sono particolari tipi di dato che contengono un elenco di costanti, ciascuna delle quali è associata ad un valore intero. Nello specifico i valori costanti contenuti...

MSXgl una libreria di giochi scritta in C

MSXgl una libreria di giochi scritta in C

MSXgl è una libreria di giochi scritta in C e destinata ai computer MSX. L'obiettivo di questa libreria è quello di offrire ai programmatori C l'intero set di funzionalità per creare un gioco ad alte prestazioni. Anche se un programma C non potrà mai essere efficiente...

Linguaggio C per MSX – lezione 3

Linguaggio C per MSX – lezione 2

Linguaggio C per MSX Rubrica a cura di Nicola Brogelli (Parte 2) Conversioni di Tipo Come abbiamo visto nella dispensa precedente, in C ogni dato ha un Tipo ben definito. Quando in una espressione compaiono variabili di tipo diverso, spesso il compilatore è in grado...

it_ITIT_IT