Informatica 2 – modulo C · • In programmazione moderna, il primo meccanismo di scomposizione...

47
Informatica 2 modulo C Massimo Callisto De Donato [email protected] www.cs.unicam.it/massimo.callisto LEZIONE 6 FUNZIONI Università degli studi di Camerino Scuola di scienze e tecnologia - Sezione Informatica

Transcript of Informatica 2 – modulo C · • In programmazione moderna, il primo meccanismo di scomposizione...

Informatica 2 – modulo CMassimo Callisto De Donato

[email protected]

www.cs.unicam.it/massimo.callisto

LEZIONE 6 – FUNZIONI

Università degli studi di CamerinoScuola di scienze e tecnologia - Sezione Informatica

Le funzioni in generale• Le funzionalità richieste ai computer tendono ad essere man mano sempre più

complesse.

• Ogni programma tende inevitabilmente ad essere sempre più grandi e difficile da gestire.

• Si rende necessario sfruttare meccanismi capaci di scomporre i programmi più piccoli da organizzare, scrivere e testare.

• Vantaggio: i programmi di grandi dimensioni non sono altro che composizione di programmi più piccoli già collaudati e testati.

• In programmazione moderna, il primo meccanismo di scomposizione è rappresentato dalle funzioni (note anche come sottoprogramma, procedura, etc.)

Le funzioni in generale• Programmazione modulare: il blocco monolitico del programma (main) in

cui ci muoviamo (con iterazioni/condizioni) viene snellito ed il progettista affida ad un sottoprogramma un determinato compito.

• Esempi: calcolare il valore assoluto, calcolare la radice quadrata, etc.

• Riusabilità del codice: i sottoprogrammi possono essere riutilizzati ogni volta che sia necessario svolgere quel preciso compito evitando di dover riscrivere ogni volta le stesse cose.

• Chiaro che alle funzioni predefinite del linguaggio che usiamo, possiamo associare funzioni create ad-hoc da richiamare in modo opportuno.

Le funzioni in C• In C i sottoprogrammi sono dette funzioni il cui concetto è molto simile a quello di

funzione matematica:– Ogni funzione prende in input dei valori (dominio) e restituisce dei valori (tipo di ritorno o

codominio della funzione).

• Dal punto di vista informatico, una funzione è come ad una scatola nera (black-box) che a determinati valori in ingresso fa corrispondere un valore in uscita.

• Esempio: int abs(int i), double sqrt(double x), int

atoi(const char *str), ...

• Chiaro che una funzione deve essere usata in base a come è stata definita a meno di casting controllati (es. float in sqrt).

• Scrivere delle funzioni proprie (definite dal’utente) richiede che questa scatola venga “aperta” (white-box) e definirne esplicitamente il comportamento.

Esempio: uso di funzioni standard#include <stdio.h>

main ()

{

double a, b;

printf("Inserisci un numero: ");

scanf("%f", &a);

b = a*a*a;

printf("\nValore di b al cubo (%f) rispetto ad a (%f)\n", b, a);

system("pause");

}

Esempio: la prima funzione#include <stdio.h>

double cubo(float valore); // Dichiaro il PROTOTIPO della funzione

main ()

{

double a, b;

printf("Inserisci un numero: ");

scanf("%f", &a);

b = cubo(a);

printf("Valore di b al cubo (%f) rispetto ad a (%f)\n", b, a);

system("pause");

}

double cubo(double valore){ // Definisco la funzione

double temp = valore * valore * valore;

return valore;

}

Esempio: la prima funzione (2)#include <stdio.h>

/* In questo caso, definizione e dichiarazione coincidono.

Quindi prima del main non mettiamo nessun prototipo. */

double cubo(double valore){ // Definisco la funzione

double temp = valore * valore * valore;

return valore;

}

main ()

{

double a, b;

printf("Inserisci un numero: ");

scanf("%f", &a);

b = cubo(a);

printf("Valore di b al cubo (%f) rispetto ad a (%f)\n", b, a);

system("pause");

}

Le funzioni in C: definizione• La dichiarazione permette di introdurre un nuovo nome di funzione in modo che

