Sommario
< Home
Stampa

Manipolazione di stringhe

ABC delle stringhe

Le stringhe sono sequenze di caratteri, come ad esempio una parola, una frase, un testo. Le stringhe in C/C++ non sono un “tipo base” ma sono un tipo di array speciale, che gode di tutte le caratteristiche di un array, più altre specifiche che vediamo qui sotto.

Vediamo un esempio di dichiarazione edi un array di caratteri:

char hello[] = { ‘h’, ‘e’, ‘l’, ‘l’, ‘o’ }

Questa istruzione crea un array che contiene 5 caratteri. Per farlo diventare un tipo stringa è necessario aggiungere un ulteriore carattere di terminazione “\0” (il cui valore ASCII è 0). Questo perché rende possibile al compilatore di capire quando termina la stringa.

char hello[] = { ‘h’, ‘e’, ‘l’, ‘l’, ‘o’, '\0' }

Quindi una stringa è un array di caratteri che contiene un carattere terminatore. E’ possibile definire una stringa anche in modo semplice:

char hello[] = “Hello”;

ed automaticamente il compilatore aggiunge il carattere di terminazione ed inferisce la dimensione dell’array (che sarà pari alla lunghezza della stringa più uno). Nota bene: le espressioni definite da virgolette (ad esempio “Hello”) vengono chiamate “literal”.

Come detto le stringhe sono a tutti gli effetti array di char, o per essere più precisi gli array di char sono dei “contenitori” di stringhe, perché possono essere anche solo parzialmente riempiti dal contenuto di una stringa. Valgono quindi tutte le caratteristiche degli array:

cout << hello[2];  // stampa il 3° carattere della stringa, cioè ‘l’

Vediamo altri tipi di inizializzazione e assegnazione.

char hello[50]; // crea una stringa di dimensione 50
char myString[30] = {'c'}; // inizializza una stringa con il carattere c

Bisogna tuttavia fare attenzione: gli array di char e le stringhe non sono esattamente la stessa cosa. Infatti possiamo anche creare un array di char di una certa dimensione e poi assegnare una stringa che occupa solo un sottoinsieme dell’array. Ad esempio:

char hello[10] = ‘hello’; // crea una stringa di dimensione definita e le assegna un valore

A differenza della assegnazione senza dimensione (in quel caso è il compilatore C++ che autoinferisce la dimensione) è il programmatore che assegna una dimensione fissa e quindi la dimensione dell’array sarà diversa da quella della stringa. Quando si inizializza una stringa con un valore più corta della dimensione definita i restanti caratteri vengono messi a 0. Quindi sarà

{ ‘h’, ‘e’, ‘l’, ‘l’, ‘o’, ‘\0’, ‘\0’, ‘\0’, ‘\0’, ‘\0’ }

Quando si inizializza una stringa più lunga dell’array… beh cerchiamo di non fare questo errore, perché non esistono come per gli array meccanismi di controllo e quindi andiamo ad occupare memoria dello heap magari occupata da altre variabili.

Le stringhe possono essere usate per input ed output come se fossero semplici variabili, quindi senza fare cicli for:

cout << hello << endl;
cin >> hello;

Va osservato però che l’inserimento tramite cin ha l’inconveniente di terminare la stringa appena l’utente inserisce uno spazio (o qualsiasi carattere non alfanumerico). Se si vuole inserire una intera linea compresa di spazi si usa cin.getline:

int size = 100;
char hello[size];
cin.getline(hello, size);

dove size è la dimensione massima di caratteri inseribili (inferiore o uguale alla dimensione della stringa).

Non è possibile assegnare una stringa dopo averla inizializzata:

char hello[10];
hello = “ciao”; // qui il compilatore da errore

Per assegnare valori ad una stringa (dopo la sua inizializzazione) si usa la libreria string.h, descritta sotto.

Libreria string.h

Le stringhe possono essere manipolate mediante speciali funzioni presenti nella libreria <string.h>

