Lettura e Scrittura degli Interi in Linguaggio C

Abbiamo visto nelle lezioni precedenti come dichiarare e inizializzare variabili intere in linguaggio C specificandone sia la dimensione che il fatto che siano con o senza segno.

Adesso risulta fondamentale capire come stampare a schermo questi valori e come leggerli da tastiera. In questo articolo vedremo come fare utilizzando le funzioni printf e scanf applicando gli appositi specificatori di formato.

printf e tipi interi

Abbiamo visto come dichiarare e inizializzare variabili intere in linguaggio C. Ora vediamo come possiamo leggere e scrivere tali variabili utilizzando la funzione printf.

Finora, quando abbiamo utilizzato la funzione printf per stampare a schermo degli interi, abbiamo sempre adoperato all'interno della stringa di formato lo specificatore di formato %d. La lettera d sta, appunto, per decimal (decimale), in quanto il numero intero viene stampato in base 10.

Ad esempio, per stampare a schermo il valore di una variabile intera numero, abbiamo utilizzato la seguente istruzione:

int numero = 42;
printf("Il valore di numero è %d\n", numero);

Tuttavia, abbiamo visto nelle lezioni precedenti che esistono diversi tipi di variabili intere in linguaggio C, come ad esempio short int, long int e long long int.

In tali casi, lo specificatore di formato %d non è adatto a rappresentare correttamente il valore di tali variabili. Infatti, %d è adatto solo per variabili di tipo int.

Per tal motivo, la funzione printf mette a disposizione degli specificatori diversi a seconda del tipo specifico di intero che vogliamo stampare. In particolare bisogna apporre una lettera prima del carattere d per specificare il tipo di intero che vogliamo stampare:

  • %hd per variabili di tipo short int;
  • %ld per variabili di tipo long int;
  • %lld per variabili di tipo long long int.

L'esempio che segue mostra come utilizzare tali specificatori di formato:

short int numero_short = 42;
long int numero_long = 2147483647;
long long int numero_long_long = 9223372036854775807;

printf("Il valore di numero_short è %hd\n", numero_short);
printf("Il valore di numero_long è %ld\n", numero_long);
printf("Il valore di numero_long_long è %lld\n", numero_long_long);

Se proviamo a compilare ed eseguire il codice di sopra otteniamo un output come il seguente:

Il valore di numero_short è 42
Il valore di numero_long è 2147483647
Il valore di numero_long_long è 9223372036854775807

Bisogna prestare attenzione quando si stampano interi. Infatti, utilizzare uno specificatore errato, specialmente quando si usa uno specificatore di formato per un tipo di dimensioni inferiori, può portare a risultati errati.

Ad esempio, se proviamo a stampare una variabile di tipo long int utilizzando lo specificatore %hd, otteniamo un risultato errato:

long int numero_long = 2147483647;
printf("Il valore di numero_long è %hd\n", numero_long);

In questo caso, il risultato stampato a schermo sarà:

Il valore di numero_long è -1

Questo perché il valore di numero_long è troppo grande per essere rappresentato da un short int, e quindi il risultato è errato.

Definizione

Specificatori di Formato per Interi in printf

Per stampare correttamente variabili intere di tipo diverso da int in linguaggio C, è necessario utilizzare gli specificatori di formato seguenti:

  • %hd per variabili di tipo short int;
  • %ld per variabili di tipo long int;
  • %lld per variabili di tipo long long int.

La funzione printf mette a disposizione anche uno specificatore di formato per indicare che l'intero da stampare è senza segno, unsigned.

In tal caso bisogna utilizzare, al posto della lettera d, la lettera u:

unsigned int numero_unsigned = 42;
printf("Il valore di numero_unsigned è %u\n", numero_unsigned);

Come sopra, lo specificatore u può essere combinato con le lettere h, l e ll per specificare il tipo di intero senza segno:

  • %hu per variabili di tipo unsigned short int;
  • %lu per variabili di tipo unsigned long int;
  • %llu per variabili di tipo unsigned long long int.

Ricapitolando:

Definizione

Sintassi degli Specificatori di Formato per Interi della funzione printf

La sintassi degli specificatori di formato per interi della funzione printf è la seguente:

%<dimensione><formato>

Dove <dimensione> può essere una delle seguenti lettere:

  • h per short int;
  • l per long int;
  • ll per long long int;
  • se omessa, si assume int.

