1 ALCUNE INFORMAZIONI PRELIMINARI Docente: E. Burattini e-mail: [email protected] Libri di testo: Deitel H.M., Deitel P.J. – C++ Fondamenti di programmazione, ed. Apogeo Chianese A. , Picariello A. , Moscato V. - Alla scoperta dei fondamenti dell’informatica. Un viaggio nel mondo dei BIT - ed. Liguori, 2008 Programma: •Strutture e file binari •Ricorsione •Puntatori •Liste legate •Alberi •Cenni di programmazione a oggetti Il compilatore dev C++, utilizzato per gli esercizi può essere scaricato all’indirizzo http://www.toggle.com/lv/group/view/kl39865/Dev-C%2B%2B.htm 2 SVOLGIMENTO DEL CORSO LEZIONI PROVA INTERCORSO valida solo per chi sostiene l’esame nella sessione di giugno PROVA SCRITTA ESAME ORALE I lucidi del corso si possono rinvenire sul sito: http//:people.na.infn.it/~ernb/programmacioneBC/index.php Oppure su www.federica.unina.it 3 4 Questo corso fa seguito al corso di Programmazione I. Si danno, quindi, per note tutte le conoscenze trasmesse in quel corso in particolare: Tipi di dati in C++ Espressioni numeriche e booleane Function Array Algoritmi di ordinamento In alcuni casi esse saranno esplicitamente richiamate 5 Si richiamano alcune nozioni fondamentali introdotte in Programmazione I Interfacciamento: fase durante la quale avviene il passaggio dei parametri effettivi del processo chiamante ai parametri formali della function. Il passaggio dei parametri avviene attraverso due modalità: Passaggio per valore: al parametro formale è assegnata una copia del valore del parametro effettivo. La function può quindi anche modificarne il valore senza che nessuna delle variabili del processo chiamante ne risulti modificata. 6 Passaggio per riferimento ( per indirizzo): al parametro formale, che deve essere un riferimento, è passato l’indirizzo della corrispondente variabile del parametro effettivo. Il parametro formale si comporta come un sinonimo o alias del corrispondente parametro effettivo. Ogni modifica apportata al parametro formale è in realtà una modifica apportata al corrispondente parametro effettivo. Al termine della function ed al ritorno nel processo chiamante solo le variabili di quest’ultima corrispondenti ai parametri effettivi passati per indirizzo risulteranno modificati. Per questi motivi tutto ciò che serve ad una procedura per poter effettuare i suoi calcoli, cioè i parametri di input, deve essere passato per valore, mentre tutte le variabili dichiarate nel processo chiamante che la procedura deve modificare o inizializzare , ovverosia i parametri di input-output ed i parametri di output devono essere passati per riferimento. 7 Regola Scrivere una function che ritorna un valore solo se si tratta di una funzione, cioè quando tutti suoi parametri devono essere passati per valore. In tutti gli altri casi scrivere una procedura. L’uso del for è fortemente sconsigliato 8 TIPI STANDARD Ricapitoliamo i tipi di dati introdotti in Programmazione I int ------- numeri interi ----------------- 435 float --- numeri reali semplice precisione----- 3.1416 double --- numeri reali doppia precisione------- 7.1416934523 char ------- caratteri ----------------- a boolean ----- valori vero o falso ------------ true array ----- insieme di valori di un prefissato tipo ---string ----- insieme di caratteri ------enumerated ----- insieme finito di valori -----9 Le strutture I dati che riguardano situazioni reali sono composti da elementi formati da tipi distinti. Ad esempio: i dati relativi ad uno studente sono costituiti da nome e cognome (stringhe), numero di matricola (numero), data di nascita (tre numeri interi), reddito (numero reale); i dati relativi ad un libro sono formati da titolo e autore (stringhe), anno di edizione (intero), prezzo (reale) e così via. Un array, pur essendo un dato complesso, è comunque formato da elementi dello stesso tipo, quindi non adatto a descrivere situazioni reali del tipo di quella sopra descritta relativa ad uno studente.10 Le strutture Il tipo struct Per superare tale ostacolo è stato introdotto un tipo di dato detto strutturato denominato record o struttura e identificato dalla parola riservata struct. 11 RECORD O STRUCT Studente Anagrafe Nascita Matricola Reddito Cognome Nome Giorno Mese Anno Studente Anagrafe Nascita Matricola Reddito Cognome Nome Giorno Mese Anno Rossi Ugo Bianchi Carlo 3 12 5 2 1972 8796 1971 8746 23000 15000 12 Studenti e libri dell’esempio precedente possono essere definiti come dati strutturati. La sintassi di una struttura è data dalla parola riservata struct seguita da un identificatore, che rappresenta l’introduzione del nuovo tipo, e da una coppia di parentesi graffe al cui interno è contenuta la lista dei suoi componenti; l’ultima parentesi graffa termina con il simbolo “;” . Esempio struct Tpdata { int giorno; int mese; int anno; }; Il Tpdata è un tipo che contiene i campi giorno, mese, anno; esso rappresenta un nuovo tipo definito dall’utente, per cui sono lecite dichiarazioni come Tpdata oggi, domani; 13 Le componenti della struttura, detti anche campi, possono essere tipi elementari ( int, float, char, bool ), array o altre strutture. Definiamo, per esempio, un tipo persona, Tpersona, contenente i dati essenziali di una persona, cognome, nome, luogo e data di nascita: struct TPersona { char cognome[20]; char nome[20]; Tpdata nascita; char luogo[20]; }; struct Tstudente { Tpersona anagrafe; int matricola; int esami[4]; }; struct Tpdata { int giorno; int mese; int anno; }; struct Tlibro { char titolo[40]; TPersona autore; int annoedizione; Tpdata dataAcq; char editore[20]; float prezzo; }; e le due strutture, Tstudente e Tlibro, che si avvalgono dei tipi Tpersona e Tpdata. Si noti che il tipo studente ha, tra i suoi 14 campi, anche un array. Osserviamo che, pur creando un nuovo tipo, la definizione della struttura con la parola riservata struct, non crea spazio di per sé. Lo spazio viene creato quando la variabile viene dichiarata. Per poter assegnare dei valori ad una struct è necessario definire una variabile di quel tipo. In questo caso diciamo che abbiamo creato una istanza del tipo. Il computer provvede a creare lo spazio necessario la cui grandezza in byte possiamo conoscerla applicando la function sizeof(tipo-struttura). 15 Per esempio, creiamo tre variabili di diverso tipo: studente, persona, libro: struct Tpdata { Tstudente studente; TPersona persona; Tlibro libro; struct TPersona { char cognome[20]; char nome[20]; Tpdata nascita; char luogo[20]; }; struct Tstudente { Tpersona anagrafe; int matricola; int esami[4]; }; int giorno; int mese; int anno; }; struct Tlibro { char titolo[40]; TPersona autore; int annoedizione; char editore[20]; float prezzo; }; Notiamo innanzitutto che il Tpdata viene utilizzato nella definizione della struct Tstudente (tipostudente), mentre il tipo persona è ripreso nel Tlibro: una struttura complessa come la struct si può servire di altre strutture complesse (ancora struct) oppure array. 16 Tstudente studente; TPersona persona; Tlibro libro; struct TPersona { char cognome[20]; char nome[20]; Tpdata nascita; char luogo[20]; }; struct Tstudente { Tpersona anagrafe; int matricola; int esami[4]; }; struct Tlibro { char titolo[40]; TPersona autore; int annoedizione; char editore[20]; float prezzo; }; Per poter accedere al campo nome della variabile persona della struct TPersona, dobbiamo porre un punto tra i due dati; l’istruzione cout<<persona.nome mostrerà sul video il dato contenuto nella struttura persona, campo nome. 17 Per accedere al nome dell’autore della struct libro dobbiamo scrivere: cout<<libro.autore.nome L’operatore punto (.) rappresenta la specifica di campo, per cui in libro.autore.nome libro richiama la struct di tipo Tlibro autore richiama il campo autore che, a sua volta, è una struct di tipo Tpersona nome richiama il campo del tipo Tpersona la variabile libro.autore.nome è un array di char avente una lunghezza massima in caratteri predeterminata. 18 Poiché le struct definiscono un nuovo tipo, è possibile dichiarare ed utilizzare anche array di struct con le dichiarazioni: Tlibro libri[100]; // viene dichiarato un array di record libri contenente al massimo 100 libri Tpdata festivi[30]; // viene dichiarato un array festivi contenente al massimo 30 date corrispondenti a giorni festivi struct Tlibro { char titolo[40]; TPersona autore; int annoedizione; char editore[20]; float prezzo; }; struct Tpdata { int giorno; int mese; int anno; }; 19 Per leggere una data da tastiera possiamo introdurre le seguenti istruzioni, dopo aver definito la variabile data1 di tipo Tpdata: Tpdata data1 do cout<<”Introduci giorno mese anno separati da spazi: ”; cin >> pers1.nascita.giorno>>pers1.nascita.mese >>pers1.nascita.anno; while (!(data_corretta(pers1))); 20 La funzione data_corretta(data1) potrebbe essere definita come segue: bool data_corretta(Tpersona persona) { return ((persona.nascita.giorno>0) && (persona.nascita.giorno<=31)&& (persona.nascita.mese >0) && (persona.nascita.mese<=12)); } Questa funzione è richiamata nel programma tante volte finché il giorno della data non è compreso tra 1 e 31 ed il mese tra 1 e 12. Esercizio: scrivere una funzione che tenga conto anche dei mesi con numero di giorni diversi (Apr, Giu, Sett, Nov, 30gg, Feb 28/29 (se anno bisestile) tutti gli altri 31 gg.) 21 Se abbiamo un’altra variabile data2 di tipo Tpdata possiamo scrivere data2=data1 ed il compilatore assegnerà opportunamente i valori (data1.giorno viene scritto in data2.giorno, data1.mese in data2.mese e data1.anno in data2.anno). 22 Se l’operazione di assegnazione consente di trattare le struct come una struttura unica, gli operatori di confronto necessitano invece un’analisi più dettagliata delle componenti. Scrivere, ad esempio, if (data1==data2)…. provocherà un errore del compilatore, per cui è opportuno scrivere una funzione del tipo bool confrontadata (Tpdata data1, Tpdata data2) { confrontadata= (data1.giorno == data2.giorno) && (data1.mese == data2.mese) && (data1.anno == data2.anno); } 23 Osservazioni sulle struct. 1. All’interno di una struttura NON si può utilizzare il tipo string perché è un tipo che non ha grandezza fissa ma varia in modo dinamico: servirsi sempre di array di caratteri come negli esempi. 2. Nelle chiamate di funzioni, per eliminare il tempo necessario per la copia, passare le strutture per riferimento. 3. Nelle chiamate di funzioni, se la struttura non deve essere variata aggiungere la clausola const. 4. I membri di una struttura possono essere di tipo diverso; essa, comunque, NON può avere un’istanza di se stessa. Eser record 24 Esercizio. Scrivere una funzione int confrontadata (Tpdata data1, Tpdata data2) che restituisca 0 se le due date sono uguali -1 se data1 è minore di data2 +1 se data1 è maggiore di data2 25 Scrivere le strutture necessarie alla gestione di un rivenditore di moto. es. Venditore Compratore Descrizione estetica Descrizione tecnica Prezzo Modalità di pagamento Magazzino 26