1 / 36

laboratorio di calcolo II AA 2003/04 seconda settimana

UNIVERSITA’ DEGLI STUDI ROMA TRE DIPARTIMENTO DI FISICA “E. AMALDI”. laboratorio di calcolo II AA 2003/04 seconda settimana. a cura di Domizia Orestano Dipartimento di Fisica Stanza 159 - tel. (06 5517) 7281 www.fis.uniroma3.it/~orestano orestano@fis.uniroma3.it. Indice. Puntatori

cyrus-rosa
Télécharger la présentation

laboratorio di calcolo II AA 2003/04 seconda settimana

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. UNIVERSITA’ DEGLI STUDI ROMA TRE DIPARTIMENTO DI FISICA “E. AMALDI” laboratorio di calcolo IIAA 2003/04seconda settimana a cura di Domizia Orestano Dipartimento di Fisica Stanza 159 - tel. (06 5517) 7281 www.fis.uniroma3.it/~orestano orestano@fis.uniroma3.it

  2. Indice • Puntatori • Puntatori e vettori • Vettori di caratteri e stringhe • Allocazione dinamica della memoria • Strutture dati • Reference • Passaggio dei dati ad una funzione per “referenza” e per “valore” nella prossima lezione

  3. i: p: int * int 3 Puntatori • Un puntatore è un oggetto che fa riferimento ad un altro oggetto • Lo si dichiara in uno dei due modi seguenti int* p; int *p; Dove p è il puntatore • Non gli si può assegnare un valore direttamente, ma solo un oggetto cui puntare int i=3; // l’oggetto salvato in memoria int *p=&i; // dove &i è l’indirizzo di memoria di i (questa istruzione equivale a int *p; p=&i;) • L’oggetto puntato si ottiene “dereferenziando” il puntatore: *p • Se p vale 0 (puntatore nullo)*p non è definito (il programma si ferma!)

  4. . . numero 0x09053 00110101 01000010 00000001 0x09050 00000000 01010000 10010000 . . Esempio intnumero = 82485; // un oggetto intero a 32 bit // che in binario si scrive // 00000000 00000001 // 01000010 00110101 int *puntatore; // puntatore ad un oggetto intero puntatore = № // puntatore a numero // (posto uguale all'indirizzo di numero) puntatore

  5. x[0] x[1] x[2] x[3] x[4] x: float float * float float float float Puntatori e Vettori (Arrays) • float x[5]; // dichiarazione di un vettore di numeri reali con 5 elementi • x e &x[0] sono la stessa cosa: il puntatore al primo elemento dell’array • *x e x[0] sono la stessa cosa: il primo elemento dell’array

  6. Aritmetica dei puntatori float x[5]; float *y=&x[0]; // y è un puntatore a x[0] float *z=x; // z è un puntatore a x[0] (y+1) punta a x[1] *(y+1) , y[1] e x[1] accedono lo stesso oggetto sono consentite operazioni di somma e sottrazione ed è possibile confrontare tra loro due puntatori (si confrontano gli indirizzi di memoria, che sono numeri interi)

  7. Esempi di uso dei puntatori somma degli elementi di un vettore float x[5]; // qui gli elementi vengono inizializzati… double sum=0; for(int i=0;i<5;i++) { sum+=x[i]; } oppure float x[5]; // qui gli elementi vengono inizializzati… float *y=x; double sum=0; for(int i=0;i<5;i++) { sum+=*y++; }

  8. Esempi inversione dell’ordine degli elementi di un vettore float x[10]; // qui gli elementi vengono inizializzati… float *left = &x[0]; float *right = &x[9]; while(left < right) { float temp = *left; *left++ = *right; *right-- = temp; } azzeramento degli elementi di un vettore float x[10]; // qui gli elementi vengono inizializzati… float *p = &x[10]; //attenzione a non usare *p !!! while ( p != x ) *--p=0;

  9. vettori di caratteri e stringhe Programma che usa char e stringhe C #include <iostream.h> #include <string.h> int main() { // Voglio scrivere il mio nome // Introduco un vettore di caratteri nomechar,// lungo 7 caratteri, ed introduco il mio // nome, 1 lettera alla volta. // L'output utilizza un loop, con o senza il// puntatore (piu' o meno raffinato) // input dei dati char nomechar[7]; nomechar[0] = ‘D'; nomechar[3] = nomechar[5] = ‘i'; nomechar[1] = ‘o'; nomechar[2] = ‘m'; nomechar[4] = ‘z'; nomechar[6] = ‘a';

  10. // In realta' sarebbe anche possibile// istanziare e inizializzare nomechar con // una sola istruzione. La dimensione viene// assegnata automaticamente dal compilatore. // La linea di istruzione equivalente alle// precedenti e': // char nomechar[] // = {‘D’,’o’,’m’,’i’,’z’,’i’,’a’ }; // Oppure l'input potrebbe essere gestito // tramite lettura da tastiera // cout << "Assegnare il nome( 7 caratteri): " // << endl; // for (int i=0; i<7; i++) { // cin >> nomechar[i]; // };

  11. // Passiamo all'output // Senza l'uso del puntatore cout << endl << " Output senza l'uso del puntatore: "; for(int m=0;m<=7;m++) { cout << nomechar[m]; }; //Ora passiamo all'uso delle stringhe di tipo C // Istanzio un puntatore alla stringa C che // contiene il nome char *nomeC; nomeC = “Domizia"; // Notare l'uso e la funzione del doppio apice cout << endl << " Stringa di tipo C: " << nomeC << endl;

  12. // Da notare che si puo' effettuare l'output // anche pensando alla stringa C come una serie // di caratteri cout << "Output carattere per carattere: "; for(int j=0;j<7;j++) { cout << ' ' << nomeC[j] ; }; cout << endl; // oppure ... cout << " "; char *q=nomeC; // q e’ un puntatore ad un carattere for(int j=0;j<7;j++) { cout << ' ' << *q++; }; cout << endl << endl; return 0; }

  13. Programma che usa le stringhe C++ #include <iostream.h> #include <string> int main() { string name; name = “Domizia"; cout << name << endl; string cognome=“Orestano"; string tutto=name+" "+cognome; cout << endl << tutto << endl; return 0; }

  14. Nota al Programma che usa i caratteri e le stringhe C • Sarebbe meglio introdurre una variabile cmax const int cmax=7; • E poi sostituire tutte le ricorrenze di 7 con la variabile cmax. In questo modo il programma diventa più elegante ed eventuali variazioni di lunghezza non richiederebbero sostituzioni se non nel valore di cmax. • Il problema non si pone nell'uso di stringhe C++ (programmazione OO ed allocazione dinamica della memoria)

  15. Dimensionamento dei vettori (1) // Un esempio da CorpoCeleste class CorpoCeleste { protected: char *Nome; …………….}; // Variante a dimensione fissa, // memoria allocata a compilation time class CorpoCeleste { protected: char Nome[20] ; ……………};

  16. // Tentativo di variante a dimensione variabile, // ma non compila! class CorpoCeleste { protected: int n; char Nome[n]; …………….}; vettori di dimensione variabile, fissata in fase di esecuzione, non possono essere inseriti tra gli attributi di una classe !

  17. ===File prova_fp.h class prova_fp { private: // ....... public : prova_fp() { } ; ~prova_fp() { } int * int_fp() { int a = 5 ; return &a ; }; } ; ===Main: #include <iostream.h> #include <string.h> #include "prova_fp.h" int main() { int * p; prova_fp myprova; p = myprova.int_fp(); cout << endl << endl; cout << " Puntatore : " << p << endl ; cout << " Valore : " << *p << endl ; return 0; }; Puntatori a variabili locali (1) Warning in compilazione e stampa di un Valore privo di senso !

  18. Allocazione dinamica della memoria • L’allocazione statica degli oggetti in memoria consente maggiore velocità di esecuzione perchè lo spazio usato e il tempo di utilizzo (“lifetime” dell’oggetto) sono determinati già in fase di compilazione. • due problemi: • vogliamo poter allocare di vettori di dimensione definita durante l’esecuzione del programma • vogliamo avere accesso agli oggetti definiti localmente (all’interno di uno { “scope”}) • una soluzione: allocazione dinamica della memoria. Gli oggetti vengono creati in un’area di memoria chiamata heap. Si utilizzano gli operatori • new • delete

  19. Dimensionamento dei vettori (2) class CorpoCeleste { protected: char * Nome; …………….}; E poi nel costruttore inizializzato int n = strlen(nomeCorpo); Nome=new char[n]; Ma tutti gli oggetti creati con new devono essere distrutti esplicitamente con l’operatore delete, questi oggetti infatti non vengono cancellati automaticamente all’uscita dallo “scope”. In caso di vettori la sintassi è delete [ ] Nome; Dobbiamo modificare CorpoCeleste::~CorpoCeleste inserendovi questa istruzione!

  20. CorpoCeleste.cc Prima parte #include "CorpoCeleste.h" #include <string.h> #include <iostream.h> #include <iomanip.h> CorpoCeleste::CorpoCeleste() { } CorpoCeleste::CorpoCeleste (const char *nomeCorpo, float mass, float xpos, float ypos, float vxi, float vyi) { Nome = new char[strlen(nomeCorpo)]; strcpy(Nome, nomeCorpo); m = mass; x = xpos; y = ypos; vx = vxi; vy = vyi; } void CorpoCeleste::calcolaPosizione(float fx, float fy, float t) { double ax = fx/m; double ay = fy/m; vx += ax*t; vy += ay*t; x += vx*t; y += vy*t; }

  21. void CorpoCeleste::stampaPosizione() { cout.setf(ios::fixed); cout.setf(ios::showpos); cout << " " << setprecision(4) << setw(9) << x*1.e-11 << " " << setprecision(4) << setw(9) << y*1e-11 ; } void CorpoCeleste::stampaVelocita() { cout.setf(ios::fixed); cout.setf(ios::showpos); cout << " " << vx << " " << vy ; } CorpoCeleste::~CorpoCeleste() {delete [] Nome;} const char* CorpoCeleste::nome() {return Nome; } double CorpoCeleste::M() { return m; } double CorpoCeleste::X() { return x; } double CorpoCeleste::Y(){return y; } double CorpoCeleste::Vx(){return vx; } double CorpoCeleste::Vy(){return vy; } CorpoCeleste.cc Seconda parte

  22. class prova_fp_n { private: // ....... public : prova_fp_n() { } ; ~prova_fp_n() { } ; int * int_fp() { int * p = new int(5); return p ; }; }; ===Main: #include <iostream.h> #include <string.h> #include "prova_fp_n.h" int main() { int * p; prova_fp_n myprova; p = myprova.int_fp(); cout << endl << endl; cout << " Puntatore : " << p << endl ; cout << " Valore : " << *p << endl ; delete p; return 0; }; Puntatori a variabili locali (2) Nessun warning in compilazione e stampa del Valore corretto: 5!

  23. Esercitazione • Obiettivi: • Utilizzare la classe CorpoCeleste • Studiare il comportamento dei costruttori e del distruttore • Utilizzare puntatori, vettori, vettori di puntatori • Modificare il distruttore di CorpoCeleste includendo l’operazione di delete [ ] Nome • Aggiungere stampe nei costruttori e nel distruttore • Provare i seguenti programmi che usano CorpoCeleste:

  24. Programmi • Es1_a.cc (costruttore, uso dei metodi “Get”, distruttore) • Es1_b.cc (allocazione dinamica, puntatori) • Es1_c.cc (vettore di oggetti, costruttore di default) • Es1_cbis.cc (vettore di puntatori ad oggetti) • Es1_d.cc (vettore con allocazione dinamica) • Es1_dbis.cc (vettore di puntatori con allocazione dinamica)

  25. CorpoCeleste.cc Prima parte #include "CorpoCeleste.h" #include <string.h> #include <iostream.h> #include <iomanip.h> CorpoCeleste::CorpoCeleste() { cout << “invocato costruttore di default di CorpoCeleste”<<endl; } CorpoCeleste::CorpoCeleste (const char *nomeCorpo, float mass, float xpos, float ypos, float vxi, float vyi) { Nome = new char[strlen(nomeCorpo)]; strcpy(Nome, nomeCorpo); m = mass; x = xpos; y = ypos; vx = vxi; vy = vyi; cout << “invocato costruttore di CorpoCeleste ”<<Nome<<endl; } void CorpoCeleste::calcolaPosizione(float fx, float fy, float t) { double ax = fx/m; double ay = fy/m; vx += ax*t; vy += ay*t; x += vx*t; y += vy*t; }

  26. void CorpoCeleste::stampaPosizione() { cout.setf(ios::fixed); cout.setf(ios::showpos); cout << " " << setprecision(4) << setw(9) << x*1.e-11 << " " << setprecision(4) << setw(9) << y*1e-11 ; } void CorpoCeleste::stampaVelocita() { cout.setf(ios::fixed); cout.setf(ios::showpos); cout << " " << vx << " " << vy ; } CorpoCeleste::~CorpoCeleste() { cout << “invocato distruttore di CorpoCeleste ”<<Nome<<endl; delete [] Nome; } const char* CorpoCeleste::nome() {return Nome; } double CorpoCeleste::M() { return m; } double CorpoCeleste::X() { return x; } double CorpoCeleste::Y(){return y; } double CorpoCeleste::Vx(){return vx; } double CorpoCeleste::Vy(){return vy; } CorpoCeleste.cc Seconda parte

  27. #include <iostream.h> #include "CorpoCeleste.h” int main () { // istanzio una serie di oggetti di tipo CorpoCeleste   CorpoCeleste sole("Sole", 2.e30,0.,0.,0.,0.); CorpoCeleste pietra("dolomite",1.,0.,0.,1.,1.); CorpoCeleste sasso("quarzo",2.,1.,0.,0.,1.); // Scrivo alcune caratteristiche degli oggetti che ho istanziato: // massa e posizione cout << endl << "Pianeta n. Massa Posizione iniziale " << endl << " x y " << endl << endl; cout << " " << "1" << " " << sole.M() << " " << sole.X() << " " << sole.Y() << endl; cout << " " << "2" << " " << pietra.M() << " " << pietra.X() << " " << pietra.Y() << endl; cout << " " << "3" << " " << sasso.M() << " " << sasso.X() << " " << sasso.Y() << endl; cout << endl; // Il programma e' finito. // Il compilatore provvede a distruggere gli oggetti di tipo CorpoCeleste   return 0;  } Es1_a.cc

  28. Es1_b.cc Prima parte #include <iostream.h> #include "CorpoCeleste.h" int main () { // istanzio una serie di oggetti di tipo CorpoCeleste // Uso l'allocazione dinamica della memoria, tramite new CorpoCeleste * Psole = new CorpoCeleste("Sole", 2.e30,0.,0.,0.,0.); CorpoCeleste * Ppietra = new CorpoCeleste("dolomite",1.,0.,0.,1.,1.); CorpoCeleste * Psasso = new CorpoCeleste("quarzo",2.,1.,0.,0.,1.); // Scrivo alcune caratteristiche degli oggetti che ho istanziato; // Ad esempio la massa e la posizione cout << endl << "Pianeta n. Massa Posizione iniziale " << endl << " x y " << endl << endl; cout << " " << "1" << " " << Psole->M() << " " << Psole->X() << " " << Psole->Y() << endl; cout << " " << "2" << " " << Ppietra->M() << " " << Ppietra->X() << " " << Ppietra->Y() << endl; cout << " " << "3" << " " << Psasso->M() << " " << Psasso->X() << " " << Psasso->Y() << endl; cout << endl;

  29. Es1_b.cc Seconda parte // Ora devo cancellare gli oggetti allocati dinamicamente tramite new cout << endl << "Prima delle chiamate a delete " << endl; delete Psole; delete Ppietra; delete Psasso; cout << endl << "Dopo le chiamate a delete " << endl; // Il programma e' finito // Notate (tramite il distruttore intelligente) che il compilatore // ha provveduto a distruggere gli oggetti di tipo CorpoCeleste // ai quali puntavano Psole, Ppietra, Psasso. return 0; }

  30. Es1_c.cc #include <iostream.h> #include "CorpoCeleste.h" int main () { // uso un vettore di oggetti di tipo Corpoceleste const int np = 6; CorpoCeleste Pianeti[np]; // Con un loop scrivo gli elementi del vettore for (int i=0; i<np; i++) { CorpoCeleste Ausiliario(" ",i,i,i,i,i); Pianeti[i] = Ausiliario; } // Con un loop posso estrarre le informazioni cout << endl << "Pianeta n. Massa Posizione iniziale " << endl << " x y " << endl << endl; for ( int i=0; i<np; i++) { cout << " " << i+1 << " " << Pianeti[i].M() << " " << Pianeti[i].X() << " " << Pianeti[i].Y() << endl; } cout << endl; return 0; }

  31. #include <iostream.h> #include "CorpoCeleste.h" int main () { // Ora uso un vettore di puntatori a oggetti di // tipo CorpoCeleste const int npp = 8; CorpoCeleste* MieiPianeti[npp]; // Con un loop scrivo gli elementi del vettore for ( int i=0; i<npp; i++) { MieiPianeti[i] = new CorpoCeleste(" ",i,i,i,i,i); } // Con un loop posso estrarre le informazioni. Ad esempio la massa cout << endl << "Pianeta n. Massa Posizione iniziale " << endl << " x y " << endl << endl; for ( int i=0; i<npp; i++) { cout << " " << i+1 << " " << MieiPianeti[i]->M() << " " << MieiPianeti[i]->X() << " " << MieiPianeti[i]->Y() << endl; } cout << endl; Es1_cbis.cc Prima parte

  32. Es1_cbis.cc Seconda parte // devo ricordarmi di cancellare gli oggetti allocati dinamicamente for ( int i=0; i<npp; i++) { cout << i+1; delete MieiPianeti[i]; } return 0; }

  33. #include <iostream.h> #include "CorpoCeleste.h" int main () { // uso un vettore di oggetti di tipo Corpoceleste // Il vettore di oggetti e' allocato dinamicamente // tramite new, che fornisce il puntatore all'array const int np = 6; CorpoCeleste * Pianeti= new CorpoCeleste[np]; // Con un loop scrivo gli elementi del vettore for (int i=0; i<np; i++) { CorpoCeleste Ausiliario("",i,i,i,i,i); Pianeti[i] = Ausiliario; } // Con un loop posso estrarre le informazioni. Ad esempio la massa cout << endl << "Pianeta n. Massa Posizione iniziale " << endl << " x y " << endl << endl; for ( int i=0; i<np; i++) { cout << " " << (i+1) << " " << Pianeti[i].M() << " " << Pianeti[i].X() << " " << Pianeti[i].Y() << endl; } Es1_d.cc Prima parte

  34. Es1_d.cc Seconda parte // Ora devo cancellare il vettore allocato dinamicamente cout << endl << endl << " Prima di chiamare delete [] Pianeti " << endl; delete [] Pianeti; cout << endl << " Dopo aver chiamato delete [] Pianeti " << endl; return 0; }

  35. #include <iostream.h> #include "CorpoCeleste.h" int main () { // Ora uso un vettore di puntatori a oggetti di tipo CorpoCeleste // Il vettore di puntatori e' a sua volta allocato dinamicamente, // tramite new, che fornisce il puntatore all'array di puntatori. // Per questo motivo la prima chiamata di new istanzia un oggetto di // tipo CorpoCeleste ** , cioe' un puntatore ad un puntatore. const int npp = 8; CorpoCeleste** MieiPianeti = new CorpoCeleste*[npp]; // Con un loop scrivo gli elementi del vettore for (int i=0; i<npp; i++) { MieiPianeti[i] = new CorpoCeleste(" ",i,i,i,i,i); } // Con un loop posso estrarre le informazioni. Ad esempio la massa cout << endl << "Pianeta n. Massa Posizione iniziale " << endl << " x y " << endl << endl; Es1_dbis.cc Prima parte

  36. Es1_dbis.cc Seconda parte for (int i=0; i<npp; i++) { cout << " " << i+1 << " " << MieiPianeti[i]->M() << " " << MieiPianeti[i]->X() << " " << MieiPianeti[i]->Y() << endl; } cout << endl; // devo ricordarmi di cancellare gli oggetti allocati dinamicamente // e poiche' ho usato new a due livelli, chiamero' delete 2 volte // 1 - per I puntatori agli oggetti di tipo CorpoCeleste // (cioe' gli oggetti contenuti nell'array di puntatori cout << endl << " Prima del loop con delete MieiPianeti[i] " << endl; for (int i=0; i<npp; i++) { cout << i+1; delete MieiPianeti[i]; } cout << endl << " Dopo il loop con delete MieiPianeti[i] " << endl; // 2 - per l'array di puntatori delete [] MieiPianeti; return 0; }

More Related