Mentre <formato> può essere una delle seguenti lettere:

  • d per interi con segno;
  • u per interi senza segno.

In ogni caso gli interi verranno stampati in base 10.

Stampare gli interi in altre basi

La funzione printf è talmente flessibile da permettere di stampare gli interi in basi diverse da quella decimale.

In particolare, possiamo utilizzare, al posto di d e u, i seguenti specificatori di formato:

  • %o per stampare l'intero in base ottale;
  • %x per stampare l'intero in base esadecimale;
  • %X per stampare l'intero in base esadecimale, con le lettere maiuscole;
  • %b per stampare l'intero in base binaria.

Nell'esempio che segue, leggiamo un numero int da tastiera e lo stampiamo in base ottale, esadecimale (sia in maiuscolo che minuscolo) e binaria:

#include <stdio.h>

int main() {
    int numero;

    printf("Inserisci un numero intero: ");
    scanf("%d", &numero);

    printf("Il numero in base ottale è %o\n", numero);
    printf("Il numero in base esadecimale è %x\n", numero);
    printf("Il numero in base esadecimale (maiuscolo) è %X\n", numero);
    printf("Il numero in base binaria è %b\n", numero);

    return 0;
}

Se eseguiamo il programma e inseriamo il numero 42, otteniamo il seguente output:

Inserisci un numero intero: 42
Il numero in base ottale è 52
Il numero in base esadecimale è 2a
Il numero in base esadecimale (maiuscolo) è 2A
Il numero in base binaria è 101010

Bisogna, però, prestare attenzione ad un dettaglio: quando usiamo uno dei quattro specificatori di sopra, il numero verrà considerato sempre come senza segno (unsigned).

Infatti, prendiamo l'esempio che segue:

#include <stdio.h>

int main() {
    int numero = -42;

    printf("Il numero in base ottale è %o\n", numero);
    printf("Il numero in base esadecimale è %x\n", numero);
    printf("Il numero in base esadecimale (maiuscolo) è %X\n", numero);
    printf("Il numero in base binaria è %b\n", numero);

    return 0;
}

Se eseguiamo il programma, otteniamo il seguente output:

Il numero in base ottale è 37777777726
Il numero in base esadecimale è fffffff6
Il numero in base esadecimale (maiuscolo) è FFFFFFF6
Il numero in base binaria è 11111111111111111111111111110110

Come si può osservare, il numero -42 è stato interpretato come un numero senza segno, e quindi il risultato è diverso da quello che ci aspettavamo.

Definizione

Specificatori di Formato per Interi in Basi Diverse in printf

Per stampare un valore int con la funzione printf in una base diversa da 10, possiamo adoperare i seguenti specificatori di formato:

  • %o per stampare l'intero in base ottale;
  • %x per stampare l'intero in base esadecimale;
  • %X per stampare l'intero in base esadecimale, con le lettere maiuscole;
  • %b per stampare l'intero in base binaria.

In ogni caso, il numero verrà considerato come senza segno (unsigned).

Gli specificatori di formato introdotti sopra possono essere combinati con i prefissi h, l e ll per specificare la dimensione dell'intero da stampare.

Ad esempio, possiamo stampare un numero short int in base ottale utilizzando il seguente specificatore di formato:

short int numero_short = 42;
printf("Il numero in base ottale è %ho\n", numero_short);

Oppure, possiamo stampare un numero long long int in base binaria utilizzando il seguente specificatore di formato:

long long int numero_long_long = 9223372036854775807;
printf("Il numero in base binaria è %llb\n", numero_long_long);

Ricapitolando:

Definizione

Sintassi degli Specificatori di Formato per Interi in Basi Diverse della funzione printf

La sintassi degli specificatori di formato per interi in basi diverse della funzione printf è la seguente:

%<dimensione><formato>

Dove <dimensione> può essere una delle seguenti lettere:

  • h per short int;
  • l per long int;
  • ll per long long int;
  • se omessa, si assume int.

Mentre <formato> può essere una delle seguenti lettere:

  • o per base ottale;
  • x per base esadecimale;
  • X per base esadecimale (maiuscolo);
  • b per base binaria.

In ogni caso il numero verrà considerato come senza segno (unsigned).

Leggere gli interi da tastiera

Il discorso fatto sopra per la funzione printf vale allo stesso modo per la funzione scanf.

Attraverso di essa possiamo leggere valori interi da tastiera. Ma dobbiamo applicare gli specificatori di formato adatti per leggere correttamente i valori interi.

