Variabili Stringa in Linguaggio C

Le variabili stringa, rappresentate da array di caratteri, costituiscono uno degli elementi cardine della programmazione in C.

Esse risultano fondamentali per la gestione di dati alfanumerici e testi. La conoscenza dei metodi per dichiarare e inizializzare correttamente le variabili stringa risulta essenziale per la realizzazione di programmi C efficaci ed efficienti. In questa lezione vedremo come fare.

Variabili Stringa

In molti linguaggi di programmazione, ad esempio in Python, C#, Java, JavaScript, PHP, ecc., esiste un tipo di dato chiamato stringa. Questo tipo di dato è utilizzato per rappresentare una sequenza di caratteri.

Il linguaggio C utilizza un approccio differente per rappresentare le stringhe. In C, una stringa è un array di caratteri terminato da un carattere speciale chiamato terminatore di stringa. Tale carattere è rappresentato dal valore 0 e se usiamo l'escape sequence possiamo indicarlo con '\0'.

Questo approccio ha i suoi vantaggi e i suoi svantaggi. Il vantaggio principale è che le stringhe possono essere manipolate come array di caratteri.

Gli svantaggi principali sono:

  • Quando si ha a che fare con le stringhe bisogna sempre tener conto del terminatore di stringa;
  • Non vi è un modo semplice di calcolare la lunghezza di una stringa se non quello di scorrere tutti i caratteri fino a trovare il terminatore.

Dichiarazione di una Variabile Stringa

Per dichiarare una variabile stringa in C, dobbiamo indicare il tipo di dato array di caratteri e la dimensione dell'array. La dimensione dell'array deve essere sufficientemente grande per contenere la stringa più lunga che potremmo utilizzare.

Vediamo con un esempio. Supponiamo di voler dichiarare una stringa che possa contenere al massimo 100 caratteri. La dichiarazione sarà la seguente:

#define STRING_MAX_LENGTH 100

char mia_stringa[STRING_MAX_LENGTH + 1];

Nell'esempio sopra, abbiamo definito una costante STRING_MAX_LENGTH che indica la lunghezza massima della stringa. Abbiamo poi dichiarato una variabile mia_stringa di tipo char (array di caratteri) di dimensione STRING_MAX_LENGTH + 1. La dimensione dell'array è STRING_MAX_LENGTH + 1 perché dobbiamo tenere conto del terminatore.

Avendo definito l'array mia_stringa in questo modo non vuol dire che conterrà sempre stringhe di lunghezza massima STRING_MAX_LENGTH. In realtà, la variabile mia_stringa potrà contenere stringhe di lunghezza qualsiasi, purché non superi tale dimensione. La lunghezza di una stringa dipende sempre e soltanto dalla posizione del terminatore.

Nota

Array di caratteri e Terminatore di Stringa

Quando si dichiara un array di caratteri per essere utilizzato come una stringa, l'errore più comune che si commette è quello di non tenere conto del terminatore di stringa.

Bisogna sempre far in modo che la lunghezza dell'array sia pari alla massima lunghezza della stringa più uno. Questo perché, se l'array contiene una stringa di lunghezza massima, il terminatore di stringa sarà posizionato nella cella successiva all'ultima cella dell'array.

Quando non si lascia lo spazio necessario per il terminatore di stringa, il comportamento del programma potrebbe essere impredicibile.

Definizione

Variabili Stringa

In linguaggio C una variabile stringa è un array di caratteri.

Un array di caratteri di lunghezza n può contenere una stringa di lunghezza massima n - 1 in quanto l'ultimo carattere deve essere sempre il terminatore di stringa: '\0'.

La lunghezza di una stringa dipende sempre e soltanto dalla posizione del terminatore di stringa.

char nome_variabile[lunghezza_massima + 1];

Inizializzazione di una Variabile Stringa

Una variabile stringa può essere inizializzata nel momento stesso in cui viene dichiarata. Vediamo un esempio:

char mia_stringa[12] = "Ciao mondo!";

Nell'esempio sopra, abbiamo dichiarato e inizializzato una variabile stringa di nome mia_stringa di lunghezza 12. Il compilatore provvederà a riempire l'array con i caratteri della stringa "Ciao mondo!" e a posizionare il terminatore di stringa alla fine della stringa.

