Vediamo alcuni esempi di dichiarazione di stringhe:
// dichiara un vettore di 100 caratteri, senza inizializzarlo char a[100]; // dichiara e inizializza un vettore di 5 caratteri char vocali[ ] = { 'a' , 'e' , 'i' , 'o' , 'u' }; // dichiara e inizializza un vettore di 5 caratteri // (tramite i corrispondenti codici ASCII) char vocali_da_ASCII[ ] = { 97 , 101 , 105 , 111 , 117 }; // dichiara e inizializza una stringa char saluto[ ] = "Ciao mondo!";
La sintassi dell'ultima istruzione definisce un array di lunghezza N+1, dove N è la lunghezza della stringa: l'ultima casella dell'array contiene il carattere speciale '\0'. Nell'esempio abbiamo un array di 12 posizioni.
C | i | a | o | m | o | n | d | o | ! | \0 | carattere | |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | posizione |
Notare la differenza tra l'uso di apici singoli e quello di apici doppi:
char x = 'a'; // ok char y = "b"; // NO!!! char z[ ] = "c"; // ok char w[ ] = 'd'; // NO!!!
Sappiamo che per stampare un array è importante conoscerne la lunghezza, altrimenti potremmo accedere a zone di memoria che non erano state allocate per l'array. Lo stesso ragionamento vale per le stringhe, che sono array particolari. Come esempio è istruttivo provare a compilare ed eseguire il seguente programma:
/* Stampa i caratteri di una stringa ed i corrispondenti codici ASCII */ #include <stdio.h> #include <stdlib.h> #define LUNGHEZZA_MAX 20 int main ( ) { int i; char stringa1[ ] = "Prova 1"; char stringa2[LUNGHEZZA_MAX] = "Prova 2"; char stringa3[ ] = "Prova 3"; for (i = 0; i < LUNGHEZZA_MAX; i++) printf("%c (ASCII %d)\n", stringa1[i], stringa1[i]); printf("===========\n"); for (i = 0; i < LUNGHEZZA_MAX; i++) printf("%c (ASCII %d)\n", stringa2[i], stringa2[i]); printf("===========\n"); for (i = 0; i < LUNGHEZZA_MAX; i++) printf("%c (ASCII %d)\n", stringa3[i], stringa3[i]); return EXIT_SUCCESS; } |
Se mandate in esecuzione il programma dovreste notare qualcosa di particolarmente strano... che evidenzia il modo in cui sono allocate le variabili nella memoria.
Provate a rispondere alle seguenti domande:
Per stampare una stringa possiamo utilizzare direttamente printf, senza doverci preoccupare di scorrerla carattere per carattere:
char nome[ ] = "Mario Rossi"; printf("ciao %s, come stai?\n", nome);Analogamente, con scanf possiamo leggere da tastiera direttamente una stringa, senza doverci preoccupare di leggerla un carattere per volta:
char nome[51]; printf("Come ti chiami? (max 50 caratteri)\n"); scanf("%s", nome);
Notare che questa volta non serve il simbolo & davanti a nome.
Attenzione: Se si immette un numero maggiore di caratteri si rischia di sovrascrivere delle zone di memoria con altri dati.
Nota: In questo modo però la stringa viene letta solo fino al primo carattere di separazione (spazio, tabulazione, new line). Per evitarlo possiamo fare un ciclo di lettura che esamina un carattere alla volta e termina quando si digita un carattere speciale (es. il tasto ESC).
int i = 0; char stringa[LUNGHEZZA_MAX+1]; scanf("%c", &stringa[i]); // leggo il primo carattere while (i < LUNGHEZZA_MAX && // se c'è spazio e stringa[i] != 27 && // ... l'ultimo carattere letto non è ESC e stringa[i] != '\0') { // ... l'ultimo carattere letto non è '\0', allora... i++; scanf("%c", &stringa[i]); // leggo il prossimo carattere } stringa[i] = '\0'; // metto '\0' come ultimo carattere
Invece della primitiva scanf di lettura formattata, possiamo anche usare la funzione getchar( ):
int i = 0; char stringa[LUNGHEZZA_MAX+1]; stringa[i] = getchar( ); // leggo il primo carattere while (i < LUNGHEZZA_MAX && // se c'è spazio e stringa[i] != 27 && // ... l'ultimo carattere letto non è ESC e stringa[i] != EOF && // ... l'ultimo carattere letto non è EOF e stringa[i] != '\0') { // ... l'ultimo carattere letto non è '\0', allora... i++; stringa[i] = getchar( ); // ... leggo il prossimo carattere } stringa[i] = '\0'; // metto '\0' come ultimo carattere
Scrivere un programma analizza.c che legga una stringa di
lunghezza inferiore a 10000 e visualizzi la frequenza di ogni
carattere alfabetico che compare nella stringa. Scaricare il file di
testo "intro_C.txt" e usarlo per
provare l'eseguibile sfruttando la redirezione dell'input.
Nota: Con il termine frequenza si intende il numero di volte
che il carattere compare nel testo.
/* Analizza la frequanza dei caratteri in una stringa letta */ #include <stdio.h> #include <stdlib.h> #include <limits.h> #define LUNGHEZZA_MAX 10000 int main ( ) { int i, codice, totale = 0; char stringa[LUNGHEZZA_MAX+1]; int frequenza[256]; for (i = 0; i < 256; i++) frequenza[i] = 0; i = 0; stringa[i] = getchar( ); while ( i < LUNGHEZZA_MAX && stringa[i] != 27 && stringa[i] != EOF && stringa[i] != '\0') { i++; stringa[i] = getchar( ); } stringa[i] = '\0'; for (i = 0; i < LUNGHEZZA_MAX && stringa[i] != '\0'; i++) { codice = stringa[i]; frequenza[codice-CHAR_MIN]++; totale++; } printf("\n===========\n"); for (i = 0; i < 256; i++) if (frequenza[i] != 0) printf("%c (ASCII %d): %d\n", i + CHAR_MIN, i + CHAR_MIN, frequenza[i]); printf("===========\n"); printf("Totale %d\n", totale); return EXIT_SUCCESS; } |