Come lavorare con variabili, tipi di dati ed espressioni aritmetiche nel linguaggio di programmazione C

C ha una ricca varietà di operatori matematici che puoi usare per manipolare i tuoi dati. In questo capitolo da Programming in C, 4th Edition, Stephen G. Kochan copre i tipi di dati int, float, double, char, e _Bool, la modifica dei tipi di dati con short, long, e long long, le regole per nominare le variabili, gli operatori matematici di base e le espressioni aritmetiche, e il type casting.

La vera potenza dei programmi che create è la loro manipolazione dei dati. Per trarre veramente vantaggio da questa potenza, avete bisogno di capire meglio i diversi tipi di dati che potete usare, così come il modo di creare e nominare le variabili. Il C ha una ricca varietà di operatori matematici che potete usare per manipolare i vostri dati. In questo capitolo coprirete:

  • I tipi di dati int, float, double, char, e _Bool
  • Modificare i tipi di dati con short, long, e long long
  • Le regole per nominare le variabili
  • Gli operatori matematici di base e le espressioni aritmetiche
  • Fusione di tipi

Comprensione dei tipi di dati e delle costanti

Si è già visto il tipo di dati base int del C. Come ricorderete, una variabile dichiarata di tipo int può essere usata per contenere solo valori integrali, cioè valori che non contengono decimali.

Il linguaggio di programmazione C fornisce altri quattro tipi di dati di base: float, double, char e _Bool. Una variabile dichiarata di tipo float può essere usata per memorizzare numeri in virgola mobile (valori contenenti cifre decimali). Il tipo double è lo stesso del tipo float, solo con circa il doppio della precisione. Il tipo di dati char può essere usato per memorizzare un singolo carattere, come la lettera ‘a’, il carattere numerico ‘6’, o un punto e virgola (‘;’) (più avanti su questo). Infine, il tipo di dati _Bool può essere usato per memorizzare solo i valori 0 o 1. Le variabili di questo tipo sono usate per indicare una situazione on/off, sì/no, o vero/falso. Queste scelte uno/altro sono anche conosciute come scelte binarie.

In C, qualsiasi numero, singolo carattere o stringa di caratteri è conosciuto come una costante. Per esempio, il numero 58 rappresenta un valore intero costante. La stringa di caratteri “Programmare in C è divertente.\n” è un esempio di stringa di caratteri costante. Le espressioni che consistono interamente di valori costanti sono chiamate espressioni costanti. Così, l’espressione

128 + 7 - 17

è un’espressione costante perché ognuno dei termini dell’espressione è un valore costante. Ma se i fosse dichiarato come una variabile intera, l’espressione

128 + 7 – i

non rappresenterebbe un’espressione costante perché il suo valore cambierebbe in base al valore di i. Se i è 10, l’espressione è uguale a 125, ma se i è 200, l’espressione è uguale a -65.

Il tipo intero int

In C, una costante intera consiste in una sequenza di una o più cifre. Un segno meno che precede la sequenza indica che il valore è negativo. I valori 158, -10 e 0 sono tutti esempi validi di costanti intere. Non sono permessi spazi tra le cifre e i valori maggiori di 999 non possono essere espressi con le virgole. (Quindi, il valore 12.000 non è una costante intera valida e deve essere scritto come 12000.)

Due formati speciali in C permettono alle costanti intere di essere espresse in una base diversa da quella decimale (base 10). Se la prima cifra del valore intero è uno 0, l’intero viene preso come espresso in notazione ottale, cioè in base 8. In questo caso, le restanti cifre del valore devono essere cifre valide in base 8 e, quindi, devono essere 0-7. Così, per esprimere il valore 50 in base 8 in C, che è equivalente al valore 40 in decimale, si usa la notazione 050. Allo stesso modo, la costante ottale 0177 rappresenta il valore decimale 127 (1 × 64 + 7 × 8 + 7). Un valore intero può essere visualizzato al terminale in notazione ottale utilizzando i caratteri di formato %o nella stringa di formato di un’istruzione printf(). In tal caso, il valore viene visualizzato in ottale senza uno zero iniziale. Il carattere di formato %#o causa la visualizzazione di uno zero iniziale prima di un valore ottale.