Per cui, dopo questa riga di codice l'array mia_stringa conterrà i seguenti valori:

[ 'C', 'i', 'a', 'o', ' ', 'm', 'o', 'n', 'd', 'o', '!', '\0' ]

A prima vista la parte a destra dell'uguale potrebbe sembrare una stringa letterale. In realtà si tratta di un'abbreviazione di un inizializzatore di array. Dal punto di vista del compilatore C, la riga di inizializzazione di sopra è del tutto equivalente a:

char mia_stringa[12] = { 'C', 'i', 'a', 'o', ' ', 'm', 'o', 'n', 'd', 'o', '!', '\0' };

Nell'esempio di sopra abbiamo dichiarato l'array mia_stringa di esattamente 12 elementi. In effetti la stringa "Ciao mondo!" è lunga 12 caratteri, compreso il terminatore di stringa. Quello che ci domandiamo adesso è cosa accade se la stringa letterale è più corta o più lunga della dimensione dell'array?

Esaminiamo il primo caso: supponiamo che la stringa letterale sia più corta. Ad esempio:

char mia_stringa[12] = "Ciao";

In tal caso il compilatore riempirà l'array con i caratteri della stringa letterale e posizionerà il terminatore di stringa alla fine della stringa. I caratteri rimanenti saranno inizializzati a zero, ossia il terminatore. Per cui il risultato sarà il seguente:

