Strutture di controllo

Documenti analoghi
Funzioni e Procedure in C. Funzioni e Procedure in C

Funzioni e procedure

Introduzione. per astrarre delle operazioni complesse

Il passaggio parametri per indirizzo

int main(){ int numero; /* numero di cui voglio calcolare il fattoriale */ int fatt; /* memorizzo il fattoriale di numero */ int somma=0;

Sottoprogrammi: motivazioni. Funzioni e procedure. Un esempio motivante. Un esempio motivante

Laboratorio di Calcolatori 1 Corso di Laurea in Fisica A.A. 2006/2007

STRUTTURE DI CONTROLLO IN C. Docente: Giorgio Giacinto AA 2009/2010

LABORATORIO di INFORMATICA

FUNZIONI E PROCEDURE IN C. Docente: Giorgio Giacinto AA 2009/2010. dall utente, sia predefiniti, il C consente di creare funzioni e procedure

7. Strutture di controllo

Strutture di controllo in C. Strutture di controllo in C -- Flow Chart --

Il costruttore struct

Ottenere una modifica del parametro attuale

Array k-dimensionali

Array e puntatori. Indice. Tipi di dati strutturati: Array Puntatori Tipi di dati strutturati: Array Esempio. Corso di Informatica A.

Variabili e Funzioni. Informatica 1 / 19

Elementi lessicali. Lezione 4. La parole chiave. Elementi lessicali. Elementi lessicali e espressioni logiche. Linguaggi di Programmazione I

Dati due punti sul piano calcolare la loro distanza

Struttura di un. Struttura dei programmi C

Il linguaggio C. Notate che...

Lezione 5 e 6. Fabio Scotti ( ) Laboratorio di programmazione per la sicurezza. Valentina Ciriani ( ) Laboratorio di programmazione

C: primi elementi. Lezione 4

Introduzione al linguaggio C Funzioni

Laboratorio di informatica Ingegneria meccanica

passaggio di vettori come parametri di funzioni/procedure. I Quando si passa un vettore come parametro ad una funzione, in

I Dati Strutturati ed il Linguaggio C

La Programmazione. Cos è la programmazione? Concetti preliminari

Introduzione al linguaggio C Puntatori

Tipo carattere. Campo di variabilità. Intervallo finito. Tipo. Dimensione (byte) char

I cicli. Iterazioni Calcolo della media Istruzioni break e continue

Il linguaggio C. Prof. E. Occhiuto INFORMATICA 242AA a.a. 2010/11 pag. 1

Scope delle variabili e passaggio parametri. Danilo Ardagna Politecnico di Milano

Le Funzioni in C. Fondamenti di Informatica Anno Accademico 2010/2011. Corso di Laurea in Ingegneria Civile Politecnico di Bari Sede di Foggia

Linguaggio C. Generalità sulle Funzioni. Variabili locali e globali. Passaggio di parametri per valore.

ESECUZIONE DI PROGRAMMI C SU MACCHINE REALI. Docente: Giorgio Giacinto AA 2008/2009. formalizzazione degli algoritmi in linguaggio C

Dove vengono definiti? il concetto di sottoprogramma

Puntatori. Obiettivi: Richiamare quanto noto sui puntatori dal modulo A Presentare l analogia tra puntatori e vettori e l aritmetica dei puntatori

Puntatori. Obiettivi: Richiamare quanto noto sui puntatori dal modulo A Presentare l analogia tra puntatori e vettori e l aritmetica dei puntatori

I/O da tastiera + Alessandra Giordani Lunedì 2 maggio

Funzioni, Stack e Visibilità delle Variabili in C

Il linguaggio C. Notate che...

Costanti e Variabili

Linguaggio C - sezione dichiarativa: costanti e variabili

C: panoramica. Violetta Lonati

Funzioni, Stack e Visibilità delle Variabili in C

Esercizio 1: media di numeri reali (uso funzioni e struct)

INTRODUZIONE ALLA PROGRAMMAZIONE AD ALTO LIVELLO IL LINGUAGGIO JAVA. Fondamenti di Informatica - D. Talia - UNICAL 1. Fondamenti di Informatica

INTRODUZIONE ALLA PROGRAMMAZIONE AD ALTO LIVELLO IL LINGUAGGIO JAVA. Fondamenti di Informatica - Programma

Cominciamo ad analizzare la rappresentazione delle informazioni... di Cassino. C. De Stefano Corso di Fondamenti di Informatica Università degli Studi

Manualistica 3 Le strutture di controllo

Laboratorio di Programmazione

Algoritmi e basi del C Struttura di un programma

Istruzioni di Controllo

Primo programma in C

Funzioni in C. Funzioni. Strategie di programmazione. Funzioni in C. Come riusare il codice? (2/3) Come riusare il codice? (1/3)

FUNZIONI. attribuire un nome ad un insieme di istruzioni parametrizzare l esecuzione del codice

Algoritmi e basi del C

LEZIONE 1 LE BASI DEL LINGUAGGIO C

Strategie di programmazione

Programmazione C Massimo Callisto De Donato

Il linguaggio C. Puntatori e dintorni

Tipi di Dati Stutturati

Linguaggio C: le funzioni. Visibilità variabili e passaggio parametri

Laboratorio di Informatica I

DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE. Funzioni e Procedure. Marco D. Santambrogio Ver. aggiornata al 11 Marzo 2014

Istruzioni di Controllo in C. Emilio Di Giacomo

Qualsiasi programma in C++ segue lo schema:

Perché il linguaggio C?

Introduzione al C. Lez. 1 Elementi. Rossano Venturini

Caratteri e stringhe

Dichiarazioni e tipi predefiniti nel linguaggio C

Introduzione alla programmazione in linguaggio C

I costrutti del C. Strutture condizionali Strutture iterative Introduzione alle funzioni

Carlo Ghezzi, Gian Pietro Picco

Struttura dei programmi C

LINGUAGGI DI PROGRAMMAZIONE

LA RICORSIONE IN C. CdL Ingegneria Informatica n.o. Anno Accademico 2006/07 Fondamenti di Informatica I corso A Giacomo Piscitelli pag.

TIPI DI DATO. e quasi sempre anche collezioni di oggetti, mediante la definizione di tipi strutturati

del Linguaggio C Istruzioni di iterazione

Tipi di dati strutturati e Linguaggio C. Record o strutture Il costruttore struct in C

Unità Didattica 2 Linguaggio C. Espressioni, Operatori e Strutture linguistiche per il controllo del flusso

Introduzione al C. Lez. 2. Funzioni e Puntatori

Caratteri e stringhe

Un programma deve essere scritto come collezione di tante piccole funzioni perché:

Assegnazione di una variabile

Puntatore. Ritorniamo sul problema dell accesso alle variabili

Strutture di controllo

Il primo programma C++

Perché il linguaggio C?

Un esecutore di un linguaggio simbolico e costituito dalla coppia Compilatore, processore (o Interprete, processore)

Laboratorio di Calcolatori 1 Corso di Laurea in Fisica A.A. 2007/2008

L AMBIENTE CODE BLOCKS E L IO

Linguaggio C: le funzioni. Introduzione e sintassi

Tipi di dato semplici

L AMBIENTE CODE BLOCKS E L IO

Fondamenti di Informatica T. Linguaggio C: i puntatori

Transcript:

Strutture di controllo abbiamo visto if-else e while domande da punto di vista teorico: 1. algoritmi NON codificabili con if-else e while? 2. strutture di controllo più potenti di quelle viste sinora? 3. strutture di controllo in grado di codificare qssi algoritmo? macchina di Von Neumann realizza istruzioni if-else e while mediante istruzioni per testare contenuto di un registro modificare il valore del registro Program Counter a seconda del valore testato in questo riferimento formulato celebre teorema di Boehm-Jacopini. istruzioni if-else e while equivalenti a istruzioni della macchina di Von Neumann che può manipolare registro Program Counter istruzioni if-else e while sono complete bastano per codificare qualsiasi algoritmo per praticità e convenienza si usano però molte altre strutture di controllo quarto fascicolo - 1 -

Il costrutto switch Istruzioni di selezione codifica scelta tra istruzioni in base a valore di variabile o espressione Esempio: scandisce un testo, conta quanti caratteri cifre numeriche, di separazione (spazi, segni di puteggiatura, a capo) di tipo diverso. char c; int n_cifre, n_separatori, n_altri; c =.; switch (c) { case '0': case '1':.. case '9': n_cifre++; /* equivale a n_cifre = n_cifre + 1; */ break; case ' ': case '\n' : case ';' : case ':' : case ', ': n_separatori++; break; default: n_altri++; sintassi parola chiave switch espressione fra parentesi tonde () sequenza di istruzioni case fra graffe ogni istruzione case consiste in: sequenza di clausole case, ognuna composta da parola chiave case espressione due punti : sequenza di istruzioni (ognuna col suo ;) al posto dell ultima istruzione case può esserci istruzione default parola default sequenza di istruzioni (ognuna col suo ; ) espressioni tra parentesi deve essere di tipo integral - 2 -

la macchina valuta espressione se c è clausola con quel valore esegue tutte istruzioni successive a clausola con valore corrispondente per evitare esecuzione a cascata si mette istruzione break fa saltare istruzioni successive e passare a istruzione successiva a switch se non c è clausola con quel valore se c è clausola default eseguita sua istruzione altrimenti effetto della switch è nullo precauzioni nell uso del costrutto switch: evitare ambiguità: valori delle espressioni case costanti e diversi (esclusività dei casi) presenza istruzione default assicura trattamento completo dei diversi casi non tralasciare break dopo ultima istruzione case non indispensabile, ma facilita aggiunta di altre istruzioni case Esempio: programma legge nome dell utente (carattere # termina nome), trasforma in melodia associando ogni carattere a una nota basato su corrispondenza tra resti della divisione per 7 e note della scala /* Programma Melodia dal tuo nome */ #include <stdio.h> main() { char C; int resto; printf("inserisci il primo carattere del tuo nome\n"); scanf("%c", &C); while (C!= '#') { resto = C % 7; switch (resto) { case 0: printf("il carattere %c corrisponde alla nota 'do'\n", C); break; case 1: printf("il carattere %c corrisponde alla nota 're'\n", C); break; case 2: printf("il carattere %c corrisponde alla nota 'mi'\n", C); break; case 3: printf("il carattere %c corrisponde alla nota 'fa'\n", C); break; case 4: printf("il carattere %c corrisponde alla nota 'sol'\n", C); case 5: break; printf("il carattere %c corrisponde alla nota 'la'\n", C); break; case 6: printf("il carattere %c corrisponde alla nota 'si'\n", C); break; printf("inserisci il prossimo carattere del tuo nome # termina il programma"); scanf("%c", &C); - 3 -

Alternative multiple istruzioni if-else annidate, in cui la successiva è parte else della precedente anche nel linguaggio parlato, spesso regole espresse con se C1 allora A1 altrimenti, se C2 allora A2 altrimenti, se C3 allora... altrimenti An Esempio: dato numero n, se ha divisori primi <15 stampa il più piccolo, altrimenti stampa messaggio che lo segnala if (n % 2 == 0) printf("%d è pari", n); else if (n % 3 == 0) printf("%d è multiplo di 3", n); else if (n % 5 == 0) printf("%d è multiplo di 5", n); else if (n % 7 == 0) printf("%d è multiplo di 7", n); else if (n % 11 == 0) printf("%d è multiplo di 11", n); else if (n % 3 == 0) printf("%d è multiplo di 13", n); else printf ("il numero %d non ha divisori primi < 15", n); struttura inerentemente lineare: si scrive meglio su una solo colonna if (n % 2 == 0) printf("%d è pari", n); else if (n % 3 == 0) printf("%d è multiplo di 3", n); else if (n % 5 == 0) printf("%d è multiplo di 5", n); else if (n % 7 == 0) printf("%d è multiplo di 7", n); else if (n % 11 == 0) printf("%d è multiplo di 11", n); else if (n % 3 == 0) printf("%d è multiplo di 13", n); else printf ("il numero %d non ha divisori primi < 15", n); - 4 -

Il ciclo for Istruzioni cicliche casi con numero ripetizioni noto al momento dell esecuzione con while si fa così VariabileDiConteggio = ValoreIniziale; while (VariabileDiConteggio <= ValoreFinale) { [Sequenza di istruzioni da ripetere]; VariabileDiConteggio = VariabileDiConteggio + 1; i = 0 ; while (i <= 9) { [Sequenza di istruzioni da ripetere]; i = i + 1; con il ciclo for for (VariabileDiConteggio = ValoreIniziale; VariabileDiConteggio <= ValoreFinale; VariabileDiConteggio = Variabile di Conteggio + 1) { /* Sequenza di istruzioni da ripetere */ istruzione VariabileDiConteggio = VariabileDiConteggio + 1 abbreviabile con VariabileDiConteggio++ operatore di autoincremento ++ operatore di autodecremento questo uso di for si può generalizzare cambiando relazione di confronto con valore finale passo dell incremento Esempio: inverte una sequenza di caratteri di lunghezza massima 100 /* Programma InvertiSequenza */ #include <stdio.h> #define LunghezzaSequenza100 main() { int Contatore; int Memorizzazione[LunghezzaSequenza]; for (Contatore = 0; Contatore < LunghezzaSequenza; Contatore++) scanf("%d", &Memorizzazione[Contatore]); for (Contatore = LunghezzaSequenza 1; Contatore >= 0; Contatore ) printf("%d", Memorizzazione[Contatore]); - 5 -

Esempio: conta # occorrenze di ogni lettera alfabetica in testo di parole separate da spazi (senza segni interpunzione) e terminato da carattere speciale \0 /* Programma ContaCaratteri */ #include <stdio.h> #define DimVettoreFrequenze 123 main() { char Dato, Cursore; int FrequenzaCaratteri[DimVettoreFrequenze]; /* Inizializza array di conteggio FrequenzaCaratteri. Considera solo lettere alfabetiche */ for (Cursore = 'A'; Cursore <= 'Z'; Cursore++) FrequenzaCaratteri[Cursore] = 0; for (Cursore = 'a'; Cursore <= 'z'; Cursore++) FrequenzaCaratteri[Cursore] = 0; scanf ("%c", &Dato); /* Inizia la lettura del testo */ while (Dato == '\n' Dato == '\r') scanf ("%c", & Dato); /* ciclo precedente salta caratteri di a capo tra un carattere e l'altro */ while (Dato!= '\0') { if (!(Dato == ' ')) /* Se il dato letto è uno spazio esso deve essere semplicemente ignorato */ if (Dato < 'A' Dato > 'z' (Dato > 'Z' && Dato < 'a')) /* ammessi solo caratteri lettere dell'alfabeto */ printf ("Il testo contiene dei caratteri non ammessi"); else FrequenzaCaratteri[Dato] = FrequenzaCaratteri[Dato] + 1; scanf("%c", &Dato); while (Dato == '\n' Dato == '\r') scanf ("%c",& Dato); for (Cursore = 'A'; Cursore <= 'Z'; Cursore++) /* stampa totali lettere maiuscole */ printf ("Il carattere %c compare nel testo %d volte \n", Cursore, FrequenzaCaratteri[Cursore]); for (Cursore = 'a'; Cursore <= 'z'; Cursore++) /* Stampa totali lettere minuscole */ printf ("Il carattere %c compare nel testo %d volte \n", Cursore, FrequenzaCaratteri[Cursore]); - 6 -

ciclo do-while sintassi del costrutto parola chiave do istruzione (o sequenza istruzioni tra graffe) parola chiave while condizione fra () e infine ; NB: il corpo del ciclo viene eseguito almeno una volta ripetizione cessa quando condizione diventa falsa Esempio: leggere sequenza caratteri (senza alcun a capo ) terminata da %, memorizzare (col %) nell array Testo #define LunghezzaMassima 100 char dato, Testo[LunghezzaMassima]; Contatore = 0; do { do scanf("%c", &Dato); while (Dato == '\n' Dato == '\r') ; /* Il ciclo precedente salta i caratteri di a capo */ Testo[Contatore] = Dato; Contatore = Contatore + 1; while (Dato!= '%' && Contatore < LunghezzaMassima); if (Contatore == LunghezzaMassima && Dato!= '%') printf("la sequenza è troppo lunga"); istruzione goto trasferimento esplicito e incondizionato del flusso di esecuzione scanf("%d"%d", &x, &y); if (y == 0) goto error; printf("%f\n", x/y); error: printf("y non può essere uguale a 0\n"); incompatibile con principi della programmazione strutturata se ne sconsiglia fortemente l uso - 7 -

istruzioni break e continue break fa uscire da corpo di un ciclo ( termina ripetizione) o da istruzione switch continue interrompe iterazione corrente di un ciclo dà inizio a iterazione successiva continue può stare solo in cicli while, do o for Esempio: ciclo con elaborazioni su una serie di valori non più di N, assunti successivamente dalla variabile intera a saltando i valori negativi interrompendo l'elaborazione al primo valore nullo incontrato for (i = 0 ; i < N ; i++ ) { scanf( immettere un intero > %d, &a); if (a < 0) continue; if (a = 0) break;. /*elaborazione degli elementi positivi */ - 8 -

Funzioni e procedure Motivi per introdurre sottoprogrammi riusabilità (scrivere una sola volta codice usato più volte) astrazione (esprimere in modo sintetico operazioni complesse) estendibilità del linguaggio (non tutte operazioni predefinite di solito solo =, ==.!=, ) Esempio #define MaxNumFatture 10000; #define MaxNumCosti 10000; typedef struct { String Destinatario; int Importo; Data DataEmissione; DescrizioneFatture; typedef struct { String Destinatario; int Importo; Data DataSpesa; DescrizioneCosti; typedef struct { int NumFatture; DescrizioneFatture Sequenza[MaxNumFatture]; ElencoFatture; typedef struct { int NumCosti; DescrizioneCosti Sequenza[MaxNumCosti]; ElencoCosti;. ElencoFatture ArchivioFatture; ElencoCosti ArchivioCosti; int FatturatoTotale, SommaCosti, RisultatoDiGestione; con variabili ArchivioFatture o ArchivioCosti serviranno operazioni come Calcolo del fatturato complessivo, Calcolo della somma dei costi complessivi operazioni (facilmente) codificabili con istruzioni che conosciamo tuttavia piuttosto che il codice: FatturatoTotale = 0; for (Cont = 0; Cont < ArchivioFatture.NumFatture; Cont++) FatturatoTotale = FatturatoTotale + ArchivioFatture.Sequenza[Cont].Importo; SommaCosti= 0; for (Cont = 0; Cont < ArchivioCosti.NumCosti; Cont++) SommaCosti = SommaCosti + ArchivioCosti.Sequenza[Cont].Importo; RisultatoDiGestione = FatturatoTotale SommaCosti; - 9 -

ci piacerebbe di più scrivere un istruzione come la seguente RisultatoDiGestione = FatturatoTotale (ArchivioFatture) SommaCosti (ArchivioCosti); più astratto: mostra esclusivamente risultato desiderato nasconde operazioni eseguite per ottenerlo meccanismi per fare ciò chiamati sottoprogrammi assomigliano a interi programmi ma asserviti ad altri programmi per un sottoprogramma deve essere definito quale operazione astratta realizza come può essere identificato dal programma principale quali parametri coinvolge dati in ingresso come punto di partenza dei calcoli valori restituiti ai programmi che lo usano un sottoprogramma definito può essere utilizzato dal programma principale utilizzazione è detta chiamata (invocazione) del sottoprogramma In C due tipi di sottoprogrammi funzioni e procedure entrambi svolgono operazioni di interesse per il chiamante funzioni restituiscono un risultato al chiamante in modo diretto ed esplicito procedure NON restituiscono un risultato al chiamante in modo esplicito - 10 -

Struttura completa di un programma C Finora visto parte di direttive programma principale (main), con sue parti dichiarativa ed esecutiva Aggiungiamo ora parte dichiarativa globale fra parte direttive e programma principale contiene dichiarazione elementi condivisi da programma principale e sottoprogrammi costanti, tipi, variabili. Esempio: se contiene int x; variabile x accessibile a programma principale e a sottoprogrammi definizioni di sottoprogrammi funzioni o procedure cominciando dal programma principale main programma principale e sottoprogrammi possono usare elementi dichiarati nella propria parte dichiarativa elementi dichiarati nella parte dichiarativa globale Domande: Perché dichiarare diversi elementi in diversi posti? quali elementi possono venire usati dai sottoprogrammi? troveranno risposta più avanti - 11 -

Le funzioni matematicamente, tutte operazioni considerate finora in C sono funzioni dominio corrisponde a operandi/dati codominio corrisponde a valori calcolati sintassi della definizione di funzione testata (header); due parti fra parentesi graffe parte dichiarativa, detta parte dichiarativa locale parte esecutiva, detta corpo della funzione (il tutto chiamato blocco) testata contiene informazioni rilevanti per uso corretto del sottoprogramma tipo del risultato matematicamente, il codominio della funzione identificatore del sottoprogramma lista delle dichiarazioni dei parametri formali tra parentesi (), separati da, matematicamente, il dominio della funzione parametro identificatore del tipo del parametro (può essere qualsiasi, built-in o user-defined) identificatore del parametro parametri detti formali non hanno valore proprio, rappresentazio argomenti della chiamata della funzione tipo del risultato built-in o user-defined NON array SÌ puntatore a qualsiasi tipo esempi di testate di funzioni: int FatturatoTotale(ElencoFatture par) /* Il tipo boolean definito tramite costruttore enum: typedef enum {false, true boolean; */ boolean Precede(StringaCaratteri par1, StringaCaratteri par2) /* Stabilisce se par1 appartiene all'insieme di interi contenuto in par2 */ boolean Esiste (int par1, SequenzaInteri par2) /* restituisce (un puntatore a) la matrice inversa di quella ricevuta (tramite puntatore) nel parametro */ MatriceReali10Per10 *MatriceInversa (MatriceReali10Per10 *par) - 12 -

dichiarazioni locali oggetti necessari per operazione del sottoprogramma ma inutili al programma principale stesse regole della parte dichiarativa di un programma nuove dichiarazioni di tipi di costanti di altri sottoprogrammi (prototipi) variabili dichiarate qui dette variabili locali o proprie del sottoprogramma corpo della funzione parte esecutiva costruita con stesse regole del programma principale in aggiunta contiene istruzione return espressione; valore dell espressione diventa risultato restituito al chiamante visto dal chiamante, valore restituito è il valore dell espressione di chiamata termina esecuzione del sottoprogramma, restituisce controllo al chiamante NB possono esserci più istruzioni return a ogni chiamata se ne esegue solo una se istruzione di return assente dal corpo della funzione o nessuna di quelle presenti eseguita sottoprogramma termina quando arriva a risultato della funzione indefinito segnalazione di errore Esempi: int FatturatoTotale (ElencoFatture parametro) { int Totale, Cont; Totale = 0; for (Cont = 0; Cont < parametro.numfatture; Cont++) Totale = Totale + parametro.sequenza[cont].importo; return Totale; /* calcola radice quadrata intera, i.e., max intero il cui quadrato <= par NB se par < 0 risultato 1 segnala uso improprio della funzione*/ int RadiceIntera (int par) { int cont; cont = 0; while (cont*cont <= par) cont = cont + 1; /* NB qui cont*cont > par, altrimenti while non terminerebbe */ return (cont 1); - 13 -

Chiamata delle funzioni sintassi ispirata a notazione matematica una funzione, applicata a suoi argomenti, fornisce un valore del suo codominio nei programmi i valori denotati da espressioni chiamata di funzione sintatticamente è un espressione sintassi identificatore della funzione lista dei parametri attuali racchiusa fra parentesi tonde parametri attuali: valori degli argomenti ai quali applicata funzione ogni parametro è un espressione può contenere altra chiamata di funzione corrispondenza tra parametri formali e attuali determinata dall ordine primo formale primo attuale secondo formale secondo attuale etc. numero parametri attuali = numero parametri formali tipo dei parametri attuali compatibile con tipo dei formali Esempi: x = sin(y) cos(pigreco alfa); /* PiGreco indica valore costante π */ x = cos(atan(y) beta); x = sin(alfa); y = cos(alfa) sin(beta); z = sin(pigreco) + sin(gamma); RisultatoDiGestione = FatturatoTotale(ArchivioFatture) SommaCosti(ArchivioCosti); Det1 = Determinante(Matrice1); Det2 = Determinante(MatriceInversa(Matrice2)); TotaleAssoluto = Sommatoria(Lista1) + Sommatoria(Lista2); ElencoOrdinato = Ordinamento(Elenco); OrdinatiAlfabeticamente = Precede(nome1, nome2); - 14 -

Prototipo delle funzioni funzione può essere chiamata solo se definita oppure dichiarata NB definizione e dichiarazione NON sono sinonimi definizione comprende testata + blocco (blocco = dichiarazioni locali + corpo) dichiarazione di funzione (detta prototipo) riporta la testata della funzione va posta nella parte dichiarativa globale o nella parte dichiarativa del main o nella parte dichiarativa propria dei sottoprogrammi che chiamano la funzione facilita controlli svolti dal compilatore parte dichiarativa del programma principale e di una funzione contengono quindi dichiarazioni di costanti dichiarazioni di tipo dichiarazioni di variabili prototipi di funzioni - 15 -

Esecuzione delle funzioni e passaggio dei parametri comportamento della macchina astratta durante esecuzione funzioni Ci riferiamo a esempio /* Programma Contabilità */ /* Parte direttiva */ #include <stdio.h> #define MaxNumFatture 1000 /* Parte dichiarativa globale */ typedef char String [30]; typedef struct { String Indirizzo; int ammontare; Data DataFattura; DescrizioneFatture; typedef struct { int NumFatture; DescrizioneFatture Sequenza[MaxNumFatture]; ElencoFatture; main() { ElencoFatture ArchivioFatture1, ArchivioFatture2; int Fatt1, Fatt2, Fatt; /* Prototipo della funzione FatturatoTotale */ int FatturatoTotale(ElencoFatture parametro);. Fatt1 = FatturatoTotale(ArchivioFatture1); Fatt2 = FatturatoTotale(ArchivioFatture2); Fatt = Fatt1 + Fatt2;. /* Fine del main del programma Contabilità */ int FatturatoTotale (ElencoFatture parametro) { int Totale, Cont;. return Totale; NB: nel main prototipo di funzione FatturatoTotale perchè uso precede definizione parte dichiarativa globale: DescrizioneFattura e ElencoFatture tipi utilizzati sia da main sia da funzione - 16 -

descrizione esecuzione con metafora di due macchine astratte una macchina principale per esecuzione main una asservita per esecuzione funzione entrambe dotate di proprio insieme di variabili detto ambiente o stato di esecuzione ambiente macchina principale contiene due variabili di tipo ElencoFatture, di nome ArchivioFatture1 e ArchivioFatture2 tre variabili di tipo int, Fatt1, Fatt2 e Fatt ambiente della macchina asservita (ambiente locale della funzione) una variabile di tipo ElencoFatture, di nome parametro due variabili intere, di nome Totale e Cont una ulteriore variabile per comunicare risultato al programma principale non esplicitamente referenziata, quindi anonima ma la immaginiamo con stesso identificatore della funzione e con tipo del risultato restituito a questa variabile assegnato valore dell espressione che segue istruzne return (nell esempio variabile Totale) effetto dell esecuzione di Fatt1 = FatturatoTotale (ArchivioFatture1); - 17 -

macchina principale valutata espressione a destra del simbolo dell operatore di assegnamento = creata macchina asservita passaggio dei parametri copiatura valore parametro attuale nel corrispondente parametro formale ceduto il controllo alla macchina asservita (esecuzione macchina principale sospesa) esecuzione del corpo della funzione fino a return o a alla fine cella FatturatoTotale contiene valore controllo restituito a macchina principale preleva valore cella FatturatoTotale diventa valore dell espressione: FatturatoTotale (ArchivioFatture1) assegna valore a Fatt1. caso leggermente più complesso: x = sin(atan(y) acos(z)); effetto complessivo del calcolo uguale a quello del codice temp1 = atan(y); temp2 = acos(z); x = sin(temp1 temp2); (al solito variabili temp1 e temp2 assunte non impiegate altrove) - 18 -

Le procedure non tutte operazioni interessanti descrivibili astrattamente da funzioni matematiche a volte si vuole effettuare qualche azione cambiare valore di variabili Esempi stampare elenco di fatture non c è alcun valore da calcolare va fatto in modo parametrico (diversi elenchi in diversi momenti) inserire nuova fattura in archivio di fatture preesistente aggiornamento di variabile, non calcolo di valore ordinare un array di interi a effetto: permutare valori presenti in a NON calcolare un valore di tipo array di interi si usa diverso tipo di sottoprogramma sottoprogramma procedurale o procedura funzione con tipo del risultato void void tipo predefinito fittizio, non possiede alcun valore nè operazione void usabile anche come tipo per parametri formali di sottoprogrammi senza parametri sintatticamente, chiamata di procedura è un istruzione identificatore della procedura elenco dei parametri attuali fra parentesi tonde (come per funzioni) - 19 -

Esempio: operazione InserisciFattura /*Programma Contabilità */ #include<stdio.h> #define MaxNumFatture 1000 typedef struct { String Indirizzo; int ammontare; Data DataFattura; DescrizioneFatture; typedef struct { int NumFatture; DescrizioneFatture Sequenza[MaxNumFatture]; ElencoFatture; ElencoFatture ArchivioFatture; /* NB condivisi non solo tipi ma anche qsta variabile */ main() { Data DataOdierna; DescrizioneFatture Fattura1, Fattura2; void InserisciFattura(DescrizioneFatture Fattura); boolean Precede(Data Num1, Data Num2); /* Sequenza di istruzioni che leggono i dati di una fattura in Fattura1 */ InserisciFattura(Fattura1); /* Sequenza di istruzioni che leggono i dati di una fattura in Fattura2 */ if (Precede(Fattura2.DataFattura, DataOdierna)) InserisciFattura(Fattura2); void InserisciFattura(DescrizioneFatture Fattura) { if (ArchivioFatture.NumFatture == MaxNumFatture) printf("l'archivio è pieno.\n"); else { ArchivioFatture.NumFatture = ArchivioFatture.NumFatture + 1; ArchivioFatture.Sequenza[ArchivioFatture.NumFatture 1] = Fattura; - 20 -

Esecuzione di questo esempio oltre ad ambiente principale e della procedura c è ambiente globale del programma contiene variabile ArchivioFatture di tipo ElencoFatture macchina esecutrice di InserisciFattura accede all ambiente globale modificandolo variabile ArchivioFatture è per la procedura una variabile globale al termine macchina asservita cede controllo alla principale senza produrre alcun risultato (effetto desiderato è modifica della variabile globale) - 21 -

passaggio dei parametri per indirizzo finora visti due modi per i sottoprogrammi di produrre effetti desiderati 1. fornendo un valore come risultato del calcolo di una funzione 2. modificando contenuto di variabili globali rispetto al sottoprogramma altro modo: passaggio parametri per indirizzo permette di modificare valore dei parametri Esempio: con riferimento a procedura InserisciFattura facciamo inserimenti scegliendo sia la fattura sia l archivio soluzione naturale: rendere un parametro anche l archivio da aggiornare void InserisciFattura( DescrizioneFatture Fattura, ElencoFatture ArchivioFatture) { if (ArchivioFatture.NumFatture == MaxNumFatture) printf("l'archivio è pieno."); else { ArchivioFatture.NumFatture = ArchivioFatture.NumFatture + 1; ArchivioFatture.Sequenza[ArchivioFatture.NumFatture 1] = Fattura; NB: effetto della chiamata: InserisciFattura (Fattura1, ArchivioFatture5); valori di Fattura1 e di ArchivioFatture5 copiati nei parametri formali Fattura e ArchivioFatture esecuzione della procedura inserisce Fattura in ArchivioFatture (il parametro formale) ma non in ArchivioFatture5 operazione eseguita su parametro formale, non su quello attuale modifica di parametro attuale ottenibile in C 1. parametro formale definito di tipo puntatore a tipo del parametro attuale desiderato (e.g., ElencoFatture) 2. alla chiamata passato indirizzo (usando &) del parametro attuale desiderato che deve essere una variabile, NON generica espressione 3. nel corpo della funzione usato operatore di dereferenziazione per accedere a parametro attuale desiderato mediante suo indirizzo questo chiamato passaggio per indirizzo l altro modo (copiatura del valore del parametro attuale, non del suo indirizzo, in quello formale) chiamato passaggio per valore - 22 -

Esempio rivisitato /*Programma Contabilità */ #include <stdio.h> main() { ElencoFatture ArchivioFatture5; /* ArchivioFatture5 è variabile locale del main. Appartiene all'ambiente del programma chiamante */ Data DataOdierna; DescrizioneFatture Fattura1, Fattura2; /* Prototipo della procedura InserisciFattura */ void InserisciFattura (DescrizioneFattureFattura, ElencoFatture *PointToArchivioFatture); /* Prototipo della funzione Precede */ boolean Precede(Data Num1, Data Num2); /* Sequenza di istruzioni che leggono i dati di una fattura in Fattura1 */ InserisciFattura(Fattura1, &ArchivioFatture5); /* Sequenza di istruzioni che leggono i dati di una fattura in Fattura2 */ if (Precede(Fattura2.DataFattura, DataOdierna) InserisciFattura(Fattura2, &ArchivioFatture5); /* NB passato valore di Fattura2 e indirizzo di ArchivioFatture5 */ /* Definizione della procedura InserisciFattura */ void InserisciFattura (DescrizioneFatture Fattura, ElencoFatture *PointToArchivioFatture) { if (PointToArchivioFatture > NumFatture == MaxNumFatture) printf("l'archivio è pieno.\n"); else { PointToArchivioFatture > NumFatture = PointToArchivioFatture > NumFatture + 1; PointToArchivioFatture > Sequenza[PointToArchivioFatture > NumFatture 1] = Fattura; Applicazione: uso della funzione scanf int dato;. scanf( %d, &dato); il secondo parametro attuale ha & perchè dev essere modificato: assume il valore letto - 23 -

Aspetti avanzati nell uso dei sottoprogrammi Riepilogo sulla struttura di un programma C parte direttiva; parte dichiarativa globale che comprende: dichiarazioni di costanti dichiarazioni di tipi dichiarazioni di variabili prototipi di procedure e funzioni programma principale main definizioni di funzioni o procedure NB: procedure e programma main considerati casi particolari di funzioni testata del programma principale si può scrivere come void main (void) (vedremo che main può anche aver parametri) main deve esserci: esecuzione programmi inizia dal suo corpo blocco: nuovo tipo di istruzione Il concetto di blocco composto da due parti racchiuse tra graffe una parte dichiarativa (facoltativa); una sequenza di istruzioni. blocco può comparire ovunque sintassi preveda istruzione sequenze di istruzioni tra graffe nelle istruzioni composte sono un istruzione blocco due blocchi possono essere annidati uno è interno all altro paralleli entrambi interni a un terzo ma non annidati tra di loro - 24 -

Esempio: /* Programma ComplessoInStruttura */ /* Parte direttiva */ #include <stdio.h> /* Parte dichiarativa globale */ rappresentazione mediante modello a contorni int g1, g2; char g3; int f1(int par1, int par2); /* Prototipo di f1 */ /* Definizione del main */ main () { int a, b; int f2(int par3, int par1); /* Prototipo di f2 */ /* blocco1 */ { char a, c; /* blocco2 annidato nel blocco1 */ { float a; /* Fine blocco2 */ /* Fine blocco1 */ /* Fine main */ /* Definizione della funzione f1 */ int f1(int par1, int par2) { int d; /* blocco3 */ { int e; /* Fine blocco3 */ /* blocco4 */ { int d; /* Fine blocco4 */ /* Fine f1 */ /* Definizione della funzione f2 */ int f2(int par3, int par4) { int f; /* Fine f2 */ - 25 -

ambito di visibilità delle variabili regole generali per uso di oggetti definiti in un programma, una funzione o un blocco (NB ricorda che main e procedure considerati particolari funzioni ) in linguaggi di programmazione c è flessibilità: è permesso dare stesso nome a entità diverse purché in parti dichiarative diverse evita proliferare di indentificatori complica nozione di visibilità degli identificatori: dove è lecito usare identificatore? quale entitià associata, in un dato punto del programma, a un dato indentificatore? Regola di visibilità delle entità in C con termine visibile intendiamo: può essere visto, cioè usato e referenziato tramite l identificatore inserito in nuove dichiarazioni valutato in un espressione assegnato valore (se variabile) elementi dichiarati nella parte dichiarativa globale del programma visibili da tutte le funzioni (incluso main e procedure) e i blocchi del programma identificatori predefiniti del linguaggio si intendono dichiarati nella parte dichiarativa globale elementi dichiarati nella parte dichiarativa di una funzione visibili da istruzioni del suo corpo, inclusi i blocchi in esso contenuti, ma non oltre elementi dichiarati nella parte dichiarativa di un blocco visibili nelle istruzioni del blocco, inclusi i blocchi in esso contenuti, ma non oltre - 26 -

NB: a parziale deroga di quanto sopra dichiarazione di un elemento in una funzione o blocco maschera eventuali entità omonime più esterne cioè se nuova dichiarazione dichiarazione sta in parte dichiarativa di funzione maschera dichiazione omonima in parte dichiarativa globale se dichiarazione sta in parte dichiarativa di blocco, maschera dichiarazione omonima in blocco o funzione contentente o in parte dichiarativa globale in altri termini entità da associare a identificatore trovata con una ricerca verso l esterno da blocco si va verso parte dichiarativa, blocchi esterni, funzione, parte dichiarativa globale l entità denotata è quella incontrata per prima ulteriore regola, tipica del C ogni identificatore di variabile non va mai usato prima della sua dichiarazione per identificatori delle funzioni regole molto semplici ogni funzione componente di un programma visibile ( richiamabile) in qualunque punto del programma. fortemente consigliato uso dei prototipi se chiamata precede definizione completa di una funzione - 27 -

applicazione delle regole viste in main visibili variabili globali g1, g2 e g3 visibili variaibli locali a e b richiamabile funzione f1 ed f2; dal blocco blocco1 visibili variabili globali g1, g2, g3 variabili locali al main b (NB a è ridefinita da blocco1) variabili a e c locali richiamabile sia f1 sia f2 dal blocco blocco2 visibili variabili globali g1, g2, g3 visibile variabile locale al main b (NB a ridefinita da blocco2) variabile del blocco blocco1 c (NB a ridefinita da blocco2) variabile a locale da blocco blocco2 richiamabili f1 ed f2 dalla funzione f1 visibili variabili globali g1, g2 e g3 variabile locale d richiamabile funzioni f2 ed f1 NON visibili variabili a, b, c, f (variabli e, d visibili in blocco1 e blocco2 dal blocco blocco3 visibili variabili globali g1, g2, g3 visibili variabile d locale a f1 visibile variabile locale e richiamabile sia f1 sia f2 dal blocco blocco4 visibili variabili globali g1, g2, g3 visibile variabile locale d (NB d di f1 mascherata) NON visibile variabile e locale al blocco blocco3 richiamabile sia f1 sia f2 dalla funzione f2 visibili variabili globali g1, g2 e g3 visibile variabile locale f richiamabile funzioni f1 ed f2 NON visibili variabili a, b, c, d, e. - 28 -

Durata delle variabili va da creazione (allocazione della memoria) alla distruzione (rilascio della memoria deallocata) due categorie di variabili variabili fisse o statiche allocate una sola volta distrutte al termine dell esecuzione del programma dichiarate nella parte dichiarativa globale fungono da canali di comunicazione tra funzioni variabili automatiche create quando esecuzione entra nel loro ambito di visibilità distrutte all uscita da tale ambito dichiarate nelle funzioni (inclusi parametri) e blocchi NB variabili automatiche di blocchi o funzioni eseguiti più volte allocate di volta in volta in celle differenti non conservati i valori prodotti da precedenti esecuzioni di funzione o blocco Esempio: g1, g2, g3 uniche variabili fisse, tutte altre automatiche Eccezione: variabili di funzione o blocco dichiarabili a durata fissa facendo precedere dichiarazione da parola chiave static Esempio static int d; - 29 -

Uso di parametri di tipo array array passato come parametro attuale passato indirizzo di base dell array (indirizzo della prima componente) NB elementi dell array NON vengono copiati nel parametro formale parametro formale della funzione trattato come puntatore Esempio typedef double TipoArray[MaxNumElem] /* n è la dimensione dell'array passato */ double sum(tipoarray a, int n) double sum(double *a, int n) double sum(double a[ ], int n) tre testate di funzione equivalenti NB nel parametro formale corripondente ad array non si può indicare dimensione (è un puntatore) Esempio: funzione che moltiplica gli elementi di un array di tipo double double mul(double a[ ], int n) /* n dimensione dell'array passato */ { int i; double ris; ris = 1.0; for ( i = 0; i < n; i = i + 1 ) ris = ris * a[i]; return ris; se nel main dichiarato double v[50]; Chiamata mul(v, 50) mul(v, 30) mul(&v[5], 7) mul(v+5, 7) Valore calcolato e restituito v[0]*v[1]* *v[49] v[0]*v[1]* *v[29] v[5]*v[6]* *v[11] v[5]*v[6]* *v[11] - 30 -

Uso di parametri di tipo struttura strutture possono essere passate per valore o per indirizzo NB si può passare struttura per valore anche quando contiene componente di tipo array NB qui C non è ortogonale Effetti collaterali a volte funzioni C non si comportano come funzioni della matematica Esempio int PrimoEsempio(int par) { return (par + x) x = 1; x = PrimoEsempio(1); /* ora x vale 2 */ x = PrimoEsempio(1); /* ora x vale 2 */ motivo della non-funzionalità: funzione utilizza variabile globale Esempio int SecondoEsempio(int *par) { *par = *par + 1; return *par; y = SecondoEsempio(&z) /* oltre a restituire valore, modifica z */ motivo della non-funzionalità: passaggio per indirizzo modifica parametro raccomandazioni per preservare funzionalità delle funzioni C passare parametri per valore non accedere a variabili non locali - 31 -

in certi casi programmazione non funzionale è comoda Esempio esamina ultima fattura inserita in ArchivioFatture la elimina se giorno di emissione non desiderato, comunque la si restituisce al chiamante DescrizioneFatture EsaminaElimina(int ParGiorno) { DescrizioneFatture FatturaLocale; FatturaLocale = ArchivioFatture.Sequenza[ArchivioFatture.NumFatture 1]; if (FatturaLocale.DataFattura.Giorno == ParGiorno) ArchivioFatture.NumFatture = ArchivioFatture.NumFatture 1; return FatturaLocale; SCONSIGLIATO uso effetti collaterali la procedura non è più parametrica (e.g., rispetto all archivio) non è esplicito, nella chiamata, su quale archivio è fatta l operazione significato della procedura dipende dal contesto passare sempre come parametro tutto quanto usato (letto o modificato) quindi meglio DescrizioneFatture EsaminaElimina(ElencoFatture *Archivio, int ParGiorno) { DescrizioneFatture FatturaLocale; FatturaLocale = Archivio -> Sequenza[Archivio.NumFatture 1]; if (FatturaLocale.DataFattura.Giorno == ParGiorno) Archivio -> NumFatture = Archivio.NumFatture 1; return FatturaLocale; - 32 -

pro e contro delle tecniche di passaggio parametri per valore occorre lunga copiatura se parametro ingombrante parametro attuale e formale distinti NON permette di restituire risultato al chiamante per indirizzo si copia indirizzo dimensione fissa NON occorre lunga copiatura parametro attuale e formale di fatto coincidono permette di restituire risultato al chiamante modo passaggio proprietà tempo e spazio necessari rischio effetti collaterali indesiderati restituzione valore al chiamante PER VALORE alti NO NO PER INDIRIZZO bassi SI SI memento: strutture si possono passare in entrambi i modi array solo per indirizzo Esempio: matrice quadrata passata a funzione per calcolo determinante se funzione esegue assegnamenti a elementi della matrice (cui punta il parametro formale) effetto collaterale (probabilmente non voluti) su parametro attuale - 33 -

Uso interscambiabile di procedure e funzioni facile trasformare funzione in procedura rendendo il risultato un parametro aggiuntivo Esempio: funzione int f(int par1) { return risultato; chiamata con istruzione y = f(x); diventa la procedura void f(int par1, int *par2) { *par2 = risultato; chiamata con istruzione f(x, &y); funzioni e procedure intercambiabili in qualche misura (mancanza di ortogonalità) problemi con array che non possono essere oggetto di assegnamento - 34 -

Procedure e funzioni predefinite standard library del C include sottoprogrammi di vasto uso non riscoprire continuamente l acqua calda nel testo, elencate in Appendice C Operazioni di ingresso/uscita (I/O) include operazioni da tastiera/video (standard input) operazioni su file I/O di stringhe e caratteri I/O formattato e non gestione degli errori Operazioni matematiche e aritmetiche. include operazioni trigonometriche (anche inverse e iperboliche) esponenziali e logaritmiche valore assoluto Operazioni di gestione della memoria per allocare e rilasciare memoria Operazioni di gestione di caratteri e stringhe include operazioni di copia, concatenamento e confronto tra stringhe ricerca di caratteri in stringhe calcolo lunghezza stringhe Operazioni di Operazioni di ricerca e ordinamento su array gestione di date e tempo generazione di numeri casuali.. comunicazione con sistema operativo gestione degli errori che fanno fallire esecuzione funzioni Header file contengono prototipi di funzioni di libreria Esempio stdio.h contiene prototipi delle operazioni di I/O formattato tra gli altri quelli di printf e di scanf Con direttiva #include <stdio.h> preprocessore copia contenuto del file stdio.h nel programma prototipi inclusi nella parte dichiarativa globale funzioni richiamabili in tutto il programma - 35 -

Esempio: legge due stringhe, le concatena in ordine alfabetico in una terza si usa libreria standard string.h assume stringhe memorizzate in array di caratteri dimensione array > lunghezza stringa effettiva (numero caratteri) parte utile terminata da carattere di fine stringa \0 (il carattere null) argomenti delle funzioni sono array di caratteri puntatori a caratteri (nome di array in C è puntatore a char) int strcmp(char *s1, char *s2); risultato è < 0 s1 alfabeticamente minore di s2 = 0 s1 alfabeticamente uguale a s2 > 0 s1 alfabeticamente maggiore di s2 char *strcpy(char *s1, char *s2); s2 copiata in s1 sino a \0 compreso (assume s1 abbastanza capiente) restituito s1. char *strcat(char *s1, char *s2); concatena s1 a s2 e pone risultato in s1 (assume s1 abbastanza capiente) unsigned strlen(char *s); restituisce numero caratteri che precedono \0 /* Programma Concatenazione di stringhe */ #include <stdio.h> #include <string.h> #define LunghezzaArray 50 main() { char PrimaStringa[LunghezzaArray], SecondaStringa[LunghezzaArray], StringaConc[2 * LunghezzaArray]; unsigned LunghezzaConc; scanf( %s, PrimaStringa); /* NB scanf assume caratteri stringa diversi da spazio */ scanf( %s, SecondaStringa); if (strcmp(primastringa, SecondaStringa) <= 0 ) { strcpy(stringaconc, PrimaStringa); strcat(stringaconc, SecondaStringa); else { strcpy(stringaconc, SecondaStringa); strcat(stringaconc, PrimaStringa); LunghezzaConc = strlen(stringaconc); printf( La stringa ottenuta concatenando le due stringhe lette è %s.\n Essa è lunga %d caratteri\n, StringaConc, LunghezzaConc); - 36 -