Se una costante intera è preceduta da uno zero e dalla lettera x (sia minuscola che maiuscola), il valore viene considerato come espresso in notazione esadecimale (base 16). Subito dopo la lettera x ci sono le cifre del valore esadecimale, che può essere composto dalle cifre 0-9 e dalle lettere a-f (o A-F). Le lettere rappresentano rispettivamente i valori 10-15. Così, per assegnare il valore esadecimale FFEF0D a una variabile intera chiamata rgbColor, si può usare l’istruzione

rgbColor = 0xFFEF0D;

. I caratteri di formato %x visualizzano un valore in formato esadecimale senza lo 0x iniziale, e usando le lettere minuscole a-f per le cifre esadecimali. Per visualizzare il valore con lo 0x iniziale, si usano i caratteri di formato %#x, come nel seguente:

printf ("Color is %#x\n", rgbColor);

Una x maiuscola, come in %X o %#X, può essere usata per visualizzare la x iniziale e le cifre esadecimali che seguono usando lettere maiuscole.

Dimensioni e intervalli di memorizzazione

Ogni valore, che sia un carattere, un numero intero o a virgola mobile, ha un intervallo di valori associato ad esso. Questo intervallo ha a che fare con la quantità di memoria che viene allocata per memorizzare un particolare tipo di dati. In generale, questa quantità non è definita nel linguaggio. Dipende tipicamente dal computer che si sta utilizzando, ed è, quindi, chiamato implementazione o dipendente dalla macchina. Per esempio, un intero potrebbe occupare 32 bit sul vostro computer, o forse potrebbe essere memorizzato in 64. Non dovreste mai scrivere programmi che fanno supposizioni sulla dimensione dei vostri tipi di dati. Tuttavia, è garantito che una quantità minima di memoria sarà messa da parte per ogni tipo di dati di base. Per esempio, è garantito che un valore intero sarà memorizzato in un minimo di 32 bit di memoria, che è la dimensione di una “parola” su molti computer.

Il tipo di numero fluttuante float

Una variabile dichiarata di tipo float può essere usata per memorizzare valori contenenti cifre decimali. Una costante in virgola mobile si distingue per la presenza di un punto decimale. Potete omettere le cifre prima del punto decimale o le cifre dopo il punto decimale, ma ovviamente non potete omettere entrambi. I valori 3., 125.8, e -.0001 sono tutti esempi validi di costanti in virgola mobile. Per visualizzare un valore in virgola mobile sul terminale, si usano i caratteri di conversione printf %f.

Le costanti in virgola mobile possono anche essere espresse in notazione scientifica. Il valore 1,7e4 è un valore in virgola mobile espresso in questa notazione e rappresenta il valore 1,7 × 104. Il valore prima della lettera e è noto come mantissa, mentre il valore che segue è chiamato esponente. Questo esponente, che può essere preceduto da un segno più o meno opzionale, rappresenta la potenza di 10 per cui la mantissa deve essere moltiplicata. Così, nella costante 2.25e-3, il 2.25 è il valore della mantissa e -3 è il valore dell’esponente. Questa costante rappresenta il valore 2,25 × 10-3, o 0,00225. Per inciso, la lettera e, che separa la mantissa dall’esponente, può essere scritta sia in minuscolo che in maiuscolo.

Per visualizzare un valore in notazione scientifica, i caratteri di formato %e devono essere specificati nella stringa di formato printf(). I caratteri di formato di printf() %g possono essere usati per far decidere a printf() se visualizzare il valore in virgola mobile in notazione normale o in notazione scientifica. Questa decisione si basa sul valore dell’esponente: Se è minore di -4 o maggiore di 5, viene usato il formato %e (notazione scientifica); altrimenti, viene usato il formato %f.

