Accedere ai caratteri di una stringa in Linguaggio C

Una stringa è un array di caratteri. Per questo motivo, è possibile accedere ai singoli caratteri della stringa utilizzando l'operatore di indicizzazione [] o l'aritmetica dei puntatori.

In questa lezione vedremo degli esempi pratici che ci mostreranno come accedere ai singoli caratteri di una stringa in Linguaggio C.

Stringhe come array

Dal momento che una stringa è, a tutti gli effetti, un array, risulta possibile accedere ai singoli caratteri della stringa allo stesso modo in cui si accede agli elementi di un array, ossia utilizzando l'operatore di indicizzazione [].

Volendo processare tutti i caratteri di una stringa è possibile utilizzare un ciclo for che incrementi una variabile indice i e selezioni i caratteri della stringa attraverso l'espressione s[i].

Prendiamo un esempio; supponiamo di voler contare tutte le vocali presenti in un stringa. Possiamo realizzare il programma in questo modo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <stdio.h>

/*
 * Definiamo la lunghezza massima della stringa in input.
 */
#define MAX_LEN 128

/*
 * Questa funzione restituisce zero se il carattere c non è una vocale, 
 * altrimenti restituisce un valore diverso da zero.
 * La funzione controlla anche se il carattere è maiuscolo o minuscolo.
 */
int vocale(char c) {
    switch (c) {
        case 'a':
        case 'e':
        case 'i':
        case 'o':
        case 'u':
        case 'A':
        case 'E':
        case 'I':
        case 'O':
        case 'U':
            return 1;
        default:
            return 0;
    }
}

/*
 * Questa funzione prende in ingresso una stringa e restituisce il numero
 * di vocali presenti nella stringa.
 */
int conta_vocali(const char s[]) {
    int i, n_vocali;

    n_vocali = 0;
    for (i = 0; s[i] != '\0'; i++) {
        if (vocale(s[i])) {
            n_vocali++;
        }
    }

    return n_vocali;
}

int main() {
    char s[MAXLEN];

    printf("Inserisci una stringa: ");
    fgets(s, MAX_LEN, stdin);

    printf("La stringa contiene %d vocali.\n", conta_vocali(s));

    return 0;
}

Se proviamo a compilare e eseguire il programma otteniamo un risultato simile al seguente:

Inserisci una stringa: Hello, world!
La stringa contiene 3 vocali.

Il fulcro del programma è la funzione conta_vocali(). Questa funzione prende in ingresso una stringa e restituisce il numero di vocali presenti nella stringa. Bisogna notare alcuni dettagli:

  • Per prima cosa la funzione accetta in ingresso una stringa a cui è stato applicato il modificatore const. Questo significa che la funzione non può modificare la stringa in ingresso. Se la funzione prova a modificarne il contenuto, il compilatore segnalerà un errore.
  • La funzione conta_vocali() utilizza un ciclo for per scorrere tutti i caratteri della stringa. La variabile i viene utilizzata come indice per accedere ai caratteri della stringa.

Questo non è l'unico modo in cui è possibile scrivere la funzione conta_vocali. Possiamo anche utilizzare l'aritmetica dei puntatori per scorrere la stringa. Vediamo come fare:

int conta_vocali(const char s[]) {
    int n_vocali;
    const char *p;

    n_vocali = 0;
    for (p = s; *p != '\0'; p++) {
        if (vocale(*p)) {
            n_vocali++;
        }
    }

    return n_vocali;
}

In questo secondo caso, piuttosto che utilizzare un indice i per accedere ai caratteri della stringa, utilizziamo un puntatore p che punta al primo carattere della stringa. Il ciclo for termina quando il puntatore p punta al carattere terminatore \0. In questo modo, il ciclo for scorre tutti i caratteri della stringa.

Una cosa importante da notare sta nel fatto che il puntatore p è stato dichiarato come puntatore a const char. Questo significa che, sebbene non possa essere usato per modificare la stringa, si può comunque modificare l'indirizzo a cui punta. In questo modo, il puntatore p può essere incrementato per spostarsi di un carattere alla volta lungo la stringa.

Ricapitolando:

Definizione

Una stringa può essere trattata come un array di caratteri.

Una stringa è a tutti gli effetti un array di caratteri. Per questo motivo, è possibile accedere ai singoli caratteri della stringa utilizzando alternativamente:

  • Le operazioni di accesso agli elementi di un array, attraverso l'operatore di indicizzazione [];
  • L'aritmetica dei puntatori, attraverso l'operatore di indirizzamento *.

Esempi

Stampa di una stringa al contrario

Supponiamo di voler scrivere un programma che legge in ingresso dalla tastiera una stringa e la stampa al contrario. Per esempio, se l'utente inserisce la stringa Hello, world!, il programma deve stampare !dlrow ,olleH.

Il fulcro di questo programma sarà la funzione stampa_al_contrario(). Questa funzione prende in ingresso una stringa const e utilizza l'aritmetica dei puntatori in congiunzione ad un ciclo for.