Gli specificatori da adoperare sono esattamente gli stessi visti sopra.

Ad esempio, il programma che segue legge tre numeri da tastiera, con segno, utilizzando formati diversi:

#include <stdio.h>

int main() {
    short int numero_short;
    long int numero_long;
    long long int numero_long_long;

    printf("Inserisci un numero short int: ");
    scanf("%hd", &numero_short);

    printf("Inserisci un numero long int: ");
    scanf("%ld", &numero_long);

    printf("Inserisci un numero long long int: ");
    scanf("%lld", &numero_long_long);

    printf("Hai inserito i seguenti numeri:\n");
    printf("short int: %hd\n", numero_short);
    printf("long int: %ld\n", numero_long);
    printf("long long int: %lld\n", numero_long_long);

    return 0;
}

Se eseguiamo il programma e inseriamo i numeri 42, 2147483647 e 9223372036854775807, otteniamo il seguente output:

Inserisci un numero short int: 42
Inserisci un numero long int: 2147483647
Inserisci un numero long long int: 9223372036854775807
Hai inserito i seguenti numeri:
short int: 42
long int: 2147483647
long long int: 9223372036854775807

Come si può osservare, i valori inseriti sono stati correttamente letti e memorizzati nelle variabili numero_short, numero_long e numero_long_long.

Allo stesso modo possiamo leggere valori senza segno da tastiera. In tal caso, dobbiamo utilizzare gli specificatori di formato %hu, %lu e %llu per unsigned short int, unsigned long int e unsigned long long int, rispettivamente.

La flessibilità della scanf sta anche nel fatto che possiamo leggere valori interi in basi diverse. Per farlo, dobbiamo utilizzare gli stessi specificatori di formato visti sopra per la funzione printf.

Ad esempio, il programma che segue legge un numero intero in base ottale, esadecimale e binaria:

#include <stdio.h>

int main() {
    int numero_ottale, numero_esadecimale, numero_binario;

    printf("Inserisci un numero in base ottale: ");
    scanf("%o", &numero_ottale);

    printf("Inserisci un numero in base esadecimale: ");
    scanf("%x", &numero_esadecimale);

    printf("Inserisci un numero in base binaria: ");
    scanf("%b", &numero_binario);

    printf("Hai inserito i seguenti numeri:\n");
    printf("Ottale: %d\n", numero_ottale);
    printf("Esadecimale: %d\n", numero_esadecimale);
    printf("Binario: %d\n", numero_binario);

    return 0;
}

Se eseguiamo il programma e inseriamo i numeri 23, ABAC, 101010, otteniamo il seguente output:

Inserisci un numero in base ottale: 23
Inserisci un numero in base esadecimale: ABAC
Inserisci un numero in base binaria: 101010
Hai inserito i seguenti numeri:
Ottale: 19
Esadecimale: 43948
Binario: 42

Un importante dettaglio riguarda l'inserimento di numeri in base esadecimale. Infatti, la funzione scanf non fa differenza tra %x e %X. Entrambi i formati leggono correttamente numeri esadecimali, indipendentemente dal fatto che le lettere siano maiuscole o minuscole.

Definizione

Leggere Interi da Tastiera con scanf

La sintassi degli specificatori di formato per leggere interi con la funzione scanf è la seguente:

%<dimensione><formato>

Dove <dimensione> può essere una delle seguenti lettere:

  • h per short int;
  • l per long int;
  • ll per long long int;
  • se omessa, si assume int.

Mentre <formato> può essere una delle seguenti lettere:

  • d per interi con segno;
  • u per interi senza segno;
  • o per base ottale;
  • x o X per base esadecimale e non si fa distinzione tra maiuscole e minuscole;
  • b per base binaria.

In Sintesi

In questa lezione abbiamo visto come leggere e scrivere variabili intere in linguaggio C utilizzando la funzione printf.

Abbiamo visto che, per stampare correttamente variabili intere di tipo diverso da int, è necessario utilizzare specificatori di formato diversi, come %hd, %ld, %lld e %u.

Inoltre, abbiamo visto che la funzione printf permette di stampare gli interi in basi diverse da quella decimale, utilizzando specificatori di formato come %o, %x, %X e %b.

Infine, abbiamo visto come leggere valori interi da tastiera utilizzando la funzione scanf, e come applicare gli stessi specificatori di formato visti sopra per la funzione printf.