Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
I linguaggi di alto livello (come il Pascal, il Basic e così via) aiutano molto il pro-
grammatore nella fase di stesura del codice. Questi linguaggi trattano i dettagli ri-
guardanti il computer in maniera astratta: non è necessario conoscere come il
processore riesce a sommare due numeri, basta usare il simbolo +. Non è ne-
cessario conoscere la locazione di memoria in cui registrare i dati da utilizzare,
poiché è possibile assegnare ai dati un nome simbolico e mnemonico (una varia-
bile). Allo stesso modo, non è necessario conoscere i dettagli del sistema operati-
vo e dell’hardware per poter leggere o scrivere un file su disco.
Nella metà degli anni Ottanta il comitato X3JI1 dell’ANSI (American National
Standards Institute) sviluppò uno standard per il linguaggio C che aggiungeva im-
portanti elementi e ufficializzava molte caratteristiche presenti nei diversi compi-
latori realizzati successivamente alla pubblicazione del libro di Kernighan e
Ritchie. Da allora l’ANSI C cominciò a essere considerato la versione “ufficiale”
del linguaggio rimpiazzando quella di K&R.
2 IL LINGUAGGIO C
Il linguaggio C
IL LINGUAGGIO C 3
Anatomia
di un programma C
La struttura di un programma in linguaggio C è la seguente:
Facoltativo
Direttive al preprocessore
Obbligatorio
Programma principale (main)
Facoltativo
Sottoprogramma 1
Facoltativo
Sottoprogramma 2
.
.
.
Facoltativo
Sottoprogramma N
4 IL LINGUAGGIO C
Anatomia di un programma C
main rappresenta il programma principale e come tale deve essere sempre pre-
sente, poiché il compilatore inizia l’esecuzione proprio da esso. Al main è asse-
gnato il compito di gestire il controllo generale dell’attività del codice.
La sintassi della funzione main è la seguente:
[<TipoRestituito>] main([<ElencoParametri>])
{
<Istruzione1>;
<Istruzione2>;
...
<IstruzioneN>;
}
dove:
• <TipoRestituito> indica il tipo di dato restituito dalla funzione, il quale, in
mancanza di esplicita dichiarazione (cioè per default), è un valore intero (int);
• <ElencoParametri> rappresenta l’insieme dei parametri che il main accetta
in ingresso (i parametri saranno trattati approfonditamente in seguito). Nel
caso in cui il main non abbia parametri in ingresso occorre comunque far se-
guire la parola main da una coppia di parentesi tonde. Ciò perché, come vedre-
mo meglio più avanti, il main può essere considerato una funzione che può ri-
cevere degli argomenti (ossia i parametri): essi, se presenti, dovranno essere
racchiusi all’interno di tali parentesi.
IL LINGUAGGIO C 5
Alfabeto e regole
lessicali
L’alfabeto del linguaggio C
L’alfabeto del linguaggio C è formato da:
1. le lettere minuscole e maiuscole dell’alfabeto inglese (dalla a fino alla z):
abcdefghijklmnopqrstuvwyz
ABCDEFGHIJKLMNOPQRSTUVXYZ
2. le dieci cifre decimali (dallo 0 al 9):
0 1 2 3 4 5 6 7 8 9
3. i seguenti caratteri speciali:
– i simboli di punteggiatura . , : ;
– i segni matematici + – * / = % < >
– i simboli spazio # $ & ! ^ | \ ‘ “ _ ? ~
– le parentesi [ ] ( ) { }
4. i simboli non grafici (o non stampabili), come quelli di:
– nuova linea (new line);
– nuova pagina (form feed);
– spazio indietro (backspace);
– tabulazione orizzontale.
Le regole lessicali
Grazie all’alfabeto del oinguaggio, il programmatore piò definire le parole da utiliz-
zare nel programma sorgente. Naturalmente tali parole devono essere valide, ossia
essere riconosciute come formalmente valide dal compilatore del linguaggio.
Ogni linguaggio prevede un certo numero di categorie lessicali; in C possiamo di-
stinguere le seguenti categorie:
• parole riservate;
• identificatori (creati dal programmatore);
• costanti letterali;
• segni di punteggiatura e operatori;
• commenti.
Le parole chiave
Il linguaggio C (come qualsiasi altro linguaggio di programmazione) consente la
realizzazione di programmi utilizzando un insieme di “parole chiave” (keyword)
che non possono essere utilizzate dal programmatore come nomi di variabili.
Lo standard ANSI ha definito il seguente insieme di parole chiave:
6 IL LINGUAGGIO C
Alfabeto e regole lessicali
Gli identificatori
Gli identificatori sono i nomi definiti dal programmatore per riferirsi a sei diverse
categorie di oggetti:
• variabili;
• costanti simboliche;
• etichette;
• tipi definiti dal programmatore;
• funzioni;
• macro.
Le variabili sono contenitori di valori; ogni variabile può contenere un singolo va-
lore, che può cambiare nel tempo. Il tipo di una variabile viene stabilito una volta
per tutte e non può essere modificato.
Le costanti simboliche servono a identificare valori che non cambiano nel tem-
po. Per tale motivo non possono essere considerate veri contenitori, ma solo
come nomi utilizzati per identificare un valore.
Funzione (in C function) è il termine che viene utilizzato per indicare i sottopro-
grammi.
Gli identificatori in C devono iniziare con una lettera o con un carattere di under-
score _. Possono essere seguiti da un numero qualsiasi di lettere, cifre o undersco-
re; viene fatta distinzione tra lettere maiuscole e minuscole (abbiamo già detto
che il C è un linguaggio case sensitive). Tutti gli identificatori presenti in un pro-
gramma devono essere diversi tra loro, indipendentemente dalla categoria a cui
appartengono. Gli identificatori non possono iniziare con una cifra numerica e
non possono contenere spazi. Ad esempio, non sono identificatori validi:
IL LINGUAGGIO C 7
Gli operandi: variabili
e costanti
In C un’espressione è una combinazione di operatori e operandi che definisce
un’elaborazione e dà origine a un valore. A elaborazione terminata, l’espressione
restituisce un risultato il cui tipo di dato determina il tipo dell’espressione stessa.
Gli operandi sono combinazioni di costanti, variabili semplici e strutturate, chia-
mate di funzioni o, ancora, di altre espressioni, e rappresentano i valori che ven-
gono manipolati nell’espressione. Nello studio degli operandi, particolare impor-
tanza assumono le variabili, le costanti e il tipo che può essere loro assegnato.
Gli operatori sono simboli che specificano come devono essere manipolati gli
operandi dell’espressione. La valutazione di un’espressione viene effettuata ese-
guendo le operazioni indicate dagli operatori sui loro operandi secondo le regole
di precedenza degli operatori tipiche dell’aritmetica.
Variabili e costanti
L’identificatore serve per individuare univocamente un dato. Ricordiamo che è
buona norma utilizzare nomi che consentano di richiamarne immediatamente il
significato. In funzione della possibilità di cambiamento del loro valore durante
l’elaborazione, i dati si classificano in variabili (il cui valore può variare nel corso
dell’elaborazione) e costanti (il cui valore non cambia).
Le costanti o valori letterali rappresentano quantità esplicite e come tali non
vanno dichiarati. Una generica costante può essere:
• un numero intero (positivo o negativo);
• un numero intero decimale in virgola mobile (in notazione scientifica o in
quella standard);
• un carattere singolo;
• una stringa (sequenza di caratteri), che può terminare con:
– un valore nullo;
– un carattere speciale.
[<Segno>][<ParteIntera>][.<ParteDecimale>][E[<Segno>]<Esponente>]
0 // 0 in virgola mobile
480E+4 // 480 * 10000 (10 elevato a 4)
.14e–2 // 0.0014
–3.5e+3 // –3500.0
.58E E25
I caratteri
Le costanti di tipo carattere sono singoli simboli racchiusi tra singoli apici, ad esempio: ‘b’, ‘!’, ‘3’.
In C++, come in tutti i linguaggi di programmazione, il numero 8 è diverso dal simbolo ‘8’ che, in-
vece, è un carattere:
I caratteri sono generalmente memorizzati come codici ASCII a 8 bit (dipende comunque dall’im-
plementazione). È anche possibile definire caratteri estesi di tipo wchar_t (wide character type),
memorizzati come codici Unicode a 16 bit.
I caratteri speciali
All’interno delle istruzioni C è possibile inserire caratteri speciali non stampabili. Ad esempio, per vi-
sualizzare sul monitor una stringa con un carattere di “a capo” si utilizza una sequenza speciale di ca-
ratteri che inizia con una barra rovesciata \, in inglese backslash, definita sequenza di escape: il pri-
mo carattere permette di uscire dalla normale rappresentazione, il secondo specifica quale carattere
non stampabile si desidera produrre (ovviamente utilizzando un carattere stampabile).
Un esempio di carattere speciale è l’apice (‘), che spesso sostituisce l’apostrofo: in quest’ultimo
caso va indicato come carattere speciale facendolo precedere da una barra rovesciata. In generale,
quindi, utilizzeremo le sequenze di escape per rappresentare caratteri non stampabili, numeri ot-
tali, numeri esadecimali e caratteri che non possono essere scritti direttamente.
La tabella seguente riporta le sequenze di escape definite dal C.
Le costanti stringa
Una costante stringa (o stringa letterale) è composta da una sequenza di caratteri terminata con
la sequenza di escape \0 e racchiusa all’interno di una coppia di virgolette. Un carattere è un qual-
siasi componente di un insieme predefinito di caratteri, o alfabeto. Molti computer impiegano l’in-
sieme di caratteri ASCII o Unicode. Ad esempio: “Ciao mondo!” è una costante stringa formata da
dodici caratteri (compreso il carattere speciale e lo spazio, che è anch’esso un carattere). Il caratte-
re speciale \0 viene inserito automaticamente dal compilatore (e come tale può non essere speci-
ficato esplicitamente dal programmatore) nel momento in cui questo riconosce una costante strin-
ga all’interno del programma sorgente.
IL LINGUAGGIO C 9
Tipi di dato primitivi
e dichiarazione
di variabili e costanti
I tipi primitivi (built-in)
I tipi rappresentano le categorie di informazioni che il linguaggio consente di ma-
nipolare. I tipi di dati elementari gestiti dal linguaggio C dipendono dall’architet-
tura del computer, perciò è particolarmente difficile definire la dimensione delle
variabili numeriche; noi ci limiteremo a fornire solo definizioni relative.
Normalmente, il riferimento è dato dal tipo numerico intero (int) la cui dimensio-
ne in bit corrisponde a quella della parola, ovvero dalla capacità dell’unità aritme-
tico-logica del microprocessore. A seconda delle varie architetture, la dimensione
di un intero normale è di 32 o 64 bit. I valori minimi e massimi consentiti e le-
gati al compilatore sono definiti all’interno di 2 file: limits.h e float.h.
I tipi di dati primitivi, che riportiamo nella seguente tabella, rappresentano un va-
lore numerico singolo:
Tipo Descrizione
char Carattere (generalmente di 8 bit; anche il tipo char è trattato come un numero)
int Intero normale
float Virgola mobile a precisione singola
double Virgola mobile a precisione doppia
I tipi primitivi possono essere estesi utilizzando appositi qualificatori quali short,
long, signed e unsigned. I primi tre fanno riferimento al numero di byte occupa-
ti, mentre gli altri modificano il modo di valutare il contenuto di alcune variabili.
Nella seguente tabella riassumiamo i tipi primitivi con le combinazioni ammissi-
bili dei qualificatori.
caratteri char Tipo char per il quale non conta sapere se il segno è considerato o meno
signed char Tipo char usato numericamente con segno
unsigned char Tipo char usato numericamente senza segno
interi short int short Intero più breve di int, con segno. Ad esempio, se il tipo int occupa 4 byte,
signed short int signed sort il tipo short int ne occuperà 2
unsigned short int unsigned short Tipo short senza segno
int Intero normale, con segno
signed int
unsigned int unsigned Tipo int senza segno
long int long Intero più lungo di int, con segno. Ad esempio, se il tipo int occupa 4 byte,
signed long int signed long il tipo long int ne occuperà 8
unsigned long int unsigned long Tipo long senza segno
reali float Tipo a virgola mobile a precisione singola
double Tipo a virgola mobile a precisione doppia
long double Tipo a virgola mobile “più lungo” di double
10 IL LINGUAGGIO C
Tipi di dato primitivi e dichiarazione
di variabili e costanti
Il classico range dei singoli tipi è riportato nella seguente tabella:
Fra i tipi primitivi non abbiamo menzionato il tipo booleano. Come sappiamo, l’insieme del tipo booleano è co-
stituito da due valori di verità: true (vero) e false (falso). Nel linguaggio C non esiste un tipo per rappresenta-
re questi due valori booleani; si rimedia simulando variabili booleane con variabili intere: in un’espressione lo-
gica, infatti, un valore uguale a 0 equivale al valore false mentre un valore diverso da 0 equivale a true.
Verso la fine degli anni ’90 lo standard del linguaggio C venne sottoposto a una revisione che portò alla pubbli-
cazione ISO 9899/1999 nel 1999. Questo standard, adottato dell’ANSI nel marzo 2000 e indicato con la sigla
C99, prevede tra l’altro le seguenti nuove caratteristiche:
• le dichiarazioni delle variabili possono essere collocate ovunque (come in C++); prima, erano consentite una
di seguito all’altra e all’inizio dell’enunciato di composizione;
• nuovi tipi di dato inclusi bool e complex;
• lunghezza variabile degli array;
• introduzione del commento di una linea con // (preso dal C++);
• nuove librerie di funzioni come snprintf();
• nuovi header file come stdint.h.
Ad esempio:
int b;
char carattere, lettera;
unsigned int tappo = 10;
char frase[20];
sono dichiarazioni di variabili valide in C. In dettaglio, con la prima viene dichiarata la variabile intera b, con la se-
conda vengono dichiarate le variabili carattere e lettera, entrambe di tipo carattere, con la terza viene dichiarata la
variabile tappo di tipo intero senza segno, alla quale è assegnato il valore iniziale 10, e infine con la quarta viene
dichiarata una variabile stringa di nome frase che potrà contenere un testo lungo al massimo 20 caratteri.
Non si deve mai dimenticare che il C è case sensitive, cioè distingue le lettere maiuscole da quelle minuscole.
Notiamo, infine, il punto e virgola che segue sempre ogni dichiarazione.
IL LINGUAGGIO C 11
L’operatore
di assegnamento
Un operatore è un simbolo che “opera” su una o più espressioni, producendo un
valore che può essere assegnato a una variabile.
Gli operatori in programmazione permettono di ottenere un determinato valore
da un’operazione che si compie su una o più variabili all’interno del programma;
così come l’operatore + serve per sommare due numeri in matematica, analoga-
mente serve per compiere la stessa operazione in un programma scritto in C.
Ovviamente ci sono delle differenze: innanzitutto le operazioni del C sono quelle
basilari (per funzioni più avanzate dobbiamo usare librerie apposite) e hanno un
risultato finito, contrariamente a quelle matematiche che possono avere un risul-
tato simbolico o infinito.
Tutti gli operatori producono sempre un risultato e alcuni possono anche modifi-
care uno degli operandi. Alcuni operatori sono rappresentati simbolicamente con
un singolo carattere, altri con due caratteri senza spazi separatori. Se non è espli-
citamente evidenziato altrimenti, tutti gli operatori operano su tipi primitivi.
L’operatore di assegnamento
Sappiamo che il C è un linguaggio profondamente basato sul paradigma impera-
tivo e questo significa che un programma C è fondamentalmente una sequenza
di assegnamenti di valori a variabili.
L’operatore di assegnamento è denotato dal simbolo = (segno di uguale) e viene
applicato con la sintassi:
<Lvalue> = <Rvalue>;
Il termine <Lvalue> indica una qualsiasi espressione che si riferisca a una regio-
ne di memoria (in generale un identificatore di variabile), mentre il termine
<Rvalue> indica una qualsiasi espressione la cui valutazione produca un valore.
Il risultato dell’assegnamento è, pertanto, il valore prodotto dalla valutazione del-
la parte destra (<Rvalue>) e ha come effetto collaterale l’assegnazione di tale va-
lore alla regione di memoria denotato dalla parte sinistra (<Lvalue>). Ecco alcu-
ni esempi:
a = 5;
orazio = ‘a’;
pluto = orazio;
a = a + 7;
b = 4 + 25;
Come si evince dal precedente esempio, l’uso del segno di uguale in questo
caso non ha niente a che vedere con la matematica, poiché serve ad assegna-
re un valore e non a effettuare confronti; per questi ultimi in C si usa l’opera-
tore == (attenzione a non inserire spazi tra i due caratteri =).
12 IL LINGUAGGIO C
L’operatore di assegnamento
x = 3 * a;
alla variabile x viene assegnato il risultato di 3*a, cioè 18, quindi il risultato del-
l’operazione di assegnamento (x = 3*a) è proprio 18.
Esaminiamo ora un particolare. L’assegnazione stessa è un’espressione con un
valore (il valore dell’espressione x = 3*a è 18), che può venire usato in un’altra
assegnazione. Ad esempio, l’istruzione:
y = (x = 3*a);
y = x;
int k = h = 33;
int b =20;
char carattere = ‘b’, lettera = ‘m’;
IL LINGUAGGIO C 13
Operatori aritmetici,
di confronto e logici
Gli operatori aritmetici
Gli operatori aritmetici si dividono in:
1. operatori unari, che possono essere postfissi e prefissi:
• Decremento: ––
Ad esempio:
Gli operatori unari aritmetici possono essere posti prima dell’operando (prefissi) o
dopo l’operando (postfissi) e il loro valore varia secondo questa posizione: l’opera-
tore prefisso modifica l’operando prima di utilizzarne il valore, mentre l’operatore
postfisso modifica l’operando dopo averne utilizzato il valore. Ad esempio, con:
x = 10;
y = x++; /* postfisso: si assegna prima il valore della variabile x
alla variabile y e poi si incrementa la variabile x
In altri termini equivale a:
y = x;
x++ */
x = 10;
y = ++x; /* prefisso: prima si incrementa la variabile X e poi
si assegna il valore alla variabile Y. In altri termini
equivale a:
x++;
y = x; */
si ottiene y = 11 e x = 11.
14 IL LINGUAGGIO C
Operatori aritmetici, di confronto e logici
Gli operatori && e || non valutano l’operando destro se non è necessario al risul-
tato, quindi il risultato dell’operatore è indipendente dal valore dell’operando de- X Y X && Y X || Y !X
stro. Ad esempio:
false false false false true
(3>1) || (x>7) non viene valutato false true false true true
true false false true false
Le tabelle di verità degli operatori logici sono riportate a lato.
true true true true false
IL LINGUAGGIO C 15
Le direttive
al preprocessore
Siamo pronti per realizzare il primo programma in C. Come è tradizione nei ma-
nuali di linguaggi di programmazione, ne realizziamo uno che visualizza sul video
la frase Ciao mondo!:
#include <stdio.h>
main( )
{
Il programma, dopo essere stato digitato, compilato ed eseguito, visualizza sul vi-
deo quanto segue:
system (“PAUSE”);
16 IL LINGUAGGIO C
Le direttive al preprocessore
Il simbolo # viene chiamato “pound” negli Stati Uniti, “hash” al di fuori degli
Stati Uniti e “cancelletto” in Italia. Verosimilmente il termine hash deriva da
“hatch” ossia “portellone”, “cancello”, porta composta da sbarre incrociate
così raffigura il simbolo stesso.
Per ora concentriamo l’attenzione sulla direttiva #include; delle altre ci occupere-
mo dettagliatamente più avanti.
La direttiva #include consente di inserire nel file sorgente i file header, ossia spe-
cifici file di intestazione con estensione ‘.h’ (da header) che contengono infor-
mazioni necessarie al programma. In particolare, essi contengono le definizio-
ni delle variabili, delle espressioni costanti e dei prototipi delle funzioni (ossia
il nome, i parametri e il valore restituito dalla funzione). Questi file costituisco-
no le librerie standard del linguaggio.
Ad esempio, nel file header stdio.h (STandarD Input/Output) sono contenute le de-
finizioni delle variabili, delle espressioni costanti e i prototipi delle funzioni di in-
put e di output della libreria standard del C. Se il file stdio.h non venisse incluso
all’interno del programma, il compilatore non riconoscerebbe le funzioni stan-
dard e genererebbe un errore di funzione non definita. Il preprocessore, leggen-
do la direttiva #include, copia (o meglio “include”) il file dichiarato all’interno del
sorgente del programma. Una volta elaborato dal preprocessore quindi, il file sor-
gente conterrà al posto della riga #include il file stdio.h stesso (perciò aumenterà
di dimensioni). Il file così modificato verrà poi elaborato dal compilatore. La diret-
tiva va racchiusa all’interno di parentesi angolari o di doppi apici. Ad esempio,:
#include <stdio.h>
#include “stdio.h”
IL LINGUAGGIO C 17
Costanti e tipi di dato
definiti dall’utente
Dichiarazione delle costanti
In precedenza abbiamo esaminato la direttiva #include che ci ha permesso di “in-
cludere” nel file sorgente i file header specificati.
Esistono altre direttive di precompilazione: una di esse ci sarà molto utile per di-
chiarare le costanti. In precedenza abbiamo visto che esistono globalmente due
tipi di costanti:
• esplicite: esprimono direttamente dei valori:
– 24 costante di tipo int
– 24L costante di tipo long
– 3.145 costante di tipo double
– ‘A’ costante di tipo char
• simboliche: sono rappresentate da nomi simbolici che il programmatore adot-
ta per indicare valori prefissati. Queste costanti hanno un tipo espresso impli-
citamente nel valore e devono essere dichiarate in precedenza.
Dichiarare una costante significa associare un simbolo a un valore. A differenza di
quanto avviene per le variabili, tale valore non cambierà mai durante l’esecuzio-
ne del programma. In C esistono due modi per dichiarare una costante:
• attraverso la parola chiave const;
• attraverso la direttiva #define.
Con il qualificatore const è possibile definire costanti tipizzate, ossia che accetta-
no un valore ammissibile per il tipo di dato al quale è associato. La sintassi è la se-
guente:
Ad esempio:
18 IL LINGUAGGIO C
Costanti e tipi di dato definiti dall’utente
#define BEGIN {
#define END }
Grazie a queste direttive, all’interno del programma sarà possibile evitare di inse-
rire le parentesi graffe e digitare, al loro posto, le parole dichiarate, quindi begin
per la parentesi graffa aperta ed end per la parentesi graffa chiusa: sarà il prepro-
cessore, poi, a sostituire i valori specificati. Nel seguito amplieremo la conoscen-
za di questa direttiva introducendo le macro.
è possibile dichiarare variabili di tipo boolean che possono assumere tutti i valori
interi, poiché sappiamo che la regola base è che i valori diversi da zero rappresen-
tano il vero, mentre il valore zero rappresenta il falso:
int a, b;
boolean finito;
#define TRUE 1
#define FALSE 0
typedef int BOOL;
IL LINGUAGGIO C 19
Il main e i commenti
Il programma principale
Dopo le direttive al precompilatore, il nostro programma che scrive sul video la
frase Ciao mondo! presenta il suo programma principale caratterizzato dalla paro-
la chiave main.
Il main deve essere sempre presente poiché costituisce il punto di ingresso di un
programma C: l’esecuzione di un programma, infatti, inizia dalla prima istruzio-
ne del main e termina con l’ultima. Eventuali altri sottoprogrammi (ossia altre
funzioni) entreranno in gioco solo se e quando richiamate (direttamente o indiret-
tamente) dal main. In assenza di una funzione main, il compilatore non può pro-
durre un programma eseguibile.
La struttura generale del main è la seguente:
main ( )
{
}
main
(
)
{
}
oppure:
main( )
{ }
o, ancora:
main( ) {
}
Questi vari modi di scrivere il main possono sembrare strani (e in effetti lo sono)
ma sono corretti e comprensi dal compilatore. In sostanza non è importante la po-
sizione dei simboli, ma è importante che ogni parentesi aperta venga poi chiusa.
Questi due programmi non producono alcun risultato in quanto non contengono
istruzioni: sono programmi vuoti; possono produrre un errore di tipo warning da
parte del compilatore, ossia degli avvertimenti che non bloccano la creazione del-
l’eseguibile, si limitano ad avvertire il programmatore della possibilità che venga
prodotto un programma eseguibile errato e malfunzionante. Generalmente i mes-
saggi di tipo warning possono anche essere ignorati.
Per inserire le parentesi graffe utilizzando una tastiera che non riporta esplici-
tamente il tasto, si può usare una tra le seguenti combinazioni di tasti:
{ Alt+123 (tastierino numerico) Ctrl+Alt+Shift+[ Shift+AltGr+[
} Alt+125 (tastierino numerico) Ctrl+Alt+Shift+] Shift+AltGr+]
20 IL LINGUAGGIO C
Il main e i commenti
I commenti
Riprendiamo il nostro primo programma realizzato in precedenza. Subito dopo le
direttive al precompilatore è presente la frase Questo programma scrive la frase
Ciao mondo sul video: è un commento.
In un programma C, come in qualsiasi altro linguaggio, i commenti hanno valore
soltanto per il programmatore e vengono ignorati dal compilatore. Nel linguaggio
C è possibile inserire i commenti in due modi diversi.
1. Secondo il puro stile C, ovvero racchiudendoli tra i simboli /* e */, ad esempio:
Nel primo caso è considerato commento tutto ciò che è racchiuso tra /* e */; il
commento, quindi, si può anche trovare in mezzo al codice. Analizziamo il se-
guente esempio:
main( )
{
Nel secondo caso, proprio del C++, è invece considerato commento tutto ciò che
segue // sino alla fine della linea. Ne consegue che non è possibile inserire un
commento di questo tipo in mezzo al codice, o dividerlo su più righe (a meno che
anche l’altra riga non cominci con //). Vediamo un esempio:
main( )
{
int x = 10; // Questo è un commento valido
x = 100; // Attenzione! La riga successiva produce un errore
Questa riga non è un commento: non è preceduta da //
}
IL LINGUAGGIO C 21
La gestione
dell’output
Riprendiamo il programma di esempio con il quale abbiamo visualizzato sul vi-
deo la frase Ciao mondo!. All’interno del main del nostro programma è presente
la funzione printf, che ci permette di controllare ciò che viene stampato, nel sen-
so che permette di decidere che cosa stampare e in quale forma. Il funzionamen-
to più semplice di questa funzione è il seguente: la printf scorre la stringa di for-
mato racchiusa tra virgolette da sinistra verso destra e scrive a video (il dispositivo
di uscita standard, stdout) tutti i caratteri che incontra. È proprio il caso del no-
stro programma in cui è presente l’istruzione
printf(“Ciao mondo!”);
printf(<StringaDiFormato> , <Espressione>)
Espressione che
int a = 20; /* dichiarazione ed inizializzazione */ segue la stringa
printf(“Il valore della variabile a e’: %d”, a);
%d specifica che si deve valutare l’espressione che segue la stringa come un nu-
mero intero decimale. Il risultato a video sarà la scritta:
int a = 20;
printf(“Il valore della variabile a e’: %d”, a+2);
che scriverà il valore della variabile a aumentato di due unità. Il valore della varia-
bile resta però invariato, in quanto non è stato riassegnato.
22 IL LINGUAGGIO C
La gestione dell’output
Il seguente esempio evidenzia, invece, come inserire più specificatori di formato all’interno del-
la stringa. L’importante è inserirli nel punto in cui occorra scrivere il valore di un’espressione:
int a = 10;
b = 20;
printf(“Il valore di a e’ %d e il valore di b e’ %d ”, a, b);
Il risultato sarà:
Le specifiche introdotte dal simbolo % non sono soltanto identificatori di formato, ma an-
che specificatori di conversione: indicano, infatti, il tipo di valore risultante dall’espressio-
ne e come tale tipo di dato deve essere convertito in caratteri da visualizzare sullo schermo.
Riprendiamo gli esempi appena visti. Se per un qualsiasi motivo l’espressione che segue la
stringa ha un valore reale (ad esempio, una variabile dichiarata di tipo float) e si utilizza lo
specificatore %d, verrà comunque stampato qualcosa, che però non corrisponderà al valo-
re esatto. La ragione è che un int utilizza la metà dello spazio occupato da un float. Per tale
motivo, verrà visualizzato solamente il contenuto dei primi due byte, che verranno interpre-
tati come la rappresentazione in complemento a due di un numero intero con segno. Tutto
ciò è molto lontano dal corrispondere anche solo alla parte intera del numero reale, rappre-
sentato in complemento a due ma notazione a virgola mobile.
I due aspetti importanti da ricordare sono quindi i seguenti:
1. l’identificatore che segue il % specifica il tipo di variabile che deve essere visualizzato e
il formato dell’espressione che segue;
2. nel caso in cui vi sia una differenza tra l’identificatore indicato e il valore calcolato del-
l’espressione, il dato visualizzato non è necessariamente corretto e può causare errori an-
che sugli altri elementi della printf.
Alla luce di quanto detto, esaminiamo un programma completo in C:
#include <stdio.h>
int a = 20;
main()
{
printf(“Il valore della variabile a è: %d”, a+2);
system(“PAUSE”);
}
Per la gestione dell’output si utilizzano anche le funzioni putchar() e puts() che visualizzano a video, rispettiva-
mente, un carattere e una stringa. Queste funzioni non utilizzano gli specificatori di formato. Un esempio del
loro utilizzo è il seguente:
char a = ‘y’;
char nome[10] = “piero”;
putchar(a);
puts(nome);
Se si desidera stampare sulla carta anziché sul video, occorre utilizzare l’istruzione fprintf che funziona con le
stesse modalità di printf. È necessario soltanto specificare il nome della stampante, stdprn (stampante stan-
dard o predefinita), per indicare la ridirezione dal video alla stampante (cioè da stdout alla stampante). Ad
esempio, la seguente istruzione invia l’output alla stampante:
fprintf(stdprn, “Somma totale = %d “, Tot);
IL LINGUAGGIO C 23
Gestione dell’output
e sequenze di escape
Gli specificatori di formato
In precedenza abbiamo esaminato gli specificatori %d e %f per visualizzare ri-
spettivamente il risultato di espressioni intere e reali. Gli specificatori di formato
previsti dall’ANSI C sono i seguenti:
Istruzione Output
printf(“%c”, x); s
printf(“%d”, a); 2
printf(“%20d”, a); 2
printf((%020d”, a); 00000000000000000002
printf(“%f”, y); 3.140000
printf(“%20.2f”, y); 3.14
printf(“%20d %10.2f”, a, y); 2 3.14
printf(“%-20d %-10.2f”, a, y); 2 3.14
printf(“%s”, nome); Piero
printf(“%10s”, nome); Piero
printf(“%-10s”, nome); Piero
printf(“%-20s 10.2f”, nome, y); Piero 3.14
24 IL LINGUAGGIO C
Gestione dell’output e sequenze di escape
Le sequenze di escape
In precedenza abbiamo visto che alcuni caratteri non sono stati visualizzati cor-
rettamente a video (ad esempio la è accentata) e che non abbiamo avuto modo di
scrivere frasi su righe diverse. A risolvere tali problemi pensano alcuni codici di
controllo detti tecnicamente sequenze di escape, che non stampano caratteri vi-
sibili ma contribuiscono a formattare ciò che viene stampato. Le sequenze di
escape iniziano con il carattere backslash (\) e sono interpretate come un singolo
carattere:
Presentiamo subito degli esempi. Il seguente programma:
#include <stdio.h>
main()
{
#include <stdio.h>
int a = 0;
main()
{
printf(“%a”); /* emette un beep */
printf(“Il valore di a e\’%d\n”, a);
printf(“E l\’altro valore qual e\’\? %d\n”, a+10);
system(“PAUSE”);
}
IL LINGUAGGIO C 25
Gestione dell’output
ESEMPI
e sequenze di escape
Esempio 1
Realizzare un programma che visualizzi i limiti di tutti i tipi interi; questi limiti
sono costanti memorizzate nel file header limits.h.
#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
main()
{
printf(“minimum char = %d\n”, CHAR_MIN);
printf(“maximum char = %d\n”, CHAR_MAX);
printf(“minimum short = %d\n”, SHRT_MIN);
printf(“maximum short = %d\n”, SHRT_MAX);
printf(“minimum int = %d\n”, INT_MIN);
printf(“maximum int = %d\n”, INT_MAX);
printf(“minimum long = %d\n”, LONG_MIN);
printf(“maximum long = %d\n”, LONG_MAX);
printf(“minimum signed char = %d\n”, SCHAR_MIN);
printf(“maximum signed char = %d\n”, SCHAR_MAX);
printf(“maximum unsigned char = %d\n”, UCHAR_MAX);
printf(“maximum unsigned = %u\n”, UINT_MAX);
printf(“maximum unsigned short = %d\n”, USHRT_MAX);
printf(“maximum unsigned long = %u\n”, ULONG_MAX);
system(“PAUSE”);
}
Esempio 2
Realizzare un programma che visualizzi sul video la frase ciao mondo servendosi
di sole variabili char.
#include <stdio.h>
main()
{
char a=99,b=105,c=97,d=111,e=32,f=109,g=111,h=110,i=100,j=111;
printf(“%c%c%c%c%c%c%c%c%c%c\n”, a,b,c,d,e,f,g,h,i,j);
system(“PAUSE”);
}
Esempio 3
Realizzare un programma che visualizzi sul video la tavola pitagorica riportata
nella figura servendosi delle tabulazioni.
x 2 3 4 5 6 7 8 9
2 4
3 6 9
4 8 12 16
5 10 15 50 25
6 12 18 24 30 36
7 14 21 28 35 42 49
8 16 24 32 40 48 56 72
9 18 27 36 45 54 63 72 81
26 IL LINGUAGGIO C
Gestione dell’output e sequenze di escape
ESEMPI
#include <stdio.h>
main()
{
printf(“\n\nx \t 2 \t 3 \t 4 \t 5 \t 6 \t 7 \t 8 \t 9 \n”);
printf(“2 \t 4 \n”);
printf(“3 \t 6 \t 9 \n”);
printf(“4 \t 8 \t 12 \t 16 \n”);
printf(“5 \t 10 \t 15 \t 20 \t 25 \n”);
printf(“6 \t 12 \t 18 \t 24 \t 30 \t 36 \n”);
printf(“7 \t 14 \t 21 \t 28 \t 35 \t 42 \t 49 \n”);
printf(“8 \t 16 \t 24 \t 32 \t 40 \t 48 \t 56 \t 64 \n”);
printf(“9 \t 18 \t 27 \t 36 \t 45 \t 54 \t 63 \t 72 \t 81 \n \n \n”);
system(“PAUSE”);
}
Esempio 4
I seguenti frammenti di codice chiariscono la funzione degli operatori unari ++
e ––.
int i;
i = 15;
printf(“%d, %d, %d”, ++i, i++, i);
...
16, 16, 17
IL LINGUAGGIO C 27
Le istruzioni di input
In C esistono vari modi per effettuare l’acquisizione di dati, ma tutti hanno in co-
mune il fatto che prelevano i dati dal dispositivo standard di input: la tastiera.
Prima di esaminarli, descriviamo brevemente i dispositivi standard.
In C esistono tre dispositivi standard predefiniti (denominati anche stream):
stdin (standard input), stdout (standard output) e stderr (standard error).
Il file stdin è associato alla tastiera e ogni lettura da tastiera viene vista come una
lettura dal file stdin.
Il file stdout (che abbiamo analizzato trattando la funzione printf) è associato al di-
spositivo di visualizzazione (il monitor) e ogni scrittura su di esso viene vista
come una scrittura sul monitor.
Il file stderr è associato comunemente con il monitor ed è utilizzato per visualiz-
zare messaggi di errore: ogni scrittura sul file stderr viene vista come una scrittu-
ra sul monitor.
La funzione getc
La funzione getc (non annoverata tra le funzioni ANSI C) legge un carattere dal di-
spositivo standard indicato e lo restituisce convertito in un intero. In altri termini,
questa funzione attende che venga premuto un tasto sulla tastiera, dopodiché ne
restituisce immediatamente il valore. Il carattere digitato non viene visualizzato
sullo schermo (la funzione analoga che però visualizza il carattere digitato sullo
schermo è getche()).
#include <stdio.h>
int c;
main()
{
c = getc(stdin);
printf(“\n%d”, c);
system(“PAUSE”);
}
La funzione getchar
La funzione getchar() equivale a getc(stdin) e, di conseguenza, legge un carattere
da stdin. Nonostante getchar() sia una funzione prevista dallo standard ANSI, il
suo comportamento può differire a seconda dell’implementazione del compilato-
re. In alcune versioni, infatti, restituisce immediatamente il valore del carattere
immesso da tastiera, in altre, invece, attende fino a quando non viene premuto il
tasto Invio.
#include <stdio.h>
int c;
main()
{
c = getchar();
printf(“\n%d”, c);
system(“PAUSE”);
}
28 IL LINGUAGGIO C
Le istruzioni di input
La funzione scanf
La funzione scanf consente di acquisire una sequenza di caratteri (lettere o cifre)
dalla tastiera (il dispositivo di ingresso standard, stdin) e di memorizzarli all’inter-
no di opportune variabili. Questa funzione lavora in modo simile a printf, che ab-
biamo esaminato in precedenza. La sua sintassi è la seguente:
scanf(<StringaDiFormato>,<Variabile>)
scanf(“%d”, &a);
#include <stdio.h>
int i;
main()
{
scanf(“%d %d”,&i,&j);
IL LINGUAGGIO C 29
Le istruzioni condizionali
(o di selezione)
Il blocco
Il linguaggio C utilizza quattro istruzioni condizionali principali: if, if..else, ? e
switch. L’istruzione ?, per la sua estrema semplicità, è già stata esaminata in pre-
cedenza. Prima di affrontare lo studio delle altre istruzioni di selezione è dovero-
so introdurre il concetto di blocco.
Le istruzioni condizionali consentono di eseguire in modo selettivo una singola
riga di codice o una serie di righe che costituiscono un blocco di codice. Quando
all’istruzione condizionale è associata una sola riga di codice, non è necessario
racchiudere l’istruzione da eseguire fra parentesi graffe. Se invece sono associate
più righe di codice, le stesse (ossia il blocco) dovranno essere racchiuse fra paren-
tesi graffe. Volendo, è comunque possibile utilizzare tali parentesi anche quando
l’istruzione da eseguire è soltanto una: il compilatore non segnalerà alcun errore.
L’istruzione if..else
La struttura alternativa viene implementata in C attraverso l’istruzione if..else. È
un’istruzione molto intuitiva, se si considera che le parole inglesi if ed else corri-
spondono rispettivamente alle italiane “se” e “altrimenti”. Secondo i canoni della
programmazione strutturata, la struttura alternativa può presentarsi con o senza
il ramo “altrimenti”. In C la sintassi da seguire per codificare le due forme è la se-
guente:
if (<Condizione>)
[{]
<Istruzione/i da eseguire se la condizione è vera>;
[}]
if (<Condizione>)
[{]
<Istruzione/i da eseguire se la condizione è vera>;
[}]
else
[{]
Nel caso in cui sia necessario condizionare anche le istruzioni rette da else (le co-
siddette if in cascata) si impiega la seguente sintassi:
if (<Condizione1>)
[{]
<Istruzione/i da eseguire solo se la Condizione1 è vera>;
[}]
else if (<Condizione2>)
[{]
else if (<Condizione3>)
[{]
...
30 IL LINGUAGGIO C
Le istruzioni condizionali (o di selezione)
#include <stdio.h>
int n;
main( )
{
if (voto < 5)
{
printf( “Sei totalmente insufficiente! \n”);
}
else
{
printf(“Forza! Ricomincia a studiare! \n”);
}
}
che è senz’altro più comprensibile. Adesso, infatti, diventa chiaro che l’istruzione
else è riferita all’istruzione if(voto < 5).
IL LINGUAGGIO C 31
Le istruzioni condizionali
ESEMPI
(o di selezione)
Considerata la semplicità degli esercizi proposti, riportiamo solo la codifica in C
evitando l’analisi del problema.
Dati in input tre voti, fornire in output la media in decimi o trentesimi
in funzione della scelta fatta dall’utente
#include <stdio.h>
#include <stdlib.h>
int a,b,c;
float media;
char scelta;
main()
{
printf(“Inserisci il primo voto: “);
scanf(“%d”,&a);
printf(“Inserisci il secondo voto: “);
scanf(“%d”,&b);
printf(“Inserisci il terzo voto: “);
scanf(“%d”,&c);
if ((a>=18) && (a<=30) && (b>=18) && (b<=30) && (c>=18) && (c<=30))
{
printf(“\nVuoi visualizzare la media in trentesimi o in centesimi [t/c]? “);
scanf(“\n%c”,&scelta);
...
}
system(“PAUSE”);
}
scanf(“\n%c”,&scelta);
Ciò ha una spiegazione importante. Il problema è che ogni volta che viene premu-
to un tasto, il carattere corrispondente viene inserito in un’opportuna area di me-
moria, chiamata buffer. Quando viene eseguita un’istruzione scanf, i caratteri
vengono letti dal buffer e portati nella variabile che deve essere letta.
Quando si inserisce da tastiera il terzo numero (quello che deve essere inserito
nella variabile c), si premono i tasti corrispondenti alle cifre (ad esempio 27), e
poi si preme Invio. Nel buffer vengono quindi inseriti 3 caratteri: il 2, il 7 e l’invio.
Il carattere ‘2’ e il carattere ‘7’ vengono convertiti in numero intero e assegnati
alla variabile c. Il carattere ‘invio’ rimane nel buffer. Se la lettura successiva è:
scanf(“%c”,&scelta);
il carattere ‘invio’ viene letto dalla scanf e, quindi, nella variabile scelta verrà inse-
rito il carattere ‘invio’.
Uno dei modi per risolvere questo inconveniente è quello di costringere la scanf
a leggere esplicitamente il carattere ‘invio’, che nel linguaggio C è rappresentato
con ‘\n’.
Quindi il codice:
scanf(“\n%c”,&scelta);
legge il carattere invio e lo scarta, poi legge il carattere successivo e lo assegna alla
variabile scelta. Completa l’esercizio inserendo al posto dei puntini le istruzioni
per calcolare la media e visualizzarla.
32 IL LINGUAGGIO C
Le istruzioni condizionali (o di selezione)
ESEMPI
Dato in input un numero intero positivo che indica la misura del
raggio, fornire in output la misura della circonferenza
/* Prima soluzione */
#include <stdio.h>
int r;
float circ;
main()
{
printf(“Inserire la misura del raggio ”);
scanf(“%d”, &r);
if (r>=0)
{
circ= 2*3.14*r;
printf(“Circonferenza e\’ %3.2f\n”, circ);
}
else
printf(“Il valore del raggio deve essere positivo”);
system(“PAUSE”);
}
IL LINGUAGGIO C 33
Le istruzioni iterative:
i costrutti while
e do...while
Nella risoluzione dei problemi capita molto spesso di dover ripetere molte volte
una serie di istruzioni. È evidente, quindi, la necessità di disporre di una struttu-
ra in grado di consentire la ripetizione di una sezione di codice per un numero fi-
nito di volte: la struttura iterativa o ciclica.
Il linguaggio C dispone di tre tipi di istruzioni iterative: while, do..while, for.
Ognuno di essi ha il proprio specifico utilizzo. I costrutti while e do..while consen-
tono l’esecuzione ripetuta di una sequenza di istruzioni in base al valore di verità
di una condizione.Vediamo innanzitutto la sintassi di while:
while (<Condizione>)
<Istruzione>;
Analizziamo ancora un altro esercizio che contiene alcuni cicli while annidati:
dati in input N numeri interi, scomporli in fattori primi.
#include <stdio.h>
#define TRUE 1
#define FALSE 0
typedef int bool;
int count;
char risposta;
bool continuo;
unsigned int n, d;
34 IL LINGUAGGIO C
Le istruzioni iterative:
i costrutti while e do...while
main( )
{
continuo = TRUE;
while(continuo == TRUE)
{
printf(“Inserisci un numero intero “);
scanf(“%d\n” &n);
d = 2;
while(n >1)
{
while (n%d != 0)
d++; /* trova i vari divisori primi di N partendo dal più piccolo */
n /= d;
count = 1;
while(n%d == 0) /* trova quante volte il divisore attuale divide N */
{
n /= d;
count++;
}
printf(“\n %d elevato a %d”, d, count);
}
printf(“\nVuoi continuare? (s/n)”);
scanf(“\n%c”, &risposta);
if (risposta == ‘n’)
continuo = FALSE;
}
system(“PAUSE”);
}
IL LINGUAGGIO C 35
Le istruzioni iterative:
ESEMPI
i costrutti while e do...while
Dato in input un numero intero positivo che indica la misura del
raggio, fornire in output la misura della circonferenza
Riprendiamo questo problema già analizzato precedentemente e vediamo, ora,
come fare per accettare in input soltanto valori che soddisfino il problema (nel
nostro caso, solo numeri interi positivi). Dal codice si evince, infatti, che dal ciclo
while si esce solo quando l’utente inserisce un valore valido. È un tipico esempio
di validazione dell’input dell’utente:
#include <stdio.h>
int r;
float circ;
main()
{
r=-1; /* inizializzazione che permette di entrare nel ciclo la prima volta */
while (r<0 || r>32767)
{
printf(“Inserire la misura del raggio “);
scanf(“%d”, &r);
if ((r<0) || (r>32767))
printf(“Il valore del raggio deve essere positivo minore di 32767”);
} /* fine del while */
circ= 2*3.14*r;
printf(“Circonferenza è %f”, circ);
system(“PAUSE”);
}
ESEMPI
è 5/9 di un grado Celsius. Notiamo che la temperatura di 32 °F corrisponde a
0°C. Quindi, un metodo per convertire gradi Celsius in gradi Fahrenheit è quello
di moltiplicare per 9/5 e aggiungere 32, mentre per convertire gradi Fahrenheit in
gradi Celsius occorre sottrarre 32 e moltiplicare per 5/9.
#include <stdio.h>
int fahr, celsius, lower, upper, step;
main()
{
lower = -300;
upper = 300;
step = 10;
fahr = lower;
printf(“Fahr\tCelsius\n”);
while(fahr <= upper)
{
celsius = 5 * (fahr-32) / 9;
printf (“%d\t%d\n”, fahr, celsius);
fahr = fahr + step; /* fahr avanza di 10 in 10) */
}
system(“PAUSE”);
}
IL LINGUAGGIO C 37
Il costrutto for
L’istruzione for viene utilizzata tradizionalmente per codificare la cosiddetta ripe-
tizione enumerativa o ripetizione con contatore: istruzioni cicliche che devono es-
sere ripetute per un numero prestabilito di volte. Come i più esperti sapranno, il
ciclo for rappresenta una specializzazione del ciclo while; tuttavia, nel linguaggio
C la differenza tra for e while è così sottile che i due costrutti possono essere lib-
eramente scambiati tra loro.
La sintassi dell’istruzione for è la seguente:
dove:
• <InizializzazioneContatore> può essere un’espressione che inizializza le va-
riabili del ciclo o una dichiarazione di variabili (in quest’ultimo caso le variabi-
li dichiarate hanno visibilità limitata a tutto il ciclo.
• <Condizione> è una qualsiasi espressione booleana; il corpo del ciclo for
sarà eseguito fintanto che la condizione si mantiene vera;
• <IncrementoContatore> è solitamente una istruzione di incremento o di
decremento del contatore da eseguire dopo ogni iterazione, ma può anche es-
sere un’istruzione che comprende altre manipolazioni sulla variabile;
• <Istruzione>, come nei precedenti cicli esaminati, indica un’istruzione sin-
gola o una sequenza di istruzioni racchiusa tra parentesi graffe.
Come si evince dalla sintassi, i primi tre elementi appena descritti sono opzion-
ali; in particolare, se <Condizione> non viene specificata, si assume che essa sia
sempre verificata.
Occorre prestare molta attenzione ai punti e virgola presenti nell’istruzione,
poiché in assenza di qualche elemento è comunque obbligatorio inserirli tra le in-
formazioni non dichiarate.
Facciamo subito un semplice esempio: supponiamo di voler ottenere la somma
di cinque numeri interi immessi dall’utente. Il codice è il seguente:
#include <stdio.h>
int i, numero, somma;
main( )
{
somma = 0;
for (i = 1; i <= 5; i++)
{
printf(“Inserire il %d numero ”, i);
scanf(“%d”, &numero);
somma += numero;
}
printf(“\nLa somma e\’ %d\n”, somma);
system(“PAUSE”);
}
38 IL LINGUAGGIO C
Il costrutto for
#include <stdio.h>
int numero, somma;
main( )
{
printf(“Inserire u numero intero positivo (0 per terminare) ”);
scanf(“%d”, &numero);
for (somma = 0; numero;)
{
somma += numero;
printf(“Inserire u numero intero positivo (0 per terminare) ”);
scanf(“%d”, &numero);
}
printf(“\nLa somma e\’ %d \n”, somma);
system(“PAUSE”);
}
Il ciclo esegue l’azzeramento della variabile somma (che verrà effettuato una sola
volta) e, subito dopo, controlla se il valore di numero è diverso da zero: nel caso in
cui ciò sia vero verranno eseguite le istruzioni del ciclo. Terminate le istruzioni,
poiché manca la terza espressione del for, viene ripetuto il controllo su numero.
L’inizializzazione della variabile somma avrebbe potuto essere svolta fuori dal ci-
clo for: in tal caso sarebbe mancata anche la prima espressione.
Poiché nel linguaggio C ogni ciclo while può essere codificato utilizzando un ciclo
for e viceversa, è bene tenere presente che la scelta del tipo di codifica da effet-
tuare va sempre fatta in modo da ottenere la massima chiarezza e leggibilità del
programma.
Con il ciclo for si utilizza spesso la cosiddetta istruzione nulla. Essa contiene solo
il ; e può apparire ovunque è consentita un’istruzione; quando viene eseguita non
succede sulla. L’istruzione nulla viene utilizzata nei casi in cui è richiesta almeno
un’istruzione, ad esempio nei cicli e nelle istruzioni condizionali.
Nel seguente caso, ad esempio, l’istruzione for è utilizzata esclusivamente come
un ciclo di ritardo software e, di conseguenza, non è necessario che venga ese-
guita alcuna istruzione:
...
for(i=0; i < 500000; i++)
;
...
IL LINGUAGGIO C 39
IL costrutto for
ESEMPI
40 IL LINGUAGGIO C
Il costrutto for
ESEMPI
Dato in input un intero n>0 e n numeri floating point, stampare il massimo e il minimo
#include <stdio.h>
#include <stdlib.h>
float max, x, min;
int n,i;
main()
{
do
{
printf(“Di quanti numeri vuoi calcolare max e min? ”);
scanf(“%d”, &n);
} while (n<1);
printf(“Inserisci un numero: ”);
scanf(“%f”, &max);
min=max;
for(i=1; i<n; i++)
{
printf(“Inserisci un numero: ”);
scanf(“%f”, &x);
if(x<min)
min=x;
else
if(x>max)
max=x;
}
printf(“Il max degli interi digitati e\’ %.3f, e il minimo e\’ %.3f.\n”, max, min);
system(“PAUSE”);
}
IL LINGUAGGIO C 41
Training
PROVE APERTE PER LA VERIFICA DELLE ABILITÀ
1. Tra le seguenti istruzioni di input è presente una priva 4. Il seguente programma C presenta degli errori e non è
di errori mentre le altre presentano ognuna un errore. scritto secondo le regole dell’indentazione. Interpreta il
Sapresti identificare quella corretta e trovare gli errori programma e prova a impostarlo in maniera corretta.
presenti nelle altre?
a scanf(“%d, k”); #include <stdio.h>;
b scanf(%d, k); int h;
c scanf(“%d, &k);
main( )
d Scanf(“%d, &k); {
e scanf(%d, “k”); printf(“Inserisci un numero ”);
f scanf(%”d”, $k); scanf(“%d”, &x);
if(h=3);
2. Il seguente programma C non usa l’istruzione if in ma- printf(Numero uguale a tre);
niera ottimale; inoltre presenta degli errori e non è scrit-
to secondo le regole dell’indentazione. Interpreta il pro- x+;
gramma e prova a impostarlo in maniera più efficiente. else
printf(Numero diverso da tre);
#include <stdio.h> system(PAUSA)
int k;
}
main( )
{
printf(“Inserisci un numero ”); 5. Enuncia il testo del problema relativo al seguente pro-
scanf(“%d”, &k); gramma C:
if(k==5)
printf(“\nNumero = 5 \n”); #include <stdio.h>
k++; int a, i, t;
printf(“Il valore di k e\’ %d\n”, k); float r;
printf(“Inserisci un numero “);
scanf(“%d”, &k); main()
if(k==5) {
{ t = 0;
printf(“\nNumero = 5\n”); i = 0;
k++; printf (“Numeri da inserire: ”);
} scanf(“%d”,&a);
printf(“Il valore di k e\’ %d\n”, k); while (a >= 0)
system(“PAUSE”);
{
}
i++;
t += a;
3. Il seguente programma C presenta degli errori e non è r = t/i;
scritto secondo le regole dell’indentazione. Interpreta il
programma e prova a impostarlo in maniera corretta. printf (“La media attuale e\’: %.3f\n”, r);
printf (“Inserisci un numero: ”);
#include <stdio> scanf(“%d”,&a);
int a; }
main printf (“La media finale e\’: %.3f\n”, r);
{ system(“PAUSE”);
printf(“Inserisci un numero ”); }
scanf(“%d”, &x);
if (x=3); Quale accorgimento puoi adottare per evitare di
printf(“Numero uguale a tre”) richiedere in input il dato sia fuori dal ciclo, sia
system(PAUSE) all’interno di esso.
}
42 IL LINGUAGGIO C
Training
PROVE APERTE PER LA VERIFICA DELLE ABILITÀ
IL LINGUAGGIO C 43
Le funzioni
Nel linguaggio C la componente principale dei codici è costituita da funzioni. Per
poter simulare le procedure (che non restituiscono alcun valore) è stato introdot-
to il tipo void. Ricordiamo, comunque, che il tipo void o tipo indefinito è utilizza-
to dal C ogni volta che il valore di ritorno di una funzione non deve essere preso
in considerazione. In altri termini, nel linguaggio C le procedure sono funzioni
che restituiscono un void. Possiamo riassumere il processo di costruzione e uso
di una funzione nelle seguenti tre fasi.
1. Definizione della funzione, cioè scrittura dell’elenco delle operazioni da essa
svolte. La definizione specifica nell’ordine il tipo di valore restituito, il nome
scelto dal programmatore (valgono le stesse regole viste per l’assegnazione dei
nomi alle variabili) e, infine, l’elenco dei parametri. All’interno del corpo della
funzione vengono inserite le dichiarazioni delle variabili della funzione e le
istruzioni. La sintassi generale è quindi la seguente:
[<TipoRestituito>] <NomeFunzione>([<ElencoParametri>])
{
<Istruzioni>
[return [(]<Risultato>[)]]
}
44 IL LINGUAGGIO C
Le funzioni
Giunti a questo punto del nostro percorso, è doveroso ricordare che anche il
main è una funzione ed è proprio questo il motivo della presenza della coppia
di parentesi tonde dopo la parola main. È una funzione speciale, poiché viene
eseguita per prima all’avvio del programma. L’istruzione return può essere pre-
sente anche nella funzione main, in tal caso il valore viene restituito diretta-
mente al sistema operativo, che è il programma chiamante della funzione.
Da questo momento, quindi, nei successivi esercizi sarà indicato il tipo int prima
di main, per indicare il tipo del valore restituito, e alla fine del main verrà indica-
ta l’istruzione return seguita dal valore 0, il modo più comune per indicare la ter-
minazione di un programma che non ha rilevato errori durante l’esecuzione.
Non è superfluo far notare che in questo programma la funzione è totalmente inu-
tile e può solo moltiplicare interi. L’abbiamo inserita unicamente per mostrare
come si costruisce una funzione.
IL LINGUAGGIO C 45
Le funzioni
ESEMPI
Equazione
secondo grado
Calcolo Risoluzione
Inserimento
Main Calcolo Delta e visualizzazione equazione
dei coefficienti
soluzioni di primo grado
46 IL LINGUAGGIO C
Le funzioni
ESEMPI
#include <stdio.h>
#include <stdlib.h>
#include <math.h> /* la libreria math consente di utilizzare funzioni
matematiche */
void Acquisisci_Coefficienti();
void Calcola_Delta();
void Visualizza_Soluzioni();
void Risolvi_Equazione();
int a, b, c;
float x, x1, x2, d;
int main()
{
Acquisisci_Coefficienti();
if(a != 0)
{
Calcola_Delta();
Visualizza_Soluzioni();
}
else
Risolvi_Equazione();
system(“PAUSE”);
return 0;
}
void Acquisisci_Coefficienti()
{
printf(“Inserisci il valore del coefficiente a ”);
scanf(“%d”, &a);
printf(“\nInserisci il valore del coefficiente b ”);
scanf(“%d”, &b);
printf(“\nInserisci il valore del coefficiente c ”);
scanf(“%d”, &c);
}
void Calcola_Delta()
{
d=(b*b)–(4*a*c);
}
void Visualizza_Soluzioni()
{
if(d<0)
printf(“\nL\’equazione non ammette soluzioni reali\n”);
else
{
x = (–b – sqrt(d))/(2*a);
x = (–b + sqrt(d))/(2*a);
printf(“\nx1= %–3.1f x2= %–3.1f\n”, x, x2);
}
}
void Risolvi_Equazione()
{
if((b==0) && (c==0))
printf(“\nEquazione indeterminata\n”);
else
if(b==0)
printf(“\nEquazione impossibile\n”);
else
x = –c/b;
}
IL LINGUAGGIO C 47
Passaggio dei
parametri per valore
Le funzioni comunicano tra di loro attraverso i parametri. L’operazione attraverso
la quale la funzione main o un’altra funzione chiamante invia i valori alla funzio-
ne, assegnandoli ai parametri, si chiama passaggio dei parametri. In particolare:
• le variabili indicate nella chiamata della funzione prendono il nome di para-
metri attuali;
• le variabili indicate nell’intestazione della funzione e che accettano i valori dei
parametri attuali prendono il nome di parametri formali.
Il passaggio di parametri (dal chiamante al chiamato) può avvenire secondo due
specifiche modalità:
• per valore (by value) se il chiamante comunica al chiamato il valore che è con-
tenuto in quel momento in una sua variabile (parametro attuale). Il chiamato
accoglierà tale valore all’interno di una variabile locale opportunamente predi-
sposta (parametro formale). Il chiamato può operare su tale valore, anche mo-
dificandolo, ma tali modifiche riguarderanno solo la copia locale su cui sta la-
vorando. Terminato il sottoprogramma, il parametro formale viene deallocato
e viene ripristinato il parametro attuale con il valore che conteneva prima del-
la chiamata al sottoprogramma.
• per riferimento o per indirizzo (by reference) se il chiamante comunica al chia-
mato l’indirizzo di memoria di una determinata variabile (parametro attuale).
Il chiamato, per accogliere il parametro attuale, può utilizzare un parametro
formale con un nome diverso, ma le locazioni di memoria a cui ci si riferisce
sono sempre le stesse. Viene soltanto stabilito un riferimento diverso alle stes-
se posizioni di memoria: ogni modifica effettuata sul parametro formale si ri-
percuoterà su quello attuale, anche se il nuovo nome cessa di esistere alla con-
clusione del sottoprogramma.
In mancanza di specifiche indicazioni (cioè per default) si assume che il pas-
saggio di parametri avvenga per valore. È doveroso ricordare che la lista dei pa-
rametri attuali (quelli inviati dal programma chiamante) e quella dei parametri
formali (quelli presenti nell’intestazione della funzione) devono essere entrambe
coerenti rispetto a tre elementi fondamentali:
• numero: il numero dei parametri formali deve essere uguale a quello dei para-
metri attuali;
• tipo: parametri attuali e parametri formali corrispondenti devono essere dello
stesso tipo;
• ordine: il passaggio dei parametri è posizionale, nel senso che il primo para-
metro attuale invierà il suo contenuto al primo parametro formale, il secondo
attuale al secondo formale e così di seguito.
Al fine di chiarire ulteriori dettagli sul passaggio dei parametri, riprendiamo
l’esercizio svolto a pagina 91, che calcolava il prodotto di due numeri interi. Il pro-
gramma che abbiamo realizzato faceva uso di di variabili globali che, essendo vi-
sibili all’interno di tutte le funzioni, non necessitavano di essere trasmesse alla
funzione che si occupava di calcolare il prodotto. Nei due esercizi che seguono,
invece, le variabili che utilizzeremo saranno dichiarate locali al main, per cui oc-
correrà “farle conoscere” alle funzioni che si occuperanno di svolgere determina-
te operazioni.
Per comprendere meglio le due modalità di passaggio dei parametri, risolviamo
due semplici problemi. Per la risoluzione del primo ci serviremo di un passaggio
di parametri per valore: dati in input due numeri interi a e x, calcolare il valo-
re della potenza ax.
#include <stdio.h>
#include <stdlib.h>
long int Potenza(int b, unsigned int e);
48 IL LINGUAGGIO C
Passaggio dei parametri per valore
int main( )
{
int a;
unsigned int x;
printf(“Inserire la base “);
scanf(“%d”, &a);
printf(“Inserire l’esponente “);
scanf(“%ud”, &x);
printf(“La potenza e\’ %ld\n” , Potenza(a, x)); /* parametri attuali */
system(”PAUSE”);
return 0;
}
long int Potenza(int b, unsigned int e) /* parametri formali passati per valore */
{
long int p;
p=1;
while(e>=1)
{
p *= b;
e ––;
}
return p;
}
Nel passaggio dei parametri per valore (by value) si ha soltanto una copia dei va-
lori dei parametri attuali nei rispettivi parametri formali. Durante l’esecuzione del
sottoprogramma, qualsiasi modifica apportata ai parametri formali sarà visibile
solo all’interno della funzione e non verrà riportata sui parametri attuali (che con-
tinueranno, così, a conservare il valore inizialmente trasmesso). I parametri for-
mali vengono considerati come variabili locali il cui valore, al ritorno dalla funzio-
ne, perde il suo significato.
Nel passaggio dei parametri per valore, all’atto della chiamata della funzione, vie-
ne allocata un’area di memoria utilizzata per contenere i parametri formali. Si ha,
così, una duplicazione dello spazio di memoria riservato ai parametri. Al passag-
gio, i parametri formali verranno inizializzati con il valore dei rispettivi parametri
attuali. In questo modo, il processore opera su questa nuova area di memoria la-
sciando inalterato il valore dei parametri attuali. Al rientro dalla funzione, que-
st’area viene rilasciata, proprio come avviene per le variabili locali.
IL LINGUAGGIO C 49
Passaggio dei parametri
ESEMPI
per valore
Stampare tutti i numeri primi compresi tra due numeri forniti in input
Per risolvere il problema ci serviamo di due funzioni: la prima, che abbiamo chia-
mato Numeriprimi, non fa altro che richiamare la funzione Numeroprimo per ogni
valore compreso nell’intervallo [i, j] fornito in input. La funzione Numeroprimo
controlla se il numero passato come parametro è primo. Tale controllo viene ef-
fettuato dividendo il valore del parametro ricevuto per tutti i numeri compresi tra
2 e il valore del parametro stesso. Nel momento in cui si trova un numero per il
quale la divisione fornisce come resto zero, si comprende che il numero non è pri-
mo e la funzione restituisce il valore booleano FALSE attraverso la variabile primo.
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
int Numeroprimo(int);
void Numeriprimi(int, int);
int main()
{
int i,j;
printf(“Inserisci il primo numero: “);
scanf(“%d”, &i);
printf(“Inserisci il secondo numero:”);
scanf(“%d”, &j);
Numeriprimi(i,j);
system(“PAUSE”);
return 0;
}
50 IL LINGUAGGIO C
Passaggio dei parametri per valore
ESEMPI
Riportiamo una versione più compatta della funzione Numeroprimo:
int numeroprimo(int n) /* versione compatta */
{
int primo=TRUE, i=2;
while(primo && (i*i<=n))
primo=n%i++;
return(primo);
}
IL LINGUAGGIO C 51
Passaggio dei
parametri per indirizzo
Talvolta la modifica dei parametri formali diviene necessaria per il corretto fun-
zionamento del programma. Per esempio il programma seguente, che effettua lo
scambio del contenuto di due variabili, non funziona correttamente perché il pas-
saggio di parametri per valore non consente di risolvere il problema.
#include <stdio.h>
#include <stdlib.h>
void Scambia(int x, int y);
int main()
{
int a, b;
printf(“Inserire il primo numero “);
scanf(“%d”, &a);
printf(“\nInserire il secondo numero “);
scanf(“%d”, &b);
Scambia(a, b); /* chiamata della funzione */
printf(“\nI valori scambiati sono:\n”);
printf(“a = %d\nb = %d\n”, a, b);
system(“PAUSE”);
return 0;
}
Questi tipi di problemi richiedono che la funzione non operi su una copia locale
dei dati, ma direttamente sui dati originali. È necessario, quindi, effettuare un
passaggio di parametri per indirizzo.
Tecnicamente, il passaggio per indirizzo differisce da quello per valore in quanto,
all’atto della chiamata della funzione, non viene allocata nessuna area di memo-
ria per valori dei parametri formali. Poiché essi si riferiscono alla stessa area di
memoria allocata per i parametri attuali, la stessa cella di memoria sarà indivi-
duabile con due nomi distinti. In questo tipo di passaggio non viene trasmesso il
valore dei parametri attuali, bensì l’indirizzo della cella di memoria a essi asse-
gnata; di conseguenza, la modifica di un parametro comporterà la modifica del-
l’altro.
Per passare l’indirizzo di una variabile è necessario anteporre al nome del para-
metro attuale l’operatore unario di indirizzo & che restituisce, appunto, l’indiriz-
zo della variabile alla quale è applicato.
D’altra parte, la funzione che riceve una variabile con passaggio per indirizzo
deve essere in grado di risalire dall’indirizzo della cella di memoria al valore in
essa contenuto; per permettere ciò è necessario che i parametri formali siano
preceduti dall’operatore * che, applicato al nome di una variabile di tipo indiriz-
zo, ne restituisce il valore.
Risolviamo ora il precedente problema relativo allo scambio del contenuto di due
variabili, servendoci questa volta del passaggio di parametri per indirizzo.
52 IL LINGUAGGIO C
Passaggio dei parametri per indirizzo
#include <stdio.h>
void Scambia(int *x, int *y);
int main()
{
int a, b;
printf(“Inserire il primo numero “);
scanf(“%d”, &a);
printf(“\nInserire il secondo numero “);
scanf(“%d”, &b);
Scambia(&a, &b); /* chiamata della funzione */
printf(“\nI valori scambiati sono:\n”);
printf(“a = %d\nb = %d\n”, a, b);
system(“PAUSE”);
return 0;
}
void Scambia(int *x, int *y)
{
int appoggio;
appoggio = *x;
*x = *y;
*y = appoggio;
}
Per consolidare la comprensione della differenza tra passaggio per valore e pas-
saggio per indirizzo presentiamo un ulteriore esempio:
#include <stdio.h>
void Incrementa(int x, int *y);
int main()
{
int a=0, b=0;
Incrementa(a, &b);
printf(“Nel main la variabile a vale %d e la variabile b vale %d \n\n”, a, b);
system(“PAUSE”);
return 0;
}
void Incrementa(int x, int *y)
{
x++;
(*y)++;
printf(“Nella funzione il parametro x vale %d e il parametro y vale
%d \n\n”, x, *y);
return;
}
Dal risultato ottenuto si nota come l’incremento del parametro x (trasmesso per
valore) all’interno della funzione non influenza il valore della variabile a, mentre
l’incremento della variabile indirizzata da y (trasmesso per indirizzo) modifica il
valore iniziale della variabile b.
IL LINGUAGGIO C 53
Gli array
In precedenza i dati da elaborare sono sempre stati considerati contenuti all’in-
terno di comuni variabili. Quando però il numero dei valori da gestire diventa ele-
vato, tali variabili si rivelano inadatte a soddisfare tutte le esigenze del program-
matore; in questo caso si ricorre a specifiche strutture di dati denominate array.
Gli array sono variabili in grado di ospitare diversi valori omogenei (cioè tutti del-
lo stesso tipo) in opportuni spazi numerati chiamati elementi. A un elemento di
un array si può accedere indicando il nome della struttura e il numero corrispon-
dente alla posizione, detto indice.
Il tipo di un elemento può essere un tipo primitivo o un oggetto più complesso:
avremo quindi array di numeri interi, di stringhe o di array, ma non array che
contengono tipi di dati diversi (per esempio numeri interi e stringhe, i cosiddetti
array densi possibili invece in altri linguaggi).
Un array può contenere più indici. Nel caso in cui contenga:
1. un solo indice, si dice che l’array è a una dimensione e si parla specificamen-
te di vettore (una rappresentazione è visibile nella figura);
2. due indici, si parla di array bidimensionale o matrice;
3. più di due indici, si parla di array multidimensionali.
Valori dell’indice
0 1 2 3 4 5 6 7
3 8 150 10 85 90 7 34
Tutti gli elementi di un array vengono memorizzati uno di seguito all’altro nella
memoria del computer e, cosa importante, l’indice del primo elemento è 0. Il
nome del vettore è un valore costante che rappresenta l’indirizzo di memoria del
primo elemento del vettore stesso.
Dichiarazione di un vettore
Per dichiarare un vettore si deve scrivere il tipo degli elementi, seguito da un
nome valido e da una coppia di parentesi quadre che racchiudono un’espressio-
ne costante. Tale espressione costante definisce le dimensioni dell’array, ossia il
numero di elementi che esso contiene.
La sintassi generale è dunque la seguente:
<TipoElementi> <NomeArray>[<Dimensione>];
Per esempio:
#define LIMITE_NUMERI 10
#define LIMITE_LETTERE 20
int numeri[LIMITE_NUMERI];
char lettere[LIMITE_LETTERE];
Inizializzazione di un vettore
Un vettore può essere inizializzato esplicitamente, al momento della creazione,
fornendo le costanti di inizializzazione dei dati, oppure durante l’esecuzione del
programma, assegnando o copiando dati nell’array.
54 IL LINGUAGGIO C
Gli array
Per inizializzare l’array numeri degli esempi precedenti in fase di creazione, con
dieci numeri interi, scriveremo:
Array dimensionato
<NomeArray>[<IndiceElemento>]
Indirizzo Contenuto
00100 23,5 temperature[0]
00104 23,0 temperature[1]
00108 22,8 temperature[2]
00112 21,6 temperature[3]
00116 23,9 temperature[4]
00120 20,6 temperature[5]
00124 22,9 temperature[6]
<IndirizzoI-esimoEelemento> = <IndirizzoPrimoElemento> + I *
<DimensioneElemento>
IL LINGUAGGIO C 55
Gli array
ESEMPI
Caricare un vettore con N elementi interi, con N ≤ 100
Questo è un problema di caricamento determinato ossia un caricamento di N va-
lori con N noto a priori. Il problema è molto semplice, perciò possiamo passare
direttamente alla codifica.
#include <stdio.h>
#define MASSIMO 50
int DimensionaVettore( );
int main( )
{
int vettore[MASSIMO];
int k, numelementi;
numelementi = DimensionaVettore( );
for (k=0; k < numelementi; k++)
{
printf(“\nInserire l’elemento di posizione %d: ”, k);
scanf(“%d”, &vettore[k]);
}
system(“PAUSE”);
return 0;
}
int DimensionaVettore( )
{
int elementi;
do
{
printf(“Quanti elementi vuoi inserire? ”);
scanf(“%d”, &elementi);
} while(elementi < 1 || elementi > MASSIMO);
return(elementi);
}
ESEMPI
#include <stdio.h>
int main()
{
int i, numeri=0, valori[200];
long somma;
double media;
do
{ /* ripetiamo il ciclo fino a quando il numero inserito è valido */
do
{
printf(“\nInserire il numero %d :”, numeri + 1);
scanf(“%d”,&valori[numeri]);
} while((valori[numeri] < 1 || valori[numeri] > 10000) && !(valori[numeri] == –1));
} while(valori[numeri++] != –1);
numeri––; /* decremento perché l’ultimo valore non si deve considerare */
somma=0;
for(i = 0; i < numeri; i++)
somma+=valori[i];
media=0;
for(i = 0; i < numeri; i++)
media=(double)somma / numeri;
printf(“\nNumero valori inseriti = %d”, numeri);
printf(“\nSomma = %d”, somma);
printf(“\nMedia = %.2f \n”, media);
system(“PAUSE”);
return 0;
}
Scrivere un programma che visualizzi i numeri primi minori di 100 utilizzando il crivello
di Eratostene
Il crivello di Eratostene è una specie di setaccio che scartando i numeri composti permette di determinare i nu-
meri primi. Supponendo di voler determinare tutti i numeri primi minori di 100, si procede nel seguente modo:
si memorizzano in un vettore i numeri fino a 100 (partendo da 2), si eliminano, dopo il 2, tutti i numeri pari
perché multipli di 2. A partire dal 3 si eliminano successivamente tutti i multipli di 3 (cioè un numero ogni tre).
Dopo il 3 si incontra il 5 e si eliminano quindi tutti i multipli di 5 (cioè un numero ogni 5) e così via finchè non
sono stati eliminati tutti i numeri composti. Il procedimento termina quando si arriva a 100.
#include <stdio.h>
main()
{
int i, j, v[100];
for (i=2; i<100; i++)
v[i] = i;
for (i=2; i<100; i++) /* useremo 1 per indicare che il numero è primo e 0 se non lo è */
if (v[i] == 1) /* se i è primo cancelliamo i suoi multipli */
for (j=2; j*i<100; j++ )
v[i*j] = 0;
for (i=2; i<100; i++) /* stampiamo i numeri primi */
if (v[i] == 1)
printf(“%d\t”, i);
printf(“\n”);
system(“PAUSE”);
return 0;
}
IL LINGUAGGIO C 57
Training
PROVE APERTE PER LA VERIFICA DELLE ABILITÀ
1. Scrivi in corrispondenza di ogni valore da memorizza- 4. Scrivi le scritture compatte equivalenti alle seguenti
re il tipo di dato più appropriato: istruzioni:
Valore Tipo di dato X = X + Y;
2 X = X – Y;
125000000 X = X * Y;
A X = X / Y;
Ab X = X % Y;
0.125
125520.25 5. Trova l’errore presente in ognuna delle seguenti di-
chiarazioni di variabili:
2. Completa la seguente tabella riportando la descrizio-
ne dei vari tipi di dati presenti: Int a;
Float b;
Tipo Descrizione int a = 12.5;
58 IL LINGUAGGIO C
Training
PROVE APERTE PER LA VERIFICA DELLE ABILITÀ
8. Osservando le porzioni di codice seguenti, scrivi il valo- 12. Qual è l’output fornito dal seguente programma?
re contenuto nella variabile c. Il primo caso appare ri-
solto, come esempio:
#include <stdio.h>
Codice Contenuto della variabile c
dopo l’esecuzione del codice #include <stdlib.h>
int a, b;
int i, i1;
double d, d2;
long l;
double res;
i=10;
i1=20;
d = 12.5;
d2 = 5.777;
l = 140000000;
res = ((i * d) / (l / d2)) + i1;
IL LINGUAGGIO C 59
Training
PROVE APERTE PER LA VERIFICA DELLE ABILITÀ
14. Qual è l’output prodotto dal seguente programma? 16. Gradi, primi e secondi
Scrivi un algoritmo che, data in input la misura di un
#include <stdio.h> angolo in gradi (G), primi (P) e secondi (S), determini
la sua ampiezza espressa in secondi.
#include <stdlib.h>
int a, b, c, d;
17. Media di tre numeri
Scrivi un algoritmo che, dati in input tre numeri,
main()
ne determini la media.
{
printf(“Inserisci il primo numero ”); 18. Area del cerchio
scanf(“%d”, &a); Scrivi un algoritmo che determini l’area del cerchio
printf(““Inserisci il secondo numero ”); circoscritto a un quadrato.
scanf(“%d”, &b);
printf(“Inserisci il terzo numero ”); 19. Perimetro e area del triangolo
scanf(“%d”, &c); Scrivi un algoritmo che, date in input le dimensioni
printf(“Inserisci il quarto numero ”); AB e BC del seguente triangolo isoscele, ne
scanf(“%d”, &d); determini perimetro e area.
printf(“%d\n”, (a>b && c<=d));
printf(“%d\n”, (a>b || c<=d)); A
printf(“%d\n”, (a<=b && c>d || a));
printf(“%d\n”, (a<=b && (c>d || a)));
system(”PAUSE”);
}
B C
15. Qual è l’output prodotto dal seguente programma?
20. Età di una persona
#include <stdio.h> Scrivi un algoritmo che, dati in input il cognome,
il nome e l’anno di nascita di una persona, fornisca
#include <stdlib.h>
in output la sua età.
int a,b,c;
60 IL LINGUAGGIO C