questa possa essere utilizzata all’interno del programma.

• La dichiarazione serve a dire al compilatore come è fatta la funzione e come deve essere usata. Un esempio di dichiarazione è:

double cubo (float v);

Con cui abbiamo specificato che:

– cubo è il nome di una funzione da usare nel codice

– restituisce un valore e quel valore è di tipo double

– accetta in ingresso un solo valore e quel valore è di tipo float.

• Questa dichiarazione va messa obbligatoriamente prima del main (a patto che, come prima, la dichiarazione non corrisponda con la definizione).

• La definizione, ovvero il corpo della funzione, può trovarsi altrove (anche su altri file). Nel caso di prima è stato messo dopo la chiusura del main.

Le funzioni in C: definizione

• Sintassi della dichiarazione di una funzione:

tipo_ritorno nome_funzione (tipoPar_1, …, tipoPar_n);

• Nella dichiarazione, tipoPar_1 può essere definito con il tipoPar_1 nome oppure solo con tipoPar_1:

double cubo (float v);

double cubo (float);

• Le due righe di sopra sono del tutto equivalenti. Tuttavia i nomi sono utili per la leggibilità del codice.

• Per i nomi delle funzione valgono le stesse regole viste per i nomi delle variabili.

Le funzioni in C: dichiarazione

• La dichiarazione della funzione (il corpo) può essere messa: prima del main (senza definizione), alla fine del main, su un altro file.

• Sintassi generica della definizione:

tipo_ritorno nome_funzione (tipoPar_1 par1, … tipoPar_n par_n){

dichiarazione di variabili locali

sequenza istruzioni

return valore;

}

• I parametri in ingresso sono detti anche parametri formali. Il valore di ritorno è opzionale.

