Traccia della lezione Lez09: Lucido 3: Perché si usa l'espressione LUNGHEZZA+1 per indicare il numero di caratteri della stringa s? Perché in questo modo si ha un vettore contenente LUNGHEZZA caratteri veri (nelle posizioni da 0 a LUNGHEZZA-1) e il terminatore null (in posizione LUNGHEZZA). Il codice STRINGA.C definisce un vettore V di 6 caratteri. - scrive in V, carattere per carattere, prova\0 e lo stampa: a video appare la scritta "prova"; - scrive in V, carattere per carattere, pro\0a\0 e lo stampa: a video appare la scritta "pro"; - scrive in V, carattere per carattere, prova1 e lo stampa: a video appare la scritta "prova1" seguita da un carattere farlocco, dovuto al fatto che il processore non sa dove termini la stringa. E' quindi possibile troncare una stringa in qualsiasi posizione scrivendovi un '\0'. Un vettore di char privo di terminatore non deve essere stampato come stringa o passato a funzioni che operano su stringhe (che vedremo in seguito); si può farlo, ma i risultati saranno scorretti. Può invece essere usato come vettore di caratteri, cioè accedendo a un carattere alla volta in lettura e in scrittura. Lucido 5: Le funzioni di gestione delle stringhe non fanno parte del linguaggio C, ma della libreria standard, che gli viene sempre collegata. Questo significa che sono disponibili identiche su ogni macchina, sistema operativo e compilatore, ma che per poterle usare bisogna includere la libreria nel proprio codice con la direttiva #include Alcuni ambienti la includono comunque anche se il codice non lo specifica; il risultato è che il codice così prodotto sembra corretto, ma non lo è, e non potrà essere compilato in altri ambienti. La funzione strlen() restituisce un valore di tipo size_t, che è un numero naturale, ma il cui tipo esatto dipende dal compilatore e processore. Se non si lavora con stringhe lunghissime, si può ignorare la cosa e trattarlo come un intero qualsiasi, sfruttando le regole di conversione implicita. Il tipo di dato size_t è lo stesso restituito da sizeof(), che però fornisce il numero di celle assegnate alla stringa, non il numero di caratteri significativi usati. Il codice STRINGA2.C aggiunge al codice STRINGA.C la direttiva #include e le seguenti istruzioni al termine di ciascuno dei tre casi considerati: StampaStringa("strlen(s) = "); StampaIntero(strlen(s)); StampaStringa("\n"); StampaStringa("\n"); Si ottiene che prova\0 ha lunghezza 5, pro\0a\0 ha lunghezza 3, mentre prova1 ha lunghezza 7 (errata, ma non si tratta di una stringa C). Esercizio: si realizzi una funzione my_strlen(s) equivalente a strlen(s) con i costrutti visti sinora a lezione. Il codice COUNTSPACES.C conta il numero di spazi bianchi contenuti in una stringa data attraverso la solita direttiva #define. Come condizione di uscita dal ciclo si può usare indifferentemente (s[i] != '\0') oppure (i < strlen(s)). La seconda condizione richiede la direttiva #include all'inizio del codice, per poter usare la funzione strlen(). Inoltre, ad ogni iterazione chiama la funzione strlen, che è molto più costosa del semplice confronto fra s[i] e il terminatore. Quindi è meglio la prima espressione. Il ciclo while può facilmente essere trasformato in un ciclo for, inglobando l'inizializzazione e l'aggiornamento: num = 0; for (i = 0; s[i] != '\0'; i++) if (s[i] == SPAZIO) num++; for (num = 0, i = 0; s[i] != '\0'; i++) if (s[i] == SPAZIO) num++; Esercizio: si modifichi la funzione NumeroSpaziBianchi(s) generalizzandola nella funzione NumeroOccorrenze(s,ch), che conta il numero di occorrenze del carattere 'ch' nella stringa "s". L'operatore di assegnamento non si può usare sulle stringhe esattamente come non si può usare sui vettori. La funzione strncpy() copia meno di n caratteri se orig è più corta. Se dest è più corta di n, copia comunque n caratteri, sporcando le celle seguenti. Se nei primi n caratteri di orig non c'è il terminatore, dest non avrà terminatore (a meno che ce l'avesse all'inizio e sia sopravvissuto alla copia). Esercizio: si realizzi una funzione my_strcpy equivalente a strcpy con i costrutti visti sinora a lezione. Lucido 6: Ovviamente, nell'aggiungere add a dest il terminatore di dest viene sovrascritto, altrimenti dest risulterebbe immutata. La funzione strncat() ha comportamento analogo alla strncpy(): se add ha meno di n caratteri, aggiunge solo quelli che ci sono. Se nei primi n caratteri di add non c'è il terminatore, il risultato non avrà terminatore. Esercizio: si realizzi una funzione my_strcat equivalente a strcat con i costrutti visti sinora a lezione. Lucido 7: La strcmp originale di Kernighan e Ritchie restituiva la differenza fra i valori numerici corrispondenti ai primi due caratteri diversi nelle stringhe confrontate. Lo standard però non impone di restituire questo valore, per cui alcuni compilatori potrebbero restituire valori diversi allo scopo di ottenere un codice più rapido. Lo standard impone solo che il risultato sia < 0, = 0 o > 0 secondo che la prima stringa sia precedente, coincidente o seguente alla seconda in ordine lessicografico. Esercizio: si realizzi una funzione my_strcmp equivalente a strcmp con i costrutti visti sinora a lezione.