Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
vuoi
o PayPal
tutte le volte che vuoi
Strutture e Unioni: Rappresentazione e Operatore Punto
Estrae da s la parte intera del numero che s contiene al suo inizio (altrimenti 0).
double atof(const char *s) <stdlib.h>
Estrae da s il numero reale che s contiene al suo inizio (altrimenti 0).
Il costruttore di tipo struttura del linguaggio C – noto più in generale come record – dà luogo a un valore aggregato formato da un numero finito di elementi memorizzati consecutivamente ma non necessariamente dello stesso tipo. Per questo motivo gli elementi non saranno selezionabili mediante indici come negli array, ma dovranno essere singolarmente dichiarati e identificati.
Una variabile di tipo struttura viene dichiarata come segue:
struct {dichiarazioneElementi} identificatoreVariabile;
oppure con contestualizzazione iniziale:
struct {dichiarazioneElementi} identificatoreVariabile = {sequenza Valori};
dove:
- Ogni elemento (o campo) è dichiarato come segue:
tipoElemento nomeElemento;
identificatoreElemento;
● Se presenti, i valori di inizializzazione sono separati da virgole e vengono ordinatamente assegnati da sinistra a destra ai corrispondenti elementi a patto che i rispettivi tipi siano compatibili.
Diversamente dal tipo array, una variabile di tipo struttura può comparire in entrambi i lati di un assegnamento – quindi il risultato di una funzione può essere di tipo struttura – e può essere passata sia per valore che per indirizzo a una funzione.
Ogni elemento di una variabile di tipo struttura può essere selezionato all'interno di un'istruzione tramite il suo identificatore. La sintassi è:
● identificatoreVariabile.identificatoreElemento
L'operatore punto, che è unario e postfisso, ha la stessa precedenza dell'operatore di indicizzazione.
Il costruttore di tipo unione del linguaggio C – noto più in generale come record variant – dà luogo a un valore aggregato
corrispondente nome di campo. Ad esempio, se abbiamo una variabile di tipo unione chiamata "myUnion" con due campi "field1" e "field2", possiamo accedere a questi campi utilizzando la sintassi "myUnion.field1" e "myUnion.field2". Le unioni sono spesso utilizzate quando si desidera risparmiare spazio di memoria, poiché solo uno dei campi può essere utilizzato alla volta. Tuttavia, è importante prestare attenzione quando si utilizzano unioni, poiché non c'è alcun controllo sul campo attualmente utilizzato e si potrebbero verificare errori se si tenta di accedere a un campo non valido. Ecco un esempio di dichiarazione e utilizzo di una variabile di tipo unione in C: ```html
union myUnion {
int field1;
float field2;
char field3;
};
int main() {
union myUnion myVar;
myVar.field1 = 10;
printf("%d\n", myVar.field1);
myVar.field2 = 3.14;
printf("%f\n", myVar.field2);
myVar.field3 = 'A';
printf("%c\n", myVar.field3);
return 0;
}
```
In questo esempio, abbiamo dichiarato una variabile di tipo unione chiamata "myUnion" con tre campi: "field1" di tipo int, "field2" di tipo float e "field3" di tipo char. Abbiamo quindi assegnato valori ai campi e li abbiamo stampati utilizzando la funzione printf.
Output:
```
10
3.140000
A
```
Come puoi vedere, possiamo accedere ai campi della variabile di tipo unione in modo simile a come accediamo ai campi di una struttura. Tuttavia, è importante notare che solo uno dei campi può essere utilizzato alla volta.identificatore utilizzando l'operatore punto. Per garantire che tale elemento sia coerente con l'interpretazione corrente della variabile, occorre testare preventivamente un'ulteriore variabile contenente l'interpretazione corrente.
Puntatori: Operatori e Funzioni di Libreria
Il costruttore di tipo puntatore del linguaggio C viene utilizzato per denotare indirizzi di memoria, che sono espressi da numeri interi. Un valore di tipo puntatore non rappresenta quindi un dato, ma l'indirizzo di memoria al quale un dato può essere reperito.
L'insieme dei valori di tipo puntatore include un valore speciale, denotato con la costante simbolica NULL definita nel file di intestazione di libreria standard stdio.h, il quale rappresenta l'assenza di un indirizzo specifico.
Una variabile di tipo puntatore a un dato di un certo tipo viene dichiarata come segue:
tipoDato *identificatoreVariabile;
oppure con contestualizzazione iniziale:
tipoDato
contenere un valore del tipo di riferimento del puntatore - tra i due puntatori. Per formattare il testo utilizzando tag HTML, puoi utilizzare i seguenti tag: - `` per evidenziare il testo in grassetto - `` per creare un testo in apice - `` per creare un testo in pedice - `` per inserire un'interruzione di linea Ecco come potrebbe apparire il testo formattato: ```html
identificatoreVariabile = indirizzo;
Lo spazio di memoria da riservare a una variabile di tipo puntatore è indipendente dal tipo del dato a cui il puntatore fa riferimento.
Poiché gli indirizzi di memoria vengono rappresentati attraverso numeri interi, i valori di tipo puntatore sono assimilabili ai valori di tipo int. Tuttavia, oltre all'operatore di assegnamento e al confronto di uguaglianza/diversità, ai valori di tipo puntatore è ragionevole applicare solo alcuni degli operatori aritmetico-logici:
- Addizione/sottrazione di un valore di tipo int a/da un valore di tipo puntatore: serve per far avanzare/indietreggiare il puntatore di un certo numero di porzioni di memoria, ciascuna della dimensione tale da poter contenere un valore del tipo di riferimento del puntatore.
- Sottrazione di un valore di tipo puntatore da un altro valore di tipo puntatore: serve per calcolare il numero di porzioni di memoria - ciascuna della dimensione tale da poter contenere un valore del tipo di riferimento del puntatore - tra i due puntatori.
contenere un valore del tipo di riferimento dei due puntatori – comprese tra idue puntatori.
Esistono inoltre degli operatori specifici per i valori di tipo puntatore:
- L'operatore valore-di “*”, applicato a un’espressione di tipo puntatore il cui valore è diverso da NULL, restituisce il valore contenuto nella locazione di memoria il cui indirizzo è dato dall’espressione. Se viene applicato a un’espressione di tipo puntatore il cui valore è NULL, il sistema operativo interrompe l’esecuzione del programma ed emette un messaggio d’errore.
- L'operatore indirizzo-di “&”, applicato a una variabile, restituisce l’indirizzo dellalocazione di memoria in cui è contenuto il valore della variabile (passaggio per indirizzo della variabile).
- L'operatore freccia “->”, il quale riguarda le variabili di tipo puntatore a struttura o unione, consente di abbreviare:
<p><em>(*identificatoreVariabilePuntatore).identificatoreElementoin</em> • <strong>identificatoreVariabilePuntatore->identificatoreElemento</strong></p>
<p>I primi due operatori sono unari e prefissi e hanno la stessa precedenza degli operatori unari aritmetico-logici, mentre l'operatore freccia è unario e postfisso e ha la stessa precedenza degli operatori di indicizzazione e punto.</p>
<p>Poiché l'identificatore di una variabile di tipo array rappresenta l'indirizzo della locazione di memoria che contiene il valore del primo elemento dell'array, c'è un legame stretto tra array e puntatori:</p>
<ul>
<li>Il valore di un elemento di una variabile di tipo array è normalmente selezionato come segue: <strong>identificatoreVariabileArray[espr_indice]</strong> poiché il suo indirizzo è: <strong>identificatoreVariabileArray + espr_indice</strong></li>
<li>Il suddetto valore può essere equivalentemente espresso come segue: <strong>*(identificatoreVariabileArray + espr_indice)</strong></li>
</ul>
<p>Un parametro formale di tipo</p>
array può essere indifferentemente dichiarato come segue:
- tipoElementi identificatoreParametroArray[]
- tipoElementi *identificatoreParametroArray
Quest'ultimo è utilizzabile anche per dichiarare variabili array la cui lunghezza è ignota.
Esempio: se una variabile stringa è dichiarata di tipo char * anziché array di char, allora il suo valore può essere acquisito tramite scanf usando il segnaposto %ms, che alloca anche lo spazio necessario, e anteponendo l'operatore "&" all'identificatore della variabile.
Il costruttore di tipo struttura e il costruttore di tipo puntatore usati congiuntamente consentono la definizione di tipi di dati ricorsivi. Il costruttore di tipo struttura permette infatti di associare un identificatore alla struttura stessa mediante la seguente sintassi:
struct identificatoreStruttura {dichiarazioneElementi}
In via di principio, ciò rende possibile la formattazione del testo utilizzando tag html.
presenza di uno o più elementi della seguente forma all'interno di {dichiarazioneElementi}:
● struct identificatoreStruttura identificatoreElemento;
come pure di elementi della seguente forma:
● struct identificatoreStruttura *identificatoreElemento;
Tuttavia, solo gli elementi della seconda forma sono ammissibili in quanto rendono la definizione ricorsiva ben posta. Il motivo è che per gli elementi di questa forma è noto lo spazio di memoria da riservare, mentre ciò non vale per gli elementi della prima forma.
Le strutture dati dinamiche, che si espandono e si contraggono mentre il programma viene eseguito, sono tipicamente implementate attraverso la definizione di tipi ricorsivi. Poiché lo spazio di memoria di cui queste strutture dati necessitano non può essere fissato a priori, l'allocazione/disallocazione della memoria per esse avviene a tempo di esecuzione nello heap attraverso l'invocazione delle seguenti funzioni, basate su puntatori:
disponibili nel file di intestazione di libreria standard stdlib.h:
void *malloc(size_t dim)
- Alloca un blocco di dim byte nello heap e restituisce l'indirizzo di tale blocco (NULL in caso di fallimento, cioè assenza di un blocco sufficientemente grande). Il blocco allocato viene marcato come occupato nello heap e il puntatore ad esso è del tipo genericovoid *
.void *calloc(size_t num, size_t dim)
- Alloca num blocchi consecutivi di dim byte ciascuno nello heap e restituisce l'indirizzo del primo blocco (NULL in caso di fallimento). Questa funzione serve per allocare dinamicamente un array nel momento in cui il numero dei suoi elementi diviene noto a tempo di esecuzione. Equivale a una malloc con parametro effettivo dato danum * dim
.void *realloc(void *vecchio_blocco, size_t nuova_dim)
- Cambia la dimensione di un blocco di memoria nello heap precedentemente allocato con malloc/calloc (senza modificarne il contenuto) e restituisce l'indirizzo del
void free(void *blocco)
Disalloca un blocco di memoria nello heap precedentemente allocato con malloc/calloc; prima di applicarla, è bene assicurarsi che non venga più fatto riferimento al blocco tramite puntatori nelle istruzioni da eseguire successivamente. Il blocco disallocato viene marcato come libero nello heap, ritornando quindi nuovamente disponibile per successive allocazioni.
Correttezza di Programmi Procedurali
Classificazione dei Tipi di Dati e Operatore sizeof
Un tipo di dato denota, come se fosse una struttura algebrica, un insieme di valori a cui sono applicabili solo determinate operazioni. L'attribuzione di un tipo a ogni identificatore presente in un programma consente al compilatore di rilevare errori staticamente, cioè senza eseguire il programma. Nel caso specifico delle variabili,
stabilisce anche la quantità di memoriane