FUNZIONI DI BIBLIOTECA
I programmi C hanno accesso a un insieme preprogrammato
standard di funzioni per:
 calcolare quantità matematiche,
 gestire l’ingresso/uscita dei caratteri,
 manipolare stringhe di caratteri.
Queste funzioni preprogrammate sono memorizate in una biblioteca
di sistema che contiene una collezione di funzioni standard e
collaudate.
Prima di usare una funzione disponibile nella biblioteca di sistema si
deve conoscere:




il nome della funzione;
gli argomenti richiesti dalla funzione;
il tipo dati del risultato (se presente) restituito dalla funzione;
una descrizione di ciò che fa la funzione.
I primi tre dati sono forniti dalla intestazione della funzione.
Ad es., consideriamo la funzione sqrt(), che calcola la radice
quadrata del suo argomento. La sua intestazione è:
double sqrt(double num)
Essa contiene tutte le informazioni necessarie per la chiamata a
sqrt(), che si aspetta un argomento in doppia precisione e
restituisce un valore pure in doppia precisione.
Per funzionare correttamente, molte funzioni di biblioteca richiedono
un insieme standard di dichiarazioni comuni e altre informazioni,
contenute in un file d’intestazione standard.
Per inserire in un programma le informazioni di questo file, il
programma deve cominciare con la seguente istruzione:
#include <nome-file-intestazione>
(che termina senza punto e virgola).
Funzioni matematiche
Per eseguire calcoli quali la potenza, la radice quadrata, il valore
assoluto di un numero e altri, ogni compilatore C fornisce un gruppo
standard di funzioni matematiche preprogrammate.
Le più comuni sono elencate in tabella (dove i tipi non dichiarati si
intendono double).
Il differente comportamento delle tre funzioni ceil(), floor() e
(int)()può essere osservato eseguendo il seguente programma:
#include <stdio.h>
#include <math.h>
main()
{
printf("ceil(3.1) =
printf("floor(3.1) =
printf("(int)(3.1) =
printf("ceil(-3.1) =
printf("floor(-3.1)=
printf("(int)(-3.1)=
}
%f
%f
%d
%f
%f
%d
ceil(3.9) =
floor(3.9) =
(int) (3.9)=
ceil(-3.9) =
floor(-3.9)=
(int)(-3.9)=
che produce la seguente uscita:
%f\n",ceil(3.1),ceil(3.9));
%f\n",floor(3.1),floor(3.9));
%d\n\n",(int)(3.1),(int)(3.9));
%f\n",ceil(-3.1),ceil(-3.9));
%f\n",floor(-3.1),floor(-3.9));
%d",(int)(-3.1),(int)(-3.9));
Come con tutte le funzioni C, gli argomenti passati a una funzione di
biblioteca matematica non devono essere necessariamente numeri,
ma possono anche essere espressioni, come nei seguenti esempi:
sqrt(4.0 + 7*3)
abs(-24 % 3 + 6)
pow(p * q, 5.0)
Anche ora vengono dapprima valutate le espressioni in parentesi,
quindi vengono forniti i risultati.
Esempi:
Come le funzioni scritte dall’utente, anche quelle di biblioteca possono
essere inserite come parte di espressioni più ampie.
Il valore restituito dalla funzione viene valutato prima che si compia
qualsiasi altra operazione, e può essere usato come argomento di
un’altra funzione.
Ad es., è valida un’espressione del tipo:
sqrt(abs(alfa))
dove l’elaborazione procede dalla coppia di parentesi interna a quella
esterna.
Esercizio. Scrivere un programma che calcoli il tempo impiegato da
una pallina per toccare terra dopo che sia stata lasciata cadere da un
edificio.
Suggerimento: impiegare la seguente formula per calcolare il tempo
[in secondi] impiegato per percorere una data distanza [in metri]:
tempo = sqrt(2*distanza/g)
dove g è l’accelerazione di gravità 9,8 m/sec2.
#include <stdio.h>
#define GRAV 9.8
void main(void)
{
double tempo, distanza;
double sqrt(double);
/* dichiarazione */
printf("Scrivi la distanza (in m): ");
scanf("%lf", &distanza);
tempo = sqrt(2 * distanza / GRAV);
printf("\nImpiegherà %4.2lf secondi", tempo);
printf("\nper cadere da %8.3lf metri.", distanza);
}
File math.h. Osserviamo che il programma precedente contiene,
dopo l’istruzione di dichiarazione delle variabili, il prototipo della
funzione sqrt().
In alternativa, tutti i compilatori possiedono un file standard di nome
math.h che contiene gli opprtuni prototipi di funzione per le
funzioni matematiche fornite.
Le informazioni contenute in questo file consentono di usare tutte le
funzioni matematiche senza scrivere esplicitamente le istruzioni
prototipi di ogni funzione, e sono disponibili inserendo nel
programma la seguente istruzione al preprocessore:
#include <math.h>
In tal modo il programma precedente si può riscrivere come:
#include <stdio.h>
#include <math.h>
#define GRAV 9.8
void main(void)
{
double tempo, distanza;
printf("Scrivi la distanza (in m): ");
scanf("%lf", &distanza);
tempo = sqrt(2 * distanza / GRAV);
printf("\nImpiegherà %4.2lf secondi", tempo);
printf("\nper cadere da %8.3lf metri.", distanza);
}
In esso non è presente l’istruzione di dichiarazione
double sqrt(double);
del programma precedente.
Funzione rand(). La funzione rand() genera un intero
compreso tra 0 e RAND_MAX, una costante simbolica definita nel
file d’intestazione stdlib.h.
Lo standard ANSI stabilisce che il valore di RAND_MAX debba essere
almeno 32767, che è il valore massimo per un intero di 2 byte
(ossia di 16 bit).
Il protoptipo per la funzione rand() si trova nel file d’intestazione
stdlib.h. Esso contiene i prototipi delle funzioni per la
conversione dei numeri in testo e viceversa, per l’allocazione della
memoria, per i numeri casuali e per altre funzioni di utilità generica.
Tuttavia, l’intervallo dei valori necessario in una applicazione
specifica potrebbe essere differente da quello dei valori prodotti da
rand().
Ad es., un programma che simuli il lancio di una moneta
richiederebbe soltanto 0 per “testa” e 1 per “croce”, mentre uno che
simuli il lancio di un dado a 6 facce richiederebbe degli interi
compresi nell’intervallo da 1 a 6.
Esempio: programma 20 lanci. Per mostrare l’utilizzo di rand(),
sviluppiamo un programma che simuli 20 lanci di un dado a 6
facce, visualizzando il valore ottenuto in ogni lancio.
Dapprima generiamo dei numeri casuali compresi nell’intervallo da
0 a 5 utilizzando l’operatore resto (%) in congiunzione con
rand() nel modo seguente:
rand() % 6
Questa operazione si chiama riduzione in scala, mentre il numero 6
è detto fattore di scala.
Quindi “trasliamo” di una unità l’intervallo dei numeri generati,
aggiungendo 1 al risultato precedente.
Se vogliamo stampare i numeri in forma di tabella a 5 colonne,
possiamo inserire un’istruzione di salto a riga nuova (carattere di
escape \n) dopo la visualizzazione di ciascun gruppo di 5
risultati.
Il programma 20 lanci completo è il seguente:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i;
for (i=1; i<=20; i++)
{
printf("%10d", (rand() % 6) + 1);
if (i % 5 == 0)
{
printf("\n");
}
}
}
Programma 6000 lanci. Il precedente programma può essere
modificato per verificare la “bontà” del generatore di numeri casuali,
simulando un numero elevato (6000) di lanci, e calcolando la
frequenza con la quale si presentano le diverse facce.
Se i lanci fossero completamente casuali, ciascuna faccia si dovrebbe
presentare più o meno lo stesso numero di volte (in questo caso
1000).
#include <stdio.h>
#include <stdlib.h>
int main()
{
int freq1 = 0;
int freq2 = 0;
int freq3 = 0;
int freq4 = 0;
int freq5 = 0;
int freq6 = 0;
int lanci, faccia;
for (lanci = 1; lanci <= 6000; lanci++)
{
faccia = 1 + rand() % 6;
switch (faccia)
{
case 1:
++freq1;
break;
case 2:
++freq2;
break;
case 3:
++freq3;
break;
case 4:
++freq4;
break;
case 5:
++freq5;
break;
case 6:
++freq6;
break;
}
}
printf("%s
printf("
printf("
printf("
printf("
printf("
printf("
}
Ecco l’uscita prodotta:
%13s\n", "Faccia Frequenza");
1 %10d\n", freq1);
2 %10d\n", freq2);
3 %10d\n", freq3);
4 %10d\n", freq4);
5 %10d\n", freq5);
6 %10d\n", freq6);
Osserviamo che:
• il programma non contiene alcun caso di default nel comando
switch;
• l’intero comando switch può essere sostituito con un’istruzione di
una sola riga, usando un vettore, come vedremo dopo avere
introdotto la funzione srand();
• se i due programmi precedenti vengono eseguiti ripetutamente, essi
producono sempre la stessa sequenza di numeri (e infatti si dice
che la funzione rand() genera dei numeri pseudocasuali).
Funzione srand(). Per modificare i due programmi precedenti in
modo che producano ogni volta una diversa sequenza di numeri
casuali (operazione detta randomizzazione), si usa la funzione di
biblioteca standard srand(), il cui prototipo è contenuto anch’esso
nel file stdlib.h.
srand() riceve un argomento intero unsigned con il quale
insemina la funzione rand(), in modo da indurla a generare una
diversa sequenza di numeri casuali a ogni esecuzione del
programma.
Ricordiamo che anche il tipo dati unsigned (abbreviazione per
unsigned int) è immagazzinato in 2 byte di memoria, ma può
contenere solo valori positivi compresi nell’intervallo da 0 a 65535.
Ricordiamo anche che per leggere un valore unsigned con la
funzione scanf() si usa la specifica di conversione %u.
Il programma 20 lanci modificato è il seguente:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i;
for (i=1; i<=20; i++)
{
printf("%10d", (rand()%6)+1);
if (i % 5 == 0)
{
printf("\n");
}
}
}
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i;
unsigned seme;
printf(“Scrivi il seme: “);
scanf(“%u”, &seme);
srand(seme);
for (i = 1; i <= 20; i++)
{
printf("%10d",(rand()%6)+ 1);
if (i % 5 == 0)
{
printf("\n");
}
}
}
Qualora si volesse randomizzare senza dovere immettere ogni volta
un seme, si potrebbe utilizzare un’istruzione del tipo:
srand(time(NULL));
Essa indurrebbe il computer a leggere il suo clock interno per
ottenere automaticamente un valore per il seme.
La funzione time restituisce l’ora corrente espressa in secondi.
Questo valore viene convertito in un intero senza segno e utilizzato
come seme per il generatore di numeri casuali.
Il prototipo per la funzione time è nel file di biblioteca time.h.
La versione definitiva del programma 20 lanci è quindi:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
int i;
srand(time(NULL));
for (i = 1; i <= 20; i++)
{
printf("%10d", (rand() % 6) + 1);
if (i % 5 == 0)
{
printf("\n");
}
}
}
Ecco ora la versione con vettore del programma 6000 lanci.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define DIMENS 7
int main()
{
int faccia, lanci, frequenza[DIMENS] = {0};
srand(time(NULL));
for (lanci = 1; lanci <= 6000; lanci++)
{
faccia = rand() % 6 + 1;
++frequenza[faccia];
}
printf("%s \n", "Faccia Frequenza");
for (faccia = 1; faccia < DIMENS; faccia++)
{
printf("%4d %10d \n", faccia, frequenza[faccia]);
}
}
Ed ecco le uscite prodotte:
Scarica

Fonda18