INFORMATICA
Sottoprogrammi
Sottoprogrammi
• Quando si scrive un programma succede spesso che si
debba eseguire numerose volte una stessa sequenza di
istruzioni, sugli stessi dati o su dati diversi.
• Supponiamo di dover realizzare un programma per il
gioco degli scacchi: ogni volta che si esegue una mossa i
pezzi devono essere ridisegnati o nella stessa posizione o
nella nuova posizione conseguente alla mossa.
• Per evitare di riscrivere più volte queste sequenze di
istruzioni e per limitare le dimensioni dei programmi, il
linguaggio C dispone di una particolare struttura chiamata
funzione
© Piero Demichelis
2
Sottoprogrammi
• Una funzione è un modulo di programma la cui
esecuzione può essere invocata più volte nel corso del
programma principale.
• La funzione può calcolare uno o più valori, che saranno
comunicati al programma chiamante al termine della sua
esecuzione, oppure può eseguire azioni generiche (come,
ad esempio, l’aggiornamento della base dati).
• Il nome funzione deriva dall'evidente analogia con le
funzioni intese in senso matematico.
• Poiché la funzione fornisce un valore, ad essa è associato
un tipo.
© Piero Demichelis
3
Sottoprogrammi
• Altra giustificazione all’esistenza dei sottoprogrammi
deriva dal fatto che un programma può consistere di
decine di migliaia di istruzioni.
• Sebbene fattibile, una soluzione “monolitica” del
problema è inefficiente in quanto complicata da
“debuggare ” e difficile da leggere.
• Per questo si tende a organizzare il programma
complessivo in “moduli ” ognuno dei quali tratta e risolve
solo una parte del problema.
• In altre parole si adotta, per la soluzione del problema, il
cosiddetto “approccio top-down ”
© Piero Demichelis
4
Approccio top-down
• Il problema è decomposto in una sequenza di
sottoproblemi più semplici.
• Quest’azione è ripetibile su più livelli, ovvero ogni
sottoproblema può a sua volta essere decomposto in una
sequenza di sottoproblemi.
• La decomposizione prosegue sino a che si ritiene che la
sequenza è composta ormai solamente da “sottoproblemi
terminali ”, ovvero da sottoproblemi risolvibili in modo
“semplice”.
© Piero Demichelis
5
Approccio top-down
• Esempio: pulizia di una casa
Pulizia Casa
Pulizia
Bagno
Togli
polvere
Lava
Pulizia
Cucina
Lucida
Togli
polvere
Lava
Pulizia
Camera
Lucida
© Piero Demichelis
Togli
polvere
Lava
Lucida
6
Approccio top-down
• I linguaggi di programmazione permettono di suddividere
le operazioni in modo simile tramite sottoprogrammi.
• La sequenza dei sottoproblemi terminali si traduce in una
sequenza di sottoprogrammi.
• Così pure, poiché una funzione può invocare un’altra
funzione, la gerarchia delle operazioni si traduce in una
gerarchia di sottoprogrammi.
• Genericamente si chiamano procedure i sottoprogrammi
che NON ritornano un risultato, funzioni i sottoprogrammi
che ritornano un risultato (di qualche tipo primitivo o
non).
© Piero Demichelis
7
Funzioni
• La forma generale è:
tipo nome_funzione (parametro_1;.........; parametro_n)
{
/* definizione delle costanti e delle variabili usate nella funzione */
/* attenzione! Saranno visibili solo nella funzione!
*/
/*
istruzioni della funzione
return (valore)
}
*/
• L'istruzione return provoca la restituzione del controllo al
programma chiamante nel quale valore viene associato al
nome della funzione che pertanto appare come una
normale variabile.
© Piero Demichelis
8
Funzioni
• La struttura è del tutto analoga a quella del programma
principale: lo stesso main è una funzione, anzi è l'unica
che può avere quel nome!
• Quando si manda in esecuzione un programma, è come
richiedere la valutazione della funzione main la quale, a
sua volta, può richiamare altre funzioni.
• Se non si specifica il tipo, il C assume che la funzione sia
di tipo intero (int).
• Capita talvolta che una funzione non debba restituire
alcun risultato: per questi casi il C prevede un tipo
speciale, void (“vacante ”): void nome_funzione è una
funzione che non restituisce nulla.
© Piero Demichelis
9
Funzioni
• Anche i parametri possono mancare: in questo caso si
può usare il tipo void, oppure niente (ma le parentesi che
delimitano la lista dei parametri devono essere sempre
presenti).
• Un modo per definire il programma principale è quindi
int main (void)
{
/*
corpo del programma
}
*/
• return può essere presente una o più volte o anche
nessuna: se manca, la funzione termina dopo l'ultima
istruzione.
© Piero Demichelis
10
Funzioni
• Nel corso del programma principale, per far eseguire la
funzione, è sufficiente “nominarla ” con gli eventuali
parametri.
• Esempio: programma per disegnare un rettangolo di
asterischi come il seguente:
************
*
*
*
*
*
*
************
• La prima e l'ultima riga contengono una sequenza di 12
asterischi, mentre le 3 righe centrali sono formate da un
asterisco seguito da 10 caratteri di spazio e da un altro
asterisco.
© Piero Demichelis
11
Esempio
• Possiamo organizzare il programma in modo tale da avere una
funzione, che chiameremo testacoda, per le righe estreme ed un'altra
funzione, corporett, per le righe intermedie.
#include <stdio.h>
void testacoda(void)
{
printf ("************\n");
*/
return;
}
void corporett(void)
{
printf ("*
return;
}
*\n");
/*
visualizza 12 asterischi
/* visualizza *, poi 10 spazi, poi * */
© Piero Demichelis
12
Esempio
main()
{
testacoda();
corporett();
corporett();
corporett();
testacoda();
}
• L'esecuzione del programma partirà dalla prima istruzione
del programma principale che è un'invocazione alla
procedura testacoda.
• Il controllo è poi trasferito alla prima istruzione della
funzione, al termine il controllo ritorna al programma
principale all'istruzione successiva alla chiamata, ecc.
© Piero Demichelis
13
Esempio
• Esempio: funzione che legge un numero intero da tastiera e lo restituisce al
programma chiamante.
#include <stdio.h>
int lettura (void)
{
int dato_letto;
printf (“\nIntroduci un intero: ");
scanf ("%d", &dato_letto);
return (dato_letto);
}
main()
{
int dato;
dato = lettura();
printf ("\nIl dato e': %d\n", dato);
}
© Piero Demichelis
14
Funzioni con parametri
• Affinché le funzioni possano essere utilizzate più volte
nello stesso programma o in programmi differenti è
necessario che possano operare su valori diversi dei dati
ad ogni chiamata.
• Il C prevede la trasmissione di parametri da un modulo ad
un altro: il programma che utilizza una funzione dichiara
nella chiamata il valore dei dati.
• Nell'esempio precedente (rettangolo), si potrebbero
generalizzare le funzioni consentendo all'utente di
specificare le dimensioni del rettangolo, la posizione dello
stesso rispetto ai bordi dello schermo, il carattere da
utilizzare per la stampa al posto di ‘*’, ecc.
© Piero Demichelis
15
Passaggio dei parametri “by value”
• Affinché una funzione possa “ricevere” dati dal
programma chiamante, occorre che essi siano indicati tra
parentesi nella dichiarazione di funzione, ognuno con il
proprio tipo, così:
tipo_parametro identificatore
e separati da “,” (virgola) tra di loro.
• Il programma richiama una funzione parametrizzata
facendo seguire al nome della funzione stessa la lista
degli identificatori dei dati racchiusi tra parentesi.
• Generalmente gli identificatori usati nel programma
chiamante sono diversi da quelli usati nella funzione: la
corrispondenza è basata solo sull'ordine nella lista.
© Piero Demichelis
16
Passaggio dei parametri “by value”
• Esempio: funzione che calcola la media tra due numeri interi.
#include <stdio.h>
int media (int val1, int val2)
{
int media;
media = (val1 + val2) / 2;
return (media);
}
/* divisione tra interi!
*/
main()
{
int primo, secondo, finale;
printf (“\nIntroduci due numeri interi: “);
scanf (“%d%d”, &primo, &secondo);
finale = media (primo, secondo);
printf (“\nLa media tra %d e %d è: %d”, primo, secondo, finale);
}
© Piero Demichelis
17
Passaggio dei parametri “by value”
• Le variabili che compaiono nella dichiarazione di funzione
(nell'esempio val1 e val2), sono detti
parametri formali.
• Le variabili che compaiono nella chiamata, (nell’esempio
primo e secondo), sono detti
parametri effettivi.
• Quando, in seguito al richiamo di funzione, il controllo del
programma passa a quest'ultima, prima dell'esecuzione
delle istruzioni viene attivato un meccanismo per cui i
valori contenuti nei parametri effettivi sono copiati nei
parametri formali corrispondenti interni alla funzione.
© Piero Demichelis
18
Passaggio dei parametri “by value”
• Osservazioni:
- Il numero e il tipo dei parametri formali deve essere uguale al
numero e al tipo dei parametri effettivi, perché l'azione di
copiatura viene eseguita in modo meccanico durante l'esecuzione.
- La modifica di un parametro formale in una funzione non provoca
alcun effetto sul corrispondente parametro effettivo del
programma chiamante.
- Si dice che i parametri sono trasferiti per valore (by value).
- Questo meccanismo restringe il campo di propagazione degli
errori: non è possibile che in una funzione, per errore, si alterino
variabili non appartenenti alla funzione stessa. Si dice che si ha la
protezione dagli effetti collaterali (side effects).
© Piero Demichelis
19
Passaggio dei parametri “by reference”
• Può succedere che una funzione debba restituire al
programma chiamante più di un risultato o comunque
effettuare alterazioni ai dati definiti nel programma
chiamante.
• Il meccanismo di passaggio “by value ” funziona solo
nella direzione programma chiamante-funzione e non
viceversa! Per restituire dati si deve ricorrere ad un nuovo
tipo di dati, il tipo puntatore, e agli operatori ad esso
connessi.
• Si consideri l'assegnazione:
dato1 = dato2;
il cui significato è: “copia il valore contenuto nel
contenitore dato2 e scrivilo nel contenitore dato1”.
© Piero Demichelis
20
Passaggio dei parametri “by reference”
• In linguaggio macchina gli identificatori dato1 e dato2
non sono altro che gli indirizzi delle celle di memoria che
costituiscono il contenitore.
• A differenza di altri linguaggi di alto livello, in C è
possibile manipolare anche gli indirizzi; l'assegnazione:
ind_dato = &dato2;
significa: assegna a ind_dato non il contenuto di dato2,
bensì l'indirizzo del contenitore (cioè della variabile) dato2
(si dice che ind_dato “punta ” a dato2).
© Piero Demichelis
21
Passaggio dei parametri “by reference”
• In questo caso quindi & è un operatore d'indirizzo.
• Affinché l'assegnazione
ind_dato = &dato2;
sia lecita, ind_dato deve essere definito come “puntatore
allo stesso tipo di dato2”: per realizzare questa
operazione occorre semplicemente anteporre l'operatore
“*” all'identificatore, così:
int dato2;
int *ind_dato;
/* Definizione di un intero
*/
/* Definizione di un puntatore a un intero */
© Piero Demichelis
22
Passaggio dei parametri “by reference”
• ind_dato quindi potrà contenere solo l’indirizzo di una
variabile intera e non un valore come le altre variabili.
• Occorre ancora rilevare come l’operatore * anteposto ad
un puntatore abbia il significato di:
“scrivi, non nella variabile puntatore, ma nell’indirizzo da
questa indicato”.
• Viene quindi realizzato il meccanismo di “indirizzamento
indiretto” ben noto in tutti i linguaggi di basso livello.
• Come possiamo utilizzare questo nuovo tipo di dato?
© Piero Demichelis
23
Passaggio dei parametri “by reference”
• Si consideri il seguente programma:
int dato2;
int *ind_dato;
main()
{
ind_dato = &dato2;
/* assegna l'indirizzo di dato2 */
dato2 = 5;
*ind_dato = 5;
}
• Le ultime due assegnazioni sono del tutto equivalenti:
assegna 5 alla variabile dato2.
© Piero Demichelis
24
Passaggio dei parametri “by reference”
• È possibile quindi usare questo tipo di dato per aggirare la protezione
messa in atto dal meccanismo di passaggio dei parametri a una
funzione.
• Infatti, trasmettendo alla funzione non il valore di un dato ma il suo
indirizzo (cioè anteponendo l’operatore & al nome della variabile), si
potrà, all’interno della funzione, scrivere direttamente in
quell’indirizzo (che però si trova nel programma chiamante!)
trasmettendone pertanto implicitamente il valore al programma
chiamante.
• Pertanto nella parentesi tonda, insieme ai parametri passati by value,
ci possono essere altri parametri (indirizzi dei dati dichiarati nel
modulo chiamante) utili per trasmettere indietro quanti risultati si
desidera.
© Piero Demichelis
25
Passaggio dei parametri “by reference”
• Ovvero, se si utilizzano i puntatori come parametri, ogni
variazione del parametro formale effettuato nella funzione
si ripercuote direttamente sul parametro effettivo, quindi
parametro formale e parametro effettivo in questo caso
sono la stessa cosa!
• E’ possibile quindi “restituire ” un risultato al programma
chiamante: questo metodo di passaggio dei parametri è
detto per riferimento (by reference).
• Poiché parametro formale e parametro effettivo sono la
stessa cosa è evidente che viene meno la protezione dagli
effetti collaterali (side effects).
© Piero Demichelis
26
Passaggio dei parametri “by reference”
• Esempio - Programma per leggere da terminale un
numero reale e calcolare il quadrato e il cubo,
visualizzando i risultati.
• Soluzione - Si realizza una funzione che, dato un numero,
ne calcola il quadrato e il cubo. Il numero è un parametro
che passa dal programma chiamante alla funzione by
value, mentre i risultati (quadrato e cubo) devono essere
restituiti al programma chiamante by reference.
© Piero Demichelis
27
Passaggio dei parametri “by reference”
#include <stdio.h>
void calcola (double valore, double *quad_val, double *cub_val)
{
/*
corpo della funzione
*/
*quad_val = valore * valore;
*cub_val = *quad_val * valore;
return;
}
main()
{
double un_dato, quadrato, cubo;
printf (“\nIntroduci un dato reale: ");
scanf ("%lf", &un_dato);
calcola (un_dato, &quadrato, &cubo);
printf (“\nIl quadrato di %lf è: %lf,", un_dato, quadrato);
printf (" il cubo è: %f ", cubo);
}
© Piero Demichelis
28
Passaggio dei parametri “by reference”
• Osservazioni:
- Nella funzione calcola, l'operatore * davanti a quad_val e cub_val
indica che questi parametri sono passati per indirizzo.
- Nel corpo della funzione, l'istruzione
*quad_val = valore * valore;
significa “calcola il prodotto e assegnalo alla variabile il cui
indirizzo è quad_val”.
- Il programma chiamante passa gli indirizzi delle variabili quadrato
e cubo anteponendo agli identificatori l'operatore &.
© Piero Demichelis
29
Definizione di una funzione
• Non è lecito inserire una funzione all'interno di un’altra,
quindi le funzioni non possono essere “annidate ”.
• Una funzione può però essere richiamata da altre funzioni
purché siano soddisfatte alcune condizioni e può
richiamare sempre se stessa (recursione).
• Non è indispensabile che la definizione delle funzioni
preceda sempre il main, tuttavia la condizione affinché si
possa richiamare una funzione è che sia già stata definita
oppure dichiarata.
© Piero Demichelis
30
Prototipo di una funzione
• La dichiarazione di una funzione è costituita dalla sua
intestazione, cioé dal tipo, nome e lista dei parametri
formali che è anche detta prototipo della funzione.
• Il compilatore, disponendo del prototipo, può effettuare i
controlli di congruenza sia sul tipo della funzione che sul
tipo e sul numero dei parametri.
• Pertanto il prototipo può apparire più volte all'interno del
programma. La definizione invece deve essere unica.
© Piero Demichelis
31
Esempio
#include <stdio.h>
float media (int primo, int secondo);
/* prototipo della funzione */
main() {
int dato1, dato2;
printf (“\nIntroduci due interi: ");
scanf ("%d%d", &dato1, &dato2);
printf (“\nMedia tra %d e %d: %f",dato1,dato2, media(dato1,dato2));
}
float media (int primo, int secondo)
{
float somma;
somma = primo + secondo;
return (somma / 2.0);
}
© Piero Demichelis
32
Osservazioni sull'uso dei parametri
• Nelle funzioni si potrebbero omettere i parametri e utilizzare variabili
globali: questo comportamento è sconsigliabile perchè in questo
modo si deve tener conto ovunque dell'utilizzo che ne vien fatto e
possono prodursi “effetti collaterali ”.
• Il passaggio dei parametri “per valore ” è sempre da preferire perchè
permette la massima elasticità senza effetti collaterali.
• Il passaggio dei parametri “per riferimento ” è indispensabile quando
si devono restituire dei risultati al programma chiamante: si mantiene
la versatilità della parametrizzazione ma si possono avere effetti
collaterali poiché, nel momento della chiamata, si crea una “identità”
tra parametri formali ed effettivi.
• Per riferimento si possono passare solo variabili: non sono accettabili
costanti od espressioni.
© Piero Demichelis
33
Osservazioni sull'uso dei parametri
• E’ buona norma dichiarare globali solo le variabili che rappresentano
la base dati di un programma e sono manipolate da tutti i moduli.
• Conviene che le variabili globali compaiano come parametri nella
chiamata di una funzione solo se ciò migliora la leggibilità del
programma, rendendo evidente su quali variabili opera quella
funzione.
• Sono invece da dichiarare locali tutti quegli identificatori a cui si fa
riferimento solo all'interno della singola funzione.
• Per una migliore leggibilità del programma, è meglio usare nomi
diversi per variabili locali e globali anche se non è affatto
necessario.
© Piero Demichelis
34
Vettori come parametri di una funzione
• Nella definizione di una funzione in cui compare come
parametro un vettore non è indispensabile che di questo
sia definita la dimensione: è sufficiente indicare il
carattere di vettore del parametro (cioè []):
int nome (int vett[], int lung,...)
• Infatti è nel programma chiamante che deve essere
riservata l’area fisica di memoria che ospita il vettore,
nella funzione il compilatore deve gestire solamente gli
indirizzi dei singoli elementi.
• Nel programma chiamante il vettore è passato
semplicemente indicandone il nome (senza []).
© Piero Demichelis
35
Vettori come parametri di una funzione
• Nelle chiamate di funzioni, per i vettori, il compilatore C
forza automaticamente il passaggio “per riferimento ”.
• La ragione del passaggio “by reference ” è conseguenza
del fatto che il nome del vettore indica l’indirizzo del
primo elemento.
• Nella funzione si usa il vettore con le stesse modalità con
cui lo si usa nel main, al contrario di quanto succede per
le variabili scalari, che devono essere gestite in funzione
del modo col quale è stato passato il parametro.
• Pertanto gli elementi di un vettore passato come
argomento possono essere modificati nella funzione e
non c’è protezione dagli “effetti collaterali ”!
© Piero Demichelis
36
Vettori come parametri di una funzione
• Poiché come sempre in C non ci sono controlli sugli indici,
è buona norma passare a una funzione insieme al vettore
anche la sua dimensione.
• Il programmatore può così controllare che all’interno della
funzione non si trasbordi fuori dall’area di memoria
dedicata al vettore.
• Esempio: scrivere una funzione nonnull che ritorni il
numero di elementi non nulli di un vettore di interi
passato come parametro.
© Piero Demichelis
37
Esercizio
int nonnull (int vett[], int dim)
{
int ind, n=0;
Per risolvere il problema
è necessario conoscere
la dimensione del vettore
for (ind = 0; ind < dim; i++)
{
if (vett[ind] != 0)
n++;
Se modificassi vett[ ] dentro la
}
funzione, il valore sarebbe
return (n);
modificato anche nel programma
}
chiamante
© Piero Demichelis
38
Esercizio
Programma che legge da tastiera 20 interi e li salva in un vettore. Ne
elimina i doppioni e visualizza i dati del vettore prima e dopo
l'eliminazione dei doppi.
#include <stdio.h>
#define NUMDATI 20
/*
prototipi
*/
void compatta (int vett[], int inizio, int *n_dati);
void visualizza (int vett[], int n_dati);
main()
{
int vett_dati[NUMDATI];
int ind, ind_aux;
int attuali;
© Piero Demichelis
39
Esercizio
/* legge i dati da tastiera */
printf (“\nIntroduci %d dati:\n",NUMDATI);
for (ind = 0; ind < NUMDATI; ind++)
{
printf (“\nDato n. %2d = ", (ind+1));/* la numerazione parte da 1 */
scanf ("%d", &vett_dati[ind]);
}
attuali = NUMDATI;
printf (“\nDati introdotti:\n");
visualizza (vett_dati, attuali);
© Piero Demichelis
40
Esercizio
for (ind = 0; ind < (attuali-1); ind++)
{
for (ind_aux = (ind + 1); ind_aux < attuali; ind_aux++)
{
if (vett_dati[ind] == vett_dati[ind_aux])
{
compatta (vett_dati, ind_aux, &attuali);
ind_aux--;
}
}
}
printf (“\nDati rimasti dopo l’eliminazione dei dati uguali:\n");
visualizza (vett_dati,attuali);
}
/*
fine programma main
*/
© Piero Demichelis
41
Esercizio
/*
/*
/*
/*
funzione che elimina l’elemento di indice inizio dal vettore vett
*/
spostando in avanti di una posizione tutti gli elementi successivi */
aggiorna infine il numero di dati che compongono il vettore
*/
decrementandolo di una unità
*/
void compatta(int vett[], int inizio, int *n_dati)
{
int posiz;
for (posiz = inizio; posiz < (*n_dati - 1); posiz++)
vett [posiz] = vett [posiz + 1];
(*n_dati)--;
return;
}
/*
/*
decrementa n_dati
fine funzione compatta
© Piero Demichelis
*/
*/
42
Esercizio
/* Funzione che visualizza sul monitor il valore degli elementi del
/* vettore vett composto da n_dati elementi.
/* I dati sono scritti uno per riga nel formato:
/*
Vettore[xx] = valore
*/
*/
*/
*/
void visualizza(int vett[], int n_dati)
{
int ind;
for (ind = 0; ind < n_dati; ind++)
printf ("Vettore[%2d] = %d\n", (ind + 1), vett [ind]);
return;
}
/*
fine funzione visualizza
*/
© Piero Demichelis
43
Funzioni di libreria
• Ogni linguaggio prevede che alcune funzioni siano già
predefinite (quindi note al compilatore e comprese nelle
sue librerie).
• In C il loro numero è grandissimo (centinaia) e sono
suddivise in files a seconda della categoria di
appartenenza: ci sono funzioni matematiche, di gestione
dell'I/O, di conversione, ecc.
• Un certo numero è esplicitamente previsto dall'ANSI C
(funzioni standard), ma i realizzatori dei compilatori sono
soliti aggiungerne molte altre: l'uso di funzioni non
standard è di ostacolo alla trasportabilità dei programmi e
quindi deve essere evitato.
© Piero Demichelis
44
Funzioni di libreria
• L'elenco completo delle funzioni definite sono reperibili
nel manuale (Reference Manual ) del compilatore usato e
a volte sono rese disponibili anche nell'ambiente di
sviluppo dei programmi (ad esempio nell’help del TURBOC della Borland)
• Per ciascuna funzione viene di solito specificato se
appartiene o meno allo standard e quale file di libreria la
contiene.
• Questo file deve essere incluso nel programma mediante
la direttiva #include. In questi file sono contenuti anche i
prototipi delle funzioni, che pertanto non devono essere
specificati altrove.
© Piero Demichelis
45
Funzioni matematiche
Utilizzabili con la direttiva:
#include <math.h>
abs(x)
calcola il valore assoluto di x; sia x che il risultato sono int;
labs(x)
calcola il valore assoluto di x; sia x che il risultato sono long
int;
fabs(x)
calcola il valore assoluto di x; sia x che il risultato sono
numeri floating-point ;
ceil(x)
restituisce un numero con parte decimale nulla e parte intera
arrotondata al valore intero successivo; x e risultato sono
double;
restituisce un numero con parte decimale nulla e parte intera
floor(x) troncata al valore intero; x e il risultato sono double;
sqrt(x)
calcola la radice quadrata di x con x positivo; x e il risultato
sono double;
© Piero Demichelis
46
Funzioni matematiche
Utilizzabili con la direttiva:
log(x)
log10(x)
exp(x)
pow(x, y)
#include <math.h>
calcola il logaritmo naturale di x con x positivo; x e il
risultato sono double;
calcola il logaritmo in base 10 di x con x positivo; x e il
risultato sono double;
calcola ex; x e il risultato sono double;
calcola xy: se x è negativo y deve avere parte decimale
nulla; x, y e risultato sono tutti double;
sin(x)
calcola il seno di x; x è l'angolo espresso in radianti; x e il
risultato sono double;
cos(x)
calcola il coseno di x; x è l'angolo espresso in radianti; x e
risultato sono double;
tan(x)
calcola la tangente di x; x è l'angolo espresso in radianti; x
e il risultato sono double;
© Piero Demichelis
47
Funzioni matematiche
Utilizzabili con la direttiva:
#include <math.h>
asin(x)
calcola l’arcoseno di x (tra –π /2 e +π /2); x e risultato
sono double;
acos(x)
calcola l’arcocoseno di x (tra 0 e +π); x e risultato sono
double;
atan(x)
calcola l’arcotangente di x (tra –π /2 e +π /2); x e risultato
sono double;
atan2(y, x)
arcotangente di y / x (tra -π e +π); x, y e risultato sono
double;
sinh(x)
calcola il seno iperbolico di x; x e risultato sono double;
cosh(x)
calcola il coseno iperbolico di x; x e risultato sono double;
tanh(x)
calcola la tangente iperbolica di x; x e il risultato sono
double;
© Piero Demichelis
48
Funzioni di classificazione dei caratteri
Utilizzabili con la direttiva:
#include <ctype.h>
isalnum(c)
restituice vero (1) se c è un carattere alfabetico o una
cifra; c è char;
isalpha(c)
restituice vero (1) se c è un carattere alfabetico; c è
char;
isdigit(c)
restituice vero (1) se c è una cifra; c è char;
iscntrl(c)
restituice vero (1) se c è delete o un carattere di
controllo; c è char;
isascii(c)
restituice vero (1) se c è un carattere ASCII valido; c è
char;
isprint(c)
restituice vero (1) se c è un carattere stampabile; c è
char;
isgraph(c)
restituice vero (1) se c è un carattere stampabile escluso
lo spazio; c è char;
© Piero Demichelis
49
Funzioni di classificazione dei caratteri
Utilizzabili con la direttiva:
#include <ctype.h>
islower(c)
restituice vero (1) se c è un carattere minuscolo; c è
char;
isupper(c)
restituice vero (1) se c è un carattere maiuscolo; c è
char;
ispunct(c)
restituice vero (1) se c è un carattere di punteggiatura; c
è char;
isspace(c)
restituice vero (1) se c è spazio, tab, carriage return,
new line, vert. tab, form feed; c è char;
isxdigit(c)
restituice vero (1) se c è una cifra esadecimale; c è char;
© Piero Demichelis
50
Funzione per le stringhe
Utilizzabili con la direttiva:
strlen(s)
strcmp(s1, s2)
#include <string.h>
restituice la lunghezza (numero di caratteri) della
stringa s; il risultato è intero;
confronta due stringhe e restituisce un valore
intero: negativo se s1 precede s2, zero se sono
uguali, positivo se s1 succede a s2
nell'ordinamento alfabetico;
strncmp(s1, s2, n)
come strcmp, ma effettua il confronto per i primi n
caratteri.
strcat(s1, s2)
concatena s1 con s2, copiando i caratteri di s2 in
coda a quelli di s1 compreso il carattere NULL
(quello di s1 viene sovrascritto). Il valore restituito
dalla funzione è un puntatore a s1.
strcpy(s1, s2)
copia s2 in s1;
strncpy(s1, s2, n)
copia i primi n caratteri di s2 in s1.
© Piero Demichelis
51
Funzione per le stringhe
Utilizzabili con la direttiva:
#include <string.h>
strchr(str, car)
cerca se il carattere car è presente in str. Il valore
restituito dalla funzione è un puntatore alla prima
occorrenza di car in str, oppure NULL se il
carattere è assente;
strstr(s1, s2)
verifica se s2 è contenuta in s1. Il valore restituito
dalla funzione è un puntatore al punto di s1 dove
inizia s2, oppure NULL se s2 non è presente;
strpbrk(s1, s2)
cerca in s1 la prima occorrenza di uno dei caratteri
presenti in s2. Mentre strchr cerca un unico
carattere questa opera su un gruppo di caratteri:
è utile, ad esempio, per cercare i caratteri
d'interpunzione in un testo. Il valore restituito è
un puntatore alla prima occorrenza di uno dei
caratteri in s1, oppure NULL se nessun carattere
di s2 è presente in s1.
© Piero Demichelis
52
Funzioni di conversione di stringhe
Utilizzabili con la direttiva:
#include <stdlib.h>
atof (stringa)
converte stringa in un numero reale in doppia precisione:
restituisce il valore convertito in un tipo double;
atoi (stringa)
converte stringa in un numero intero; restituisce il
valore convertito in un tipo int;
atol (stringa)
converte stringa in un numero intero lungo; restituisce il
valore convertito in un tipo long int;
Queste funzioni operano sulle stringhe con le stesse modalità
della scanf: gli spazi neutri iniziali vengono ignorati, viene cercata una
sequenza di caratteri compatibile con il tipo di dato, infine viene
effettuata la conversione.
© Piero Demichelis
53
Osservazioni sulle funzioni per le stringhe
• Data la loro natura di tipo “aggregato”, le stringhe non
possono essere usate come variabili qualunque.
• E’ già stato osservato, ad esempio, che non è lecito
assegnare una stringa a un altra o “aggiungere” una
stringa ad un altra.
char s1[20], s2[10], s3[50];
...
s1 = “abcdefg”;
s2 = “hijklmno”;
s3 = s2;
s3 = s1 + s2;
NO!
• Per questi scopi si devono usare le apposite funzioni di
libreria.
© Piero Demichelis
54
Osservazioni sulle funzioni per le stringhe
• NOTE:
- Non è possibile usare vettori come valori di ritorno
delle funzioni di libreria.
• Esempio:
char finale[40], stringa1[10], stringa2[10];
...
finale = strcat (stringa1, stringa2);
NO!
- Alcune funzioni possono essere usate “senza risultato”.
• Esempio:
........
strcpy (finale, stringa1);
strcat (finale, stringa2);
© Piero Demichelis
55
Scarica

I sottoprogrammi