Esercizi FUNZIONI Passaggio di parametri per valore, variabili e tipi locali e globali, prototipo
Funzioni Definizione: tipo_ritornato nome (lista di parametri) { istruzioni; } int calcolatrice(char operazione,int a,int b) { … } Segnatura (signature) Prototipo: tipo_ritornato nome (lista di parametri); Deve essere in accordo con la definizione
Funzioni Parametri: Valore di ritorno: Definizione: tipo nome int somma(int a, int b) { return a + b; } … void main() int x, u=3, w=5; /* chiamata */ x = somma (u, w); Parametri: Definizione: tipo nome Parametri formali ed attuali Passati per copia Valore di ritorno: Istruzione: return espressione; Il tipo di espressione deve essere in accordo con tipo_ritornato Posso usare più return.
Regole di visibilità funz2() non ancora def. Ambiente globale g, h #include <stdio.h> int g, h; float funz1() { char b, g; funz2(5.0); return 33.0; } void funz2(float x); void main() float a, b, h; a = funz1(); void funz2(float x) printf("%f", pow(x,2)); funz2() non ancora def. Ambiente globale g, h funz1() b, g main() a, b, h, funz1(), funz2() funz2() Manca stdlib.h
Regole di visibilità E’ necessario definire ogni identificatore (tipo, variabile o funzione) prima di usarlo Variabili (e tipi) locali e globali: Visibili nel blocco all’interno del quale sono definiti ed in tutti i suoi sotto-blocchi E’ possibile usare lo stesso nome in blocchi diversi: Blocchi disgiunti: nessuna interferenza Blocchi innestati: la definizione più interna maschera quelle più esterne Funzioni: Sono visibili da ogni altra funzione definita successivamente Prototipo globale/locale #include<file_libreria_prototipi.h>
Riassumendo: quando usare… Variabili locali: Quando la variabile deve essere “vista” (cioè, “utilizzata”) solo dalla funzione nella quale è definita Variabili globali: Quando la variabile deve essere “vista” da tutte le funzioni del programma Usate le variabili locali! Per trasferire dati tra una funzione e l’altra, usare il passaggio di parametri ed il meccanismo del valore di ritorno.
Elevamento a potenza Scrivere una funzione in grado di calcolare ab, con a e b interi L’utente inserisce la base e l’esponente; l’elaboratore esegue il calcolo, controllando e segnalando eventuali situazioni di errore Ricordiamo che: Se a = 0 e b < 0 errore! Altrimenti: Se b < 0 risultato = 1 / a|b| Se b = 0 risultato = 1.
Elevamento a potenza #include <stdio.h> #include <stdlib.h> int matError; /* Variabile globale */ float eleva (int a, int b) { unsigned int i; /* Variabili locali a eleva()*/ float tot = 1; /* Se b==0, tot=1… */ if (a == 0 && b < 0) matError = -1; } .
Elevamento a potenza else { matError = 0; /* abs() calcola valore assoluto; stdlib.h */ for (i = 1; i <= abs (b); i++) /* Se b==0… */ tot = tot * a; } if (b < 0) tot = 1.0 / tot; return tot; } /* Fine funzione eleva() */ .
Elevamento a potenza void main() { int base, esponente; /* Var. locali al main()*/ float risultato; printf ("Base (intera): "); scanf ("%d", &base); printf ("Esponente (intero): "); scanf ("%d", &esponente); risultato = eleva (base, esponente); .
Elevamento a potenza Notare "%.8f" if (matError == 0) { printf ("Risultato: %.8f\n", risultato); } else printf ("Errore!\n"); Notare "%.8f"
Operazioni con numeri complessi Si implementino i sottoprogrammi che effettuano le operazioni di somma e prodotto tra numeri complessi Si assuma che i due numeri complessi su cui operare vengano sempre passati come parametro ai sottoprogrammi da implementare e che il risultato dell'operazione venga ritornato mediante il meccanismo del valore di ritorno L’utente inserirà i due numeri complessi e l’elaboratore calcolerà somma e prodotto Un esempio di numero complesso: 23,5 + 3,4 i .
Operazioni con numeri complessi #include <stdio.h> /* tipo globale */ typedef struct { float Re; float Imm; } Complesso; /* dichiarazione dei prototipi delle funzioni somma() e prodotto()*/ Complesso somma (Complesso c1, Complesso c2); Complesso prodotto (Complesso c1, Complesso c2); .
Operazioni con numeri complessi /* adesso definiamo il main() posso usare somma() e prodotto() perché ho dichiarato in precedenza il loro prototipo */ void main() { Complesso n1, n2, n3; printf ("reale immaginario: "); scanf ("%f %f", &n1.Re, &n1.Imm); scanf ("%f %f", &n2.Re, &n2.Imm); n3 = somma (n1, n2); printf("n1 + n2 = %f%+fi\n", n3.Re, n3.Imm); n3 = prodotto (n1, n2); printf("n1 * n2 = %f%+fi\n", n3.Re, n3.Imm); } .
Operazioni con numeri complessi /* Adesso definiamo le due funzioni */ Complesso somma (Complesso c1, Complesso c2) { Complesso ris; ris.Re = c1.Re + c2.Re; ris.Imm = c1.Imm + c2.Imm; return ris; } Complesso prodotto (Complesso c1, Complesso c2) ris.Re = c1.Re * c2.Re - c1.Imm * c2.Imm; ris.Imm = c1.Imm * c2.Re + c2.Imm * c1.Re; } .
Calcolatrice L’utente inserisce un carattere (‘+’, ‘-’, ‘*’, ‘/’, ‘^’), che rappresenta l’operazione da eseguire, e due operandi. L’operazione viene eseguita, se possibile. Implementare la funzione: float calcola(char operazione,float op1,float op2) che esegue il calcolo. Se durante il calcolo dovesse verificarsi una condizione di errore, la funzione deve utilizzare la variabile globale errore per segnalarlo. Il main() chiede all’utente quale operazione effettuare e gli operandi; chiama la funzione calcola() e, in base al valore ottenuto ed al valore della variabile errore, comunica all’utente il risultato.
Calcolatrice #include <stdio.h> #include <stdlib.h> #define NO_ERR 0 #define DIV_ERR 1 #define OP_ERR 2 unsigned int errore; float calcola (char operazione, float op1, float op2); void main() { float operando1, operando2, risultato; char oper; printf ("Operazione (+,-,*,/,^): "); scanf ("%c", &oper); .
Calcolatrice printf ("Primo operando: "); scanf ("%f", &operando1); printf ("Secondo operando: "); scanf ("%f", &operando2); risultato = calcola (oper, operando1, operando2); switch (errore) { case NO_ERR: printf ("%f\n", risultato); break; case DIV_ERR: printf ("Divisione per zero\n"); case OP_ERR: printf ("Operazione errata\n"); } } .
Calcolatrice float eleva (int a, int b) /* un po’ modificata… */ { unsigned int i; float tot = 1; if (a == 0 && b < 0) errore = DIV_ERR; else for (i = 1; i <= abs (b); i++) tot = tot * a; if (b < 0) tot = 1.0 / tot; } return tot; } .
Calcolatrice float calcola (char operazione, float op1, float op2) { float totale; errore = NO_ERR; switch (operazione) case '+': totale = op1 + op2; break; case '-': totale = op1 - op2; case '*': totale = op1 * op2; break; .
Calcolatrice case '/': if (op2 != 0) { totale = op1 / op2; } else errore = DIV_ERR; break; case '^': totale = eleva (op1, op2); default: errore = OP_ERR; return totale; } .
Lettura codice segreto Si vuole leggere un codice numerico naturale, dando all’utente un numero prefissato di tentativi Se l’utente non inserisce il codice corretto entro il numero previsto di tentativi il calcolatore visualizza “codice errato”, altrimenti visualizza “codice corretto” Utilizzare le funzioni per: Leggere il codice Verificare se è corretto Visualizzare il risultato.
Lettura codice segreto #include <stdio.h> typedef enum {falso, vero} Booleano; /* Tipo globale */ void main() { /* Prototipi locali al main() */ Booleano leggiCodice (unsigned int nTentativi, unsigned int codice); void visualizza(Booleano corretto); /* Variabile locale al main() */ Booleano ok; ok = leggiCodice(3, 1234); visualizza(ok); } .
Lettura codice segreto void visualizza (Booleano corretto) { if (corretto) printf ("Codice corretto\n"); } else printf ("Codice errato\n"); } .
Lettura codice segreto Booleano leggiCodice (unsigned int nTentativi, unsigned int codCorr) { /* Prototipo locale a leggiCodice() */ int leggi(unsigned int i); /* Variabili locali a leggiCodice() */ int codTent; unsigned int i = 0; do codTent = leggi(i); i++; } while (i < nTentativi && codTent != codCorr); .
Lettura codice segreto if (codTent == codCorr) { return vero; } else return falso; } .
Lettura codice segreto int leggi(unsigned int i) { /* Variabile locale a leggi() */ int codLetto; printf ("Codice (tentativo %u): ", i + 1); scanf ("%d", &codLetto); return codLetto; } .