06 1 array_stringhe_typedef

63
Fondamenti di Informatica Array, stringhe e gestione delle sequenze 1

description

 

Transcript of 06 1 array_stringhe_typedef

Page 1: 06 1 array_stringhe_typedef

Fondamenti di Informatica

Array, stringhe e gestione delle sequenze

1

Page 2: 06 1 array_stringhe_typedef

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

Page 3: 06 1 array_stringhe_typedef

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

Page 4: 06 1 array_stringhe_typedef

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

Page 5: 06 1 array_stringhe_typedef

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

Page 6: 06 1 array_stringhe_typedef

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

Page 7: 06 1 array_stringhe_typedef

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

Page 8: 06 1 array_stringhe_typedef

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

Page 9: 06 1 array_stringhe_typedef

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

Page 10: 06 1 array_stringhe_typedef

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

Page 11: 06 1 array_stringhe_typedef

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

Page 12: 06 1 array_stringhe_typedef

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

Page 13: 06 1 array_stringhe_typedef

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]

Page 14: 06 1 array_stringhe_typedef

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

Page 15: 06 1 array_stringhe_typedef

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

Page 16: 06 1 array_stringhe_typedef

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

Page 17: 06 1 array_stringhe_typedef

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

Page 18: 06 1 array_stringhe_typedef

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;}

Page 19: 06 1 array_stringhe_typedef

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

Page 20: 06 1 array_stringhe_typedef

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

Page 21: 06 1 array_stringhe_typedef

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

Page 22: 06 1 array_stringhe_typedef

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

Page 23: 06 1 array_stringhe_typedef

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

Page 24: 06 1 array_stringhe_typedef

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

Page 25: 06 1 array_stringhe_typedef

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

Page 26: 06 1 array_stringhe_typedef

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;

}

Page 27: 06 1 array_stringhe_typedef

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

Page 28: 06 1 array_stringhe_typedef

Manipolatori

28

iostream

iomanip

Page 29: 06 1 array_stringhe_typedef

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

Page 30: 06 1 array_stringhe_typedef

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;}

Page 31: 06 1 array_stringhe_typedef

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;

}

Page 32: 06 1 array_stringhe_typedef

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à

Page 33: 06 1 array_stringhe_typedef

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

Page 34: 06 1 array_stringhe_typedef

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;}

Page 35: 06 1 array_stringhe_typedef

Check this out

• https://www.youtube.com/watch?v=INHF_5RIxTE

Page 36: 06 1 array_stringhe_typedef

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

Page 37: 06 1 array_stringhe_typedef

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)

Page 38: 06 1 array_stringhe_typedef

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

Page 39: 06 1 array_stringhe_typedef

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

Page 40: 06 1 array_stringhe_typedef

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

Page 41: 06 1 array_stringhe_typedef

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

Page 42: 06 1 array_stringhe_typedef

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"

Page 43: 06 1 array_stringhe_typedef

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 !

Page 44: 06 1 array_stringhe_typedef

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

Page 45: 06 1 array_stringhe_typedef

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

Page 46: 06 1 array_stringhe_typedef

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

Page 47: 06 1 array_stringhe_typedef

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

Page 48: 06 1 array_stringhe_typedef

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

Page 49: 06 1 array_stringhe_typedef

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

Page 50: 06 1 array_stringhe_typedef

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

Page 51: 06 1 array_stringhe_typedef

Le funzioni della libreria cctype

51

Page 52: 06 1 array_stringhe_typedef

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

Page 53: 06 1 array_stringhe_typedef

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

Page 54: 06 1 array_stringhe_typedef

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

Page 55: 06 1 array_stringhe_typedef

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

Page 56: 06 1 array_stringhe_typedef

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

Page 57: 06 1 array_stringhe_typedef

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

Page 58: 06 1 array_stringhe_typedef

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

Page 59: 06 1 array_stringhe_typedef

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)

Page 60: 06 1 array_stringhe_typedef

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

Page 61: 06 1 array_stringhe_typedef

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

Page 62: 06 1 array_stringhe_typedef

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

Page 63: 06 1 array_stringhe_typedef

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)