Tipo char in Linguaggio C

Un ultimo tipo fondamentale, o primitivo, in linguaggio C è il tipo char.

Attraverso di esso possiamo rappresentare un singolo carattere alfanumerico. Inoltre, il linguaggio C tratta i caratteri come numeri interi, permettendoci di eseguire operazioni aritmetiche su di essi.

In questa lezione studieremo il tipo char in dettaglio, analizzando le variabili char, le operazioni sui valori char e le sequenze di escape.

Tipo char

Il tipo char è un tipo di dato che rappresenta un singolo carattere alfanumerico.

Il valore di una variabile di tipo char può variare da un sistema ad un altro, in quanto sistemi differenti possono adoperare character sets, ossia insiemi di caratteri diversi.

Tuttavia, oggigiorno il character set più diffuso è l'ASCII (American Standard Code for Information Interchange), che rappresenta i caratteri alfanumerici in 7 bit. Quindi è in grado di rappresentare 128 caratteri.

Ad esempio, in ASCII, il carattere '0' che rappresenta il numero 0 ha il valore 48, il carattere 'A' ha il valore 65, il carattere 'a' ha il valore 97, ecc.

L'ASCII viene spesso esteso a 8 bit, sfruttando il bit aggiuntivo. In questo modo è possibile rappresentare fino a 256 caratteri con un singolo byte. Non esiste una singola estensione dell'ASCII, ma esistono diversi standard, come ad esempio il Latin-1 o l'ISO-8859-1 che estendono l'ASCII per supportare caratteri accentati e simboli.

In generale, comunque, il tipo char è un tipo di dato che occupa 1 byte di memoria, quindi 8 bit. Sulla stragrande maggioranza dei sistemi, il character set adoperato è l'ASCII o una sua estensione. Quindi, quando si programma in C, si può tranquillamente assumere di lavorare con la codifica ASCII.

Esistono altri tipi di codifiche in grado di rappresentare un numero maggiore di caratteri, come ad esempio l'Unicode. Ci occuperemo di come gestire i caratteri Unicode in C nelle future lezioni.

Per dichiarare una variabile di tipo char la sintassi è la seguente:

char carattere;

Le costanti char si scrivono tra apici singoli, ad esempio:

char carattere1 = 'A';
char carattere2 = '0';
char spazio = ' ';
Definizione

Tipo char

Il tipo char in linguaggio C è un tipo in grado di rappresentare un singolo carattere alfanumerico:

char carattere;

Lo standard del linguaggio C impone che un valore di tipo char occupi sempre un solo byte di memoria.

Le costanti char si scrivono tra apici singoli:

char carattere = 'A';

Operazioni sui valori di tipo char

In linguaggio C, lavorare con variabili e valori di tipo char è molto semplice.

Ciò è dovuto al semplice fatto che in C i valori char sono trattati come numeri interi.

Del resto, dal momento che ogni singolo carattere è codificato in binario, in base allo standard ASCII o ad un suo derivato, ne segue che il codice binario stesso corrispondente può essere visto come un numero intero.

Nello standard ASCII, come abbiamo accennato sopra, i valori dei caratteri sono numeri interi compresi tra 0 e 127.

Quando un carattere appare in un'espressione in C, il compilatore lo sostituisce con il valore ASCII corrispondente. Addirittura, possiamo assegnare un valore numerico a una variabile di tipo char, oppure assegnare un valore di tipo char a una variabile di tipo int.

Prendiamo l'esempio che segue:

int i = 'A';

In questo caso, la variabile i conterrà il valore 65, che è il valore ASCII del carattere 'A'. Dopo l'assegnamento, possiamo usare la variabile i in qualunque espressione numerica.

Prendiamo un altro esempio:

/* ch varrà 'A', ossia 65 */
char ch = 'A';

/* Incrementa il valore di ch di 1 */
/* ch varrà 'B', ossia 66 */
ch++;

/* Incrementa il valore di ch di 5 */
/* ch varrà 'G', ossia 71 */
ch += 5;

In questo caso, la variabile ch viene incrementata di 1 e poi di 5. Siccome i caratteri sono codificati in modo sequenziale, ch passerà da 'A' a 'B' e poi a 'G'.

