Il linguaggio C offre potenti strumenti per la visualizzazione di output a schermo, il principale dei quali è la funzione printf. Questa funzione, che si trova nella libreria stdio.h e pertanto deve essere caricata con la direttiva #include all'inizio del programma C, consente di stampare testo, variabili e dati formattati. Il testo tra doppi apici in un'istruzione printf è una stringa da visualizzare in output a video. Ad esempio, printf(" Hello World! "); stamperà la frase " Hello World! " sullo schermo.
La Natura del Tipo char e la Codifica dei Caratteri
Al cuore della rappresentazione dei caratteri nel C vi è il tipo di dato char. Attraverso di esso, possiamo rappresentare un singolo carattere alfanumerico. Il tipo char occupa un singolo byte di memoria, ovvero 8 bit. Sulla stragrande maggioranza dei sistemi, il character set adoperato è l'ASCII (American Standard Code for Information Interchange) o una sua estensione. L'ASCII rappresenta i caratteri alfanumerici in 7 bit e viene spesso esteso a 8 bit, sfruttando il bit aggiuntivo per rappresentare fino a 256 caratteri con un singolo byte. Esistono anche altre codifiche, come l'Unicode, in grado di rappresentare un numero maggiore di caratteri.
Quando un carattere appare in un'espressione in C, il compilatore lo sostituisce con il valore ASCII corrispondente. Questo significa che i caratteri possono essere trattati come numeri. Ad esempio, se si assegna il carattere 'A' a una variabile intera, come in int i = 'A';, la variabile i conterrà il valore 65, che è il valore ASCII del carattere 'A'. I caratteri sono codificati in modo sequenziale, il che permette operazioni aritmetiche su di essi. Per esempio, incrementando una variabile ch di tipo char di 1 e poi di 5, si sposterà il carattere rappresentato di sei posizioni nel set di caratteri ASCII.

È importante notare che trattare i char come numeri può provocare anche errori. 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. Per questo motivo, è fondamentale non fare mai assunzioni sul fatto che il tipo char abbia segno o meno, al fine di garantire la portabilità del codice.
Sequenze di Escape per Caratteri Speciali
Le sequenze di escape sono caratteri speciali che permettono di formattare il testo e rappresentare caratteri non stampabili o che hanno un significato speciale nel contesto delle stringhe. Una sequenza di "escape" è un carattere speciale non visualizzabile, generalmente un carattere di controllo. È possibile utilizzare questo tipo di carattere, per esempio, per indicare il termine della linea e il ritorno a capo. Una sequenza di escape è rappresentata dal carattere "backslash" (\), seguito da un altro carattere o simbolo. Per esempio, la sequenza di escape che ci permette di andare a capo nella linea successiva è \n. In un'istruzione printf, printf(" Hello \n World! "); stamperà " Hello " su una riga e " World! " sulla riga successiva. Una sequenza di escape può essere inserita anche tra i doppi apici di un'istruzione printf o printfn.
I caratteri di escape - Corso Programmazione C
Le sequenze di escape coprono i caratteri non stampabili più comuni. Alcuni esempi comuni includono:
\n: Nuova riga (newline)\t: Tabulazione orizzontale\a: Allarme (beep)\b: Backspace\f: Form feed (nuova pagina)\r: Carriage return (ritorno a capo)\v: Tabulazione verticale\\: Backslash\': Apostrofo\": Virgolette doppie\?: Punto interrogativo (il carattere di escape\?è raramente necessario, in quanto il punto interrogativo non ha un significato speciale al di fuori delle trigraphs, che sono state deprecate in C11)
Rappresentazione di Caratteri Speciali con Codici Ottali ed Esadecimali
Per i caratteri non presenti nelle sequenze di escape predefinite, è possibile utilizzare la loro rappresentazione numerica, sia in formato ottale che esadecimale. Questo è particolarmente utile per i caratteri di controllo ASCII.
- Sequenze di escape ottali: Una sequenza di escape ottale è rappresentata da un backslash (
\) seguito da una, due o tre cifre ottali (da 0 a 7). Queste cifre rappresentano il valore ASCII del carattere. Ad esempio, il carattere speciale ESC, che in ASCII ha valore 27, in ottale il suo valore è 33. Quindi,\33rappresenta il carattere ESC. - Sequenze di escape esadecimali: Similmente, una sequenza di escape esadecimale è rappresentata da un backslash (
\) seguito da unaxe quindi da una o due cifre esadecimali (0-9, A-F o a-f). Tornando all'esempio del carattere ESC, in esadecimale il suo valore è 1B. Pertanto,\x1Brappresenta il carattere ESC.
L'uso di queste sequenze permette una flessibilità notevole nella gestione dei caratteri, specialmente quelli non stampabili o con funzioni di controllo specifiche.
Specificatori di Formato per printf
Oltre alle sequenze di escape, la funzione printf utilizza degli specificatori di formato per controllare come i dati delle variabili vengono visualizzati in output. Questi specificatori iniziano con il simbolo percentuale (%) seguito da un carattere che indica il tipo di dato e, opzionalmente, da modificatori che controllano ulteriori aspetti della formattazione. È importante utilizzare lo specificatore di formato giusto per il tipo di variabile che si sta tentando di stampare.

