06 1 array_stringhe_typedef

Post on 18-Jan-2015

331 views 2 download

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)