06 1 array_stringhe_typedef
-
Upload
piero-fraternali -
Category
Technology
-
view
331 -
download
2
description
Transcript of 06 1 array_stringhe_typedef
Fondamenti di Informatica
Array, stringhe e gestione delle sequenze
1
La memorizzazione di sequenze
• Molti problemi richiedono la memorizzazione di sequenze di dati
• Esempio: stampare al contrario una parola fornita dall'utente– Solo quando l'ultimo carattere è stato inserito è possibile
procedere alla stampa– Ma nel frattempo si devono conservare i caratteri
precedenti• I linguaggi di programmazione mettono a disposizione
un costruttore di tipi complessi che permette di definire sequenze di valori dello stesso tipo
• Due tipi principali di costruttori:– Sequenze di lunghezza fissa (array)– Sequenze di lunghezza variabile (vector, string)
2
3
• Gruppo di celle consecutive– Stesso nome e tipo
• Per riferirsi a un elemento, si specificano:– Il nome dell’array– La posizione dell’elemento (indice)
• Formato: nomearray[posizione]– Il primo elemento ha indice 0– L’n° elemento dell’array v è v[n-1]
v[6]
-45
6
0
72
1543
-89
0
62
-3
1
6453
78
dichiarazione
v[0]
v[1]
v[2]
v[3]
v[11]
v[10]
v[9]
v[8]
v[7]
v[5]
v[4]
posizione elemento
int v[12];nome array
Gli array
Il costruttore di tipo array
• Array: sequenza di elementi, omogenei, accessibili individualmente mediante un indice– char parola[12];
• È un array di 12 elementi di tipo char, vale a dire un vettore di 12 caratteri
• La lunghezza dell’array è assegnata nella dichiarazione e inizializzazione dell'array– La lunghezza dell’array fa parte del tipo– char parolaCorta[10]; – char parolaLunga[100]; hanno tipi diversi
• La dimensione degli array deve essere un'espressione costante, determinabile dal compilatore, che alloca la memoria necessaria all’intero array
5
• Ogni elemento della sequenza è individuato mediante un indice con valore da 0 a N-1 (dove N è la dimensione dell’array)
• L’accesso avviene mediante l’operatore []Esempioint v[100];. . .v[3]=0; assegna il valore 0 al 4° elemento dell’array
• N.B. l’accesso di un elemento al di fuori dei limiti (v[i] con i >= 100) produce un errore e il comportamento del programma è indefinito
Accesso agli elementi di un array
Gestione della memoria
• int a[100];– Si alloca spazio per 100 elementi interi, a partire
da un certo indirizzo di memoria, per questo• la dimensione deve essere nota al compilatore
• deve essere una espressione costante
• Per accedere all' i-esimo elemento di a– Si calcola l'indice i (può essere un'espressione)
– all’indirizzo della prima cella di a si somma il numero di celle pari allo spazio occupato da i elementi
• Si ottiene così l'indirizzo dell'elemento cercato
Dichiarazione di un array
• Attenzione all'uso di espressioni costanti per le dimensioni
unsigned cnt = 42; // not a constant expressionconstexpr unsigned sz = 42; // constant expression// (oppure: const unsigned sz = 42;) int arr[10]; // ok array of ten intsint bad[cnt]; // error: cnt not constant expression
• Alcuni compilatori ammettono l’uso di variabili nella dichiarazione delle dimensioni di un array
• Caratteristica dipendente dal compilatore: meglio evitare
7
8
• Sintassi compatta (list initialization):int n[5] {1, 2, 3, 4, 5};
– Inizializzazione parziale: gli elementi mancanti sono posti al valore di default (0)
int n[5] {13}; gli ultimi 4 elementi sono posti a 0– Specificare troppi elementi è un errore di sintassi
• Se la lunghezza dell’array è omessa, gli inizializzatori la determinano:
int n[] {5, 47, 2, 0, 24};è equivalente a:
int n[5] {5, 47, 2, 0, 24};– In tal caso la dimensione è inferita automaticamente, e si
avranno 5 elementi nell’array (con indici che variano tra 0 e 4)
Inizializzazione di un array
Inizializzazione esplicita
• Array di tipi integral (ma non char)const unsigned sz = 3;int ia1[sz] = {0,1,2}; // array of three ints with values 0, 1, 2int a2[] = {0, 1, 2}; // an array of dimension 3int a3[5] = {0, 1, 2}; // equivalent to a3[] = {0, 1, 2, 0, 0}int a5[2] = {0,1,2}; // error: too many initializers
• Array di char– Sono trattati in modo speciale, per compatibilità con il concetto di
stringa del linguaggio Cchar a1[] = {'C', '+', '+'}; // list initialization, no nullchar a2[] = {'C', '+', '+', '\0'}; // list initialization, explicit nullchar a3[] = "C++"; // null terminator added automaticallyconst char a4[6] = "Daniel"; // error: no space for the null!
• Dimensione a1 = 3; Dimensione di a2 e a3 = 4• La definizione di a4 è errata• Ricordare sempre che le stringhe alla C hanno il
terminatore '\0' che occupa un carattere in più
9
Inizializzazione per copia e assegnamento
• Il tipo array non supporta la copia diretta dei valori– Né nell'assegnamento– Né nell'inizializzazione
int a[] = {0, 1, 2}; // array of three ints
int a2[] = a; // error: cannot init one array with another
a2 = a; // error: cannot assign one array to another
10
11
• Si opera sui singoli elementi, uno per volta
• Non è possibile operare sull’intero array, agendo su tutti gli elementi simultaneamente
/ come ricopiare array1 in array2 /int array1[10], array2[10]; . . .array2 array1; / ERRATO / . . .for (int i 0; i 10; ++i)
array2[i] array1[i]; / CORRETTO /
Copia di array
Inizializzazione per default
• Gli elementi di un array non inizializzati esplicitamente sono inizializzati per default
• Se la dichiarazione dell'array NON è contenuta in una funzione il valore degli elementi è il default per il loro tipo (0)
• Se la dichiarazione dell'array è contenuta in una funzione il valore degli elementi non è definito
12
Uso degli elementi
• Gli elementi di un array sono normali variabili:– vett[0] 3;– cout << vett[0];– > 3– cin >> vett[1];– > 17 vett[1] assume valore 17
• Si possono usare espressioni come indici:– se x 3, y=7 e z=4– vett[52] è uguale a vett[3]– ed è uguale a vett[x] – ed è uguale a vett[y-z]
14
• Dichiarazione del vettore:int a[20];
• Riempimento del vettore:for (int i = 0; i < 20; ++i)
a[i] = 0;
• Lettura da terminale dei valori:for (int i = 0; i < 20; ++i) {
cout << "Scrivi un intero: " << endl; cin >> a[i];}
Esempi sugli array
15
• Ricerca del massimo:max = a[0];for (int i = 1; i < 20; ++i)
if (a[i] > max)max = a[i];
• Calcolo della media:media = 0;for (i = 0; i <20; ++i)
media += a[i];media = media / 20.0; // attenzione alle
// conversioni di tipo
Esempi sugli array
16
• Calcolo di massimo, minimo e media di un vettore– È sufficiente una sola scansione del vettore (un solo ciclo)
int main() {const int size = 10;int a[size] = {1,2,3,4,5,6,7,8,9,10};float media = a[0];int max = a[0], min = a[0];for (int i = 1; i < size; ++i) {
media += a[i];if (a[i] > max)
max = a[i];if (a[i] < min)
min = a[i];}media /= size;cout << "Media: " << media << " Min: " << min
<< " Max: " << max << endl;return 0;
}
Esempi sugli array
17
Problemi di elaborazione delle sequenze
• Invertire una sequenza di tot (10) interi introdotta dall’utente
• Cosa serve?– Un array di tot caratteri– Un contatore che scorra sull'array
• Flusso di controllo?– Leggi la sequenza e mettila nell'array – Stampa il contenuto dell'array a partire dal
fondo fino all'inizio
Codice sorgente: versione base
int main() { const int size = 10; char buffer[size]; int i=0; while (i<size){ cout << "Prossimo carattere: " << endl; cin >> buffer[i]; ++i; } --i; // perché serve? while (i>=0){ cout << buffer[i] << endl; --i; }
return 0;}
Sequenza di lunghezza variabile, ma limitata
int main() {
const int maxSize = 10;
char buffer[maxSize];
int size, i = 0;
cout << "Inserire la lunghezza della sequenza: " << endl;
cin >> size;
if (size > maxSize)
cout << "Sequenza troppo lunga, max = " << maxSize << endl;
else {
while (i < size) {
cout << "Prossimo carattere: " << endl;
cin >> buffer[i];
++i;
}
--i;
while (i >= 0) {
cout << buffer[i] << endl;
--i;
}
}
return 0;
}
19
Sequenza delimitata da end-of-fileint main() { // uso ctrl-z come sentinella
const int maxSize = 10;char buffer[maxSize];int i = 0;cout << "Prossimo carattere, ctrl-z per finire: " << endl;while (i < maxSize && cin >> buffer[i]) {
cout << "Prossimo carattere, ctrl-z per finire: " << endl;++i;
}--i;while (i >= 0) {
cout << buffer[i] << endl;--i;
}
return 0;}
20
Analizzare le condizioni di uscita dal primo ciclo
Stampa di un istogramma
• Data una serie di valori interi, stampare un istogramma dei valori a barre orizzontali
• Cosa serve?– Un array contenente la serie– Un contatore per iterare sulla serie
• Flusso– Per ogni elemento della serie– Stampa un numero di caratteri pari al valore
dell'elemento
21
22
Element Value Histogram
0 19 ******************* 1 3 *** 2 15 *************** 3 7 ******* 4 11 *********** 5 9 ********* 6 13 ************* 7 5 ***** 8 17 ***************** 9 1 *
Output richiesto
Codice sorgente
int main() {
const int size = 10;
int arr[size] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
for (int i = 0; i < size; ++i) {
for (int j = 1; j <= arr[i]; ++j)
cout << "*";
cout << '\n';
}
return 0;
}
23
24
Esercizio (semplice, ma apparentemente difficile)
• Si scriva un programma che visualizzi gli istogrammi verticalmente:
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 19 3 15 7 11 9 13 5 17 1 0 1 2 3 4 5 6 7 8 9
Progettazione
• Cosa serve?– Un array contenente la serie– Un contatore per iterare sulla serie
• Flusso– Calcola l'altezza della barra più alta (cioè il
massimo valore dell'array)– Altezza corrente = max– Per ogni riga j da max a 1
• Per ogni colonna i da 1 a size– Se array[i] >= j stampa * altrimenti stampa uno spazio– Decrementa j
– Stampa righe con valori e indici
25
Codice sorgente#include <iostream>
#include <iomanip>
using namespace std;
int main() {
int arr[size] = { 1, 4, 3, 10, 5, 6, 7, 8, 9, 2 };
int max = arr[0];
cout << "Istogramma Verticale" << endl;
for (int k = 1; k < size; ++k) // trovo il massimo
if (arr[k] > max)
max = arr[k];
for (int riga = max; riga >= 1; --riga) { // per ogni riga da max a 1
for (int col = 0; col < size; ++col) // per ogni colonna da 1 a size
if (arr[col] >= riga)
cout << setw(3) << "*";
else
cout << setw(3) << " ";
cout << '\n';
}
for (int i = 0; i < size; ++i) {
cout << setw(3) << i;
}
cout << '\n';
for (int i = 0; i < size; ++i) {
cout << setw(3) << arr[i];
}
return 0;
}
Output formattato
• La librerie iostream e iomanip contengono la definizione di vari manipolatori
• Un manipolatore assomiglia a una variabile stampabile ma produce un cambio nel modo in cui l'output viene presentato
• I manipolatori definiscono– La modalità di rappresentazione dei valori
numerici, la precisione– L'incolonnamento dell'output
• setw(int): definisce l'ampiezza in numero di colonne del successivo comando di output
• left, right giustificano a sx, dx l'output
27
Manipolatori
28
iostream
iomanip
Ricerca e ordinamento
• Sono due tra le operazioni più importanti sulle sequenze– Dato un elemento verificare se esiste nella
sequenza e restituire la posizione – Data una sequenza, rielaborarla in modo che
gli elementi risultino ordinati
• Oggetto di molto studio, per cui esistono molti algoritmi diversi
• Usate come esempio per spiegare e comparare la complessità degli algoritmi
29
30
Ricerca sequenziale in un arrayconst int size=10;
int main() { int dato, posizione= -1; int array[size] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; cout << "Inserisci il numero da ricercare: " << endl; cin >> dato; int i; // riusato al di fuori del ciclo for! for (i = 0; i < size; ++i) // riscrevetelo con ciclo while if (array[i] == dato) { posizione = i; break; // interrompe il ciclo } if (posizione != -1) cout << "Risultato trovato all'indice: " << i << endl; else cout << "Risultato non presente" << endl; return 0;}
31
Ricerca binaria in un arrayint main() {
int dato, posizione;bool trovato = false;int array[size] = { -6, -2, -1, 4, 5, 6, 7, 8, 9, 10 };cout << "Inserisci il numero da ricercare: " << endl;cin >> dato;int low = 0, high = size - 1, mid;while (low <= high && !trovato) {
mid = (low + high) / 2;if (array[mid] == dato) {
trovato = true;posizione = mid;
} else if (array[mid] > dato)high = mid - 1;
else// array[mid] < datolow = mid + 1;
}if (trovato)
cout << "Risultato trovato all'indice: " << posizione << endl;else
cout << "Risultato non presente" << endl;return 0;
}
Ordinare un array
• Data un vettore V[n] permutare i suoi elementi in modo che risulti ordinato in senso crescente:V[0] <= V[1] <= V[2] <= … <= V[n-1]
• Esistono diversi algoritmi– Gli algoritmi vengono valutati in base alle loro
prestazioni nel caso peggiore– Per la caratterizzazione delle prestazioni nel
caso peggiore si utilizza il concetto di complessità
Bubblesort
• Confronta i primi due elementi e se non sono ordinati si scambia– Confronta il secondo e il terzo e se non sono ordinati li scambia
… e così via sino a confrontare penultimo e ultimo elemento– Dopo aver scandito una prima volta tutto il vettore si è sicuri che
l’elemento maggiore è nella cella più a destra, • Si comincia un nuovo ciclo che confronta ancora a due a
due le celle dalla prima all’ultima. • Se n è il numero di elementi del vettore si itera questo
processo di scansione per n-1 volte • Alla fine il vettore risulta ordinato• Algoritmo semplice ma inefficiente
– Numero di scambi proporzionale a N2 (N dimensione dell’array)• Ci sono algoritmi più veloci che richiedono l’uso della
ricorsione
Codice sorgenteint main() {
int aux, array[size];
cout << "Inserire gli elementi del vettore:" << endl;for (int k = 0; k < size; ++k)
cin >> array[k];
for (int i = 0; i < size - 1; ++i) {for (int j = 0; j < size - 1 - i; ++j) {
if (array[j] > array[j + 1]) { // se l'ordine è invertitoaux = array[j + 1]; // scambia elementi
consecutiviarray[j + 1] = array[j];array[j] = aux;
}}
}cout << "Il vettore ordinato e’: " << endl;for (int h = 0; h < size; ++h)
cout << array[h] << endl;
return 0;}
Check this out
• https://www.youtube.com/watch?v=INHF_5RIxTE
Sequenze a lunghezza variabile
• Gli array memorizzano sequenze di lunghezza predefinita
• Farne uso per sequenze di lunghezza non nota o variabile porta al sovra-dimensionamento con conseguente spreco di memoria
• Esistono tipi di dati C++ più idonei a rappresentare sequenze di lunghezza variabile– Stringhe: sequenze di caratteri– Vettori: sequenze di elementi di un qualunque altro
tipo
La libreria string
• Sequenza di caratteri di lunghezza variabile• Il tipo string è definito in una libreria• Per utilizzarlo:
#include <string>
using std::string;
• Lo standard C++ 11 definisce le operazioni effettuabili, ma anche i requisiti di prestazione
• L’uso del tipo string è perciò piuttosto efficiente• Il tipo string è un tipo class (class type)
Definizione e inizializzazione
• Il tipo string ammette varie forme di inizializzazione
• Esempistring s1; // default initialization; s1 is the empty string
string s2 = s1; // s2 is a copy of s1
string s3 = "hiya"; // s3 is a copy of the string literal
string s4(10, 'c'); // s4 is cccccccccc
Inizializzazione per copia
• Quando l’inizializzazione fa uso esplicito dell’operatore di assegnamento ( = ), si dice per copia – l’oggetto di sinistra riceve come valore iniziale una copia
dell’oggetto di destra
• Altrimenti l’inizializzazione è gestita dal compilatore e si dice diretta
string s5 = "hiya"; // copy initializationstring s6("hiya"); // direct initializationstring s7(10, 'c'); // direct initialization; s7 is cccccccccc
• La forma
string s8 = string(10, 'c'); // copy initialization; s8 is cccccccccc
• Equivale a string temp(10, 'c'); // temp is ccccccccccstring s8 = temp; // copy temp into s8
• Attenzione: con la modalità diretta il compilatore può creare oggetti temporanei, se necessari per l’inizializzazione
Operazioni del tipo string
• La definizione del tipo string comprende le operazioni effettuabili su variabili di quel tipo
• Le operazioni ammissibili sono:– is = input stream– os = output stream
Uso del tipo string
• Grazie al meccanismo delle classi il tipo string si usa (quasi) come se fosse un tipo predefinito
• Lettura e scrittura• La lettura scarta spazi/tab/a capi iniziali e si
arresta al primo spazioint main(){ string s; // empty string cin >> s; // read a whitespace-separated string into s cout << s << endl; // write s to the output return 0;}
• NB: se si inserisce “Hello world” la stampa produce Hello
Lettura ripetuta di stringhe
• Simile alla lettura ripetuta di tipi predefinitiint main() {
string word;while (cin >> word) // read until end-of-file
cout << word << endl; // write each word // followed by a new linecout << "Thank you for playing !" << endl;return 0;
}
• Provare ad eseguirlo per familiarizzare con la gestione (non ovvia) dell’input di tipo stringa
• cin >> word si arresta al primo spazio bianco e copia la parola precedente in word, ma l'input viene comunicato al programma a seguito dell'invio di un "a capo"
Lettura per linee
• A volte è nbecessario leggere anche gli spazi • getline(istream, string)
– Legge lo stream di input fino al primo carattere di a capo (newline)
– Copia il contenuto (escluso newline) nella stringa– Se il primo carattere letto è newline, la stringa è vuotaint main() {string line;
// read a line at a time until end-of-linewhile (getline(cin, line)) cout << line << endl; // emit NL & flushreturn 0;
}
• Verificare la differenza !
cin.ignore(), >>, getline()
• http://stackoverflow.com/questions/6649852/getline-not-working-properly-what-could-be-the-reasons
• http://stackoverflow.com/questions/12691316/getline-does-not-work-if-used-after-some-inputs
44
Le dimensioni di una stringa
• Un valore di tipo string per definizione non ha una lunghezza prefissata
• La libreria offre funzioni per:– Verificare se è vuota (empty())– Determinare la lunghezza (size())
• La funzione empty() torna un valore di tipo bool• La funzione size() torna un valore di un tipo speciale string::size_type– In questo modo non si deve scegliere quale tipo integral usare
per rappresentare la dimensione ci pensa il compilatore– Per brevità si può lasciare al compilatore l’incombenza di
definire il tipo nella dichiarazioni di variabili di tipo “lunghezza”– auto lung = line.size();– auto tipo stabilito dal compilatore – Poi però è meglio non usare tipi int in espressioni che
comprendano lung
Comparare stringhe
• La libreria string mette a disposizione gli operatori relazionali == != < > <= >=
• La comparazione tra s1 e s2 avviene così1. Se s1 è più corta di s2 e tutti i caratteri di s1 sono
uguali ai corrispondenti di s2 s1<s22. Se due caratteri in posizione corrispondente di s1 e
s2 differiscono, il risultato coincide con quello della comparazione della prima coppia di caratteri corrispondenti diversi
string str1 = "Hello";string str2= "Hello World";string str3 = "Hiya";
– str1 < str2 per la regola 1– str2< str3 per la regola 2
46
Assegnamento e concatenazione
• A differenza degli array, la libreria string supporta l'operatore di assegnamento– Esempio di tipo di alto livello, che nasconde i dettagli realizzativi
interni di un operatore e ne consente l'uso come per i tipi predefiniti
string st1="Hello", st2;st1=st2; // assegnamento sostituisce il contenuto // di st1 con una
copia del contenuto di st2 // entrambe stringhe vuote
• L'operatore + concatena le stringhestring s1 = "hello, ", s2 = "world\n";string s3 = s1 + s2; // s3 is hello, world\n
• E' possibile concatenare una stringa anche con caratteri o costanti di tipo stringa, ma attenzione all'associatività del +:
string s4 = s1 + ", "; // ok: adding a string and a literalstring s5 = "hello" + ", "; // error: no string operandstring s6 = s1 + ", " + "world"; // ok: each + has a string operandstring s7 = "hello" + ", " + s2; // error: can't add string literals
47
Accesso agli elementi
• Esistono due notazioni per farlo
• Una simile a quella per l'array, mediante l'operatore []
• Come per gli array, l'uso di indicizzazione esplicita con [] richiede attenzione a non eccedere la dimensione della stringa
• Il C++ offre un metodo di accesso più "astratto", che evita l'uso di un indice numerico esplicito (range for)
48
Accesso in lettura#include <iostream>#include <string>#include <cctype> // contiene funzioni per il controllo del tipo dei caratteriusing namespace std;
int main() { string s("Hello World!!!!!"); decltype(s.size()) punct_cnt = 0; // let the compiler decide the type // punct_cnt assumes same type as s.size() for (decltype(s.size()) index = 0; index < s.size(); ++index) // for every char in s if (ispunct(s[index])) // if the character is punctuation
++punct_cnt; // increment the punctuation counter cout << punct_cnt << " punctuation characters in " << s << endl; return 0;}
•Conta i caratteri simbolo di punteggiatura•index != s.size() garantisce di non uscire dai limiti della stringa•funzione bool ispunct(char) della libreria cctype•decltype (C++11): si usa nelle dichiarazioni per introdurre una variabile dello stesso tipo di un'espressione (nel caso presente evitiamo così precisare il tipo integral delle dimensioni di una stringa)
49
Accesso in modifica
int main() {
string str("some string");
// uppercase and print the characters in str
cout << "Use of subscripting with strings" << endl;
for (decltype(str.size()) index = 0; // for every char in str
index < str.size(); ++index)
str[index] = toupper(str[index]);
cout << str << endl; // print the modified string
return 0;
}
•Converte i caratteri in maiuscoli•Usa la funzione char toupper(char) della libreria cctype
50
Le funzioni della libreria cctype
51
Iterazione con range for
• C++ 11 offre un nuovo costrutto (range for) per iterare sulle sequenze di lunghezza indefinita senza usare []for (declaration : expression) statement
• Expression denota un oggetto di tipo sequenza, declaration dichiara una variabile che assume in successione i valori degli elementi della sequenzastring str("some string");// print the characters in str one character to a linefor (auto c : str) // for every char in str cout << c << endl; // print the current character // followed by a newline
• La variabile c (cursore)–Ha tipo determinato dal compilatore, in questo caso char–Ad ogni iterazione contiene una copia del carattere corrente della stringa–Va bene anche char c: str, visto che il tipo degli elementi della sequenza è noto (char)
52
Accesso in lettura
• Anche con range for è possibile analizzare/modificare il contenuto di una stringa, es: conteggio dei simboli di punteggiatura
#include <iostream>#include <string>#include <cctype>using namespace std;int main() { string s("Hello World!!!"); decltype(s.size()) punct_cnt = 0; // punct_cnt assumes same type as s.size() for (auto c : s) // for every char in s if (ispunct(c)) // if the character is punctuation ++punct_cnt; // increment the punctuation counter cout << punct_cnt << " punctuation characters in "
<< s << endl;return 0;
}
53
Il costruttore di tipo reference &
• Una reference è un nome alternativo per una variabileint ival = 1024;int &refVal = ival; // refVal è sinonimo di ivalint &refVal2; // errore manca l'oggetto!!
• Quando si legge/modifica refVal si legge/modifica ival!
refVal = 2; // assegna 2 a … ivalint ii = refVal; // stesso che ii = ival
• Il tipo di refVal si dice "reference to int"• Le reference devono riferirsi a oggetti, non a literal• Il tipo dell'oggetto e della reference devono coincidere
int &refVal4 = 10; // error: initializer must be an objectdouble dval = 3.14;int &refVal5 = dval; // error: initializer must be an int object
54
Accesso in modifica
• Si può dichiarare il cursore come reference– Il cursore è un altro nome per l'elemento
corrente della stringa, non una sua copia!– Se si modifica il cursore si modifica l'elemento
della stringa– Convertiamo una stringa in maiuscolostring s("Hello World!!!"); // convert s to uppercasefor (auto &c : s) // for every char in sc = toupper(c); // c is a reference, the assignment // changes the char in scout << s << endl;
55
56
• Per compatibilità con il C, C++ supporta funzioni su array di caratteri che svolgono compiti simili a quelli della libreria string
• #include <cstring> include la versione C++ della libreria, corisponde a string.h del C– Meglio usare il tipo nativo C++ string
• Dichiarazione+inizializzazione di una stringa C:char stringa[] "word";
• Bisogna ricordarsi che il carattere nullo '\0' termina le stringhe– Perciò l’array stringa ha 5 elementi (non 4):
• Dichiarazione equivalente:char stringa[] {'w', 'o', 'r', 'd', '\0'};
drow \0
Le stringhe del C
57
char str1[32]; / str1 ha spazio per 32 char. /char str2[64]; / str2 ha spazio per 64 char. /
/ assegna a str1 la stringa "alfa" /strcpy(str1, "alfa"); / str1 contiene "alfa" /
/ copia str1 in str2 /strcpy(str2, str1); / str2 contiene "alfa" /
/ lunghezza di str1 /x = strlen(str1); / x assume valore 4 /
/ scrivi str1 su standard output /cout << str1; / scrive str1 su stdout /
/ leggi str1 da standard input /cin >> str1; / legge str1 da stdin /
Operazioni su stringhe C
58
• Inizializzazione e accesso ai singoli caratteri:
char stringa[] "word";stringa[3] è un’espressione di valore 'd'
• cin >> stringa;• Questa istruzione legge dall'input i caratteri fino a
quando trova il carattere “blank” (lo spazio), o l’invio• Perciò se in input si inserisce una stringa troppo lunga,
essa è memorizzata oltre la fine dell'array !!! Ed è un errore grave !!!
Problemi con le stringhe C
59
• E se non ci fosse la funzione strcpy()?– Assegneremmo sempre un carattere alla volta
char s1[N], s2[M];…
int i = 0;
while( i <= strlen(s2) && i < N ) {
s1[i] = s2[i];
++i;
}N.B. funziona correttamente se s2 è una stringa ben formata (terminata da ‘\0’) e s1 è sufficientemente grande (N >=
strlen(s2))
strcpy(s1, s2)
Confrontare due stringhe
• Una funzione apposita: strcmp(s1,s2)– restituisce un intero– confronta le due stringhe fino al terminatore ‘\0’
char str1[32], str2[64];int diverse; /*... acquisizione di valori per le stringhe ... (codice
omesso)*/ris = strcmp(str1, str2);if (ris == 0) cout << "UGUALI\n";else if ( ris < 0 ) cout << str1 << "MINORE DI" << str2;else cout << str1 << "MAGGIORE DI" << str2;
• Da confrontare con l'uso diretto degli operatori relazionali nel tipo string
I "livelli di astrazione" del C++
• I linguaggi di programmazione hanno diversi livelli di astrazione dall'architettura del calcolatore – Linguaggi di alto livello ( C, C++, Java..)– Assembler– Linguaggio macchina
• Ma anche all'interno di un linguaggio di alto livello si possono distinguere diversi ulteriori livelli di astrazione
• Il C++ è un buon esempio
61
Astrazione: confront0 string - array
Array• Simile alla struttura fisica della
memoria: insieme di celle contigue
• Dimensione prefissata• Simulazione della variabilità
mediante terminatore \0• Accesso mediante
indicizzazione esplicita• Assegnamento non definito• Operatori relazionali non
definiti• Errori di fuoriuscita dai limiti e
assenza del terminatore
String• Sequenza di elementi• Dimensione non predefinita• Mascheramento dei dettagli
interni• Accesso mediante cursore,
compatibilità con l'accesso per indicizzazione
• Assegnamento e operatori relazionali predefiniti nel tipo
• Protezione da errori di fuoriuscita
• Terminatore non necessario
62
Typedef
• C e C++ mettono disposizione un meccanismo per definire "tipi nuovi": typdef
• Combinando typedef e costruttore di array:typedef char venticaratteri[20];• si introduce un nuovo tipo, venticaratteri, il tipo degli
array di 20 elementi di tipo char• La dichiarazioneventicaratteri nome, cognome;• usa venticaratteri come sinonimo di char[20]• Attenzione!!
– venticaratteri ha le stesse identiche proprietà e limitazioni di char[20]
– È solo una scrittura più leggibile per il programmatore, che rende più facile modificare i programmi (pe: per cambiare la dimensione del tipo, agendo su una sola definizione)