Una possibile implementazione della funzione stampa_al_contrario() è la seguente:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void stampa_al_contrario(const char s[]) {
    const char *p;

    /*
     * Per prima cosa scorriamo la stringa per trovare
     * il carattere terminatore '\0'.
    */
    for (p = s; *p != '\0'; p++) {
        /* Non facciamo nulla */
    }

    /*
     * Una volta trovato il carattere terminatore, scorriamo
     * la stringa al contrario, stampando ogni carattere.
     * Questo finché non raggiungiamo il primo carattere.
     */ 
    for (p--; p >= s; p--) {
        puts(p);
    }

    /*
     * Infine stampiamo il carattere di nuova linea.
     */
    puts('\n');
}

La funzione stampa_al_contrario() è abbastanza semplice. Per prima cosa scorre la stringa per trovare il carattere terminatore \0. Al termine del primo ciclo for, il puntatore p punta al carattere terminatore \0. Successivamente, il secondo ciclo for scorre la stringa al contrario, stampando ogni carattere fino a raggiungere il primo carattere della stringa.

Il programma completo è il seguente:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <stdio.h>

#define MAX_LEN 128

/*
 * Questa funzione prende in ingresso una stringa e la stampa al contrario.
 */
void stampa_al_contrario(const char s[]) {
    const char *p;

    /*
     * Per prima cosa scorriamo la stringa per trovare
     * il carattere terminatore '\0'.
    */
    for (p = s; *p != '\0'; p++) {
        /* Non facciamo nulla */
    }

    /*
     * Una volta trovato il carattere terminatore, scorriamo
     * la stringa al contrario, stampando ogni carattere.
     * Questo finché non raggiungiamo il primo carattere.
     */ 
    for (p--; p >= s; p--) {
        puts(p);
    }

    /*
     * Infine stampiamo il carattere di nuova linea.
     */
    puts('\n');
}

int main() {
    char s[MAX_LEN];

    printf("Inserisci una stringa: ");
    fgets(s, MAX_LEN, stdin);

    stampa_al_contrario(s);

    return 0;
}

Se proviamo a compilare e eseguire il programma otteniamo un risultato simile al seguente:

Inserisci una stringa: Hello, world!
!dlrow ,olleH

Conteggio dei simboli di punteggiatura

Supponiamo di voler scrivere un programma che legge in ingresso una stringa e conta il numero di simboli di punteggiatura presenti, tra cui virgole, punti, punti esclamativi, punti interrogativi, ecc.

Possiamo realizzare una funzione conta_punteggiatura() usando l'aritmetica dei puntatori. Vediamo come fare:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
int conta_punteggiatura(const char s[]) {
    int n_punteggiatura;
    const char *p;

    n_punteggiatura = 0;
    for (p = s; *p != '\0'; p++) {
        if (punteggiatura(*p)) {
            n_punteggiatura++;
        }
    }

    return n_punteggiatura;
}

Questa funzione, a sua volta, utilizza una funzione punteggiatura() che restituisce un valore diverso da zero se il carattere passato come parametro è un simbolo di punteggiatura. Vediamo come implementare la funzione punteggiatura():

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
int punteggiatura(char c) {
    switch (c) {
        case ',':
        case ':':
        case ';':
        case '.':
        case '!':
        case '?':
            return 1;
        default:
            return 0;
    }
}

Il programma completo è il seguente:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <stdio.h>

#define MAX_LEN 128

/*
 * Questa funzione prende in ingresso un carattere e restituisce
 * un valore diverso da zero se il carattere è un simbolo di punteggiatura.
 */
int punteggiatura(char c) {
    switch (c) {
        case ',':
        case ':':
        case ';':
        case '.':
        case '!':
        case '?':
            return 1;
        default:
            return 0;
    }
}

/*
 * Questa funzione prende in ingresso una stringa e restituisce
 * il numero di simboli di punteggiatura presenti.
 */
int conta_punteggiatura(const char s[]) {
    int n_punteggiatura;
    const char *p;

    n_punteggiatura = 0;
    for (p = s; *p != '\0'; p++) {
        if (punteggiatura(*p)) {
            n_punteggiatura++;
        }
    }

    return n_punteggiatura;
}

int main() {
    char s[MAX_LEN];
    int n_punteggiatura;

    printf("Inserisci una stringa: ");
    fgets(s, MAX_LEN, stdin);

    n_punteggiatura = conta_punteggiatura(s);
    printf("La stringa contiene %d simboli di punteggiatura.\n", n_punteggiatura);

    return 0;
}

Se proviamo a compilare e eseguire il programma otteniamo un risultato simile al seguente:

Inserisci una stringa: Hello, world!
La stringa contiene 2 simboli di punteggiatura.

In sintesi

In questa lezione abbiamo visto che, dal momento che una stringa è un array di caratteri, possiamo alternativamente usare l'indicizzazione di un array o l'aritmetica dei puntatori per accedere ai caratteri di una stringa.

A partire dalla prossima lezione vedremo le funzioni che la libreria standard del linguaggio C mette a disposizione per manipolare le stringhe. Partiremo dal come copiare una stringa in un'altra.