Ecco alcuni degli specificatori di formato più comuni:
%do%i: Intero con segno.%u: Intero senza segno.%f:floatodoubleper il reale con segno (notazione decimale).%lf:doubleper il reale con segno (notazione decimale, comune perscanf, ma%ffunziona perdoubleinprintf).%eo%E:floatodoubleper il reale con segno in notazione scientifica (esponenziale).%go%G:floatodoubleper il reale con segno, usando%fo%ea seconda di quale sia più corto.%c: Singolo carattere.%s: Stringa di caratteri.%p: Puntatore (indirizzo di memoria).%%: Stampa un simbolo di percentuale letterale.
Gli specificatori di formato possono includere anche modificatori per controllare aspetti come la larghezza del campo, la precisione, l'allineamento e il riempimento.
Modificatori di Larghezza del Campo
La larghezza del campo indica il numero minimo di caratteri che devono essere scritti per il dato corrispondente. Se il dato è più corto della larghezza specificata, verrà riempito con spazi (o altri caratteri di riempimento) sulla sinistra. Se il dato è più lungo, la larghezza del campo viene ignorata e il dato viene scritto per intero, occupando lo spazio strettamente necessario. Ad esempio, %10d stamperà un intero occupando almeno 10 caratteri.
Modificatori di Precisione
La precisione, indicata da un punto . seguito da un numero, controlla il numero di cifre decimali per i numeri in virgola mobile o il numero massimo di caratteri per le stringhe.
- Per i numeri in virgola mobile: La precisione specifica il numero di cifre che devono essere scritte dopo il punto decimale. Se il numero ha meno cifre significative di quelle specificate, vengono aggiunti zeri a destra. Se ha più cifre, il numero viene arrotondato. Ad esempio,
%.2fstamperà un float con esattamente due cifre decimali. Gli zeri non significativi a destra non vengono scritti se non specificato altrimenti. - Per gli interi: La precisione specifica il numero minimo di cifre che devono essere scritte. Se il numero ha meno cifre, vengono aggiunti zeri iniziali.
- Per le stringhe: La precisione specifica il numero massimo di caratteri che devono essere scritti. I caratteri in eccesso non vengono scritti, causando un troncamento.
Flag e Altri Modificatori
Diversi flag possono essere usati prima della larghezza del campo per modificare ulteriormente il comportamento di stampa:
-: Allinea il dato a sinistra all'interno del campo. Senza questo flag, l'allineamento predefinito è a destra.+: Forza la visualizzazione del segno (+o-) per i numeri con segno.: Se il numero non ha segno, viene anteposto uno spazio.#: Modificatore di forma alternativa. Per i tipi ottali e esadecimali, antepone0o0x/0X. Per i tipi float, assicura che il punto decimale sia sempre presente.0: Riempie con zeri iniziali invece di spazi quando la larghezza del campo è maggiore della lunghezza del dato. Questo flag è ignorato se è presente il flag-.
Combinando questi elementi, è possibile ottenere un controllo estremamente fine sull'output del programma, rendendo i dati presentati chiari e leggibili per diverse finalità.