[ 'C', 'i', 'a', 'o', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' ]

Questo comportamento è consistente con il comportamento che il compilatore usa per gli array normali. Ossia, quando la lista di inizializzazione è più corta della dimensione dell'array, il compilatore C riempie gli elementi rimanenti con il valore di zero, che nel caso delle stringhe è il terminatore.

Nel caso in cui, invece, la stringa letterale sia più lunga della dimensione dell'array, il compilatore C non potrà riempire l'array con tutti i caratteri della stringa letterale. In questo caso il compilatore C emetterà un errore di compilazione.

Tuttavia, se la stringa letterale ha esattamente la stessa lunghezza dell'array meno il terminatore, il compilatore C non emetterà alcun errore. Vediamo un esempio:

char mia_stringa[11] = "Ciao mondo!";

In questo caso il compilatore C riempirà l'array con i caratteri della stringa letterale ma non potrà posizionare il terminatore di stringa alla fine della stringa. Per cui il risultato sarà il seguente:

[ 'C', 'i', 'a', 'o', ' ', 'm', 'o', 'n', 'd', 'o', '!' ]

Quindi sebbene il compilatore C non emetta alcun errore, l'array non potrà essere usato come una stringa.

Nota

Inizializzazione di una Variabile Stringa e Terminatore di Stringa

Quando si inizializza un array di caratteri per essere utilizzato come una stringa, se la lunghezza della stringa letterale è esattamente uguale alla dimensione dell'array meno uno, il compilatore C non emetterà alcun errore. Tuttavia, l'array non potrà essere usato come una stringa.

Come nel caso degli array normali, anche nel caso delle variabili stringa è possibile omettere la lunghezza iniziale dell'array. In tal caso il compilatore C calcolerà la lunghezza dell'array in base alla lunghezza della stringa letterale più uno per il terminatore di stringa. Vediamo un esempio:

char mia_stringa[] = "Ciao mondo!";

In tal modo il compilatore C farà in modo che la lunghezza di mia_stringa sia esattamente uguale a 12.

Usare questa tecnica riduce la possibilità di commettere errori in quanto calcolare a mano la lunghezza di una stringa letterale per l'inizializzazione di un array di caratteri è un'operazione error-prone.

Ricapitolando:

Definizione

Inizializzazione di una Variabile Stringa

Una variabile stringa può essere inizializzata nel momento stesso in cui viene dichiarata. Per inizializzare una variabile stringa si usa la seguente sintassi:

char nome_variabile_stringa[lunghezza_array] = "stringa_letterale";

Se lunghezza_array è omessa, il compilatore C calcolerà la lunghezza dell'array in base alla lunghezza della stringa letterale più uno per il terminatore di stringa.

Nel caso in cui la stringa letterale sia più lunga della dimensione dell'array, il compilatore C emetterà un errore di compilazione.

Viceversa, se la stringa letterale ha una lunghezza inferiore alla dimensione dell'array, il compilatore C riempirà l'array con i caratteri della stringa letterale e con il terminatore mentre i caratteri rimanenti saranno inizializzati a zero.

Array di caratteri e puntatori a caratteri

Abbiamo visto in una lezione precedente che esiste una stretta relazione tra array e puntatori nel linguaggio C.

Nel caso delle stringhe, ossia degli array di caratteri, possiamo avere delle dichiarazioni di questo tipo:

char mia_stringa[] = "Ciao mondo!";

char *puntatore_stringa = "Ciao mondo!";

Le due dichiarazioni sono molto simili. Nel primo caso abbiamo dichiarato un array di caratteri e l'abbiamo inizializzato con una stringa letterale. Nel secondo caso abbiamo dichiarato un puntatore a carattere e l'abbiamo inizializzato facendolo puntare alla stringa letterale.

Da questo punto di vista le due dichiarazioni possono essere usate in maniera intercambiabile. Per esempio, possiamo usare mia_stringa e puntatore_stringa in modo intercambiabile nelle seguenti espressioni:

printf("%s\n", mia_stringa);
printf("%s\n", puntatore_stringa);

La funzione printf, come vedremo, accetta lo specificatore di conversione %s per stampare una stringa. In questo caso, mia_stringa e puntatore_stringa sono entrambi puntatori a carattere. Quindi la funzione printf li tratterà come puntatori a carattere e li userà per stampare la stringa.

Tuttavia, bisogna prestare attenzione perché tra le due dichiarazioni esistono delle importanti differenze. Vediamo quali sono:

  • Nel caso dell'array, i caratteri della stringa letterale vengono copiati in fase di inizializzazione all'interno dell'array stesso. Per tal motivo possiamo modificare i caratteri contenuti nell'array in un secondo momento. Vediamo un esempio:

    char mia_stringa[] = "Ciao mondo!";
    mia_stringa[0] = 'c';
    printf("%s\n", mia_stringa);
    

    In questo caso la funzione printf stampa la stringa ciao mondo! perché il carattere in posizione 0 è stato modificato.

    Nel secondo caso, invece, il puntatore punterà sempre alla stringa letterale che, per definizione, è immutabile. Quindi non possiamo modificarne i caratteri. Vediamo un esempio:

    char *puntatore_stringa = "Ciao mondo!";
    /* ERRORE */
    puntatore_stringa[0] = 'c';
    

    In questo caso il compilatore C emetterà un errore di compilazione perché non è possibile modificare i caratteri di una stringa letterale.

  • Nel caso dell'array, mia_stringa è il nome di un array e come tale non potrà puntare ad un altro array nel corso dell'esecuzione del programma. Viceversa, puntatore_stringa è un puntatore e come tale può puntare ad un altro array nel corso dell'esecuzione del programma.

Quando si vuole dichiarare una stringa che potrà essere modificata nel corso dell'esecuzione del programma è sempre responsabilità del programmatore creare un array in grado di contenerla. Dichiarare un puntatore a char non è sufficiente. In futuro vedremo come allocare dinamicamente un array di caratteri.

Nota

Puntatori a carattere non inizializzati

Usare un puntatore a carattere non inizializzato è un errore molto grave e può portare a comportamenti imprevedibili. Ad esempio:

char *puntatore_stringa;
puntatore_stringa[0] = 'c';
puntatore_stringa[1] = 'i';
puntatore_stringa[2] = 'a';
puntatore_stringa[3] = 'o';
puntatore_stringa[4] = '\0';

Dal momento che puntatore_stringa non è stato inizializzato, il suo valore è indefinito, ossia potrebbe puntare ad un qualsiasi indirizzo di memoria. In questo caso, il programma scrive i caratteri c, i, a, o e il terminatore di stringa in un indirizzo sconosciuto e il programma potrebbe terminare in modo inaspettato.

In Sintesi

In questa lezione abbiamo visto come dichiarare e inizializzare una variabile stringa. In particolare abbiamo studiato che:

  • Una variabile stringa è un array di caratteri terminato dal carattere '\0'.
  • Una variabile stringa può essere inizializzata nel momento stesso in cui viene dichiarata.
  • Una variabile stringa può essere inizializzata con una stringa letterale.

Nella prossima lezione vedremo come leggere e scrivere stringhe in linguaggio C.