LdL - LP1 - lez 11 - ver 6 - aa Linguaggi di programmazione I Stringhe (II) Prof. Luigi Di Lascio Lezione 11
LdL - LP1 - lez 11 - ver 6 - aa Gli argomenti di questa lezione (12°) Richiami La funzione sizeof Allocazioni dinamica della memoria: malloc, free Input, Output di Stringhe, di Testo Funzioni per il trattamento di stringhe nella librerie standard Stringhe e Puntatori Stringhe come array di puntatori
LdL - LP1 - lez 11 - ver 6 - aa Richiami: Il tipo char (I) Il dominio D del tipo char è dato da: le lettere dell’alfabeto (maiuscole, minuscole) segni di punteggiatura cifre decimali: ‘0’, ‘1’, … ‘9’ altri simboli: quelli della tabella dei codici ASCII il dominio D associato al tipo char è ordinato, l’ordine è dato dal codice ASCII: 0 … 255 il C rappresenta i dati di tipo char come degli interi: ogni carattere è rappresentato dal suo codice ASCII
LdL - LP1 - lez 11 - ver 6 - aa Dichiarazioni di variabili di tipo char: char nome_variabile Costanti di tipo char: ogni valore di tipo char viene specficato tra singoli apici: ‘a’, ‘b’, ‘2’,.... Dimensione della Rappresentazione: sizeof(char) (vedi dopo) Operatori relazionali: ==, !=,, >, < Relazione d’ordine x<=y sse ASCII(x)<=ASCII(y) Operatori aritmetici e logici: quelli visti per il tipo int Richiami: Il tipo char (II)
LdL - LP1 - lez 11 - ver 6 - aa ‘C’ < ‘a’ VERO, perché 67<97 ‘1’+’A’=ASCII(‘1’)+ASCII(‘A’)=carattere(49+65) = CARATTERE(114) = ‘r’ !’A’ FALSO, ‘A’ && ‘a’ VERO Richiami: Il tipo char (III) #include int main() { int x; x='A'+'B'; printf("%d\n",x); printf("%c\n",x); return 0;} 131 â Premere un tasto per continuare...
LdL - LP1 - lez 11 - ver 6 - aa Richiami: Stringhe e Puntatori Dichiarazioni equivalenti di stringhe: char *corso = “LP1”; char *corso; /* attenzione: occorre inizializzarlo */ char corso[] = “LP1”; char corso[4]; /* attenzione: occorre inizializzarlo */ ; char corso[4] = {‘L’, ‘P’, ‘1’, ‘\0’}; char corso[] = {‘L’, ‘P’, ‘1’, ‘\0’}; Quando usate un puntatore per definire una stringa, l’imprevedibilità della lunghezza della stringa impone di allocare dinamicamente spazio in memoria per la gestione della stringa.
LdL - LP1 - lez 11 - ver 6 - aa sizeof(espressione) oppure sizeof(tipo) L’operatore sizeof restituisce la memoria necessaria per espressione o per tipo. Dimensione della memoria utilizzata per rappresentare espressioni o dati: sizeof() Esempi: char a[10]; int i; char c; double d; i = sizeof(a[10]); printf("L'array %s ha dimensione = %d\n", a, i); i = sizeof(int); printf("Gli interi hanno dimensione %d", i); c = sizeof(char); printf(“I caratteri hanno dimensione %c", c); d = sizeof(double); printf(“Un dato di tipo double hanno dimensione %lf", d);
LdL - LP1 - lez 11 - ver 6 - aa sizeof() : implementazione #include int main(void) { printf(“char:%3d byte\n”, sizeof(char)); printf(“int:%3d bytes\n”, sizeof(int)); printf(“long:%3d bytes\n”, sizeof(long)); printf(“float:%3d bytes\n”, sizeof(float)); printf(“double:%3d bytes\n”, sizeof(double)); printf(“long double:%3d bytes\n”, sizeof(long double)); return (0);} char: 1 byte int: 2 bytes long: 4 bytes float: 4 bytes double: 8 bytes long double: 10 bytes
LdL - LP1 - lez 11 - ver 6 - aa Allocazione dinamica di spazio in memoria La funzione malloc() in è utilizzata a tal fine. Vediamo come. Allocazione di memoria per una stringa di 100 caratteri Dichiarazione char * str; str = (char *) malloc(100*sizeof(char)); Allocazione di memoria per un array di 50 interi Dichiarazione int *elementi; elementi = (int *) malloc(50*sizeof(int)); (tipo *) malloc(n*sizeof(tipo)) alloca un blocco di memoria per n dati di tipo tipo
LdL - LP1 - lez 11 - ver 6 - aa Allocazione dinamica di spazio in memoria La funzione malloc() in è utilizzata a tal fine. Vediamo come. Allocazione di memoria per una stringa di 100 caratteri Dichiarazione char * str; str = (char *) malloc(n_var*sizeof(char)); Allocazione di memoria per un array di 50 interi Dichiarazione int *elementi; elementi = (int *) malloc(n_var*sizeof(int)); (tipo *) malloc(n_var*sizeof(tipo)) alloca un blocco di memoria per n dati di tipo tipo
LdL - LP1 - lez 11 - ver 6 - aa Allocazione dinamica di spazio in memoria: malloc if((str=(char *) malloc(100*sizeof(char))) == NULL) { printf(“memoria insufficiente”);exit(-1);} #include char i, *pPtr, *p; int main() { /* riserva un blocco per stringa di 34 caratteri*/ pPtr=(char*)malloc(35*sizeof(char)); if(pPtr==NULL) { {puts(“no memoria”); exit(-1);} Ma bisogna assicurarsi che la memoria richiesta sia disponibile ogni volta che si usa malloc(). Come si fa? p=pPtr; /* salviamo l’indirizzo iniziale */ for(i=65;i<91;++i) *p++=i; /* {*p=i; p++;}*/ *p = ‘\0’; puts(pPtr); return 0;} Out del programma: ABC……………XYZ
LdL - LP1 - lez 11 - ver 6 - aa Allocazione dinamica di spazio in memoria: free #include char i, *pPtr, *p; int main() { pPtr=(char*)malloc(35*sizeof(char)); if(pPtr==NULL) {puts(“no memoria”); exit(-1)}; …… pPtr=free(pPtr); ….. return 0;} Come si rende di nuovo libero un blocco di memoria allocato dinamicamente con malloc() ? Con free() in. free(pPtr); /* rilascia il blocco di memoria al quale punta pPTR */
LdL - LP1 - lez 11 - ver 6 - aa Visualizzazione di stringhe e caratteri Input di stringhe, caratteri e testo su più righe
LdL - LP1 - lez 11 - ver 6 - aa Visualizzazione di stringhe e caratteri #include int main() { char *parola =“oggi”; puts(parola); return 0; } La funzione puts()
LdL - LP1 - lez 11 - ver 6 - aa Visualizzazione di stringhe e caratteri #include int main() { char *parola =“oggi”; printf(“%s”, parola); return 0; } La funzione printf()
LdL - LP1 - lez 11 - ver 6 - aa Visualizzazione di stringhe e caratteri #include int main() { char *parola =“oggi”; while(*parola!=‘\0’) { printf(“%c”, *parola); ++parola; } return 0;} Carattere per Carattere
LdL - LP1 - lez 11 - ver 6 - aa Input di stringhe dalla tastiera gets() riceve una stringa dalla tastiera, leggendo tutti i caratteri digitati fino a quando non viene premuto INVIO, in tal caso scarta tale carattere e aggiunge il carattere di terminazione ‘\’0 La funzione gets() /1 #include int main() { char input[81]; puts(“Inserire un testo e premere INVIO: “); gets(Input); printf(“\n%s”, Input); return 0; }
LdL - LP1 - lez 11 - ver 6 - aa Input di più righe di testo dalla tastiera #include int main() { char input[81],*pPtr; puts("Inserire la riga premere INVIO. "); puts("Per terminare non digitare nulla e premere INVIO\n"); while(*(pPtr=gets(input))!= NULL) printf("DIGITATO: %s\n",input); /* printf("\nDIGITATO: %s\n",input);*/ return 0; } La funzione gets() /2a gets() restituisce un valore che rappresenta un puntatore al tipo char con l’indirizzo al quale è stata memorizzata la stringa char *gets(char *str)
LdL - LP1 - lez 11 - ver 6 - aa Input di più righe di testo dalla tastiera Inserire la riga premere INVIO Per terminare non digitare nulla e premere INVIO oggi DIGITATO: oggi sono DIGITATO: sono andato DIGITATO: andato al mare DIGITATO: al mare DIGITATO: Premere un tasto per continuare... La funzione gets() /2b
LdL - LP1 - lez 11 - ver 6 - aa Input di stringhe dalla tastiera #include int main() { char *parola =“oggi”; scanf(“%s”, parola); return 0; } La funzione scanf() AAA! scanf() non vede gli spazi vuoti!
LdL - LP1 - lez 11 - ver 6 - aa Funzioni per il trattamento di stringhe nella libreria
LdL - LP1 - lez 11 - ver 6 - aa size_int strlen(const char *s) #include int main(void) { char *s1="abc"; char *s2="four"; char *s3="cinque"; printf("Lunghezza di %s = %d\n",s1, strlen(s1)); printf("Lunghezza di %s = %d\n",s2, strlen(s2)); printf("Lunghezza di %s = %d\n",s3, strlen(s3)); return(0); } Funzioni per il trattamento di stringhe nella libreria /1
LdL - LP1 - lez 11 - ver 6 - aa Funzioni per il trattamento di stringhe nella libreria /2 char *strcpy(char *s1, const char *s2) copia la stringa s2 nell’array s1 e ritorna s1 char *strncpy(char *s1, const char *s2, size_t n) copia al più n caratteri di s2 nell’array s1 e ritorna s1 char *strcat(char *s1, const char *s2) attacca la stringa s2 all’array s1, quindi ritorna s1. char *strncat (char *s1, const char *s2, size_t n) attacca al più n caratteri della stringa s2 all’array s1, quindi ritorna s1
LdL - LP1 - lez 11 - ver 6 - aa Funzioni per il trattamento di stringhe /2 : esempio/a #include int main(){ char x[]="Ciao"; char y[10], z[3]; strcpy(y,x); printf("stringa in x = %s, stringa in y = %s\n",x,y); strncpy(z,x,2); z[2]='\0'; printf("stringa in z = %s\n",z); return 0;}
LdL - LP1 - lez 11 - ver 6 - aa Funzioni per il trattamento di stringhe /2 : esempio/a stringa in x = Ciao stringa in y = Ciao stringa in z = Ci Premere un tasto per continuare...
LdL - LP1 - lez 11 - ver 6 - aa Funzioni per il trattamento di stringhe /2 : esempio /b #include int main() { char s1[20]="Happy "; char s2[]= "New Year "; char s3[]= " "; printf("s1 = %s\ns2 = %s\n", s1, s2); strcat(s1,s2); printf("s1+s2=%s\n",s1); strncat(s3,s1,6); printf("s3+s1(3 car) =%s\n", s3); strcat(s3,s1); printf("s3+s1=%s\n", s3); return 0;}
LdL - LP1 - lez 11 - ver 6 - aa Funzioni per il trattamento di stringhe /2 : esempio /b s1 = Happy s2 = New Year s1+s2=Happy New Year s3+s1(3 car) = Hap s3+s1= HapHappy New Year Premere un tasto per continuare...
LdL - LP1 - lez 11 - ver 6 - aa int strcmp( const char *s1, const char *s2) confronta le stringhe s1 ed s2; se s1 s2 dà un numero positivo (ordine lessicografico) int strncmp( const char *s1, const char *s2, size_t n) confronta i primi n caratteri di s1 con i primi n caratteri di s2; il valore restituito segue le regole date sopra Funzioni per il trattamento di stringhe nella libreria /3
LdL - LP1 - lez 11 - ver 6 - aa Array di Puntatori: array di stringhe Inizializzazione, Scansione per Stringhe Immissione di un testo su più righe fissate Passaggio di un array di puntatori ad una funzione
LdL - LP1 - lez 11 - ver 6 - aa Array di Puntatori: array di stringhe #include int main() { char *parole[3] = {“oggi”,”domani”,”mai”}; int i; for(i=0;i<3;++i) printf(“%s”, parole[i]); return 0; } Inizializzazione, Scansione per Stringhe
LdL - LP1 - lez 11 - ver 6 - aa Array di Puntatori: array di stringhe Immissione di un testo su più righe fissate #include #define NUM_RIGHE 3 int main() { char *parole[NUM_RIGHE], stringa[80+1]; int i; for(i=0;i<NUM_RIGHE;++i) { gets(stringa); parole[i]=(char *)malloc((strlen(stringa)+1)* sizeof(char)); if(parole[i]==NULL) exit(EXIT_FAILURE); strcpy(parole[i], stringa); } for(i=0;i<NUM_RIGHE;++i) printf("%d: %s\n",i,parole[i]); return 0;} exit(EXIT_SUCCESS) terminazione con successo exit(EXIT_FAILURE) terminazione con fallimento oggi sono andato al mare 0: oggi sono 1: andato al 2: mare Premere un tasto per continuare...
LdL - LP1 - lez 11 - ver 6 - aa Array di Puntatori: array di stringhe #include void visualizza(char *[], int); int main() { char *parole[3] = {“oggi”,”domani”,”m ai”}; visualizza(parole, 3); return 0; } Passaggio di un array di puntatori ad una funzione void visualizza(char *pPtr[], int n) { int i; for(i=0;i<n;++i) printf(“%s\n”, pPtr [i]); return ;} oggi domani mai Premere un tasto per continuare...
LdL - LP1 - lez 11 - ver 6 - aa Array di Puntatori: ultimo esempio /1 La dichiarazione char *semi[4]={“cuori”, “picche”, “quadri”, “fiori”} ha il seguente significato: semi[4] indica un array di 4 elementi char * indica che ogni elemento dell’array sarà del tipo “puntatore a char”, quindi … ognuno degli elementi sarà immagazzinato in memoria come una stringa di caratteri terminata da ‘\0’. Per accedere a questi elementi, basta sapere che: semi[0] punta a (contiene l’indirizzo della locazione di memoria con) ‘c’ (di cuori), semi[1] a ‘p’ (di picche), semi[2] a ‘q’ di (di quadri), semi[3] a ‘f’ (di fiori). ++semi[0]: permette di avanzare lungo “cuori” ++semi[1]: permette di avanzare lungo “picche” ++semi[2]: permette di avanzare lungo “quadri” ++semi[3]: permette di avanzare lungo “fiori”
LdL - LP1 - lez 11 - ver 6 - aa Array di Puntatori: ultimo esempio /2 Input, Scansione per Carattere per giovedi’ Progettare e implementare un programma che accetti a tempo di esecuzione l’array seguente {“cuori”, “picche”, “quadri”, “fiori”}, quindi visualizzi l’array carattere per carattere, segnalando la fine di ogni stringa Progettare e implementare un programma che accetti a tempo di esecuzione l’array seguente {“cuori”, “picche”, “quadri”, “fiori”}, quindi visualizzi l’array carattere per carattere, segnalando la fine di ogni stringa, mediante un’opportuna funzione
LdL - LP1 - lez 11 - ver 6 - aa Array di Puntatori: ultimo esempio /3 Provate, allenatevi, riprovate, riallenatevi Linguaggi di Programmazione 1 Appello, 26 novembre 2004, ore 14, aule C31 (matr. 6), C38 (matr. 7) prof. Luigi Di Lascio 3) Progetta ed implementa in C una funzione, i cui parametri di input sono un array di n parole della lingua italiana e due caratteri dell’alfabeto della lingua italiana, che calcoli la frequenza dei due caratteri nell’array (p. 15)
LdL - LP1 - lez 11 - ver 6 - aa Array di Puntatori: aiuto Provate, allenatevi, riprovate, riallenatevi #include int main() { char *semi[4]={"cuori", "picche", "quadri", "fiori"}; printf("%c\n",*semi[0]); /*c*/ printf("%c\n",*(semi[0]+2)); /*o*/ printf("%c\n",*semi[1]); /*p*/ printf("%c\n",*(semi[1]+1)); /*i*/ printf("%c\n",*semi[2]); /*q*/ printf("%c\n",*(semi[2]+3)); /*d*/ printf("%c\n",*semi[3]); /*f*/ printf("%c\n",*(semi[3]+1)); /*i*/ return 0;}