La presentazione è in caricamento. Aspetta per favore

La presentazione è in caricamento. Aspetta per favore

Caratteri e stringhe di caratteri Una (costante di) stringa è una qualsiasi sequenza di caratteri racchiusi tra doppi apici, ad es.: Buon giorno!. Una.

Presentazioni simili


Presentazione sul tema: "Caratteri e stringhe di caratteri Una (costante di) stringa è una qualsiasi sequenza di caratteri racchiusi tra doppi apici, ad es.: Buon giorno!. Una."— Transcript della presentazione:

1 Caratteri e stringhe di caratteri Una (costante di) stringa è una qualsiasi sequenza di caratteri racchiusi tra doppi apici, ad es.: Buon giorno!. Una stringa è memorizzata come un vettore di caratteri che termina con uno speciale marcatore di fine di stringa, detto carattere NULL e rappresentato dalla sequenza di escape \0. Ad es., la stringa Buon giorno! verrebbe rappresentata in memoria come Essa usa 13 locazioni di memoria, e va pertanto dichiarata come char string[13] per riservare uno spazio anche per il carattere NULL, che funge da sentinella per denotare la fine della stringa.

2 Inizializzazione. La inizializzazione di un vettore di caratteri può essere semplificata scrivendo una dichiarazione del tipo: char codici[] = prova; nella quale si usa la stringa prova per inizializzare il vettore codici, di 6 elementi, come indicato in figura. I primi 5 elementi consistono nelle lettere p r o v a, lultimo è la sequenza di escape \0 o carattere NULL, che il compilatore C aggiunge automaticamente alla fine di ogni stringa. Dato che una stringa è memorizzata come un vettore di caratteri, i suoi singoli caratteri possono essere immessi, manipolati o messi in uscita usando le tecniche standard di gestione dei vettori, tramite le notazioni di indice o di puntatore.