• Nota che è necessario specificare sia il tipo che il nome di ciascun parametro. Il primo caso è sbagliato:tipo_ritorno nome_funzione (tipoPar_1, … tipoPar_n){

tipo_ritorno nome_funzione (tipoPar_1 par1, … tipoPar_n){

Esempio di funzione: esempi uguali#include <stdio.h>

int pari(int);

main ()

{

int x;

printf("Inserisci un numero: ");

scanf("%d", &x);

if (pari(x))

printf(“Numero pari\n");

else

printf(“Numero dispari\n");

system("pause");

}

int pari(int a)

{

if (a%2 == 0 )

return 1;

else

return 0;

// potevamo scrivere

// return (a % 2) ? 0 : 1;

// oppure

// return !(a % 2);

}

#include <stdio.h>

int pari(int a)

{

if (a%2 == 0 )

return 1;

else

return 0;

// potevamo scrivere

// return (a % 2) ? 0 : 1;

// oppure

// return !(a % 2);

}

main ()

{

int x;

printf("Inserisci un numero: ");

scanf("%d", &x);

if (pari(x))

printf(“Numero pari\n");

else

printf(“Numero dispari\n");

system("pause");

}

Esempio di funzione#include <stdio.h>

#define DIM_INT 16

void stampa_bin(int);

main ()

{

char resp[2];

int num;

do {

printf("\nInserisci un intero: ");

scanf("%d", &num);

printf("\nRappresentazione binaria: ");

stampa_bin(num);

printf("\nVuoi continuare (si/no): ");

scanf("%s", resp);

} while((resp[0]=='s') || (resp[0]=='S'));

}

void stampa_bin(int n){

int bin[DIM_INT];

int i,j;

if ((n<0) || (n >= 65536)){

printf("numero non rappresentabile\n");

return 0;

}

// Metodo delle divisioni successive

i=0;

do {

bin[i] = n%2;

n= n/2;

i++;

}while (n>0);

for (j=i-1; j>=0; --j)

printf("%d", bin[j]);

}

Esempio di funzione#include <stdio.h>

#include <math.h>

#define YES 1

#define NO 0

int is_prime(int);

int primes(int);

main ()

{

int n, num;

float x, y;

printf("Inserisci un intero: ");

scanf("%d", &n);

printf("\nNumeri primi tra 1 e %d:\n", n);

num = primes(n);

printf("\n\n");

system("pause");

}

int is_prime(int n)

{

int max, i;

if (n >= 1 && n <= 3) return YES;

if (!(n%2)) return NO;

/* basta controllare tra 3 e radice di n*/

max = sqrt((double) n);

for (i=3; i <=max; i+=2)

if (!(n%i)) return NO;

return YES;

}

int primes(int n)

{

int count, i;

count = 0;

for (i=1; i <=n; i++){

if (is_prime(i)){

printf("%5d", i);

count++;

}

}

return count;

}

Le funzioni in C: no polimorfismo• In diversi linguaggi supportano il polimorfismo (es.: C++, Java), ovvero

definire funzioni con lo stesso nome ma parametri diversi. In C questo non è ammesso.

• Ad esempio, le seguenti funzioni usate all’interno di uno stesso programma darebbero luogo ad un errore:

double cubo(float c){

return (c * c * c);

}

float cubo(int c){

return (c * c * c);

}

• Quindi avere l'accortezza di mantenere nomi diversi per funzioni diverse. Inoltre il nome dovrebbe essere indicativo su ciò che fa la funzione.

Le funzioni in C: il return• Ad ogni funzione associamo il tipo (come avviene per le variabili). Il tipo in questo

caso è determinato dal valore di ritorno (il tipo di valore calcolato dalla funzione).

• Il tipo (ed il vaore valore) di ritorno viene determinato dalla return:return (espressione); oppure return espressione;

• La funzione termina appena si esegue una return (oppure alla chiusura della ‘}’ se non c'è).

– Possiamo avere più return all'interno della funzione.

– Se definiamo un tipo di ritorno ma per qualche ragione non c’è un ritorno di valore il comportamento diventa non predicibile.

int pari (int a)

{

if (a%2 == 0) return 1;

else return 0;

}

int pari (int a)

{

// uso di espressione

return ((a%2 == 0) ? 1 : 0);

}

int pari (int a)

{

// uso di espressione

return (!(a%2) ? 1 : 0);

}

Le funzioni in C: il valore nullo• Spesso capita di creare funzioni che adempiano ad un certo compito e

terminano senza restituire un valore.

• In questi casi si può usare la parola chiave void per dire “nessun valore”.

• Ad esempio, la funzione è una routine di gestione degli errori personalizzati (nota l’uso del return)

void myEerror(char a){

switch(a){

case „A‟:

printf(“error 1”);

return;

break;

case „B‟:

printf(“error 2”);

break;

}

// Questo è opzionale

return;

}

main(){

if(condizioneA)

myError(„A‟);

else if(condizioneX)

myError(„X‟);

}

Le funzioni in C: esercizio

• Definire una funzione che converta un valore inteso come temperatura espressa in gradi Celsius nel corrispettivo valore Fahrenheit. Scrivere anche la funzione opposta.

• Formule di conversione:

– [°C] = ([°F] - 32) × 5/9

– [°F] = [°C] × 9/5 + 32

• Se volessimo usare delle costanti simboliche? Dove e come?

Le funzioni in C: esercizio• Definire due funzioni toUpperC() e toLowerC() che prese in input un

carattere ritorni la sua versione, rispettivamente, minuscola e maiuscola.

char toUpperC(char);

char toLowerC(char);

• Riscrivere il tutto con una singola funzione toUppurLowerC() e che usi le costanti simboliche per definire l’operazione da eseguire sul carattere.

char toUppurLowerC(char C, boolean scelta); //(??)

• Re-implementare il programma per le stringhe palindrome e per la comparazione utilizzando le funzioni riportate sopra.

• Inoltre, i programmi dovranno offrire la scelta se fare una comparazione case-sensitive oppure no. La scelta ovviamente deve essere implementata con una funzione

Stringhe: palindrome (vecchia versione)#include<stdio.h>

#define LEN 100

main ()

{

char stringa[LEN];

int i, j;

int len, palindroma = 1;

printf("Inserisci una frase: ");

scanf("%s", stringa);

for(i=0; stringa[i] != '\0'; i++){}

len = i;

i--;

j = 0;

while(palindroma && (j < (len/2))){

if (stringa[i] != stringa[j])

palindroma = 0;

j++;

i--;

}

if (palindroma)

printf("palindroma\n");

else

printf("non palindroma\n");

}

Stringhe: comparazione (vecchia versione)#include <stdio.h>

#define LEN 100

main ()

{

int i, flag;

char s1[LEN], s2[LEN];

/* immissione stringhe */

printf("Inserisci le due stringhe separate da spazio\n");

scanf("%s %s", s1, s2);

i=0;flag = 0;

while ((s1[i] !='\0') && (s2[i] != '\0')){

if(s1[i] != s2[i]){

flag = (s1[i] < s2[i]) ? -1: 1;

break;

}

i++;

}

if (flag == -1) printf("%s e' minore di %s\n", s1, s2);

else if (flag == 1) printf("%s e' maggiore di %s\n", s1, s2);

/* se flag=0, allora o entrambe le stringhe sono arrivate a '\0',

oppure qualcuna è arrivata prima dell'altra. */

else if (!flag){

if ( (s1[i] == '\0') && (s2[i] == '\0') )

printf("Le due stringhe %s e %s sono uguali\n", s1, s2);

else if (s1[i] == '\0')

printf("%s e' minore di %s\n", s1, s2);

else

printf("%s e' maggiore di %s\n", s1, s2);

}

} // Il controllo è case-sensitive… Per farne uno non case-sensitive?

Le funzioni in C: i parametri• Abbiamo visto che ogni funzione può essere definita con dei dati in ingresso (i parametri):

tipo_ritorno nome (tipoPar_1 par1, … tipoPar_n par_n);

• Nell'invocazione (uso effettivo della funzione) sostituiamo a par_1,…, par_n i valori

effettivi (parametro attuali).

• Tali valori possono essere una qualsiasi espressione che fornisca un valore di quel tipo:

nome (espr_1, ..., espr_n)

• Ciascun parametro attuale (il risultato dell'espressione) viene assegnato al corrispondente

parametro formale.

#include <stdio.h>

int fun1 (int, int, int);

main()

{

int x;

x = fun1((3 + 5), abs(-9), !((42%2)<1));

printf("Val x: %d\n", x);

} // x==y alla fine?

int fun1(int a, int b, int c)

{

int y = a + b + c;

printf("Val y: %d\n", y);

return y++;

}

Le funzioni in C: altro esempio/* Che stampiamo?? */

#include <stdio.h>

int fun1 (int, int, int);

main()

{

int x;

x = fun1((3 + 5), abs(-9), !((42%2)<1));

printf("Val x: %d\n", x);

x = fun1((3 + 5), abs(-9), !((42%2)<1));

printf("Val x: %d\n", x);

} // x==y alla fine?

int fun1(int a, int b, int c)

{

int y;

printf("Val1 y: %d\n", y);

y = a + b + c;

printf("Val2 y: %d\n", y);

return y++;

}

Le funzioni in C: parametri formali ed attuali

• Abbiamo parlato di parametri formali e parametri attuali.

– Parametri formali: i parametri specificati nella funzione

– Parametri attuali: i parametri usati nel momento in cui la funzione viene invocata

• Il legame che c'è nel passaggio tra i due tipi di parametri sono:

– passaggio per valore: passiamo il valore contenuto nel parametro attuale

– passaggio per riferimento: passiamo effettivamente il parametro attuale

• Nel primo caso, se la funzione altera il parametro formale, il parametro attuale rimane invariato. Nel secondo caso, le eventuali modifiche si riflettono sull’altro.

• In C si usa solo il passaggio per valore (vedremo che i puntatori simulano il secondo caso).

Le funzioni in C: parametri formali ed attuali#include <stdio.h>

int fattoriale (int);

main()

{

int x = 5, i, fact = 1;

for(i = x; i >= 0; i--){

if(!i)

break;

fact *= i;

}

printf("Fattoriale di x: %d\n", fact);

printf("Fattoriale di x: %d\n", fattoriale(x));

system("PAUSE");

}

int fattoriale(int a)

{

if(!a) return 1;

return (a * fattoriale(a - 1));

}

Le funzioni in C: parametri formali ed attuali/* Che stampiamo? */

#include <stdio.h>

int fun1 (int);

int fun2 (int);

main(){

int x = 3;

printf("Val x: %d\n", x);

x = fun1(++x);

printf("Val x: %d\n", x);

}

int fun1(int x){

int y;

y = fun2(x);

printf("Val y, x: %d, %d\n", y, x);

return y + y + 4;

}

int fun2(int x){

printf("Val x2: %d\n", x);

printf("Val x2_1: %d\n", x++);

printf("Val x2_2: %d\n", x);

return x - 1;

}

Le funzioni in C: parametri formali ed attuali

• Abbiamo detto che il passaggio di parametri per valore intende che le modifiche sui parametri attuali non si ripercuotono su quelli formali:

main(){ void func(int a){

int a = 3; a++;

while(1) }

if(a==5) break;

else func(a);

}

• Avviene perché la visibilità delle variabili è locale alla funzione in cui sono dichiarate. Es.: la variabile a della funzione main è locale alla main ed è diversa dalla variabile a di func. Il seguente codice è scorretto:

#include <stdio.h>

void func(void);

main(){

int a = 3;

while(1)

if(a==5) break;

else func();

}

void func(void){

a++;

}

Le funzioni in C: variabili globali

• Per dare alle variabili una visibilità nell’intero programma (estende a tutto il file) definiamo le variabili globali.

Le funzioni in C: variabili globali/* ??? */

#include <stdio.h>

void func(void);

int a; // sono globale ma l‟inizializzazione?

main(){

int a = 3;

while(1)

if(a==5) break;

else func();

}

void func(void){

printf("a: %d", a);

return a++;

}

Le funzioni in C: variabili globali/* Ora: inizializzazione + fine */

#include <stdio.h>

void func(void);

int a = 3; // sono globale

main(){

//int a = 3; // giusto per far finire il programma

while(1)

if(a==5) break;

else func();

}

void func(void){

printf("a: %d", a);

return a++;

}

Le funzioni in C: i parametri• Dato un generico programma, le variabili si possono distinguere in base

alla loro visibilità:

– Ambiente globale: costituito dalle dichiarazioni/definizioni che compaiono nella parte di dichiarazioni globali.

– Ambiente locale a una funzione: l’insieme delle dichiarazioni/definizioni che compaiono nella parte dichiarazioni della funzione, più i suoi parametri formali.

• Ogni dichiarazione introduce un nome in un determinato ambito di definizione detto scope.

• E' ammesso che ci siano variabili con lo stesso nome che appaiano in scope diversi.

• Con le variabili globali, variabili con lo stesso nome hanno lo stesso scope. In tal caso, lo scope delle variabili locali nasconde quello della variabili globali.

Le funzioni in C: scope/* ?? */

#include <stdio.h>

int x = 13;

void f();

main ()

{

int i;

printf(“main: x = %d\n", x);

f();

printf("main: x = %d\n", x);

system("pause");

}

void f()

{

int x = 4;

printf("blocco f: x = %d\n", x++);

}

Esercizio

• Scrivere una funzione swap() che presi in

input due valori interi a e b li scambi.

Le funzioni in C: passaggio di array

• Ad una funzione possiamo anche passare gli array. La sintassi è la seguente

ritorno nome_funzione(tipo array[]);

• Se la dimensione max non è stata definita globalmente (es.: #define MAX_LEN 100) dobbiamo passare anche la dimensione massima:

ritorno nome_funzione(tipo array[], int dim_max);

• Attenzione! Gli array sono passati per riferimento. Significa che se la funzione modifica l’array allora la modifica si riflette nella funzione chiamante.

Le funzioni in C: passaggio di array/* ?? */

#include <stdio.h>

void stampa_vettore(int v[], int len);

void aumenta(int v[], int len);

main()

{

int x[] = {1,2,3,4};

stampa_vettore(x, 4);

aumenta(x, 4);

stampa_vettore(x, 4);

}

void aumenta(int v[], int len)

{

int i;

for(i = 0; i < len;)

v[i++]++;

}

void stampa_vettore(int v[], int len){

int i;

for(i = 0; i < len ; i++)

printf("%d, ", v[i]);

printf("\n");

}

Le funzioni in C: passaggio di array (multi)

• Possiamo anche passare array multidimensionali.

• In questo caso DOBBIAMO specificare le dimensioni successive alla prima:

ritorno nome_funzione(tipo array[][DIM2_MAX][DIM3_MAX]);

• E’ evidente che dobbiamo definire qualche variabile globale o costante per le varie dimensioni successive alla prima.

• Ad esempio una cosa del genere non funziona:

ritorno nome_funzione(tipo array[][int dim2][int dim3]);

• Attenzione! Gli array sono passati per riferimento. Significa che se la funzione modifica l’array allora la modifica si riflette nella funzione chiamante.

Le funzioni in C: passaggio di array (multi)/* ?? */

#include <stdio.h>

#define MAX_COL_LEN 3

void stampa_vettore(int v[], int len);

void aumenta(int v[], int len);

void stampa_vettore_multi(int v[][MAX_COL_LEN]);

main()

{

int i, j;

int x[] = {1,2,3,4};

int xx[4][MAX_COL_LEN];

for(i = 0; i < 4; i++)

for(j = 0; j < MAX_COL_LEN;)

xx[i][j++] = i;

stampa_vettore(x, 4);

aumenta(x, 4);

stampa_vettore(x, 4);

stampa_vettore_multi(xx);

}

void aumenta(int v[], int len)

{

int i;

for(i = 0; i < len;)

v[i++]++;

}

void stampa_vettore(int v[], int len){

int i;

for(i = 0; i < len ; i++)

printf("%d, ", v[i]);

printf("\n");

}

void stampa_vettore_multi(int

v[][MAX_COL_LEN]){

int i, j;

for(i = 0; i < 4; i++){

printf("\n");

for(j = 0; j < MAX_COL_LEN; j++)

printf("%d, ", v[i][j]);

}

}

Se volessimo riusare la funzione stampa_vettore invece del for?

Le funzioni in C: passaggio di array (multi)/* ?? */

#include <stdio.h>

#define MAX_COL_LEN 3

void stampa_vettore(int v[], int len);

void aumenta(int v[], int len);

void stampa_vettore_multi(int v[][MAX_COL_LEN]);

main()

{

int i, j;

int x[] = {1,2,3,4};

int xx[4][MAX_COL_LEN];

for(i = 0; i < 4; i++)

for(j = 0; j < MAX_COL_LEN;)

xx[i][j++] = i;

stampa_vettore(x, 4);

aumenta(x, 4);

stampa_vettore(x, 4);

stampa_vettore_multi(xx);

}

void aumenta(int v[], int len)

{

int i;

for(i = 0; i < len;)

v[i++]++;

}

void stampa_vettore(int v[], int len){

int i;

for(i = 0; i < len ; i++)

printf("%d, ", v[i]);

printf("\n");

}

void stampa_vettore_multi(int

v[][MAX_COL_LEN]){

int i;

for(i = 0; i < 4; i++)

stampa_vettore(v[i], MAX_COL_LEN);

}

Esercizio

• Scrivere una funzione swap() che presi in

input due valori interi a e b li scambi.

• Riusciamo a fare qualcosa in più ora?

Le funzioni in C: variabili statiche

• Una variabile statica è una normale variabile locale ad

una funzione.

• Viene inizializzata una sola volta (la prima volta che

viene richiamala la funzione genitore) ed il suo valore

resta inalterato quando si esce dalla funzione.

• A chiamate successive alla stessa funzione, la variabile

statica ha ancora il valore assegnatogli in precedenza.

• Sintassi: static tipo nome;

Le funzioni in C: variabili statiche/* ?? */

#include <stdio.h>

void func();

int a2 = 99;

main(){

int i;

for (i=0; i<5; ++i)

func();

printf("a2: %d \n", a2);

}

void func(){

int a1 = 0;

static int a2 = 0;

printf("a1: %d, a2: %d \n", ++a1, ++a2);

}

Le funzioni in C: altro esempio/* Che stampiamo?? */

#include <stdio.h>

int fun1 (int, int, int);

main()

{

int x;

x = fun1((3 + 5), abs(-9), !((42%2)<1));

printf("Val x: %d\n", x);

x = fun1((3 + 5), abs(-9), !((42%2)<1));

printf("Val x: %d\n", x);

} // x==y alla fine?

int fun1(int a, int b, int c)

{

static int y;

printf("Val1 y: %d\n", y);

y = a + b + c;

printf("Val2 y: %d\n", y);

return y++;

}

Esercizio

• Fare un programma calcolatrice che:

– Realizzi le 4 operazioni fondamentali su interi oltre che il modulo, radice quadrata, dice se è primo;

– Ogni operazione è una funzione;

– Usi solo la funzione getchar() per l’input e caratteri non ammessi vengono ignorati;

– Usi una funzione buildOp() che ri-costruisca la cifra intera a partire dalla sequenza di caratteri letti in input;

Le funzioni in C: una nota sul main()

• Abbiamo sempre usato la funzione main() dicendo che

identifica l’entry-point e la sua presenza è obbligatoria.

• L’uso è implicito ma anche la funzione main ha un

prototipo (in realtà 3):

int main(void);

int main(int argc, char *argv[]);

int main(int argc, char *argv[], char *envp[]);

Le funzioni in C: una nota sul main()int main(int argc, char *argv[], char *envp[]);

• int argc: rappresenta il numero di parametri passati al programma all’avvio, compreso il nome stesso.

• char *argv[]: lista degli argomenti passati in forma testuale (stringhe), compreso il nome del programma stesso.

• char *envp[]: rappresenta la lista delle variabili ambiente disponibili nel sistema operativo.

• Valore di ritorno int: serve a comunicare all’OS (o chi ha invocato il nostro programma) la condizione di terminazione. Es. possiamo assumere che:

– 0 - il programma dice che tutto è andato bene, – -1 - il programma dice che qualcosa è andato male.

Esempio di main() con argomenti#include <stdio.h>

int main (int argc, char *argv[])

{

int count;

// argc è sempre > 0 argv[0] è sempre corretto

printf ("Nome del programma '%s'\n",argv[0]);

printf ("Argomenti passati al programma:\n");

if (argc > 1)

for (count = 1; count < argc; count++)

printf("argv[%d] = %s\n", count, argv[count]);

else

printf("Nessun parametro passato.\n");

return 0;

}

/* nota che argc e argv sono nomi che si usano per convenzione. Potevamo

anche usare altri nomi. */

Esempio di main() con argomenti e variabili di ambiente

#include <stdio.h>

int main (int argc, char *argv[], char *envp[])

{

int count;

printf ("Nome del programma '%s'\n",argv[0]);

printf ("Argomenti passati al programma:\n");

if (argc > 1)

for (count = 1; count < argc; count++)

printf("argv[%d] = %s\n", count, argv[count]);

else

printf("Nessun parametro passato.\n");

// envp ha l‟elementi i-esimo == „\0‟ quando finisce

for(count = 0; envp[count] != '\0'; count++)

printf("Variabile envp[%d]: %s\n", count, envp[count]);

return 0;

}

Esercizio

• Modificare il programma della calcolatrice in modo tale che:

– Il programma si auto-configuri all’avvio per attivare o meno una funzione myLog() di logging su buildOp();

– myLog(), se attiva, stampa su schermo possibili errori di input (e.s. immissione di un carattere invece che numero);

– L’auto-configurazione si ottiene passando il relativo parametro di input log=1 (log attivo) oppure log=0 (log inattivo) all’avvio del programma nella forma (x = 1, 0): > nome_programma log=x

– Nota che log=valore corrisponde ad una stringa. Affinché myLog() interpreti valore, la stringa log=valore va spezzata su ‘=‘ e la parte finale valore deve essere convertita nel rispettivo valore decimale 0 oppure 1.