Utilizza i caratteri del formato %g per visualizzare i numeri in virgola mobile: produce l’output esteticamente più gradevole.

Una costante esadecimale fluttuante consiste di uno 0x o 0X iniziale, seguito da una o più cifre decimali o esadecimali, seguito da una p o P, seguito da un esponente binario firmato facoltativamente. Per esempio, 0x0.3p10 rappresenta il valore 3/16 × 210 = 0.5.

Il tipo a precisione estesa double

Il tipo double è molto simile al tipo float, ma è usato quando l’intervallo fornito da una variabile float non è sufficiente. Le variabili dichiarate di tipo double possono memorizzare circa il doppio delle cifre significative di una variabile di tipo float. La maggior parte dei computer rappresenta i valori doppi usando 64 bit.

A meno che non venga detto altrimenti, tutte le costanti in virgola mobile sono prese come valori doppi dal compilatore C. Per esprimere esplicitamente una costante di tipo float, aggiungete una f o una F alla fine del numero, come segue:

12.5f

Per visualizzare un valore doppio, possono essere usati i caratteri di formato %f, %e, o %g, che sono gli stessi caratteri di formato usati per visualizzare un valore float.

Il tipo di carattere singolo char

Una variabile char può essere usata per memorizzare un singolo carattere.1 Una costante di carattere si forma racchiudendo il carattere in una coppia di apici singoli. Così ‘a’, ‘;’, e ‘0’ sono tutti esempi validi di costanti di carattere. La prima costante rappresenta la lettera a, la seconda è un punto e virgola, e la terza è il carattere zero, che non è lo stesso del numero zero. Non confondete una costante di carattere, che è un singolo carattere racchiuso tra virgolette singole, con una stringa di caratteri, che è un qualsiasi numero di caratteri racchiusi tra virgolette doppie.

La costante di carattere ‘\n’-il carattere newline- è una costante di carattere valida anche se sembra contraddire la regola citata precedentemente. Questo perché il carattere backslash è un carattere speciale nel sistema C e non conta effettivamente come un carattere. In altre parole, il compilatore C tratta il carattere ‘\n’ come un singolo carattere, anche se in realtà è formato da due caratteri. Ci sono altri caratteri speciali che vengono iniziati con il carattere backslash. Consultare l’Appendice A, “Riassunto del linguaggio C”, per una lista completa.

I caratteri di formato %c possono essere usati in una chiamata printf() per visualizzare il valore di una variabile char al terminale.

Il tipo di dati booleani _Bool

Una variabile _Bool è definita nel linguaggio per essere abbastanza grande da memorizzare solo i valori 0 e 1. La quantità precisa di memoria che viene usata non è specificata. Le variabili _Bool sono usate nei programmi che hanno bisogno di indicare una condizione booleana. Per esempio, una variabile di questo tipo potrebbe essere usata per indicare se tutti i dati sono stati letti da un file.

Per convenzione, 0 è usato per indicare un valore falso, e 1 indica un valore vero. Quando si assegna un valore ad una variabile _Bool, un valore di 0 viene memorizzato come 0 all’interno della variabile, mentre qualsiasi valore diverso da zero viene memorizzato come 1.

Per facilitare il lavoro con le variabili _Bool nel vostro programma, il file header standard <stdbool.h> definisce i valori bool, true e false. Un esempio di questo è mostrato nel Programma 5.10A nel Capitolo 5, “Prendere decisioni.”

Nel Programma 3.1, vengono usati i tipi di dati di base del C.

Programma 3.1 Usare i tipi di dati di base

Programma 3.1 Output

integerVar = 100floatingVar = 331.790009doubleVar = 8.440000e+11doubleVar = 8.44e+11charVar = WboolVar = 0;

La prima frase del Programma 3.1 dichiara la variabile integerVar come una variabile intera e le assegna anche un valore iniziale di 100, come se invece fossero state usate le seguenti due dichiarazioni:

