Compound types (CAP 4)
Transcript
Compound types (CAP 4)
Outline Arrays Strings Strutture Puntatori Outline Arrays Strings Strutture Puntatori Strutture Puntatori Outline Compound types (CAP 4) Gli Array Alberto Garfagnini Le Stringhe Università degli studi di Padova 24 Novembre 2010 Le Strutture I puntatori Outline Arrays Strings Strutture Puntatori Outline Arrays Gli Array • Tipo composito che può contenere diversi valori dello stesso tipo • Ogni valore è immagazzinato in un elemento separato dell’array • Il calcolatore mantiene tutti i valori in zone contigue di memoria Strings La creazione di Array • Creo un array con 4 elementi: • primo elemento seasons[0] • ... • ultimo elemento seasons[3] int seasons[4]; [0] [1] [2] [3] Sintassi di dichiarazione di un array Tipo di dato numero di elementi TypeName arrayName[arraySize]; nome dell’array Esempio short months[12]; float loans[20]; // crea un array con 12 // elementi di tipo short // 20 elementi di tipo float TypeName arrayName[arraySize] • arraySize può essere: una costante intera una espressione variabile const int size = 4; wine[size]; double wine[8*sizeof(int)]; ma NON è lecita una variabile il cui valore cambia run-time int dim = 3; double boxes[dim]; Outline Arrays Strings Strutture Puntatori // arrayone.cpp - Lavora con piccoli arrays di interi #include <iostream> int main( ) Output del programma: { Total yams: 8 using namespace std; Il pacchetto 2 costa 20 int yams[3]; Costo totale: 500 yams[0] = yams[1] = 2; Dimensione array: 12 bytes yams[2] = 4; Un elemento: 4 bytes int yamcost[3] = {20, 30, 100}; cout << "Total yams: " << yams[0]+yams[1]+yams[2] << endl; cout << "Il pacchetto " << yams[0] << " costa " << yamcost[0] << endl; int total_exp = yams[0]*yamcost[0] + yams[1]*yamcost[1] + yams[2]*yamcost[2]; cout << "Costo totale: " << total_exp << endl; Outline Arrays Strings Strutture Array: regole di inizializzazione • Si può inizializzare un array soltanto in fase di definizione. • Esistono varie regole: int cards[4] = {3,6,8,10}; Standard: tutti gli elementi specificati int Tips[4] = {3, 1}; Lista parziale: gli elementi non specificati sono posti uguale a zero char cards[] = {’H’,’u’,’u’}; ArraySize non specificata: il compilatore determina le dimensioni at compile-time cout << "Dimensione array: " << sizeof yams << " bytes" << endl; Inizializzazioni non permesse cout << "Un elemento: " << sizeof yams[0] << " bytes" << endl; return 0; Tips[4] = {1, 2, 3, 4}; Tips = cards; } Outline Arrays Strings Strutture Puntatori Outline Arrays Stringhe C-style • Sono array di char • L’ultimo carattere della stringa è il NULL byte ’\0’ (ASCII code: 0) char cat[] = {’a’,’b’,’c’,’\0’}; // a string. char dog[] = {’a’,’b’,’c’}; // not a string! • Il NULL byte serve per capire dove terminare la stringa // manca il tipo // No! Strings Strutture Produce cout << " cat[] : " << cat << endl; cat[] : abc Il codice Produce cout << " dog[] : " << dog << endl; dog[] : abc@úÿÿÿ • cout continua a interpretare i byte in memoria come char fino al primo NULL byte che incontra Puntatori Stringhe: utilizzo della memoria • Modo più conveniente per inizializzare una stringa: char bird[10] = "Robin"; char fish[] = "Salmon"; • Le stringhe costanti includono automaticamente un NULL byte per terminare la stringa bird[0] Il codice Puntatori R bird[9] o b i n \0 \0 \0 \0 \0 aggiunto auto- aggiunti in fase maticamente di inizializzazione S fish[0] a l m o n \0 fish[6] Outline Arrays Strings Strutture Puntatori Outline Arrays Inizializzazione di Stringhe Strings Strutture Puntatori Es: utilizzo di stringhe come array di char // strings.cpp - C-strings #include <iostream> #include <cstring> Una stringa costante non è equivalente ad un carattere costante Come ti chiami? Luca Ciao Luca Il tuo nome ha 4 caratteri int main( ) { using namespace std; const int Size = 15; char nome[Size]; char bird = ’R’; // corretto • Assegna correttamente alla variabile bird, il carattere costante ’R’ Come ti chiami? Luca Corti Ciao Luca Il tuo nome ha 4 caratteri char fish = "R"; // illegale • cin può essere utilizzato per • "R" rappresenta una stringa costante: cout cin cout cout << "Come ti chiami >> nome; << "Ciao " << nome << "Il tuo nome ha << strlen( nome ) << " caratteri."<< return 0; è composta da due caratteri: ’R’ e ’\0’ char insect[] = "R"; // corretto // array di 2 caratteri • "R" indica l’indirizzo di memoria dove è immagazzinata la stringa ? "; << endl; " endl; } acquisire stringhe, ma ignora tutti i caratteri whitespace che precedono il testo (spazi, tabs o caratteri newline) ferma la lettura al primo carattere whitespace successivo • strlen( ) ritorna la dimensione della stringa immagazzinata nell’array (esclude nel computo il NULL character) Outline Arrays Strings Strutture Puntatori Es: lettura di più stringhe #include <iostream> int main( ) { using namespace std; const int Size = 25; char nome[Size], nick[Size]; cout << "Come ti chiami ? "; cin >> nome; cout << "Nickname ? "; cin >> nick; cout << "Ciao " << nome << endl; << "Il tuo nickname e’: " << nick << endl; return 0; } Luca\0 nome Corti input buffer Corti\0 Strings Strutture Puntatori • il C++ fornisce un metodo per cin, cin.getline( ) • permette di acquisire una linea intera inclusi i caratteri di whitespace all’inzio e in mezzo al testo, fino al carattere di terminazione new-line const int SIZE = 80; char name[SIZE], city[SIZE]; cout << "Inserire un nome: "; cin.getline( name, SIZE ); cout << "Inserire una citta’: "; cin.getline( city, SIZE ); cout << "Ciao: " << name << endl; cout << "Abiti a: " << city << endl; nick • cin utilizza whitespace (space | tab | newline) per delimitare una stringa: • legge la prima stringa e la inserisce nella variabile nome • la seconda stringa rimane nell’input buffer e viene incamerata dalla successiva chiamata a cin Arrays Line-Oriented input with getline( ) Come ti chiami? Luca Corti Nickname ? Ciao Luca Il tuo nickname e’ Corti Luca Outline Inserire un nome: John Doe Inserire una citta’: New York Ciao: John Doe Abiti a : New York Outline Arrays Strings Strutture Puntatori Outline Line-Oriented input with get() Arrays Strings Strutture Puntatori Line-Oriented input with get( ): example • La classe istream definisce il metodo, get( ), con diverse forme. Eccone alcune (dal file header istream) • int get( ); Extracts a character from the stream and returns its value (casted to an integer). • istream & get( char * c, streamsize n); Extracts characters from the stream and stores them as a C-string into the array beginning at s. Characters are extracted until either (n - 1) characters have been extracted or the delimiting character ’\n’ is found. If the ’\n’ character is found, it is not extracted from the input sequence and remains as the next character to be extracted. #include <iostream> int main() { const int SIZE = 80; char name[SIZE]; cout << "Inserire un nome: "; cin.get( name, SIZE ); cin.get( ); Inserire un nome: John Doe Inserire una citta’: New York Ciao: John Doe Abiti a : New York char city[SIZE]; cout << "Inserire una citta’: "; cin.get( city, SIZE ).get( ); • istream & get( char * c, streamsize n, char delim); Same as above, except that the delimiting character is the one specified in delim instead of ’\n’. cout << "Ciao: " << name << endl; cout << "Abiti a: " << city << endl; } • una possibilità è chiamare cin.get(char *, streamsize) e successivamente cin.get( ) per rimuovere il carattere di fine linea. • È possibile concatenare due member functions: cin.get( city, SIZE ) ritorna l’oggetto cin che a sua volta invoca get( ) Outline Arrays Strings Strutture Puntatori La funzione cin.get( char ) • A volte è comodo leggere un solo carattere dalla tastiera • Utilizzando char ch; cin >> ch non è possibile inserire uno <spazio> o il solo carattere ENTER. • Il metodo cin.get( char c ) legge un qualsiasi carattere, inclusi i caratteri di whitespace char ch; cout << "Press ANY KEY to continue"; cin.get( ch ); cout << "Process restored" << endl; Press ANY KEY to continue [ENTER] Process restored Outline Arrays Strings Strutture Puntatori Input tra tipi diversi cout << "Quanti anni hai ? "; int eta; cin >> eta; cin >> eta; cin.get( ); cout << "Dove abiti ? "; char indirizzo[80]; cin.getline( indirizzo ); cout << "Riepilogo dati:" « endl; cout << "Eta’: " « eta « endl; cout << "Citta’: " « indirizzo « endl; Quanti anni hai? 18 Dove abiti ? Padova Riepilogo dati: Eta’ : 18 Citta’ : Padova Quanti anni hai? 18 Dove abiti ? Riepilogo dati: Eta’ : 18 Citta’ : • Non si riesce ad inserire l’indirizzo! • cin >> eta lascia il carattere \n nella input queue Outline Arrays Strings Strutture Puntatori Outline La classe string #include <string> • Inizializzazione: string str = "Chimica"; char c_string[] = "Fisica"; string str1 = c_string; // copio C-string • Si può usare cin per l’input: cin >> str; • E visualizzare contenuto con cout: " << str1; • È possibile accedere ai singoli caratteri della stringa con la notazione ad array: cout << "Carattere iniziale: Outline Arrays Strings Puntatori Operazione su stringhe: std::string vs char[] const int N = 132; char cstr1[N], cstr2[N]; string str1, str2, str3; • Copiamo una stringa C++ strings: • Semplice assegnazione: str2 = str1; C strings: • Funzione di libreria: Outline Arrays strcpy( cstr1, str3 = str1 + str2; //join str1 = str1 + str2; //append Strings Strutture Puntatori str1 += " bianca"; strcat( cs1, " nera" ); • Concateniamo due stringhe • Usiamo l’operatore +: Puntatori // strtype3.cpp - operazioni su stringhe #include <iostream> #include <string> // classe string #include <string> // definizioni per C-style strings int main( ) { using namespace std; char cs1[30], cs2[30] = "pantera"; string str1, str2 = "tigre"; str1 = str2; strcpy( cs1, cs2 ); cstr2 ); C++ strings: Strutture Dammi due animali feroci ? leone pantera Ecco le belve: giaguaro leone pantera Prima lettera di leone : l Prima lettera di pantera : p " << str[0]; Strutture Strings // string.cpp - Utilizzo classe string #include <iostream> #include <string> int main( ) { using namespace std; char ani_1[30] = "giaguaro", ani_2[30]; string str; cout << "Dammi due animali feroci ? "; cin >> ani_2 >> str cout << "Ecco le belve: "; cout << ani_1 << " " << ani_2 << " " str << endl; cout << "Prima lettera di "<< ani_1 << " : " ani_1[0] << endl; cout << "Prima lettera di "<< str << " : " str[0] « endl; return 0; } • È parte delle librerie standard del C++ (namespace std) • Le definizioni della classe sono nel file header string cout << "La mia materia preferita: Arrays int len_s = str1.size( ); int len_c = strlen( cs1 ); C strings: cout << "La stringa ¨ " << cs1 << "¨ ha " << len_c << " caratteri " << endl; • Funzione di libreria: La stringa "pantera nera" ha 12 caratteri strcat( cstr1, cstr2 ); cout << "La stringa ¨ " << str1 << "¨ ha " << len_s << " caratteri " << endl; return 0; } La stringa "tigre bianca" ha 12 caratteri Outline Arrays Strings Strutture Puntatori Outline string : la funzione getline( ) Arrays spazio sufficiente per contenere l’informazione char site[10] = "casa"; strcat( site, "di Aldo" ); // memory problem! string name, city; cout << "Inserire un nome: "; getline( cin, name ); cout << "Inserire una citta’: "; getline( cin, city ); cout << "Ciao: " << name << endl; cout << "Abiti a: " << city << endl; site[0] c a site[9] s a Inserire un nome: John Doe Inserire una citta’: New York Ciao: John Doe Abiti a : New York Strings Strutture Puntatori • Con le stringhe std::string non c’e’ bisogno di controllare che ci sia spazio a disposizione per lo storage • Utilizzando gli array di char bisogna controllare sempre che ci sia spazio sufficiente per contenere l’informazione char site[10] = "casa"; strncat( site, "di Aldo", 10 ); // + sicuro Outline a s a Arrays a d i c a s a \0 \0 d i A l d o \0 Strings A Strutture • Le strutture sono dei tipi composti, definibili dall’utente • possono contenere tipi di dati diversi tra loro • It’s a two-process step: 1. create the structure description define and label the different data types 2. instantiate a structure data object tag = name for the new type struct wine_bootle { char name[40]; int anno; double prezzo; }; l • Se la stringa da copiare è più lunga, aggiungere il NULL byte: site[9] = ’\0’; site[0] \0 Il tipo structure site[9] s \0 site[9] keyword a \0 • La stringa sconfina intaccando zone contigue di memoria Possibili errori con C-style strings (2) c \0 site[0] c site[0] Puntatori • Utilizzando gli array di char bisogna sempre controllare che ci sia whitespace all’inzio e in mezzo al testo: Arrays Strutture Possibili errori con C-style strings (1) • funzione analoga per le stringhe del C • permette di acquisire una linea intera inclusi i caratteri di Outline Strings struct members site[9] d i A \0 • wine_bottle a; crea un oggetto di tipo wine_bottle • tramite il l’operatore di appartenenza . si acccede agli elementi della struttura: • a.name, a.anno e a.prezzo Puntatori Outline Arrays Strings Strutture Puntatori Outline Arrays Strings Strutture Puntatori Structure properties #include <iostream> #include <cmath> Structures = User Defined Types struct complex { double re; double im; }; // A complex number // type definition complex x = {1.0, 2.0}, y; y = x; It is possible to 1. use the assignement operator (memberwise assignment) Program output int main( ) { using namespace std; z = 3 + 4.6i complex vec[2] = { {1.,2.}, {0.,2.} }; cout << vec[1].re; |z| = 5.49181 complex x = { 2.0, 1.1 }; complex y = { 1.0, 3.5 }; 2. define arrays of structures double real_part( complex x) { return x.re; } complex z; z.re = x.re + y.re; z.im = x.im + y.im; 3. pass structures to functions cout << " z = " << z.re << " + " << z.im << "i" << endl; cout << "|z| = " << sqrt(x.re*x.re + y.re*y.re) << endl; 4. define a function that returns a structure return 0; } Outline Arrays Strings Strutture Puntatori Outline Arrays complex unity( ) { complex a = {1.0, 1.0}; return a; } Strings L’operatore & Strutture I puntatori • Determina la locazione di memoria di una variabile che identifica un tipo semplice o composto • Sono un tipo speciale: contengono una locazione di memoria Esempio di programma: int donuts = 6; cout << "donuts: " << donuts; cout << "indirizzo: " << &donuts; double cups = 4.5; cout << "cups: " << cups; cout << "indirizzo: " << ∪︀ Output del programma: donuts: 6 indirizzo: 0xbf9afaa4; cups: 4.5 indirizzo: 0xbf9afa98; Sintassi tipo al quale punta typeName * nomePuntatore; nome del puntatore Esempi di puntatori (1) short * pin; double * misure; string * name; // punta a uno short // punta a un double // punta a una stringa Puntatori Outline Arrays Strings Strutture Puntatori Outline Arrays Esempio di utilizzo di puntatori (1) // punt.cpp - Utilizzo dei puntatori #include <iostream> int main( ) { using namespace std; double cup = 5.3; double * pd = & cup; cup: *pd: &pd: cup: Strings Strutture Puntatori Esempio di utilizzo di puntatori (2) // punt.cpp - Utilizzo dei puntatori #include <iostream> int main( ) size { size double cup = 5.3; size double * pd = & cup; size ... 5.3 &cup: 0xbf8f9160 5.3 pd: 0xbf8f9160 pd: 0xbf8f9160 0xbf8f915c 12.3 &cup: 0xbf8f9160 of of of of size of // creo un puntatore e lo inizializzo cup: 8 pd: 4 mug: 2 pi: 4 (long long *): 4 cout << "size of cup: " << sizeof cup << endl; cout << "size of pd: " << sizeof pd << endl; cout << "cup: " << cup << " &cup: " << &cup << endl; cout << "*pd: " << *pd << " pd: " << pd; cout << " &pd: " << &pd << endl; short mug = 7; cout << "size of mug: " << sizeof mug << endl; *pd = 12.3; cout << " cup: " << cup << " &cup: " << &cup << endl; short * pi = & mug; cout << "size of pi: return 0; " << sizeof pi << endl; cout << "size of (long long *): return 0; } " << sizeof (long long *) << endl; } Outline Arrays Strings Strutture Puntatori Outline Arrays Dichiarazione e inizializzazione di puntatori • Un puntatore contiene sempre una locazione di memoria: ⇒ occupa la stessa dimensione per tutti i tipi • Con l’operatore * davanti a un puntatore si accede al contenuto della zona di memoria a cui punta Strings Strutture Gli operatori new e delete • L’operatore new permette di allocare memoria all’interno di un programma durante l’esecuzione (run-time) • Sintassi: typeName * nomePuntatore = new typeName; Inizializzate sempre un puntatore prima di usarlo! • L’operatore delete libera la memoria allocata (da new) • Sintassi: Esempio long * d; cout << " d: " << *d = 7; // BOOM! int * pi = new int; // spazio per un intero double * pd = new double; // e per un double delete nomePuntatore; d; // random memory d : 0x8048819 Segmentation fault delete pi; // libera spazio dell’ intero delete pd; // e del double Puntatori Outline Arrays Strings Strutture Puntatori Outline Arrays Gli operatori new e delete per gli arrays Strings Strutture Puntatori Esempio : utilizzo di new con arrays • Con l’operatore new possiamo creare nuovi array con dimensioni // dynarr.cpp - New con arrays #include <iostream> int main( ) { using namespace std; cout << "Dimensione array: " << endl; int n; cin >> n; conosciute soltanto durante l’esecuzione • Sintassi: typeName * nomePuntatore = new typeName[size]; int * pi = new int[500]; // array di 500 int double * pd = new double[7]; // e di 7 double Dimensione array: 3 3.2 10.75 -23.2 la media è: -9.25 // Creo un array per contenere le n misure double * data = new double[n]; • L’operatore delete libera la memoria allocata (da new) double mean = 0.0; for (int i=0; i<n; i++) { cin >> data[i]; mean = (data[i] + i * mean) / (i + 1); } • Sintassi: delete [] nomePuntatore; delete [] pi; // libera spazio degli interi delete [] pd; // e dei double cout << "la media è: " << mean << endl; return 0; } Outline Arrays Strings Strutture Puntatori Outline Arrays Aritmetica dei puntatori Strings Strutture Differenza array/puntatori • Aggiungere una unità ad un puntatore significa incrementare di una unità la locazione di memoria alla quale punta • L’incremento tiene conto del numero di bytes occupati dal tipo del puntatore Puntatori a double -1.5 | -1.5 3.0 long double a[3] = {-1.5L, 3.0L, 5.5L}; 3.0 | -1.5 3.0 long double *pld = &a[0]; cout << *pld << " | " << a[0] << a[1] << endl; pld++; cout << *pld << " | " << a[0] << a[1] << endl; • ∃ una sottile differenza: 1. una variabile puntatore può assumere indirizzi differenti; 2. il nome di un array è un puntatore fissato (costante) • Le seguenti espressioni non sono valide const int N = 10; int a[N], *p; Puntatori a char char c[3] = {’A’,’B’,’C’}; char *pch = c; cout << *pch << c[0] << c[1] << endl; pch++; cout << *pch << c[0] << c[1] << endl; AAB BAB • Nome array ≡ locazione di memoria primo elemento ⇒ & a[0] ≡ a a = p; // ILLEGALE ++a; // ILLEGALE a += 2; // ILLEGALE Puntatori