FUNZIONI Ivan Lanese
Argomenti Tecniche di debugging Funzioni
Di solito i programmi non funzionano int main() { int n, prod = 1; do { cout << "Inserire un numero (0 per uscire):"; cin >> n; prod = prod * n; } while (n!= 0); cout << "Il prodotto è " << prod << "\n"; return 0; }
3 tipi di errori Errori di compilazione Errori a run time Errori logici
3 tipi di errori Errori di compilazione Esempio: manca un ; Notificati dal compilatore Semplici da individuare Non sempre semplici da correggere A volte il messaggio di errore non è preciso A volte il messaggio di errore si riferisce alla riga sbagliata Errori a run time Errori logici
3 tipi di errori Errori di compilazione Errori a run time Esempio: divisione per 0 Si verificano durante l'esecuzione e ne causano l'interruzione Non necessariamente in tutte le esecuzioni Difficili da individuare In quali circostanze si verifica l'errore? Quale ne è la causa? Errori logici
3 tipi di errori Errori di compilazione Errori a run time Errori logici Esempio: il programma restituisce sempre 0 Il programma esegue normalmente ma il risultato non è quello atteso Non semplice rendersi conto dell'esistenza dell'errore il risultato potrebbe essere simile a quello atteso il risultato atteso potrebbe non essere noto l'errore potrebbe presentarsi solo in certe esecuzioni Molto difficili da individuare In quali circostanze si verifica l'errore? Quale ne è la causa? Quali risultati parziali sono giusti e quali sbagliati?
Tecniche di debugging Debugging a mano Si inseriscono delle stampe ausiliarie per capire il flusso dell'esecuzione gli stati intermedi Non richiede supporto dai tool Richiede attenzione a non introdurre ulteriori errori Potrebbe essere necessario aggiungere parentesi Un po' artigianale Uso di tool di debug Richiede l'uso di tool dell'ambiente di sviluppo o esterni Consente di verificare il flusso dell'esecuzione: tracing, breakpoints gli stati intermedi Molto potente Eclipse fornisce un buon supporto
Debugging in Eclipse: tracing Lanciate il programma con Debug dal menu Run Passate alla prospettiva Debug A destra potete vedere i valori delle variabili e i breakpoints definiti Potete modificare i valori delle variabili per vedere cosa succede Potete aggiungere espressioni da visualizzare con Add watch expression... Eseguite il programma passo passo con Step into del menu Run Potete far completare l'esecuzione con Resume del menu Run
Debugging in Eclipse: breakpoints Potete definire un breakpoint con Toggle breakpoint Sospende l'esecuzione quando viene raggiunta la riga in cui si trova Se il programma è eseguito in modalità Debug (tramite Resume) Potete gestire i vostri breakpoint nella finestra a destra Abilitarli/disabilitarli Aggiungere informazioni di log Eliminarli Visibili nell'apposita console
Errori classici Alcuni errori classici vengono individuati da Eclipse e segnalati come warning Assegnamento al posto di una condizione Variabili non usate... Obi Wan (off by one) Quando un ciclo viene eseguito una volta in più o in meno di quanto serve Errore nei casi limite Nei programmi che lavorano su numeri controllate sempre cosa succede se un numero è 0 Un buon modo per evitare errori è scrivere codice pulito
Funzioni: reminder Una funzione è un blocco di codice a cui è associato un nome int square (int n) { return (n*n); } Le funzioni consentono di risparmiare codice Scrivendo una volta sola codice ripetuto Rendendo il codice parametrico tramite passaggio dei parametri L'uso di funzioni in modo opportuno Rende il codice più leggibile Rende il codice più facile da modificare
Funzioni: quando usarle Una funzione contiene un blocco di codice con una funzionalità chiara e con poche dipendenze verso l'esterno che corrispondono ai parametri e ai valori di ritorno Le funzioni vanno usate quando lo stesso blocco di codice è usato più volte all'interno del programma o in programmi diversi Quando lo stesso codice compare più volte nel programma non esitate a trasformarlo in una funzione lo sforzo richiesto sarà ripagato in seguito Le funzioni ricorsive oltre a consentire un notevole risparmio di codice forniscono uno stile di programmazione alternativo
Funzioni: parametri e valore di ritorno Rappresentano i legami tra la funzione e il resto del programma Vanno evitate altre dipendenze, quali accessi a variabili globali, che rendono il programma poco leggibile e poco modificabile Una funzione ha un numero arbitrario ma fissato di parametri Anche il tipo di ogni parametro è fissato Una funzione restituisce al più un valore, di tipo fissato Se nessun valore viene restituito si usa void Se vogliamo restituire più di un valore si usano parametri passati per riferimento Va evitato se possibile, perchè rende il programma meno chiaro In seguito vedremo soluzioni alternative
Funzioni: esercizi Scrivere un programma che legge un numero binario da tastiera e lo stampa in decimale Scrivere un programma che calcola il massimo comun divisore di 4 numeri interi Scrivere un programma che legge due numeri binari da tastiera e ne stampa la somma e il prodotto (sempre in binario) Scrivere una funzione che dati due numeri interi x e y calcoli x^2+y^2 e x^2*y
Funzioni: debugging Per effettuare il debugging di un problema complicato conviene prima verificare il funzionamento delle singole funzioni Definite un semplice main che consente di testarle con vari parametri Testate anche i casi inaspettati Quando siete confidenti nella correttezza della funzione potete eseguirla in un passo solo durante il debugging con Step over Si ferma comunque in presenza di breakpoints