int integerVar;integerVar = 100;

Nella seconda riga dell’output del programma, si noti che il valore di 331,79, che è assegnato a floatingVar, viene effettivamente visualizzato come 331,790009. In effetti, il valore effettivo visualizzato dipende dal particolare sistema informatico che state usando. La ragione di questa imprecisione è il modo particolare in cui i numeri sono rappresentati internamente nel computer. Probabilmente vi siete imbattuti nello stesso tipo di imprecisione quando avete a che fare con i numeri sulla vostra calcolatrice tascabile. Se dividi 1 per 3 sulla tua calcolatrice, ottieni il risultato .33333333, con forse alcuni 3 aggiuntivi aggiunti alla fine. La serie di 3 è l’approssimazione della calcolatrice a un terzo. Teoricamente, ci dovrebbe essere un numero infinito di 3. Ma la calcolatrice può contenere solo un certo numero di cifre, quindi l’imprecisione intrinseca della macchina. Lo stesso tipo di imprecisione si applica qui: Alcuni valori in virgola mobile non possono essere rappresentati esattamente nella memoria del computer.

Quando si visualizzano i valori delle variabili float o double, si può scegliere tra tre diversi formati. I caratteri %f sono usati per visualizzare i valori in modo standard. A meno che non venga detto altrimenti, printf() visualizza sempre un valore float o double con sei cifre decimali arrotondate. Vedrete più avanti in questo capitolo come selezionare il numero di cifre decimali che vengono visualizzate.

I caratteri %e sono usati per visualizzare il valore di una variabile float o double in notazione scientifica. Ancora una volta, sei cifre decimali sono visualizzate automaticamente dal sistema.

Con i caratteri %g, printf() sceglie tra %f e %e e rimuove automaticamente dal display qualsiasi zero finale. Se nessuna cifra segue il punto decimale, non visualizza neanche quello.

Nella penultima istruzione printf(), i caratteri %c sono usati per visualizzare il singolo carattere ‘W’ che avete assegnato a charVar quando la variabile è stata dichiarata. Ricordate che mentre una stringa di caratteri (come il primo argomento di printf()) è racchiusa in una coppia di doppi apici, una costante di caratteri deve sempre essere racchiusa in una coppia di singoli apici.

L’ultima printf() mostra che una variabile _Bool può avere il suo valore visualizzato usando i caratteri di formato intero %i.

Specificatori di tipo: long, long long, short, unsigned, e signed

Se lo specificatore long è posto direttamente prima della dichiarazione int, la variabile intera dichiarata è di range esteso su alcuni sistemi informatici. Un esempio di una dichiarazione long int potrebbe essere

long int factorial;

Questo dichiara che la variabile factorial è una variabile intera lunga. Come per i float e i double, la particolare precisione di una variabile long dipende dal vostro particolare sistema informatico. Su molti sistemi, un int e un long int hanno lo stesso range ed entrambi possono essere usati per memorizzare valori interi fino a 32 bit di larghezza (231 – 1, o 2.147.483.647).

Un valore costante di tipo long int è formato aggiungendo opzionalmente la lettera L (maiuscola o minuscola) alla fine di una costante intera. Non sono ammessi spazi tra il numero e la L. Così, la dichiarazione

long int numberOfPoints = 131071100L;

dichiara che la variabile numberOfPoints è di tipo long int con un valore iniziale di 131.071.100.

Per visualizzare il valore di un long int usando printf(), la lettera l è usata come modificatore prima dei caratteri di formato intero i, o e x. Questo significa che i caratteri di formato %li possono essere usati per visualizzare il valore di un long int in formato decimale, i caratteri %lo possono visualizzare il valore in formato ottale, e i caratteri %lx possono visualizzare il valore in formato esadecimale.

C’è anche un tipo di dati long long integer, quindi

long long int maxAllowedStorage;

