Guida di C (base)

La funzione printf()

Il programma di esempio Hello World utilizzava la funzione printf() (print formatted) per scrivere sullo schermo una frase, ma questa istruzione può essere utilizzata in molti altri modi. Vediamo dunque come sfruttare, almeno in parte, le potenzialità di printf().

L'aggettivo formatted, rappresentato dalla lettera f di printf, si riferisce alla possibilità di stampare dati numerici specificando speciali attributi di formattazione, come la lunghezza totale, posizione della virgola, base decimale o esadecimale ecc...

Caratteri speciali

Cominciamo col dire che printf() deve sempre essere chiamata specificando come primo parametro un testo tra doppi apici, detto stringa di controllo (in informatica per stringa si intende una qualsiasi sequenza di caratteri). Tutti i caratteri di questa stringa saranno stampati sullo schermo così come sono. O meglio, tutti tranne questi tre:

  1. " - I doppi apici non possono essere inseriti come testo, perchè servono a terminare la stringa.
  2. % - Il carattere % serve ad introdurre una specifica di stampa (se ne vedrà il significato nel prossimo paragrafo)
  3. \ - il carattere di back-slash si usa per introdurre speciali elementi detti sequenze di escape.

Una sequenza di escape è una sorta di "parola magica" che serve a produrre testi particolari. Ad esempio: leggendo il primo punto qualcuno si sarà chiesto "E se volessi stampare proprio i doppi apici?"... Premesso che, lavorando in C, la risposta a simili domande non è mai "Non si può", la risposta è semplice: basta utilizzare la sequenza di escape \".
Per quanti stessero ripensando ad Hello world utilizzando il cervello... Sì, \n è la sequenza di escape corrispondente al carattere di "a capo".

Riporto qui sotto alcune tra le più usate sequenze di escape...

printf("\n");	/* Stampa un carattere di 'a capo' */
printf("\"");	/* Stampa i doppi apici */
printf("\t");	/* Stampa un carattere di tabulazione */
printf("\\");	/* Stampa un carattere di 'back-slash' */
printf("%%");	/* Stampa un carattere di percentuale
                 * (si noti che è l'unica sequenza ad essere
                 * introdotta da '%' anzichè da '\') */

...e qualche esempio su come possono essere utilizzate:

printf("A tutto il mondo voglio dire \"Ciao!\".");
/* Stampa: A tutto il mondo voglio dire "Ciao!". */

printf("uno\ndue\ntre");
/* Stampa: uno
 *         due
 *         tre
 */

printf("C:\\Windows\\System\\kernel32.dll");
/* Stampa: C:\Windows\System\kernel32.dll */

Stampare i numeri

Parliamo ora di quello che forse è il carattere più interessante: il "per cento". Mi permetto di introdurre da subito l'argomento con un esempio:

printf("1234");		/* Stampa: 1234 */
printf("%d",1234);	/* Stampa: 1234 */

Queste due righe di codice, apparentemente equivalenti (entrambe scrivono sullo schermo il numero "1234"), differiscono parecchio dal punto di vista concettuale. Per capire la differenza bisogna "mettersi nei panni" del compilatore, che le andrà ad analizzare.

Nel primo caso il numero 1234 è inserito in una stringa, quindi non sarà realmente visto come un numero vero e proprio, ma piuttosto come una semplice sequenza di 4 caratteri (uno-due-tre-quattro), ciascuno dei quali occuperà, slegato da tutti gli altri, un pezzetto di memoria.

Nel secondo caso invece, la stringa di controllo contiene una specifica di stampa: %d. Questo significa che a quel punto il compilatore andrà a cercare un ulteriore parametro "attaccato" alla stringa di controllo (in questo caso ,1234), e lo tratterà come un numero intero (la d indica proprio i numeri interi). Ovvero in memoria non ci saranno più quattro spazi distinti, come avveniva nel primo caso, ma un unico spazio, contenente il valore del numero (milleduecentorentaquattro, per intenderci).

Questo significa che il computer (com'è noto computers e numeri vanno parecchio d'accordo) potrà fare qualcosa di più della semplice trascrizione a schermo del numero: sarà infatti possibile operare con esso in vari modi, come è mostrato nell'esempio sottostante:

