Estratto del documento

Teoria - Programmazione BStream come parametri di funzione

Funzione copia file

void copia_file(ifstream &S, ofstream &D) {
char c;
c = s.get();
while (!s.eof()) {
d.put(c);
c = s.get();
}
return;
}

int main() {
ifstream f1;
f1.open("prova.txt");
ofstream f2;
f2.open("copia.prova.txt");
//copia_file (f1,cout) (stampa a video)
copia_file (f1,f2);
}

ifstream / ofstream sono sottoclassi (derivate) delle classi generali istream / ofstream (sottotipi).
In C++, se un parametro di una funzione f è di tipo/classe t è possibile passare a f (parametro di tipo t un tipo t' sottotipo di t (conviene però dichiarare prima il parametro di tipo t).
In particolare: void copia_file(istream &s, ostream &d) {...}
cin: istream, cout: ostream parametri della copia_file

Leggi e stampa classe razionale

class razionale {
public:
void stampa(ostream &dest) {
dest << n << "/" << d;
return;
}
void leggi(istream &sorg) {
sorg >> num >> sep >> den;
...
}
};
int main() {
razionale a(2,3);
...
a.stampa(cout);
ofstream f_out;
f_out.open("risultati.txt");
a.stampa(f_out);
}

Overloading operatori >> e <<

1) operatori >> e << come funzioni proprie della classe razionale (stesso di prima cambiando il nome del void)
int main() {
razionale a(2,3);
cout << a; //errore
a << cout; //OK
cout.operator<<(a); //?
}
2) gli operatori >> e << li definiamo come funzioni esterne alla classe razionale → n e d non accessibili → funzioni proprie della classe razionale leggi e stampa mentre operator >> e operator<< si limitano a richiamare leggi e stampa.

Teniamo la classe razionale di partenza:
ostream &
void operator << (ostream &dest, razionale x) {
x.stampa(dest);
return;
} //return dest
istream &
void operator >> (istream &sorg, razionale &x) {
x.leggi(sorg);
return;
} //return sorg
int main() {
razionale a(2,3);
cout << a; //operator << (cout,a) OK
razionale b;
cin >> b; //operator >> (cin,b) OK
}
3) miglioramento della 2: gli operatori >> e << li definiamo come funzioni esterne con tipo delle funzioni ostream / istream → cout << a << endl; "ostream &" → reference return;

Parametri const reference

es: int f(const int & x) {...}
& → evita la copia
const → evita modifica da parte di f
Vantaggi:
– No side-effect sul parametro attuale (come per il passaggio per valore) il parametro passato non può essere modificato.
– Efficienza
– No copia: evita problemi con oggetti difficili da copiare

Esempio: Classe razionale

class razionale{ ...
razionale operator+ (const razionale & s) const {...}
razionale operator < (const razionale & s) const {...}
void stampa (ostream & dest) const {...}
}
ofstream & operator << (ostream & dest, const razionale & x) {...}
istream & operator >> (istream & sorg, razionale & x) {...}