dichiara che la variabile indicata è della precisione estesa specificata, che è garantita essere di almeno 64 bit. Invece di una singola lettera l, due l sono usate nella stringa printf per visualizzare interi lunghi lunghi, come in “%lli”.

Lo specificatore lungo è permesso anche davanti a una dichiarazione di doppio, come segue:

long double US_deficit_2004;

Una costante lunga doppia è scritta come una costante fluttuante con la lettera l o L immediatamente successiva, come

1.234e+7L

Per visualizzare un doppio lungo, viene usato il modificatore L. Così, %Lf visualizza un valore doppio lungo in notazione a virgola mobile, %Le visualizza lo stesso valore in notazione scientifica, e %Lg dice a printf() di scegliere tra %Lf e %Le.

Lo specificatore short, quando è posto davanti alla dichiarazione int, dice al compilatore C che la particolare variabile dichiarata è usata per memorizzare valori interi abbastanza piccoli. La motivazione per l’uso delle variabili short è principalmente quella di conservare lo spazio di memoria, che può essere un problema in situazioni in cui il programma ha bisogno di molta memoria e la quantità di memoria disponibile è limitata.

In alcune macchine, un int short occupa la metà della quantità di memoria di una normale variabile int. In ogni caso, avete la garanzia che la quantità di spazio allocato per uno short int non sarà inferiore a 16 bit.

Non c’è modo di scrivere esplicitamente una costante di tipo short int in C. Per visualizzare una variabile short int, mettete la lettera h davanti a uno qualsiasi dei normali caratteri di conversione degli interi: %hi, %ho, o %hx. In alternativa, potete anche usare uno qualsiasi dei caratteri di conversione degli interi per visualizzare short int, grazie al modo in cui possono essere convertiti in interi quando vengono passati come argomenti alla routine printf().

L’ultimo specificatore che può essere messo davanti ad una variabile int è usato quando una variabile intera sarà usata per memorizzare solo numeri positivi. La dichiarazione

unsigned int counter;

dichiara al compilatore che il contatore della variabile è usato per contenere solo valori positivi. Limitando l’uso di una variabile intera alla memorizzazione esclusiva di numeri interi positivi, la precisione della variabile intera viene estesa.

Una costante int senza segno si forma mettendo la lettera u (o U) dopo la costante, come segue:

0x00ffU

Si possono combinare le lettere u (o U) e l (o L) quando si scrive una costante intera, così

20000UL

dice al compilatore di trattare la costante 20000 come un lungo senza segno.

Una costante intera che non è seguita da nessuna delle lettere u, U, l, o L e che è troppo grande per entrare in un int di dimensioni normali è trattata come un unsigned int dal compilatore. Se è troppo piccolo per entrare in un unsigned int, il compilatore lo tratta come un long int. Se ancora non può entrare in un long int, il compilatore lo rende un unsigned long int. Se non ci sta, il compilatore lo tratta come un long long int se ci sta, e come un unsigned long long int altrimenti.

Quando si dichiarano variabili di tipo long long int, long int, short int, o unsigned int, si può omettere la parola chiave int. Pertanto, il contatore della variabile senza segno potrebbe essere stato dichiarato in modo equivalente come segue:

unsigned counter;

Puoi anche dichiarare le variabili char come senza segno.

Il qualificatore signed può essere usato per dire esplicitamente al compilatore che una particolare variabile è una quantità firmata. Il suo uso è principalmente davanti alla dichiarazione char, e un’ulteriore discussione è rimandata al Capitolo 13, “More on Data Types.”

Non preoccupatevi se le discussioni di questi specificatori vi sembrano un po’ esoteriche a questo punto. Nelle sezioni successive di questo libro, molti di questi diversi tipi sono illustrati con esempi di programmi reali. Il capitolo 13 approfondisce i tipi di dati e le conversioni.

La tabella 3.1 riassume i tipi di dati e i qualificatori di base.

Tabella 3.1 Tipi di dati di base