// Numeri INTERI
printf("2+2 fa 2+2");                   /* 2+2 fa 2+2 */
printf("2+2 fa %d",2+2);                /* 2+2 fa 4 */

printf("16 in base 10 (%%d): %d\n",16); /* 16 in base 10 (%d): 16 */
printf("16 in base 8 (%%o): %o\n",16);  /* 16 in base 8 (%o): 20 */
printf("16 in base 16 (%%x): %x\n",16); /* 16 in base 16 (%x): 10 */

// Numeri DECIMALI
printf("float (%%f): %f\n",3.14);        /* float (%f): 3.140000 */
printf("esponenziale (%%e): %e\n",3.14); /* esponenziale (%e): 3.140000e+00 */

Formattare i numeri

Alcune altre cose vanno dette sulla caratteristica che dà il nome a printf(), la formattazione.

Modifocando opportunamente la specifica di stampa è possibile ottenere alcuni effetti sulla rappresentazione dei numeri. Non ho intenzione di descrivere in dettaglio come ottenere tutti gli effetti possibili, ma riporto alcune delle specifiche più usate:

  • %Nd (%d): un numero N inserito tra il % e la d indica la larghezza minima che il numero dovrà occupare. Se il numero da stampare ha meno di N cifre, le cifre mancanti (a sinistra) saranno sostituite da spazi vuoti (linea 2 dell'esempio qui sotto). È possibile mutare gli spazi vuoti in zeri, anteponendo un 0 ad N (linea 3 dell'esempio).
  • %N.Pf (%f): come per i numeri interi (%d), anche per i numeri con la virgola (%f, ma anche %e) è possibile stabilire la larghezza minima (N). In più si può decidere il numero minimo di cifre dopo la virgola (la precisione, P, linee 5 e 6 dell'esempio).

Qualche esempio per capire meglio...

printf("%d. Questo numero occupa 5 spazi.\n",12345); /* 12345. Questo numero occupa 5 spazi. */
printf("%5d. Anche questo occupa 5 spazi.\n",12);    /*    12. Anche questo occupa 5 spazi. */
printf("%05d. 5 spazi riempiti con zeri.\n",12);     /* 00012. 5 spazi riempiti con zeri. */

printf("numero: %15.2f\n",3.14159); /* numero:            3.14 */
printf("numero: %15.4e\n",1936.27); /* numero:      1.9363e+03 */

Conclusioni

Per concludere, riassumo i concetti fondamentali contenuti in questo articolo:

  • La funzione printf() serve a stampare sullo schermo ogni frase (stringa) che le viene passata come argomento.
  • La frase che viene stampata è chiamata stringa di controllo, ed è un testo (sequenza di singoli caratteri) qualsiasi racchiuso tra doppi apici.
  • La stringa di controllo può contenere alcune speciali combinazioni di caratteri: le sequenze di escape e le specifiche di stampa
  • Le sequenze di escape servono a produrre alcuni caratteri speciali, come le virgolette (\"), i back-slash (\\), il carattere di a capo (\n)
  • o il per cento (%%).
  • Le specifiche di stampa si usano per inserire dati speciali (tipicamente numeri) nella frase da stampare. Quando il compilatore incontra una specifica di stampa nella stringa di controllo, la sostituirà con il parametro corrispondente, che dovrà essere specificato dal programmatore dopo la stringa di controllo.
  • Le specifiche di stampa possono essere utilizzate per formattare i numeri. È possibile specificare:
    • la lunghezza totale minima del numero. Se le cifre del numero sono inferiori della lunghezza da occupare verrà aggiunto un giusto numero di spazi (o di zeri, a seconda della specifica) a sinistra del numero.
    • il numero di cifre decimali (solo per i numeri decimali %f e %e) del numero.
  1. Introduzione
  2. Preparare l'ambiente
  3. Il primo programma
  4. La funzione printf()
  5. Le variabili
  6. Input da tastiera
  7. Esecuzione condizionale: if
  8. Cicli
  9. Esempi
  10. Bibliografia