FunzioneUtilizzo
strcpy(s1, s2);Copia s2 in s1: s2 può essere un literal.
strcat(s1, s2);Concatena s2 alla fine di s1: s2 può essere un literal
strlen(s1);Lunghezza di s1. La lunghezza si intende al carattere di terminazione.
strcmp(s1, s2);Compara s1 con s2 (0 se identiche, > 0 se se s1 è alfabeticamente successiva, < 0 altrimenti). Possono una o entrambe dei literal.
atoi(s1)Converte la stringa in intero. Può essere un literal.
atof(s1)Converte la stringa in double. Può essere un literal.
sprintf(s1, “%d”, n)Converte il numero n in stringa copiando il valore su s1. Nota s1 deve avere un sufficiente numero di caratteri per contenere il numero.

Vediamo un po’ di esempi. Partiamo da strcpy:

char string1[] = "Ciao";
char string2[5];
strcpy(string2, string1); 
cout << string2; // string2 conterrà "ciao"

E’ anche possibile usare strcpy per assegnare uno string literal:

char string[20];
strcpy(string, "Hello world");

E’ importante osservare che la dimensione della stringa di destinazione può essere diversa (maggiore o uguale) a quella di origine. Ancora una volta bisogna stare attenti a non copiare stringhe più grandi in array di char più piccoli.

Strcpy è il sistema da usare per assegnare una stringa.

Vediamo strcat e strlen:

string s[20] = "Ciao";
cout << strlen(s); // stampa 4 notare che la lunghezza non coincide con quella dell'array
strcat(s, " Mario");
cout << s; // "Ciao Mario"
cout << strlen(s); // stampa 10

Vediamo strcmp:

char s[] = "abate";
cout << strcmp(s, "abaco"); // < 0
cout << strcmp(s, "abate"); // == 0
cout << strcmp(s, "amaca"); // > 0

Atoi e Atof:

char n1[] = "36";
char n2[] = "21.2";
cout << atoi(n1); // 36
cout << atoi(n2); // 21
cout << atof(n1); // 36.0
cout << atof(n2); // 21.2

Vediamo infine sprintf:

char s1[20];
int x = 3;
float pi = 3.14159;
sprintf(s1, “%d”, x); // "3"
sprintf(s1, “%f”, pi); // "3.14159";
sprintf(s1, “%.2f”, pi); // "3.14";

Come si vede il codice di formattazione passato determina la forma della stringa, dove %d indica un intero, mentre %f un float, di cui si può anche determinare la precisione indicando le cifre dopo la virgola.

STRTOK

strtok è una funzione che estrae elementi di tipo stringa (detti “token”) da una stringa, a partire da un carattere separatore. 

Esempio 1: dalla stringa “salve mondo” se eseguo strtok(stringa, ” “) otterrò il token “salve”, in quanto la funzione estrae tutti caratteri da quella stringa fino al separatore (escluso).

Esempio 2: dalla stringa “Mario,Sandra,Franco,Luisa” se eseguo la funzione strtok(stringa, “,”)otterrò il token “Mario”.

L’obiettivo di Strtok è quello di permettere al programma di estrarre parole da una frase (esempio 1), o elementi da un elenco separato da virgole (esempio 2), o interpretare comandi veri e propri (“3 + 5”).

Strtok non si limita ovviamente ad estrarre il primo token dalla lista, ma estrae anche i successivi. Se richiamato con primo argomento NULL continua ad estrarre token dalla stringa precedentemente usata, perchè “si ricorda” il punto a cui era arrivato.

Vediamo un esempio pratico.

#include <iostream>
#include <string.h> 
using namespace std;
int main()
{
  char line[80];
  cout << "Inserisci una riga: ";
  cin.getline(line, 80); // viene inserita la riga 
  char *token; // il token viene definito come un puntatore a un array di caratteri
  token = strtok(line, “ “); // prima esecuzione
  while (token != NULL) { // se non nullo si ripete
    cout << token << endl; 
    token = strtok(NULL, “ “); // esecuzioni successive
  }
  return 0;
}

Come si vede:

  • È necessario definire la variabile token come puntatore ad array.
  • All’estrazione del primo valore si usa strtok passandogli il nome della stringa da cui estrarre (SOLO la prima volta)
  • Negli utilizzi successivi, si usa strtok passandogli il valore NULL. Strtok continua ad usare la stringa precedente, ed estrae ad ogni chiamata il token successivo.

Output:

Inserisci una riga: hello world
hello
world

Qui il codice funzionante: https://onlinegdb.com/IfRb1gw_b