3 Funzioni di ingresso e uscita Sebbene, per elaborare una stringa già in memoria, si possa usare sia una funzione di biblioteca sia una scritta dallutente, limmissione di una stringa da tastiera o la sua visualizzazione sullo schermo richiedono qualche supporto da funzioni di biblioteca standard. La tabella seguente elenca le funzioni di biblioteca comunemente disponibili per lingresso e luscita di una stringa, sia carattere per carattere sia come unità completa. Le definizioni delle funzioni indicate in tabella sono contenute nel file dintestazione stdio.h, che pertanto va incluso in ogni programma che le utilizzi (con la solita direttiva #include ). Le due funzioni scanf() e printf() sono già state usate ampiamente. Vediamo perciò le altre quattro funzioni.

4 Funzione getchar(). La funzione getchar() restituisce il prossimo carattere battuto alla tastiera. Ha come intestazione: int getchar() ed è usata per lingresso di singoli caratteri in unistruzione quale car_in = getchar(); Essa memorizza il prossimo carattere battuto nella variabile car_in, ed equivale alla più lunga scanf(%c, &car_in); getchar() non si aspetta che le vengano passati argomenti, e restituisce un dato di tipo intero. Ciò per consentire che venga restituita la sentinella EOF (End-Of-File) già vista, che ha un codice intero ( ). getchar() risulta utile per immettere in continuazione stringhe di caratteri da file di dati, come vedremo più avanti.

5 Funzione putchar(). La funzione di uscita corrispondente a getchar() è putchar(), che si aspetta un argomento costituito da un singolo carattere e lo visualizza sullo schermo. Ad es. listruzione putchar(a); visualizza sullo schermo la lettera a, ed è equivalente alla più lunga printf(%c, a); Il programma seguente usa le funzioni getchar() e putchar() per fare leco sullo schermo dei caratteri battuti sulla tastiera. #include int main() { int car_in; while ((car_in = getchar()) != EOF) putchar(car_in); }

6 Funzioni gets(), puts(). Queste funzioni trattano le stringhe come unità complete, e sono scritte usando le routine più elementari getchar() e putchar() (che forniscono lingresso e luscita di singoli caratteri). Unistruzione quale: gets(messaggio); accetta in continuazione i caratteri digitati da tastiera e li memorizza nel vettore di caratteri messaggio. La memorizzazione dei caratteri nel vettore termina quando si preme il tasto. Esso genera un carattere di linea nuova ( \n ) che gets() traduce in un carattere NULL ( \0 ), scrivendolo come ultimo carattere nel vettore messaggio.

7 Unistruzione quale: puts(messaggio); visualizza sullo schermo il vettore di caratteri messaggio, che contiene la stringa immessa. Come mostra la figura, puts() traduce il carattere NULL ( \0 ) in una sequenza di escape di linea nuova ( \n ), che invia automaticamente al video dopo che la stringa è stata visualizzata.

8 Il seguente programma Getsputs usa gets() e puts() per fare leco sullo schermo di una stringa (lunga fino a 80 caratteri) immessa da tastiera. #include main() { char messaggio[81]; printf(Scrivi una stringa:\n); gets(messaggio); printf(La stringa appena scritta è:\n); puts(messaggio); }

9 In esso osserviamo che: la funzione gets() accetta in continuazione i caratteri digitati da tastiera e li memorizza nel vettore di caratteri messaggio; la pressione del tasto genera un carattere di linea nuova, \n, che gets() interpreta come un fine-carattere; tutti i caratteri incontrati da gets(), tranne quello di linea nuova, sono memorizzati nel vettore di caratteri messaggio; prima di restituire un valore, la funzione gets() aggiunge il carattere NULL al gruppo di caratteri memorizzati, come mostra la figura. gets() B u o n g... \n il programma usa quindi la funzione puts() per visualizzare la stringa.

10 Equivalenza tra puts() e printf(). Si tenga presente che, in generale, Ad es., listruzione puts(mesaggio) usata nel programma precedente può essere sostituita con listruzione printf(%s\n, messaggio); nella quale la sequenza di controllo di conversione %s avverte la funzione che si accederà a una stringa; la sequenza di escape di linea nuova \n sostituisce la linea nuova generata automaticamente da puts() dopo che la stringa è stata visualizzata. una chiamata alla funzione puts() può sempre essere sostituita con una chiamata alla funzione printf()

11 Non equivalenza tra gets() e scanf(). Lequivalenza tra le funzioni di uscita puts() e printf() non è sussiste tra le funzioni di ingresso gets() e scanf(). Ad es., gets(messaggio); e scanf(%s, messaggio); non sono equivalenti. Infatti gets() legge un gruppo di caratteri fino a quando incontra un carattere di linea nuova. scanf() legge un gruppo di caratteri fino a quando incontra un carattere di linea nuova oppure uno spazio vuoto. Perciò, se si tentasse di immettere nel vettore messaggio i caratteri Questa è una stringa usando listruzione scanf(%s, messaggio); solo la parola Questa verrebbe assegnata al vettore.

12 Per immettere la linea completa usando una chiamata alla funzione scanf() sarebbe necessaria una istruzione del tipo: scanf(%s %s %s %s, mess1, mess2, mess3, mess4); che assegna la parola…alla stringa… Questamess1 èmess2 unamess3 stringamess4 Il fatto che scanf() accetti anche lo spazio vuoto come delimitatore, la rende poco utile per immettere stringhe di dati.

13 messaggio è equivalente a &messaggio[0]. Perciò abbiamo potuto usare la chiamata di funzione scanf(%s, messaggio); in luogo di scanf(%s, &messaggio[0]); Osservazione se si usa la funzione scanf() per immettere una stringa di dati, davanti al nome del vettore non si usa il carattere &. Dato che, come sappiamo, un nome di vettore è una costante puntatore, equivalente allindirizzo della prima locazione di memoria riservata per il vettore,

14 Manipolazione di stringhe di caratteri Copia carattere per carattere. Le stringhe si possono manipolare usando o le tecniche di elaborazione standard dei vettori o le funzioni di biblioteca standard. Vediamo dapprima come si elabora una stringa carattere per carattere, il che farà capire come sono costruite le funzioni di biblioteca standard e come creare funzioni di biblioteca proprie. Costruiamo una funzione, strcopia(), che copi la stringa2 nella stringa1. void strcopia(char string1[], char string2[]) { int i = 0; while (string2[i] != \0) { string1[i] = string2[i]; ++i; } string1[i] = \0; return; }

15 Sebbene questa funzione possa essere abbreviata e scritta in maniera più compatta, essa illustra le caratteristiche principali della manipolazione di stringhe. Nella linea dintestazione, le due stringhe sono passate a strcopia() come vettori, quindi ciascun elemento di string2 è copiato nellelemento corrispondente di string1 fino a che ( while ) sincontra il marcatore di fine-stringa NULL ( \0 ), la cui rilevazione fa terminare il ciclo while che copia gli elementi. Dato che il carattere NULL non è copiato da string2 a string1, lultima istruzione di strcopia() aggiunge a string1 un carattere di fine-stringa. Prima di chiamare strcopia(), si deve allocare spazio sufficiente per il vettore string1, in modo che possa accogliere gli elementi di string2. Il programma seguente alloca per ciascuno dei due vettori lo spazio di una linea di schermo completa (80 caratteri), più uno per il fine- stringa, dichiara la funzione strcopia() che si aspetta due vettori di caratteri e la chiama passandole gli indirizzi dei due vettori.

16 #include void main(void) { char messaggio[81]; char nuovo_mess[81]; int i; void strcopia(char [], char []); printf("Scrivi una frase:"); gets(messaggio); strcopia(nuovo_mess, messaggio); puts(nuovo_mess); } void strcopia(char string1[], char string2[]) { int i = 0; while (string2[i] != '\0') { string1[i] = string2[i]; ++i; } string1[i] = '\0'; return; }

17 Immissione di stringhe carattere per carattere. Con la stessa tecnica con cui può esere copiata carattere per carattere, una stringa può essere anche immessa e visualizzata. Ad es., il programma seguente usa la funzione dingresso caratteri getchar() per fare immettere una stringa carattere per carattere. #include void main(void) { char messaggio[81], c; int i; printf("Scrivi una frase:\n"); printf("La frase appena scritta è:\n"); puts(messaggio); } i = 0; while(i<80 && (c = getchar()) != '\n') { messaggio[i] = c; ++i; } messaggio[i] = '\0';

18 La parte di programma evidenziata in colore sostituisce listruzione gets(messaggio) usata nel programma Getsputs. Listruzione while fa leggere i caratteri immessi purché il loro numero sia inferiore a 81 e il carattere restituito da getchar() non sia quello di linea nuova ( \n ). Osservazione. Le parentesi attorno allespressione c = getchar() sono necessarie per assegnare il carattere restituito da getchar() alla variabile c prima di confrontarlo con una sequenza di linea nuova ( \n ). In loro assenza, dato che loperatore di confronto != ha la precedenza su quello di assegnazione =, lespressione sarebbe equivalente a c = (getchar() != \n) Essa confronta il carattere restituito da getchar() con \n, e il valore dellespressione relazionale (getchar() != \n) è 0 o 1 a seconda che getchar() abbia ricevuto o no il carattere di linea nuova. Così anche il valore assegnato a c sarebbe 0 o 1, a seconda del risultato del confronto.

19 Funzione scritta dallutente. Il programma precedente illustra anche unutile tecnica per sviluppare le funzioni. Le istruzioni evidenziate in colore costituiscono una unità autoconsistente per immettere una linea completa di caratteri da tastiera. Pertanto esse possono essere scorporate da main() e messe insieme in una nuova funzione, chiamata getlinea(), come illustrato nel programma seguente.

20 #include void main(void) { char messaggio[81]; int i; void getlinea(char []); printf("Scrivi una frase:\n"); getlinea(messaggio); printf("La frase appena scritta è:\n"); puts(messaggio); } void getlinea(char strin[]) { int i = 0; char c; while (i < 80 && (c = getchar()) != '\n') { strin[i] = c; ++i; } strin[i] = '\0'; return; }

21 Una scrittura compatta. Possiamo anche riscrivere getlinea() in modo più compatto assegnando direttamente alle componenti del vettore strin i caratteri restituiti da getchar(), eliminando la variabile locale c. void getlinea(char strin[]) { int i = 0; while (i < 80 && (strin[i++] = getchar()) != '\n') ; strin[i] = '\0'; return; } Osservazione. Listruzione di assegnazione (strin[i++] = getchar()) assegna il carattere restituito da gethcar() direttamente al vettore strin, quindi incrementa il subscritto i usando loperatore postfisso ++.

22 la successiva istruzione NULL ( ; ) soddisfa lesigenza che un ciclo while contenga almeno una istruzione. Entrambe le versioni di getlinea() sono sostituti accettabili di gets(), e dimostrano la intercambiabilità delle funzioni di biblioteca del C con quelle scritte dallutente.

23 Puntatori e funzioni di biblioteca Nel costruire funzioni di gestione delle stringhe risultano particolarmente utili i puntatori: una notazione con puntatori dà luogo a istruzioni più compatte ed efficienti - rispetto agli indici - per accedere ai caratteri individuali di una stringa. Per vedere lequivalenza tra indici e puntatori quando si accede ai singoli caratteri di una stringa riprendiamo in considerazione la funzione strcopia(), che copia i caratteri da un vettore a un altro, uno alla volta. void strcopia(char string1[], char string2[]) { int i = 0; while (string2[i] != '\0') { string1[i] = string2[i]; ++i; } string1[i] = '\0'; return; }

24 Per scriverne una versione con puntatori, apportiamole due modifiche: 1. Osserviamo che lespressione (string2[i] != '\0') è vera (cioè ha un valore diverso da 0 ) fin tanto che si leggono i caratteri della stringa diversi da quello finale ( \0 ), mentre è falsa (cioè vale 0 ) solo quando si legge il carattere finale. Ma anche lespressione string2[i] ha un valore diverso da 0 per tutti i caratteri della stringa tranne lultimo, dato che solo \0 ha il codice ASCII 0. Perciò si può sostituire lespressione (string2[i] != '\0') con la più semplice string2[i] e scrivere:

25 void strcopia(char string1[], char string2[]) { int i = 0; while (string2[i]) { string1[i] = string2[i]; ++i; } string1[i] = '\0'; return; }

26 2. Listruzione di assegnazione string1[i] = string2[i]; ha come valore il codice ASCII del carattere via via copiato; esso è uguale a 0 solo dopo che il carattere NULL sia stato assegnato a string1. Perciò possiamo includere lespressione di assegnazione string1[i] = string2[i] dentro la parte di test dellistruzione while, scrivendo: In tal modo non è necessario terminare esplicitamente la prima stringa con il carattere NULL, dato che lassegnazione entro parentesi assicura che NULL sia copiato dalla seconda stringa nella prima, facendo terminare correttamente il ciclo while. void strcopia(char string1[], char string2[]) { int i = 0; while (string1[i] = string2[i]) ++i; return; }

27 void strcopia(char *string1, char *string2) { while (*string1 = *string2) { string1++; string2++; } return; } Sia nella versione con indici, sia in quella con puntatori, la funzione strcopia() riceve il nome del vettore passato (ossia lindirizzo della sua prima locazione). Nella versione con puntatori di strcopia() i due indirizzi passati sono memorizzati rispettivamente negli argomenti puntatore string1 e string2. Possiamo adesso convertire strcopia() dalla notazione con indici a quella con puntatori come segue:

28 La precedente dichiarazione (char *string1, char *string2) indica che string1 e string2 sono puntatori che contengono lindirizzo di un carattere, e fa sì che gli indirizzi passati siano trattati come valori puntatori anziché come nomi di vettori. La dichiarazione è equivalente a: (char string1[], char string2[]) Allinterno di strcopia() lespressione puntatore *string1 (lelemento il cui indirizzo è in string1 ), sostituisce lespressione con subscritto equivalente string1[i]. Analogamente per *string2. Lespressione *string1 = *string2 fa sì che lelemento puntato da string2 sia assegnato allelemento puntato da string1.

29 Dato che gli indirizzi di partenza di entrambe le stringhe sono passati a strcopia() e memorizzati rispettivamente in string2 e string1, lespressione *string2 si riferisce inizialmente a string2[0], e *string1 a string1[0]. Gli incrementi consecutivi ai due puntatori in strcopia() con le istruzioni string1++; e string2++; fanno sì che ciascun puntatore punti al carattere successivo nella rispettiva stringa. void strcopia(char *string1, char *string2) { while (*string1++ = *string2++) ; return; } Si può effettuare un ultimo cambiamento alla funzione includendo gli incrementi ai puntatori come operatori postfissi nella parte di test dellistruzione while. La forma finale della funzione di copia stringa è allora:

30 Nellespressione *string1++ = *string2++ non cè ambiguità, anche se loperatore di indirezione, *, ha la stessa precedenza di quello di incremento, ++, infatti essa fa accedere al carattere puntato prima che il puntatore sia incrementato. Solo dopo il completamento dellassegnazione *string1++ = *string2++ i puntatori sono incrementati per puntare ai caratteri successivi nelle rispettive stringhe. Quasi tutti i compilatori C comprendono nella loro biblioteca standard una funzione di copia stringa, scritta esattamente come la nostra versione con puntatori di strcopia().

31 Funzioni di biblioteca di stringa. Quasi tutti i compilatori C dispongono di un gruppo di funzioni di biblioteca per: lingresso il confronto la manipolazione luscita di stringhe di caratteri. Un loro elenco è fornito nella tabella seguente:

32 Esercizio. Inserire gli opportuni commenti nelle righe lasciate vuote del seguente programma, quindi indicare luscita prodotta dal programma, senza eseguirlo.

33 #include int main() { char x[] = "Buon compleanno a te"; char y[25]; char z[15]; printf("%s%s\n%s%s\n", "La stringa nel vettore x è: ", x, "La stringa nel vettore y è: ", strcpy(y, x)); strncpy(z, x, 14); z[14] = '\0'; printf("La stringa nel vettore z è: %s\n", z); return(0); }

34 #include int main() { char x[] = "Buon compleanno a te"; /* inizializza il vettore di caratteri x */ char y[25]; /* crea il vettore di caratteri y */ char z[15]; /* crea il vettore di caratteri z */ printf("%s%s\n%s%s\n", "La stringa nel vettore x è: ", x, "La stringa nel vettore y è: ", strcpy(y, x)); strncpy(z, x, 14); /* copia i primi 14 caratteri di x in z (non copia il carattere nullo) */ z[14] = '\0'; printf("La stringa nel vettore z è: %s\n", z); return(0); }

35 Il programma precedente utilizza le funzioni: strcpy() per copiare lintera stringa x nel vettore y strncpy() per copiare i primi 14 caratteri della stringa x nel vettore z. Al vettore z viene accodato un carattere NULL ( \0 ) perché la chiamata di strncpy() nel programma non scrive un carattere nullo di terminazione, dato che il 3° argomento è inferiore alla lunghezza della stringa indicata dal 2° argomento.

36 Esercizio. Inserire gli opportuni commenti nelle righe lasciate vuote del seguente programma, quindi indicare luscita prodotta dal programma, senza eseguirlo.

37 #include int main() { char s1[20] = "Happy "; char s2[] = "New Year "; char s3[40] = ""; printf("s1 = %s\ns2 = %s\n", s1, s2); printf("strcat(s1, s2) = %s\n", strcat(s1, s2)); printf("strncat(s3,s1,6) = %s\n", strncat(s3,s1,6)); printf("strcat(s3,s1) = %s\n", strcat(s3,s1)); return(0); }

38 #include int main() { char s1[20] = "Happy "; /* inizializza il vettore di caratteri s1 */ char s2[] = "New Year "; char s3[40] = ""; /* inizializza il vettore di caratteri s3 con la stringa vuota */ printf("s1 = %s\ns2 = %s\n", s1, s2); printf("strcat(s1, s2) = %s\n", strcat(s1, s2)); /* accoda s2 a s1 */ printf("strncat(s3,s1,6) = %s\n", strncat(s3,s1,6)); /* accoda i primi 6 caratteri di s1 a s3; inserisce \0 dopo lultimo carattere */ printf("strcat(s3,s1) = %s\n", strcat(s3,s1)); /* accoda s1 a s3 */ return(0); }

39 Il programma precedente usa due funzioni: strcat() accoda il suo 2° argomento (una stringa) al 1°, che è un vettore di caratteri che contiene una stringa. Il 1° carattere del 2° argomento sostituisce il carattere NULL ( \0 ) che termina la stringa del 1° argomento. Il vettore utilizzato per immagazzinare la prima stringa deve essere sufficientemente grande per contenere: la prima stringa, la seconda stringa, il carattere nullo di terminazione che viene copiato dalla 2^ stringa. strncat() accoda un numero specificato di caratteri dalla 2^ stringa alla 1^. Al risultato viene accodato automaticamente un carattere NULL di terminazione.

40 Funzioni per la conversione delle stringhe (atof(), atoi(), atol() ) La biblioteca di utilità generiche del C contiene funzioni che convertono le stringhe formate da numeri in valori interi e in virgola mobile, indicate in Tabella. La funzione atof() restituisce il suo argomento, costituito da una stringa che rappresenta un numero in virgola mobile, convertito in un numero in doppia precisione. Nel caso in cui il valore non possa essere convertito (per esempio, se il primo carattere della stringa non è un numero), il comportamento di atof() sarà indefinito.

41 Esempio di atof(). Scrivere un programma che converta una stringa in un numero in doppia precisione, e che produca la seguente uscita: La stringa 99.0 convertita in double è Il valore convertito, diviso 2 è: #include int main() { double d; d = atof("99.0"); printf("%s%.3f\n%s%.3f\n", "La stringa \"99.0\" convertita in double è ", d, "Il valore convertito, diviso 2 è: ", d/2.0); } Un programma che soddisa la richiesta è il seguente:

42 Esempio di atoi(). In modo analogo si comporta la funzione atoi(), che converte in un valore intero il suo argomento costituito da una stringa di cifre che rappresenta un intero. Consideriamo il seguente programma: #include int main() { int i; i = atoi("2006"); printf("%s%d\n%s%d\n", "La stringa \"2006\" convertita in int è: ", i, "Il valore convertito, meno 6, è: ", i - 6); }

43 Esempio di atol(). La funzione atol() restituisce il suo argomento, costituito da una stringa che rappresenta un numero intero lungo, convertito in un valore (intero) lungo. Qualora gli int e i long siano rappresentati entrambi mediante 4 byte, le funzioni atoi() e atol() funzionano in modo identico. Consideriamo il seguente programma: #include int main() { long l; l = atol(" "); printf("%s%ld\n%s%ld\n", "La stringa \" \" convertita in long è: ", l, "Il valore convertito, diviso 2, è: ", l / 2); }

44 Funzioni di biblioteca di carattere ( ctype.h ) Vi sono anche funzioni per operare sui caratteri, alcune delle quali sono elencate nella tabella seguente:

45 Queste funzioni sono inserite in un file standard di nome ctype.h, per cui per accedere a esse il programma dovrà contenere, prima di main(), listruzione #include Esempio ( toupper(), tolower() ). Come primo esempio, consideriamo il programma seguente: #include int main() { printf("%s%c\n %s%c\n %s%c\n", " u convertito in maiuscolo è ", toupper('u'), "7 convertito in maiuscolo è ", toupper('7'), "L convertito in minuscolo è ", tolower('L')); }

46 Esempio ( isalpha(), isdigit() ). Come altro esempio consideriamo il programma seguente, che chiede in continuazione allutente di immettere un carattere, quindi stabilisce se esso sia una lettera o una cifra. Il programma contiene un ciclo do-while dal quale si esce quando si digita una f. Per non costringere lutente a scrivere lettere minuscole o maiuscole, esso converte tutte le lettere scritte in minuscole. Esso produce la seguente uscita: u convertito in maiuscolo è U 7 convertito in maiuscolo è 7 L convertito in minuscolo è l

47 #include void main(void) { char car_ingr; do { printf("\nPremi un tasto qualsiasi (f per finire) "); getchar(); /*riceve e ignora il tasto Invio*/ if (isalpha(car_ingr)) /*un valore diverso da 0 è vero*/ printf("Il carattere immesso è una lettera.\n"); else if (isdigit(car_ingr)) printf("Il carattere immesso è una cifra.\n"); else printf("Il carattere non è né lettera né cifra.\n"); } while (car_ingr != 'f'); } car_ingr = getchar(); /*riceve il prossimo carattere*/ car_ingr = tolower(car_ingr); /*converte in minuscolo*/

48 car_ingr = getchar(); car_ingr = tolower(car_ingr); Osserviamo che, poiché le funzioni restituiscono un valore, una funzione può essa stessa essere largomento di una funzione (compresa se stessa). Perciò le due istruzioni del programma precedente possono essere fuse nellunica istruzione: car_ingr = tolower(getchar());


Scaricare ppt "Caratteri e stringhe di caratteri Una (costante di) stringa è una qualsiasi sequenza di caratteri racchiusi tra doppi apici, ad es.: Buon giorno!. Una."

Presentazioni simili


Annunci Google