I valori char, essendo numeri, possono essere adoperati in espressioni relazionali.

Ad esempio, il codice che segue controlla se un determinato carattere è una lettera minuscola:

char carattere;

/* ... */

if (carattere >= 'a' && carattere <= 'z') {
    printf("Il carattere è una lettera minuscola\n");
} else {
    printf("Il carattere non è una lettera minuscola\n");
}

Quando usati in espressioni di questo tipo, viene usato il valore numerico corrispondente. Questo è possibile grazie al fatto che i caratteri sono codificati in modo sequenziale. Quindi, ad esempio, 'a' ha un valore minore di 'b', che ha un valore minore di 'c', ecc.

Possiamo sfruttare questa caratteristica a nostro vantaggio.

Ad esempio, possiamo scrivere facilmente delle righe di codice che trasformano un carattere in maiuscolo in un carattere in minuscolo e viceversa.

char carattere;

/* ... */

if (carattere >= 'a' && carattere <= 'z') {
    carattere -= 32; /* Trasforma il carattere in maiuscolo */
} else if (carattere >= 'A' && carattere <= 'Z') {
    carattere += 32; /* Trasforma il carattere in minuscolo */
}

Oppure, possiamo implementare un ciclo for che itera tutte le lettere dell'alafabeto in minuscolo:

for (char c = 'a'; c <= 'z'; c++) {
    printf("%c ", c);
}

Ovviamente, trattare i char come numeri può provocare anche errori. Ad esempio, alcune espressioni potrebbero essere prive di alcun senso:

'a' * 'c' + 'd' / 'b';

Inoltre, c'è sempre il fatto che un altro sistema adoperi una codifica diversa da quella ASCII, per cui la portabilità del nostro codice si riduce.

Caratteri con segno e senza segno

Dal momento che il C tratta i char come numeri interi, non dovrebbe sorprendere che i char possano essere con segno o senza segno.

I char con segno possono rappresentare numeri compresi nell'intervallo da -128 a 127, mentre i char senza segno possono rappresentare numeri compresi nell'intervallo da 0 a 255.

Lo standard del C non specifica se un char sia con segno o senza segno. Alcuni compilatori trattano i char come interi con segno, altri come interi senza segno. Altri compilatori, addirittura, permettono di scegliere se trattare i char come interi con segno o senza segno.

Nella maggior parte dei casi questa distinzione non importa, ammesso che usiamo i char per rappresentare caratteri.

Se, invece, adoperiamo i char per rappresentare piccoli numeri, è meglio specificare se vogliamo che i char siano con segno o senza segno.

Per farlo, basta indicare esplicitamente se vogliamo un char con segno o senza segno con le parole chiave signed e unsigned.

signed char c1 = -1;
unsigned char c2 = 255;
Consiglio

Non assumere mai che i char siano con segno o senza segno

Mai fare assunzioni sul fatto che il tipo char abbiano segno o meno. Se è necessario, specificare esplicitamente se si vuole un char con segno o senza segno con le parole chiave signed e unsigned.

Dal momento che i char sono numeri interi, il C li raggruppa insieme a int, short, long e long long come tipi aritmetici interi.

Sequenze di escape

Una costante char, di solito, è rappresentata come un singolo carattere racchiuso tra apici singoli.

Tuttavia, esistono dei caratteri speciali che non possono essere rappresentati direttamente con un singolo carattere per due motivi:

  • si tratta di caratteri invisibili, ossia non stampabili;
  • oppure si tratta di caratteri che non possono essere inseriti attraverso la tastiera.

Un esempio è il carattere di nuova riga che corrisponde al tasto Invio della tastiera.

Per permettere, quindi, ai programmi di gestire tutti i possibili caratteri, il C utilizza una notazione speciale per rappresentare questi caratteri speciali, chiamata sequenza di escape.

Definizione

Sequenze di Escape

Le Sequenze di Escape sono una notazione che permette di rappresentare caratteri speciali che non possono essere inseriti direttamente in una stringa o in un carattere letterale.

Le sequenze di escape iniziano con un backslash (\) seguito da uno o più caratteri.

Le Sequenze di Escape si dividono in due tipi:

  1. Sequenze di Escape per Caratteri Speciali;
  2. Sequenze di Escape Numeriche.