n.b. es:
const razionale unmezzo (1,2);
...
c=a+unmezzo;
unmezzo.stampa(cout); // ½
– Il compilatore deve sapere che una funzione non modifica la const
– Tutte le funzioni invocate su un oggetto const devono essere funzioni const (la funzione const non modifica l'oggetto di invocazione)
– Stessi problemi per gli oggetti dichiarati const &

es: ostream operator << (ostream & dest, const razionale & x) {
x.stampa(dest);
}
Invoca funzione propria di razionale su oggetto const.

Passaggio parametri – valori di default

Nella dichiarazione di una funzione (interna o esterna) è possibile dare un valore di inizializzazione ad 1 o più parametri.
Es: int f(int x, int y=0) {...}
Nella chiamata di funzione è possibile omettere valore parametro attuale per parametro inizializzato.
Nb: - valori di default per ultimi - attribuiti alle funzioni overloaded

Tipo stringa

Definizione (informale): sequenze di n caratteri consecutivi (n>=0)
es: "c1,c2,...cn" "" = stringa vuota

Operazioni:

  • Lunghezza stringa (attributi stringa)
  • Confronto tra stringhe (==, !=, < etc.)
  • Assegnamento tra stringhe (r <---- s)
  • Selezione dell'i-esimo carattere
  • Lettura e scrittura di stringhe
  • Ricerca sottostringa

Implementazione stringhe

Dobbiamo scegliere una rappresentazione dei dati, abbiamo due alternative:
– Stringa come vettore: vettore statico (stringhe tipo C) o dinamico
– Stringa come lista concatenata
Implementazione in C++ : avviene tramite il costrutto CLASS e precisamente con una classe default di nome STRING

#include <string>
es:
class string {
private:
int lungh; //implementazione stringa, la rappresentazione di una struttura dati completa x la stringa
public :
//costruttori :
static const int npos= -1;
string () {lungh =0; ...}
string (char s[]) {lungh =strlen(s); // a "lungh" assegno la lunghezza di s ...}
string (int n,char f) {... for(int i=0; i<n; i++) { "assegna a i-esimo elem. F" }
//ora facciamo una funzione size
int size () {return lungh;}
string operator = ( const string& r) {...} // ottiene la copia di una stringa
string operator = ( const char r []) {...}
bool operator == (const string& r) {...}
string operator + (const string& r) {...}
string operator + (char c) {...}
char operator [] ( int i) {...}
string substr (int p,int n){...}
int find (const string& r,int p) {if("trovata") return "posizione iniziale di r" else return npos;}
istream& operator >> (istream& sorg,string& s) {...}
ostream& operator << ( ostram& dest,const string & s) { ...}
istream getline (istream&sorg,string& s,char d=='\n') {...}
}

Uso nel main

#include <string>
int main () {
string s; // ogg di classe string = stringa vuota
string r= "ciao"; // E' uguale a scrivere sting r("ciao"),"ciao" è un array di caratteri
//crea una stringa di nome r inizializzata con "ciao", l'attributo della stringa è 4
string t(3,'a'); // crea una stringa t e inizializza i primi 3 car. con la lettera a (aaa)

Lunghezza stringa (size)

s.size() ---> lunghezza stringa s
es: string data = "22 maggio 2002";
cout << data.size(); --- > 14

Assegnamento tra stringhe

s=r; //ad s assegna la stringa r;
es: string r="ciao";
string s; //vuota
s = r; // s = ciao
es: string s;
s = "ciao";
//il "=" va ridefinito per degli array char, il primo operator usato su string nn va bene!
//infatti se si vede sopra gli "operator =" sono due!

Alcune operazioni

=, ==, !=, <=, >= etc...
s==r ---> s.operator == (r)

Concatenazione

s+r --> restituisce una nuova stringa concatenando r a s
es: string s1 = "ciao";
string s2 = s1 + "mondo"; --> s1.operator + ("mondo")
string s3 = s2 + '!';
cout<<s3;
//nb: string s="a";
//string s='a'; ---> errore!

Selezione singolo carattere

s[i]
es: string s= "ciao";
cout<< s[1]; ---> stampa i //s[1] verrà tradotta in : s.operator[] (1)
s[0] ='m'; //s[0] verrà tradotta in : s.operator[] (0)
cout <<s; ---> miao

Sottostringa

s.substr (p,n) //restituisce la sottostringa r di s a partire da p lunga n
es: string data= "22 maggio 2002";
string mese;
mese= data.substr(3,6);
cout<<mese; ---> //stampa maggio

Ricerca sottostringa

s.find(r,p)//cerca una sottostringa r all'interno di s a partire dalla posizione p
il risultato è un valore int che rappresenta la posizione iniziale dove è stata trovata la stringa r, se non la trova restituisce un valore speciale npos (string :: npos)
es: string frase="informatica";
int i;
i=frase.find("for",0); // cerco "for" a partire da 0
if( i==string :: npos) {
cout<<"non trovata!"<<endl; }
else cout<<"trovata in posizione"<< i;

Lettura e scrittura stringhe

es << : string msg1= "immetti numero";
cout <<"ms1;
es: cin >> string nome,cognome;
cin >>nome;
cin>> cognome; ---> operator >> (cin,cognome)
//ignora spazi iniziali e termina al primo spazio o a capo
getline (f,s,d) // legge dallo stream di input f la stringa s; termina quando incontra il carattere d o incontra end of file
es: string nomefile;
getline(cin,nomefile,'\n');
con stringhe di tipo c:
char nome.file[100];
cin.getline (nomefile,100,'\n');

Conversione tra string e C-string

Voglio passare da string a stringa di "tipo C" e viceversa
es: char c [10]="ciao";
string s = c; --> da cstring a string!
"nb :" per fare il contrario (string --> cstring) usiamo una funzione della classe string: c_str
es: s.c_str () ---> r; // converte la stringa di tipo string nella stringa di "tipo c" r
"nb" : nome di un file è una stringa "tipo c" ( = array di char)
es : string nomefile;
cin >> nomefile;
...
istream f1;
f1.open (nomefile.c_str());

Lista di interi - Tipo di dato astratto

Valori: sequenza di n ( n >=0) numeri interi
es: ( i1,i2,...,in)

Operazioni :

  • Lunghezza della lista (attributo)
  • Elemento di testa di una lista (attributo)
  • Elemento di cosa di una lista (attributo)
  • Inserisci/estrai testa
  • Inserisci/estrai coda
  • Inserisci/estrai prima/dopo una certa informazione x
  • Concatenazione di due liste...

nb: - No dimensione massima
- Alta dinamicità
- No accesso tramite indice

Implementazione lista

Dobbiamo decidere la rappresentazione dei dati, abbiamo due scelte:
– Con un vettore (array) dinamico
– Lista concatenata

Implementazione liste concatenate con class

class lista
Sol. 1) Tipo elem con struct
struct elem {
int info;
elem*punt;
};
class lista {
private :
elem* l;
public :
lista (){l=NULL;}
void inseriscitesta (int x) {
elem *t;
t= new elem;
t->info =x;
t-put=l;
l=t;
return;
}
Uso int main (){
lista l1; //crea lista l1 vuota
lista l2; // creo lista l2 vuota
l1.inseriscitesta (5);

Class lista

struct elem {
int info;
elem*punt;
}
class lista {
private :
elem* l;
public :
lista (){l=NULL;}
void inseriscitesta (int x) {
elem*t;
t=new elem;
t->info=x;
t->int=l;
l=t;
return;
}
void stampa (ostream & dest) {
elem * t =l;
while ( t!= NULL) {
dest<<t->info<<" ";
t= t->punt;
}
return;
}
};
...
int main (){
lista l1;
int x,y;
cout <<"dai un numero"<<endl;
cin >>x;
l1.inseriscitesta(x);
cout<<"dai un numero"<<endl;
cin>>y;
l1.inseriscitesta(y);
lista l2;
l2.inseriscitesta(y);

Lista senza class

struct elem {
..};
void inseriscitesta ( elem *& l, int x) {
elem *t;
t= new elem;
t-> info=x;
t-> punt =l;
l=t;
return;
}
void stampa ( ostream& dest, elem * l) {
while ( l!=NULL) {
l = l->punt;
}
}
int main () {
elem + l1 = NULL;
int x,y;
cout <<"...";
cin >> x;
inseriscitesta (l1,x) ;
cout <<"...";
cin >>y;
inseriscitesta (l1,y);

Variante con typedef

typedef int t_info; // t_info è di tipo int
struct elem {
t_info info;
elem * punt;
};
class lista {...
void inseriscitesta ( t_info x) { => maggior modificabilità del programma...}
};

Variante 2 senza struct

class elem {
private :
int info;
elem * punt;
public :
elem () {punt =NULL;}
elem (int x,elem*s=NULL) {info= x;punt = s;}
int get_info () {return info; }
elem * get_punt () {return punt; }
void put_info (int x) {info=x;}
void put_punt ( elem *s) {punt= s;}
void stampa (ostream& dest) {dest <<info;}
}
class lista {
private :
elem *l;
public :
lista () { l=NULL;}
void inseriscitesta(int x) {
elem *t;
t=new elem;
void inseriscitesta (int x) {
elem *t;
t=new elem;
}
t->put->info (x);
t->put_punt(l);
l=t;
return;
}
void stampa (ostream & dest){...
dest<<t->get_info()<<" ";
}
}

Distruttori

struct elem {
int info;
elem*punt;
}
class lista {
private:
elem* l;
public:
lista (){l=NULL;}
Distruzione di un oggetto
void f (int x) {
razionale A;.....
return; → distruzione di A, invoca il distruttore della classe razionale e rilascia la memoria allocata per A
}
es: class razionale {...
public :...
~razionale () {...}
}
ogni classe ha distruttore predefinito (non fa nulla) con corpo vuoto {} il distruttore di qualsiasi classe può essere ridefinito quando voglio.
es: class razionale {...
public :...
~razionale (){
cout <<"sto morendo"<<endl;
}
}
es: clase lista
void f (int x) {
lista l1;....
l1.inseriscilista (x);
l1.inseriscilista (y);
return; ---> dealloca l1 ma NON dealloca elem. della lista ==> GARBAGE
}
int main () {
f(3);
soluzione: ridefinire il distruttore della classe lista che rimpiazza quello di default
~lista () {
while (l!=NULL){
elem t;
t= l-->punt;
delete l;
l=t;
}
}

Gestione memoria di un programma

3 tipo diversi di allocazione della memoria:

  • Allocazione statica → usata in particolare per variabili dichiarate globalmente del programma
  • Allocazione automatica → allocazione dati locali a un blocco. Per “blocco di dati locali” si intende variabili locali, parametri formali, variabili temporanee per risultati intermedi, indirizzo di ritorno, questi sono anche chiamati RECORD DI ATTIVAZIONE DELLA FUNZIONE
  • Allocazione dinamica

Allocazione statica

#include <iostream>
int A[10];
int x; → due variabili globali allocate staticamente (memoria allocata a compile time e deallocata alla fine del programma) il tempo di vita è l'intero programma
int main () {
......
}

Allocazione automatica

int f (int z) {
int x=0; ===> record d attivazione attivato automaticamente quando si entra nel blocco (es quando si fa la chiamata della funzione, li allora viene allocata la memoria) il record d'attivazione viene deallocato quando si esce dal blocco, quindi il tempo di vita di variabili automatiche è il blocco, ovvero il tempo di esecuzione del blocco in cui la variabile appare
return x+1;
}
int main () {
int A;
A=f(7); → r.a. allocati in area di memoria gestita come pila (stack)...
}

es2 - allocazione automatica:
int g (int y) {
int x=1;
...
}
int f (int z) {
int x=0;
x=g(3);
... → "catena dinamica delle chiamate di funzioni"
}
int main () {
int A=7;
cout <<f(A);
...
}
Pila dei record di attivazione (dimensione non nota a priori)

Allocazione dinamica (funzioni ricorsive)

fatt (int x){ ...
return fatt (x-1)*x;
}
int main () {
fatt (4);
Se la pila è piena si ha un errore runtime "stack overflow"

Allocazione dinamica (creazione tramite new)

int main() {
int* x; → allocata automaticamente
x=new int(1); → allocazione dinamica
- distruzione esplicita tramite delete
- tempo di vita variabile dinamica = intervallo di tempo tra new e delete
- allocate in heap → aree di memoria distinte tra aree libere e occupate (tramite tabella o liste)
ovviamente quelle libere sono quelle usate dalla new
es3: int A; → variabile statica
int f (){
int *x; → variabile automatica
x=new int(1); → variabile dinamica
...
}
int main () {
int z=5; → variabile automatica
f();
}
Variabile dinamica non deallocata al termine della funzione f (ma il puntatore x è deallocato) → si forma della spazzatura ("garbage") → usare delete

Gestione eccezioni

Il problema è gestire in modo opportuno situazioni anomale che si verificano durante l'esecuzione del programma (gestire gli errori a runtime). Soluzione senza gestione eccezioni: l'errore in una funzione viene tipicamente gestito nella funzione con (ad es) un messaggio d'errore

Anteprima
Vedrai una selezione di 14 pagine su 63
Programmazione B - Tutta la teoria Pag. 1 Programmazione B - Tutta la teoria Pag. 2
Anteprima di 14 pagg. su 63.
Scarica il documento per vederlo tutto.
Programmazione B - Tutta la teoria Pag. 6
Anteprima di 14 pagg. su 63.
Scarica il documento per vederlo tutto.
Programmazione B - Tutta la teoria Pag. 11
Anteprima di 14 pagg. su 63.
Scarica il documento per vederlo tutto.
Programmazione B - Tutta la teoria Pag. 16
Anteprima di 14 pagg. su 63.
Scarica il documento per vederlo tutto.
Programmazione B - Tutta la teoria Pag. 21
Anteprima di 14 pagg. su 63.
Scarica il documento per vederlo tutto.
Programmazione B - Tutta la teoria Pag. 26
Anteprima di 14 pagg. su 63.
Scarica il documento per vederlo tutto.
Programmazione B - Tutta la teoria Pag. 31
Anteprima di 14 pagg. su 63.
Scarica il documento per vederlo tutto.
Programmazione B - Tutta la teoria Pag. 36
Anteprima di 14 pagg. su 63.
Scarica il documento per vederlo tutto.
Programmazione B - Tutta la teoria Pag. 41
Anteprima di 14 pagg. su 63.
Scarica il documento per vederlo tutto.
Programmazione B - Tutta la teoria Pag. 46
Anteprima di 14 pagg. su 63.
Scarica il documento per vederlo tutto.
Programmazione B - Tutta la teoria Pag. 51
Anteprima di 14 pagg. su 63.
Scarica il documento per vederlo tutto.
Programmazione B - Tutta la teoria Pag. 56
Anteprima di 14 pagg. su 63.
Scarica il documento per vederlo tutto.
Programmazione B - Tutta la teoria Pag. 61
1 su 63
D/illustrazione/soddisfatti o rimborsati
Acquista con carta o PayPal
Scarica i documenti tutte le volte che vuoi
Dettagli
SSD
Scienze matematiche e informatiche INF/01 Informatica

I contenuti di questa pagina costituiscono rielaborazioni personali del Publisher Mr.Al di informazioni apprese con la frequenza delle lezioni di Fondamenti di programmazione e studio autonomo di eventuali libri di riferimento in preparazione dell'esame finale o della tesi. Non devono intendersi come materiale ufficiale dell'università Università degli Studi di Parma o del prof Scienze matematiche Prof.
Appunti correlati Invia appunti e guadagna

Domande e risposte

Hai bisogno di aiuto?
Chiedi alla community