Vediamole nel dettaglio.

Sequenze di Escape per Caratteri Speciali

Le sequenze di escape per caratteri speciali sono rappresentate da un backslash (\) seguito da un carattere.

La tabella che segue elenca le sequenze di escape riconosciute dal linguaggio C:

Sequenza di Escape Descrizione
\' Apice
\" Doppio Apice
\? Punto Interrogativo
\\ Backslash
\a Beep
\b Backspace
\f Avanzamento Pagina
\n Nuova Riga
\r Ritorno a Capo
\t Tabulazione
\v Tabulazione Verticale
Tabella 1: Sequenze di Escape per Caratteri Speciali in C

Le prime due sequenze della tabella rappresentano caratteri che non possono essere inseriti in una stringa o carattere letterale in quanto verrebbero interpretati come delimitatori.

Ad esempio, se volessimo rappresentare una stringa contenente un doppio apice, dovremmo usare la sequenza di escape \".

printf("Questa è una \"citazione\"");

Il carattere di escape \? rappresenta il punto interrogativo ma viene raramente adoperato.

Il carattere \\ permette di inserire un backslash all'interno di una stringa che, altrimenti, verrebbe interpretato come l'inizio di una sequenza di escape.

Le altre sequenze rimanenti, invece, rappresentano alcuni caratteri di controllo ASCII, come il carattere di nuova riga (\n), il carattere di ritorno a capo (\r), il carattere di tabulazione (\t), ecc.

Sequenze di Escape Numeriche

Le Sequenze di Escape per i caratteri speciali sono molto utili, ma non coprono tutti i possibili caratteri speciali.

Esse coprono i caratteri non stampabili più comuni. Inoltre, le sequenze di escape sono inutili per rappresentare caratteri che hanno valori superiori al massimo valore rappresentabile in ASCII, ossia 128.

Cosa fare, dunque, se vogliamo rappresentare un carattere che non è coperto dalle sequenze di escape?

La risposta è: utilizzare le Sequenze di Escape Numeriche.

Attraverso di esse è possibile rappresentare qualunque carattere in base al suo valore ASCII.

Prendiamo, ad esempio, il carattere speciale ESC che, in ASCII, ha valore 27. Possiamo rappresentare questo carattere attraverso una sequenza di escape numerica in due modi:

  1. Una sequenza di escape numerica Ottale:

    Basta convertire il numero corrispondente in ottale e anteporre il carattere \ oppure \0.

    Tornando all'esempio del carattere ESC, in ottale il suo valore è 33. Quindi, possiamo rappresentare il carattere ESC come:

    char esc = '\033';
    

    oppure:

    char esc = '\33';
    
  2. Una sequenza di escape numerica Esadecimale:

    Basta convertire il numero corrispondente in esadecimale e anteporre il carattere \x.

    Tornando all'esempio del carattere ESC, in esadecimale il suo valore è 1B. Quindi, possiamo rappresentare il carattere ESC come:

    char esc = '\x1B';
    

    Da notare che la x deve essere minuscola, mentre il numero può essere scritto in maiuscolo o minuscolo:

    char esc = '\x1b';
    
Definizione

Sequenze di Escape Numeriche

Le Sequenze di Escape Numeriche sono una notazione speciale che permette di rappresentare qualunque carattere in base al suo valore ASCII.

Esse possono essere:

  1. Ottali: la sintassi è \ o \0 seguito da un numero ottale;
  2. Esadecimali: la sintassi è \x seguito da un numero esadecimale.

In Sintesi

In questa lezione abbiamo introdotto il tipo char in linguaggio C.

I punti principali da ricordare sono:

  • Il tipo char è un tipo di dato che rappresenta un singolo carattere alfanumerico;
  • Il tipo char occupa 1 byte di memoria;
  • I valori char sono trattati come numeri interi;
  • I valori char possono essere con segno o senza segno;
  • Le sequenze di escape permettono di rappresentare caratteri speciali che non possono essere inseriti direttamente in una stringa o carattere letterale;
  • Le sequenze di escape si dividono in sequenze di escape per caratteri speciali e sequenze di escape numeriche.

Nella prossima lezione studieremo le funzioni di libreria standard per la manipolazione di caratteri.