Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato...

60
Il linguaggio C Piero Gallo – Pasquale Sirsi

Transcript of Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato...

Page 1: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

Il linguaggio CPiero Gallo – Pasquale Sirsi

Page 2: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

Il linguaggio C

2 IL LINGUAGGIO C

Generalità sul linguaggio CI linguaggi di programmazione possono essere classificati in base a diversi crite-ri. Le classificazioni non servono per stabilire se certi linguaggi sono migliori opreferibili rispetto ad altri, ma per distinguere che cosa possono fare e a qualescopo possono essere utilizzati. Una tra le più importanti classificazioni distinguei linguaggi di basso livello da quelli di alto livello.

I linguaggi di basso livello permettono di programmare il computer inserendole istruzioni che possono essere eseguite direttamente dal microprocessore.Sono linguaggi più “vicini” alla logica della macchina che a quella del program-matore.

L’Assembly è il classico linguaggio di basso livello attraverso il quale si manipoladirettamente la memoria, i registri del microprocessore e, tramite altre funzionidi basso livello fornite dal sistema operativo, si può accedere direttamente all’har-dware (per esempio a una porta, a una unità a disco e così via).

I linguaggi di alto livello sono più intuitivi e comprensibili per il programmato-re, ma le loro istruzioni non sono direttamente eseguibili dal microprocessore,è necessario che siano trasformate in istruzioni di basso livello a opera di spe-cifici software (compilatori/interpreti).

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 ilprocessore 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.

Il C è un linguaggio di programmazione di alto livello. Progettato e realizzato daDennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories allo sco-po di ottenere un linguaggio di alto livello per l’implementazione dei sistemi ope-rativi. Il linguaggio C fu utilizzato per la prima volta in modo estensivo per la ri-scrittura del codice del sistema operativo UNIX dal linguaggio Assembly;inevitabilmente, molte delle sue caratteristiche derivano dalle specifiche esigen-ze legate alla realizzazione di un sistema operativo in generale, e di UNIX in par-ticolare. Benché sia strettamente legato a quest’ultimo sistema, il C può essereimpiegato con i principali sistemi operativi oggi disponibili. Steve Johnson, nellametà degli anni Settanta, scrisse un compilatore C trasportabile su sistemi diver-si dal PDP-11: da allora il C cominciò a essere utilizzato come linguaggio in altri si-stemi operativi, come MS-DOS e CPM/80.

Nel 1978 fu pubblicato il libro The C Programming Language di Brian Kernighan eDennis Ritchie (K&R): la pubblicazione servì come definizione ufficiale del lin-guaggio, anche se già dalla distribuzione della versione V7 erano presenti alcunecaratteristiche assenti in nel volume citato.

Nella metà degli anni Ottanta il comitato X3JI1 dell’ANSI (American NationalStandards 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 eRitchie. Da allora l’ANSI C cominciò a essere considerato la versione “ufficiale”del linguaggio rimpiazzando quella di K&R.

Page 3: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

Le principali caratteristiche del linguaggio CElenchiamo di seguito le caratteristiche principali del linguaggio C.

• È un linguaggio general purpose, ossia può essere impiegato per codificareprogetti software di natura diversa, da quelli real time a quelli che operano subasi di dati, da quelli tecnico-scientifici fino alla realizzazione di moduli per ilsistema operativo.

• È un linguaggio strutturato di tipo imperativo (o procedurale).• È un linguaggio case sensitive, ossia distingue tra lettere minuscole e lettere

maiuscole. Ad esempio, la variabile PIPPO è diversa dalle variabili Pippo e pippo.• È un linguaggio compilato. Il problema dei linguaggi imperativi compilati è

che sono legati alla piattaforma su cui vengono compilati: se compiliamo unprogramma sotto UNIX, quel programma potrà essere eseguito esclusivamen-te su sistemi operativi UNIX.

• Nella versione ANSI, è facilmente portabile e perciò multipiattaforma; infatti,può essere compilato su un’ampia gamma di computer.

• Pur essendo un linguaggio di alto livello (in quanto possiede strutture di alto li-vello), e nonostante possa definirsi potente ed efficiente, il C è un linguaggiorelativamente di medio livello, in particolare per quanto riguarda la rappresen-tazione dei dati.

• Produce programmi efficienti. Essendo nato per implementare sistemi opera-tivi, il C evita, ove possibile, qualsiasi operazione che possa determinare un de-cadimento del livello di efficienza del programma eseguibile.

• Produce programmi di dimesioni ridotte. Il C ha, infatti, una sintassi che sipresta alla concisione e alla scrittura di codice compatto.

Descrizione sintattica di linguaggi di programmazionePer descrivere la sintassi di un linguaggio di programmazione ci serviamo di unformalismo molto diffuso: la BNF (Backus-Naur Form o Forma Normale di Backus).Al fine di rendere lo studio semplice ed efficace, nella nostra trattazione impie-gheremo soltanto alcuni simboli propri della BNF e poche regole. In particolare:

• le parole chiave del linguaggio saranno scritte in grassetto;• le parole racchiuse tra parentesi angolari < > rappresentano le categorie sin-

tattiche, ossia elementi generali del linguaggio che, nei vari programmi, sa-ranno sostituiti con opportune occorrenze; ad esempio:

Il linguaggio C

• le parentesi quadre [ ] racchiudono blocchi opzionali, ossia che possono anchenon essere presenti. Ad esempio:

� int <NomeVariabile> [= <ValoreIniziale>]

• le parentesi graffe { } racchiudono blocchi con possibilità di ripetizione. Adesempio:

� int <NomeVariabile> {, <NomeVariabile>}

indica che subito dopo il metodo è possibile inserire una lista opzionale di pa-rametri separati da una virgola;

• il simbolo | ha il significato di OR. Ciò significa che all’interno di una lista diparole chiave separate da questo simbolo occorre sceglierne soltanto una. Adesempio, in base alla seguente sintassi:

� int | float <NomeVariabile>

la variabile di nome <NomeVariabile> dovrà essere preceduta dalla parolachiave int oppure da float.

<NomeVariabile>=<Espressione>A = B

A = C + 2 * D

C = 0

IL LINGUAGGIO C 3

Page 4: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

.

.

.

La struttura di un programma in linguaggio C è la seguente:

Anatomia di un programma C

4 IL LINGUAGGIO C

Direttive al preprocessore

Come si evince dalla figura, un programma in linguaggio C è formato da un insiemedi sottoprogrammi (che impareremo a chiamare con il loro vero nome, funzioni).Riportiamo di seguito una schematizzazione più generale della struttura di unprogramma in linguaggio C.

� direttive per il preprocessore� dichiarazioni globali – variabili, costanti e prototipi� main()� {� variabili locali alla funzione main � istruzioni della funzione main� }� f1()� {� variabili locali alla funzione f1 � istruzioni della funzione f1� }� f2()� {� variabili locali alla funzione f2 � istruzioni della funzione f2� }

.

.

.� fn()� {� variabili locali alla funzione fn � istruzioni della funzione fn� }

Sottoprogramma 2

Sottoprogramma 1

Programma principale (main)

Dichiarazione di variabili globalie/o dei prototipi delle funzioni

Sottoprogramma N

Facoltativo

Facoltativo

Obbligatorio

Facoltativo

Facoltativo

Facoltativo

Page 5: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

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, inmancanza di esplicita dichiarazione (cioè per default), è un valore intero (int);

• <ElencoParametri> rappresenta l’insieme dei parametri che il main accettain ingresso (i parametri saranno trattati approfonditamente in seguito). Nelcaso 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 essereracchiusi all’interno di tali parentesi.

Hai notato che nella sintassi le varie istruzioni (<Istruzione1>, >Istruzione2> ecosì via) sono spostate un po’ a destra rispetto alle parentesi graffe? Le istru-zioni vengono rientrate per indicare la loro dipendenza, cioè per evidenziareche l’istruzione è contenuta in un’altra. È buona abitudine curare questi inco-lonnamenti poiché, così facendo, si garantisce una migliore leggibilità del codi-ce. La tecnica di questi incolonnamenti è chiamata indentazione.

Come si evince dalla sintassi, quando il compilatore richiama il main esegue ilgruppo di istruzioni racchiuso all’interno della coppia di parentesi graffe { } chedefiniscono il corpo del programma principale. Dal punto di vista tecnico, le pa-rentesi graffe permettono di incapsulare istruzioni composte. Tali istruzioni pos-sono consistere nella definizione del corpo di un sottoprogramma (come accadenel nostro caso per il main), oppure nel riunire più linee di codice che dipendonodalla stessa istruzione di controllo, come nel caso in cui diverse istruzioni vengo-no eseguite a seconda del risultato vero/falso del test di un’istruzione. Dalla sintassi si ricava, inoltre, che ogni istruzione C termina con un punto e vir-gola (;). Su una singola riga è anche possibile scrivere più istruzioni, ma è buonanorma scriverne solo una al fine di migliorare la leggibilità del codice. Notiamo l’utilizzo delle parentesi tonde e graffe. Le parentesi tonde () vengonoutilizzate in unione con i nomi dei sottoprogrammi (le funzioni), mentre le paren-tesi graffe {} vengono utilizzate per delimitare le espressioni. Infine, il punto evirgola (;) indica la fine di un’istruzione.

Il linguaggio C ha un formato piuttosto flessibile: istruzioni lunghe possono esse-re continuate su righe successive senza problemi: il punto e virgola segnala alcompilatore che è stata raggiunta la fine dell’istruzione. Inoltre, è possibile intro-durre spazi allo scopo di garantire una maggiore leggibilità del programma.Un errore molto comune è proprio quello di dimenticare il punto e virgola: in que-sto caso il compilatore concatenerà più linee di codice, generando un’espressio-ne priva di qualsiasi significato. Per questo motivo il messaggio d’errore che ilcompilatore restituisce non indica la mancanza del punto e virgola, quanto la pre-senza di qualcosa di incomprensibile. Attenzione dunque a non scordare i punti evirgola e a interpretare correttamente i messaggi del compilatore.

Anatomia di un programma C

IL LINGUAGGIO C 5

Page 6: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

L’alfabeto del linguaggio CL’alfabeto del linguaggio C è formato da:

1. le lettere minuscole e maiuscole dell’alfabeto inglese (dalla a fino alla z):a b c d e f g h i j k l m n o p q r s t u v w y zA B C D E F G H I J K L M N O P Q R S T U V X Y Z

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 lessicaliGrazie all’alfabeto del oinguaggio, il programmatore piò definire le parole da utiliz-zare nel programma sorgente. Naturalmente tali parole devono essere valide, ossiaessere 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 chiaveIl linguaggio C (come qualsiasi altro linguaggio di programmazione) consente larealizzazione 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:

auto break case constcontinue default do doubleelse enum extern floatfor goto if intlong register return shortsigned sizeof static structswitch typedef unsigned voidvolatile while

Alfabeto e regolelessicali

6 IL LINGUAGGIO C

Page 7: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

Gli identificatoriGli identificatori sono i nomi definiti dal programmatore per riferirsi a sei diversecategorie 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 voltaper 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 solocome nomi utilizzati per identificare un valore.

L’etichetta è un nome che identifica una istruzione del programma; è utilizzatadall’istruzione di salto incondizionato (goto).

Il tipo identifica un insieme di valori e di operazioni definite su di essi; ogni lin-guaggio (o quasi) fornisce un certo numero di tipi primitivi (a cui è associato unidentificatore predefinito) e dei meccanismi che permettono la costruzione dinuovi tipi (ai quali il programmatore deve poter associare un nome) a partire daquesti.

Funzione (in C function) è il termine che viene utilizzato per indicare i sottopro-grammi.

La macro è in sostanza un alias utilizzato per contrassegnare una porzione di co-dice. Come vedremo più avanti, le macro non sono trattate dal compilatore, mada un precompilatore che si occupa di eseguire alcune elaborazioni sul codice sor-gente prima che questo venga effettivamente compilato.

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à dettoche il C è un linguaggio case sensitive). Tutti gli identificatori presenti in un pro-gramma devono essere diversi tra loro, indipendentemente dalla categoria a cuiappartengono. Gli identificatori non possono iniziare con una cifra numerica enon possono contenere spazi. Ad esempio, non sono identificatori validi:

2biciclette primo numero

mentre sono validi i seguenti:

j MIN max eta_studente _secondo_nome

Sebbene il linguaggio non preveda un limite alla lunghezza massima di un identi-ficatore, è praticamente impossibile non prescrivere un limite al numero di carat-teri considerati significativi, per cui ogni compilatore distingue gli identificatori inbase a un certo numero di caratteri iniziali tralasciando i restanti. Il numero di caratteri considerati significativi varia comunque da sistema a siste-ma, anche se lo standard ANSI C ha stabilito che sono validi i primi 1024 caratte-ri di un identificatore.

Alfabeto e regole lessicali

IL LINGUAGGIO C 7

Page 8: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

In C un’espressione è una combinazione di operatori e operandi che definisceun’elaborazione e dà origine a un valore. A elaborazione terminata, l’espressionerestituisce 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 glioperandi dell’espressione. La valutazione di un’espressione viene effettuata ese-guendo le operazioni indicate dagli operatori sui loro operandi secondo le regoledi precedenza degli operatori tipiche dell’aritmetica.

Variabili e costantiL’identificatore serve per individuare univocamente un dato. Ricordiamo che èbuona norma utilizzare nomi che consentano di richiamarne immediatamente ilsignificato. In funzione della possibilità di cambiamento del loro valore durantel’elaborazione, i dati si classificano in variabili (il cui valore può variare nel corsodell’elaborazione) e costanti (il cui valore non cambia).Le costanti o valori letterali rappresentano quantità esplicite e come tali nonvanno 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.

Le costanti numeriche intereNel linguaggio C una costante intera si può rappresentare in sistemi di numera-zione diversi. In particolare:

• una costante intera decimale è scritta utilizzando una sequenza di numeridecimali (da 0 a 9 senza virgola); ad esempio, 85 è una costante numerica de-cimale;

• una costante intera ottale è scritta utilizzando una sequenza di numeri ottali(da 0 a 7) preceduta dal carattere 0; ad esempio, 042 rappresenta una costan-te intera ottale;

• una costante intera esadecimale è scritta utilizzando una sequenza di simbo-li esadecimali (0, 1, 2, …, 9, A, B, C, D, E, F) preceduta dalla coppia di caratte-ri 0x oppure 0X; ad esempio: 0XA, 0X18f sono costanti intere esadecimali.Come si evince dall’ultimo esempio (0X18f), le lettere dalla A alla F possonoanche essere scritte in minuscolo.

Le costanti numeriche decimali o in virgola mobileUna costante numerica decimale o in virgola mobile rappresenta un numero rea-le che può essere scritto in forma decimale oppure mediante la notazione scien-tifica. Nella forma decimale le costanti si compongono di due parti, quella interae quella decimale, separate dal punto (si utilizza infatti la notazione anglosassone,che prevede il punto al posto della virgola).I compilatori riconoscono una costante come numerica decimale soltanto se vie-ne rappresentata con la seguente configurazione, che riportiamo secondo le rego-le della BNF:

� [<Segno>][<ParteIntera>][.<ParteDecimale>][E[<Segno>]<Esponente>]

dove la lettera E indica la base 10.

Gli operandi: variabilie costanti

8 IL LINGUAGGIO C

Page 9: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

Ad esempio, le seguenti costanti sono corrette:

� 0 // 0 in virgola mobile� 480E+4 // 480 * 10000 (10 elevato a 4)� .14e–2 // 0.0014� –3.5e+3 // –3500.0

mentre non sono riconosciute dal compilatore le seguenti costanti:

� .58E E25

I caratteriLe 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 specialiAll’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 caratterenon stampabile si desidera produrre (ovviamente utilizzando un carattere stampabile).Un esempio di carattere speciale è l’apice (‘), che spesso sostituisce l’apostrofo: in quest’ultimocaso 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.

Gli operandi: variabili e costanti

IL LINGUAGGIO C 9

Sequenza di escape Descrizione

\n Nuova riga (new line)

\t Tabulazione (tab)

\a Segnale sonoro (alert)

\f Nuova pagina (form feed)

\r Ritorno a capo della stessa riga (ritorno carrello o carriage return)

\v Tabulazione verticale

\b Una battuta indietro (backspace)

\\ Barra rovesciata (backslash)

\’ Apice singolo

\” Doppi apici

\? Punto di domanda

\0 Fine stringa

\<CifraOttale> Numero ottale

\<CifraEsadecimale> Numero esadecimale

Le costanti stringaUna costante stringa (o stringa letterale) è composta da una sequenza di caratteri terminata conla 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 dadodici 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.

Page 10: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

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 dellevariabili 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 dimensionedi 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:

Tipi di dato primitivi e dichiarazione di variabili e costanti

10 IL LINGUAGGIO C

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.

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

Tipo Abbreviazione Descrizione

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 segnosigned 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

Page 11: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

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 siglaC99, 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.

Dichiarazione di variabili e costantiUna variabile è un oggetto a cui è associato:

• un nome (identificatore);• un tipo (insieme dei valori che può assumere);• un’area di memoria (per contenere il valore assunto);• un indirizzo (riferimento all’area di memoria);• un valore (in istanti diversi la variabile può assumere valori differenti, purché siano tutti coerenti con il tipo).

La dichiarazione di una variabile in C avviene in base alla seguente sintassi:

� [<Qualificatore>] <Tipo> {, <Identificatore> [=<ValoreIniziale>]};

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 lavariabile tappo di tipo intero senza segno, alla quale è assegnato il valore iniziale 10, e infine con la quarta vienedichiarata 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.

Tipi di dato primitivi e dichiarazione di variabili e costanti

IL LINGUAGGIO C 11

TIPO BYTE OCCUPATI RANGE

char 1 da –128 a 127

unsigned char 1 da 0 a 255

short int 2 da –32768 a +32767

int 4 da –21474863648 a +21474863647

long int 8 da 10–309 a 10+308

usigned short 2 da 0 a 65535

unsigned int 4 da 0 a 4294967295

unsigned long 8 notazione IEEE standard

float 32 notazione IEEE standard

double 64 notazione IEEE standard

long double 128 notazione IEEE standard

Il classico range dei singoli tipi è riportato nella seguente tabella:

Page 12: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

Un operatore è un simbolo che “opera” su una o più espressioni, producendo unvalore che può essere assegnato a una variabile. Gli operatori in programmazione permettono di ottenere un determinato valoreda 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 quellebasilari (per funzioni più avanzate dobbiamo usare librerie apposite) e hanno unrisultato 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 conun singolo carattere, altri con due caratteri senza spazi separatori. Se non è espli-citamente evidenziato altrimenti, tutti gli operatori operano su tipi primitivi.

Gli operatori che andremo ad analizzare si dividono in:

• operatori di assegnamento che consentono di assegnare un valore alle varia-bili;

• operatori aritmetici che comprendono somma, sottrazione, moltiplicazione,divisione intera e divisione con modulo;

• operatori di confronto che permettono di verificare determinate condizioni,come ad esempio l’uguaglianza o la disuguaglianza;

• operatori logici da utilizzare con le istruzioni condizionali e iterative; • operatori sui bit; • operatori speciali.

L’operatore di assegnamentoSappiamo che il C è un linguaggio profondamente basato sul paradigma impera-tivo e questo significa che un programma C è fondamentalmente una sequenzadi assegnamenti di valori a variabili.L’operatore di assegnamento è denotato dal simbolo = (segno di uguale) e vieneapplicato 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 questocaso 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 =).

L’operatore di assegnamento

12 IL LINGUAGGIO C

Page 13: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

Una variabile può apparire sia a destra che a sinistra di un assegnamento: se sitrova a destra produce il valore contenuto nella variabile, se invece si trova a sini-stra denota la locazione di memoria a cui riferisce. Poiché un identificatore di va-riabile può trovarsi contemporaneamente su entrambi i lati di un assegnamento,è necessario disporre di una semantica non ambigua: come in qualsiasi linguag-gio imperativo (Pascal, Basic e così via), la semantica dell’assegnamento imponeche prima si valuti la parte destra e poi si esegua l’assegnamento del valore pro-dotto all’operando di sinistra.Ad esempio, supponiamo di avere la variabile A con valore 6; con l’istruzione:

� 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 unvalore (il valore dell’espressione x = 3*a è 18), che può venire usato in un’altraassegnazione. Ad esempio, l’istruzione:

� y = (x = 3*a);

contiene un’assegnazione multipla: dapprima viene assegnato il valore 3*a allavariabile x e poi si assegna il risultato ottenuto alla variabile y. Con l’istruzione:

� y = x;

il valore di x viene “copiato” in y: le due variabili rimangono completamente in-dipendenti, cioè la modifica di una delle due non influenza l’altra. Ciò è vero solose x e y sono variabili di tipo primitivo. Il comportamento di questo operatore nelcaso di operandi non primitivi verrà esaminato più avanti.Occorre prestare attenzione: un’assegnazione multipla non può essere utilizzatacome una inizializzazione in una dichiarazione. Ad esempio, l’istruzione:

� int k = h = 33;

è errata perché le inizializzazioni non sono assegnazioni; sono simili, ma il com-pilatore le tratta in maniera differente. La maniera corretta di procedere in questocaso è:

� int k = 33, h = 33;

L’assegnazione di valori a una variabile segue specifiche regole in funzione deltipo di dato associato alla variabile in questione. In tal senso occorre tener presen-te che:

• le variabili intere (int) si assegnano utilizzando un numero senza parte decimale;• le variabili reali (float, double) si assegnano utilizzando per la virgola la notazio-

ne inglese, cioè quella in cui si usa un punto (e non una virgola) per dividerela parte intera da quelle frazionaria;

• le variabili carattere (char) si assegnano racchiudendo il carattere tra due apici;• le variabili stringa (una stringa è una concatenazione di caratteri) si assegnano

racchiudendo la stringa tra virgolette.

Riportiamo un esempio riassuntivo di ognuna delle precedenti assegnazioni:

� int b =20; � char carattere = ‘b’, lettera = ‘m’;� float tappo = 10.2; � char frase[20] = “Ciao a tutti”;

L’operatore di assegnamento

IL LINGUAGGIO C 13

Page 14: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

Gli operatori aritmeticiGli operatori aritmetici si dividono in:

1. operatori unari, che possono essere postfissi e prefissi:

� <Operando> <Operatore> (postfissi)� <Operatore> <Operando> (prefissi)

2. operatori binari, che hanno la forma:

� <Operando1> <Operatore> <Operando2>

Gli operatori unari aritmetici si applicano a un solo operando e ne modificano ilvalore. Si distinguono i seguenti:

• incremento: ++Ad esempio:

� p++; /* equivale a p = p+1 */

• Decremento: ––Ad esempio:

� p–– /* equivale a p = p–1 */

Gli operatori unari aritmetici possono essere posti prima dell’operando (prefissi) odopo 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’operatorepostfisso 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++ */

si ottiene y = 10 e x = 11. Invece con:

� 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.

Gli operatori binari aritmetici si applicano a due operandi e non ne cambiano ilvalore, ma memorizzano il risultato. In C si utilizzano gli operatori binari riporta-ti nella tabella all’inizio di pagina seguente.

Operatori aritmetici,di confronto e logici

14 IL LINGUAGGIO C

Page 15: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

L’operatore di assegnamento può anche essere compattato, cioè abbinato a unoperatore aritmetico. In genere le espressioni del tipo:

� <NomeVariabile> = <NomeVariabile> <Operatore> <Espressione>

possono essere scritte nella seguente forma abbreviata:

� <NomeVariabile> <Operatore> = <Espressione>

Operatori aritmetici, di confronto e logici

IL LINGUAGGIO C 15

X Y X && Y X || Y !X

false false false false true

false true false true true

true false false true false

true true true true false

Operatore Simbolo Risultato

Addizione + Addiziona due operandi o concatena due stringhe

Sottrazione – Sottrae il secondo operando dal primo

Moltiplicazione * Moltiplica i due operandi

Divisione / Divide il primo operando per il secondo. L’operatore di divisione, applicato a variabili di tipointero produce un risultato troncato della parte decimale

Resto (modulo) % Fornisce il resto della divisione tra due operandi interi. Non è possibile utilizzare l’operatore di calcolo del modulo quando gli operandi sono in virgola mobile. Se si divide il modulo per zero, si avrà un’eccezione: se l’operazione eccede il limite inferiore (underflow) il risultato sarà zero, se eccede il limite superiore (overflow) si avrà un’approssimazione

Scrittura compatta Scrittura equivalente Esempio

x += y x = x + y totale += 52; /* equivale a totale = totale + 52 */

x –= y x = x – y totale –= 40; /* equivale a totale = totale – 40 */

x *= y x = x * y totale *= 10; /* equivale a totale = totale * 10 */

x /= y x = x / y totale /= 2; /* equivale a totale = totale / 2 */

x %= y x = x % y totale %= 2; /* equivale a totale = totale % 2 */

Gli operatori di confronto (relazionali)Gli operatori di confronto richiedono operandi di tipo primitivo e producono sem-pre un risultato booleano. Sono i seguenti:

> maggiore >= maggiore o uguale == uguale< minore <= minore o uguale != diverso

Gli operatori di confronto restituiscono il valore logico true se la relazione è veri-ficata, altrimenti restituiscono il valore false.

Gli operatori logiciGli operatori logici richiedono come operandi delle espressioni booleane e produ-cono un risultato booleano. Sono i seguenti:

|| OR && AND ! NOT

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-stro. Ad esempio:

� (3>1) || (x>7) non viene valutato

Le tabelle di verità degli operatori logici sono riportate a lato.

Page 16: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

16 IL LINGUAGGIO C

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 videola frase Ciao mondo!:

� #include <stdio.h>� main( )� {� /* Questo programma scrive la frase Ciao mondo! sul video */� printf(“Ciao mondo!”); � system(“PAUSE”); � }

Il programma, dopo essere stato digitato, compilato ed eseguito, visualizza sul vi-deo quanto segue:

Diciamo subito che l’istruzione:

� system (“PAUSE”);

fa restare il computer “in attesa” (è proprio questa istruzione che fa apparire lafrase Premere un tasto per continuare). In altri termini, permette di mantenere ilprogramma aperto fino a quando l’utente non preme un tasto qualsiasi per chiu-derlo. Consente, pertanto, la visualizzazione del risultato evitando la chiusura im-mediata della finestra al termine dell’esecuzione.

L’istruzione system (“PAUSE”); funziona in ambiente Windows. Alcuni compila-tori C richiedono l’inclusione della libreria stdlib.h per poterla utilizzare.stdlib.h è il file header che dichiara funzioni e costanti di utilità generale: allo-cazione della memoria, controllo dei processi, conversione tra tipi e così via.

Il C è un linguaggio compilato. Come sappiamo, i compilatori sono programmiche accettano in ingresso un programma scritto in linguaggio di alto livello (dettoprogramma sorgente) e lo traducono interamente in un programma in linguag-gio macchina (detto programma oggetto): a traduzione ultimata, il programmapotrà essere eseguito. Lo scopo di questo processo è quindi di tradurre il program-ma originale (codice sorgente) in uno semanticamente equivalente, ma eseguibi-le su una determinata macchina.A differenza di altri linguaggi, la compilazione in C prevede una prima fase dipreelaborazione, detta precompilazione, svolta da un apposito modulo denomi-nato preprocessore.

Il processo di creazione e compilazione di un progetto C dipende strettamentedal tipo di computer e di sistema operativo che si utilizza. Possiamo compila-re ed eseguire programmi con il C in qualsiasi piattaforma, ma per ognuna diessa (Linux, Windows e così via) occorrerà scegliere un opportuno ambiente disviluppo. Per poter utilizzare sia il linguaggio C sia il linguaggio C++ si può, tral’altro, usare l’ambiente di sviluppo integrato (IDE – Integrated DevelopmentEnvironment) Visual C++ (che fa parte della suite Microsoft Visual Studio) op-pure Dev-c++, liberamente scaricabile da Internet, o, ancora, utilizzare l’am-biente testuale DOS utilizzando appositi comandi per compilare, linkare edeseguire i programmi digitandoli nella finestra del “Prompt dei comandi”.

Page 17: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

IL LINGUAGGIO C 17

Le direttive al preprocessore

Il preprocessore è un programma richiamato automaticamente durante la pri-ma fase della compilazione, che esamina ed effettua un’elaborazione prelimi-nare del sorgente. Il preprocessore (o precompilatore), seguendo alcune diretti-ve scritte dal programmatore, modifica il file sorgente effettuando sostituzionidi alcune parti di codice (preprocessing). Il file sorgente così modificato vienesuccessivamente elaborato dal compilatore vero e proprio.

Lo scopo del preprocessore è quello di rendere un programma sorgente più sem-plice da modificare e da adattare a diversi ambienti operativi. Normalmente ilpreprocessore è incluso nel compilatore del linguaggio, oppure è richiamato inmodo assolutamente trasparente al programmatore. In fase di preelaborazionenon viene eseguita alcuna azione di traduzione del codice, viene soltanto effettua-ta una preparazione del programma sorgente per la successiva compilazione. Le istruzioni di dichiarazione per il preprocessore vengono chiamate dichiarativedi precompilazione o direttive al preprocessore e iniziano con il carattere # se-guito dalla parola chiave (if, elif, else, endif, define, undef, ifdef, ifndef, include, line,error, pragma) e dalla dichiarazione della direttiva. Le direttive al preprocessorenon terminano con il punto e virgola, vengono solitamente inserite in testa alprogramma (ma possono trovarsi anche altrove, tra due funzioni, all’interno deglialtri sottoprogrammi o del main) e vengono valutate in fase di compilazione, dovevengono sostituite con codice C appropriato.

Il simbolo # viene chiamato “pound” negli Stati Uniti, “hash” al di fuori degliStati Uniti e “cancelletto” in Italia. Verosimilmente il termine hash deriva da“hatch” ossia “portellone”, “cancello”, porta composta da sbarre incrociatecosì 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 (ossiail 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 inclusoall’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 delsorgente 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”

indicano al compilatore di includere e compilare insieme al programma il filestdio.h che contiene i prototipi delle funzioni standard di input/output (I/O) del C,richiamabili poi da un qualsiasi punto del programma. Se si racchiude la direttivatra parentesi angolari (< >), il file verrà cercato nelle apposite cartelle definitedal compilatore, mentre se la si racchiude tra i doppi apici (“ “), il file verrà dap-prima ricercato nella cartella corrente. Quest’ultima soluzione viene adottataquando si scrivono funzioni appositamente sviluppate per realizzare un program-ma e le si vuole racchiudere tutte in un apposito file.

Page 18: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

18 IL LINGUAGGIO C

Dichiarazione delle costantiIn 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 duetipi 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 diquanto 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:

� const {, <Tipo> <NOMECOSTANTE> = <ValoreIniziale>};

Ad esempio:

� const float PGRECO = 3.14;� const char C = ‘a’;� const int POSTI = 100;� const char[20] ERRORE = “Rilevato errore!”;

Le costanti simboliche di questo tipo sono sostanzialmente delle variabili per lequali il compilatore non concede la modifica. Per una questione di stile, utilizze-remo nomi interamente in maiuscolo per riferirci alle costanti.Se si definisce una costante tramite const, il compilatore farà sì che in fase di ese-cuzione vi sia una locazione di memoria relativa alla costante, in cui sarà presen-te il valore associato alla stessa.La definizione di costante tramite la direttiva #define ha la seguente forma sintat-tica:

� #define <Identificatore> <TestoSostitutivo>

Dopo la direttiva #define si indicherà l’identificatore della costante, che prende ilnome di costante palese, e il relativo valore. Come tutte le direttive al precompi-latore, anche #define non deve terminare con il punto e virgola. Riprendiamo leprecedenti dichiarazioni fatte con il qualificatore const e riproponiamole con la di-rettiva #define:

� #define PGRECO 3.14� #define C ‘a’� #define POSTI 100� #define ERRORE “Rilevato errore”

Costanti e tipi di datodefiniti dall’utente

Page 19: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

IL LINGUAGGIO C 19

Se si definisce una costante tramite la direttiva #define, il compilatore sostituirà atutte le occorrenze dell’identificatore il valore associato; in questo modo non visarà alcuna locazione di memoria associata alla costante e il valore sarà inseritodirettamente all’interno del codice. La direttiva #define può essere utilizzata anche per scopi che esulano dalla dichia-razione di costanti il cui valore sarà oggetto di calcolo all’interno del programma.Prendiamo in esame le due seguenti dichiarazioni:

� #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 beginper 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.

Tipi definiti dall’utenteIl linguaggio C offre la possibilità di assegnare un alias (soprannome) a un qual-siasi tipo primitivo oppure derivato (ossia quelli introdotti dall’utente e derivatidai tipi fondamentali, che esamineremo più avanti), il che contribuisce a rendereil codice più portabile, più leggibile e a evitare espressioni altrimenti complesse.Tale assegnazione si effettua utilizzando la clausola typedef. Con essa non si de-finisce un nuovo tipo, ma si introduce un nome che corrisponde a un tipo defini-to. La sintassi è la seguente:

� typedef <NomeTipo> <NuovoNomeTipo>;

A titolo di esempio consideriamo la seguente dichiarazione:

� typedef float tiporeale;� tiporeale variabile;

che rinomina il tipo primitivo float con l’alias tiporeale.Questa clausola può essere molto utile in determinate situazioni. Prendiamo inesame l’assenza del tipo booleano. Servendoci di typedef possiamo ovviare all’in-conveniente. Ad esempio, con la dichiarazione:

� typedef int boolean;

è possibile dichiarare variabili di tipo boolean che possono assumere tutti i valoriinteri, 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;

Considerato che in moltissimi programmi vi è l’esigenza di evidenziare che unavariabile è utilizzata esclusivamente per memorizzare un valore booleano, si pos-sono premettere definizioni analoghe alle seguenti che ci permettono di definireproprio le costanti TRUE e FALSE:

� #define TRUE 1� #define FALSE 0� typedef int BOOL;

Costanti e tipi di dato definiti dall’utente

Page 20: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

20 IL LINGUAGGIO C

Il programma principaleDopo le direttive al precompilatore, il nostro programma che scrive sul video lafrase 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 unprogramma C: l’esecuzione di un programma, infatti, inizia dalla prima istruzio-ne del main e termina con l’ultima. Eventuali altri sottoprogrammi (ossia altrefunzioni) 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 ( )� {

� }

che può anche essere scritta come segue:

� 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 contengonoistruzioni: sono programmi vuoti; possono produrre un errore di tipo warning daparte del compilatore, ossia degli avvertimenti che non bloccano la creazione del-l’eseguibile, si limitano ad avvertire il programmatore della possibilità che vengaprodotto 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+]

All’interno di un programma in linguaggio C compaiono statement (istruzioni),ossia righe che rappresentano dichiarazioni di oggetti e risorse che saranno usa-te nel programma, e righe che racchiudono le istruzioni del programma che go-vernano l’elaborazione.

Il main e i commenti

Page 21: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

IL LINGUAGGIO C 21

Gli statement vengono costruiti utilizzando l’alfabeto, le parole chiave e le regolelessicali del linguaggio.

I commentiRiprendiamo il nostro primo programma realizzato in precedenza. Subito dopo ledirettive al precompilatore è presente la frase Questo programma scrive la fraseCiao mondo sul video: è un commento.In un programma C, come in qualsiasi altro linguaggio, i commenti hanno valoresoltanto per il programmatore e vengono ignorati dal compilatore. Nel linguaggioC è possibile inserire i commenti in due modi diversi.

1. Secondo il puro stile C, ovvero racchiudendoli tra i simboli /* e */, ad esempio:

� /* Questo è un commento in stile C */

Questo metodo, detto commento a blocchi, permette di commentare più li-nee di codice senza dover ripetere a ogni linea i simboli di commento.

2. Secondo lo stile proprio del C++ (se il compilatore è conforme a standard piùrecenti, come il C99), ovvero facendoli precedere dal simbolo //. In questomodo il commento si estende solo fino al termine della linea. Ad esempio:

� // Questo è un commento in stile C++

Nel primo caso è considerato commento tutto ciò che è racchiuso tra /* e */; ilcommento, quindi, si può anche trovare in mezzo al codice. Analizziamo il se-guente esempio:

� main( )� {� int x = 10; /* Questo è un commento diviso� su tre righe.� Questa è l’ultima riga di commento */� x = /* Questo commento è valido */ = 5;� }

Nel secondo caso, proprio del C++, è invece considerato commento tutto ciò chesegue // sino alla fine della linea. Ne consegue che non è possibile inserire uncommento di questo tipo in mezzo al codice, o dividerlo su più righe (a meno cheanche 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 //� }

Diversi ambienti di sviluppo evidenziano i commenti in uno specifico colore perpermettere al programmatore di distinguere meglio tra il codice e i commentistessi.

Il main e i commenti

Page 22: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

22 IL LINGUAGGIO C

La gestionedell’output

Invece della variabile a è anche possibile scrivere un’espressione, ad esempio:

� 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.

Riprendiamo il programma di esempio con il quale abbiamo visualizzato sul vi-deo la frase Ciao mondo!. All’interno del main del nostro programma è presentela 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 dispositivodi uscita standard, stdout) tutti i caratteri che incontra. È proprio il caso del no-stro programma in cui è presente l’istruzione

� printf(“Ciao mondo!”);

che scrive sul video la frase racchiusa tra virgolette.Tuttavia la funzione printf, oltre a stampare semplici stringhe di testo, può ancheessere utilizzata per stampare il contenuto di variabili. In questo caso, la funzioneprintf riceve sempre come primo argomento tra le parentesi tonde una stringa diformato (cioè una sequenza di caratteri delimitata dalle virgolette), ma dopo diessa si dovrà inserire un numero qualsiasi di altri argomenti, in base alla necessi-tà. La forma sintattica più generale è, quindi, la seguente:

� printf(<StringaDiFormato> , <Espressione>)

All’interno della <StringaDiFormato> dovranno essere presenti appositi segna-posto per ciascuna espressione successivamente elencata, in modo da specifica-re in quale punto della stringa deve essere posizionato il valore dell’espressione edi che tipo di valore si tratta.Tali segnaposto prendono il nome di specificatori di formato e sono introdotti dalsimbolo %. Quando si è in presenza di specificatori di formato, il funzionamentoè il seguente: la printf scorre la stringa di formato da sinistra verso destra e scrivea video tutti i caratteri che incontra; quando trova un carattere %, identifica il tipodi dato che deve essere stampato mediante il carattere (o i caratteri) che lo seguo-no. L’elemento % indica che in quel punto è necessario stampare il valore diun’espressione che è di un tipo ben preciso. La funzione printf utilizza tale infor-mazione per convertire e formattare il valore ottenuto dall’espressione che seguela stringa di formato. Una volta valutato, formattato e scritto a video il valore del-l’espressione, la funzione continua nell’analisi della stringa di formato, fino alprossimo % o alla fine della stringa. Facciamo alcuni esempi:

� int a = 20; /* dichiarazione ed inizializzazione */� 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:

Stringa di formato Specificatore di formato

Espressione chesegue la stringa

Page 23: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

IL LINGUAGGIO C 23

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à:

La gestione dell’output

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 lastringa ha un valore reale (ad esempio, una variabile dichiarata di tipo float) e si utilizza lospecificatore %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 talemotivo, 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. Tuttociò è 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 eil 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”);� }

Compilando ed eseguendo il programma otterremo il risultato riportato nella figura, che ècorretto ma presenta due inconvenienti:

1. la è accentata non viene visualizzata correttamente;2. dopo aver visualizzato il valore della variabile viene visualizzato il messaggio Premere un

tasto per continuare… sulla stessa riga rendendo il tutto non proprio leggibile.

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 delloro 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 lestesse 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). Adesempio, la seguente istruzione invia l’output alla stampante:

� fprintf(stdprn, “Somma totale = %d “, Tot);

Page 24: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

24 IL LINGUAGGIO C

Gli specificatori di formatoIn precedenza abbiamo esaminato gli specificatori %d e %f per visualizzare ri-spettivamente il risultato di espressioni intere e reali. Gli specificatori di formatoprevisti dall’ANSI C sono i seguenti:

Gestione dell’output e sequenze di escape

Tra il simbolo % e lo specificatore di formato è anche possibile inserire altre op-zioni di formato:• un numero intero specifica l’ampiezza del campo, ossia imposta il numero di

posizioni nelle quali il valore deve essere visualizzato;• uno zero (0) indica che le posizioni a sinistra, occupate dal numero da visua-

lizzare, devono essere riempite con zeri;• il segno meno (–) è utilizzato per eseguire la giustificazione a sinistra del dato;• due numeri separati dal punto servono per indicare rispettivamente l’ampiez-

za del campo e il numero di cifre decimali.Consideriamo le seguenti dichiarazioni di variabili e analizziamo le nuove opzioni:

� int a = 2;� char x = ‘s’; /* l’assegnazione di un carattere a una variabile char avviene� racchiudendo il carattere tra due singoli apici */� float y = 3.14; /* la notazione usata per rappresentare la virgola è quella � inglese, cioè quella in cui si usa un punto (e non una � virgola) per dividere la parte intera da quella frazionaria */� char nome[10] = “Piero”; /* per memorizzare le stringhe (che tratteremo� detttagliatamente in seguito, si usa il tipo char� indicando il nome della variabile seguito dal� numero massimo di caratteri previsto per la � stringa, racchiuso tra parentesi quadre e il� deve essere racchiuso tra virgolette*/

Specificatore di formato Espressione A video

%c char carattere singolo%d (%i) int intero decimale con segno%e (%E) float o double formato esponenziale%f float o double reale con segno%g (%G) float o double utilizza %f o %e in base alle esigenze%o int valore in base 8 senza segno%p pointer valore di una variabile puntatore%s array of char stringa (sequenza) di caratteri%u int intero senza segno%x (%X) int valore in base 16 senza segno

Istruzione Output

printf(“%c”, x); sprintf(“%d”, a); 2printf(“%20d”, a); 2printf((%020d”, a); 00000000000000000002printf(“%f”, y); 3.140000printf(“%20.2f”, y); 3.14printf(“%20d %10.2f”, a, y); 2 3.14 printf(“%-20d %-10.2f”, a, y); 2 3.14printf(“%s”, nome); Pieroprintf(“%10s”, nome); Pieroprintf(“%-10s”, nome); Pieroprintf(“%-20s 10.2f”, nome, y); Piero 3.14

Page 25: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

IL LINGUAGGIO C 25

Poiché il simbolo % è utilizzato per introdurre uno specificatore di formato, pervisualizzare questo simbolo (ad esempio, per visualizzare una percentuale) oc-corre riportarlo due volte. Ad esempio, per visualizzare a video la frase Il tassodi sconto è del 10% scriveremo:

� printf(“Il tasso di sconto e\’ del 10%%”);

Le sequenze di escapeIn precedenza abbiamo visto che alcuni caratteri non sono stati visualizzati cor-rettamente a video (ad esempio la è accentata) e che non abbiamo avuto modo discrivere frasi su righe diverse. A risolvere tali problemi pensano alcuni codici dicontrollo detti tecnicamente sequenze di escape, che non stampano caratteri vi-sibili ma contribuiscono a formattare ciò che viene stampato. Le sequenze diescape iniziano con il carattere backslash (\) e sono interpretate come un singolocarattere: Presentiamo subito degli esempi. Il seguente programma:

� #include <stdio.h>

� main()� {� printf(“prima riga ...\n”);� printf(“seconda riga ...\n”); � system(“PAUSE”);� }

Visualizza quanto è riportato nella figura.Vediamo un altro esempio:

� #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”);� }

Gestione dell’output e sequenze di escape

Sequenza di escape Significato Descrizione

\b backspace Cancella (una battuta indietro)\f Form feed avanzamento carta\n New line nuova linea\r Carriage return a capo (senza una nuova linea)\t Tab tabulatore\’ Single quote Apice\” Double quote Doppi apici\0 End of string Fine stringa\\ Backslash Barra contraria\? Question mark Punto di domanda\a Bell Segnalazione acustica

Page 26: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

26 IL LINGUAGGIO C

ESEMPIGestione dell’output e sequenze di escape

Esempio 1Realizzare un programma che visualizzi i limiti di tutti i tipi interi; questi limitisono 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 2Realizzare un programma che visualizzi sul video la frase ciao mondo servendosidi 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 3Realizzare un programma che visualizzi sul video la tavola pitagorica riportatanella 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

Page 27: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

IL LINGUAGGIO C 27

ESEMPI

Gestione dell’output e sequenze di escape

� #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 4I seguenti frammenti di codice chiariscono la funzione degli operatori unari ++e ––.

� int i;� i = 15;� printf(“%d, %d, %d”, ++i, i++, i);...

Il risultato che si ottiene è:

� 16, 16, 17

Infatti, l’espressione ++i incrementa i prima di stamparlo a video (quindi i è 16);la successiva i++ viene valutata al valore corrente di i (16) che verrà poi incre-mentato (a 17); infine, l’espressione i è il valore di i dopo il postincremento (17).

� #include <stdio.h>� #include <stdlib.h>� main()� { � int i, n;� i=4;� n=i;� printf(“Valore di n all’inizio: %d\n”,n);� n=i++;� printf(“Valore di n dopo i++: %d\n”,n);� n=++i;� printf(“Valore di n dopo un ulteriore ++i: %d\n”,n);� n+=i*(n–4);� printf(“Valore finale di n: %d\n”,n);� system(“PAUSE”);� }

La variabile n è inizialmente uguale a i, ovvero vale 4. Poi, n=i++; ma siccomel’operatore ++ segue il nome della variabile, prima il valore di i viene memorizza-to in n, poi il valore di i viene incrementato. Ecco così che n vale ancora 4, men-tre i vale 5. Successivamente n=++i; in questo caso l’operatore ++ precede ilnome della variabile, quindi prima il valore di i viene incrementato (era 4, era sta-to incrementato a 5 dall’istruzione i++, ora diventa 6) e poi il risultato viene me-morizzato in n (che, quindi, vale 6). Infine, l’espressione i*(n–4) ovvero 6 * (6 – 4)= 12 viene sommata al precedente valore di n (per via dell’operatore +=), cheera 6, quindi 12 + 6 = 18.

Page 28: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

28 IL LINGUAGGIO C

Le istruzioni di inputIn 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 unalettura 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 vistacome 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 getcLa 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é nerestituisce immediatamente il valore. Il carattere digitato non viene visualizzatosullo schermo (la funzione analoga che però visualizza il carattere digitato sulloschermo è getche()).

� #include <stdio.h> � int c; � main() � { � c = getc(stdin); � printf(“\n%d”, c);� system(“PAUSE”);� }

Nell’esempio viene letto un carattere dallo standard input (stdin) e memorizzatonella variabile c come un intero. Ad esempio, se digitiamo la lettera A, nella varia-bile c viene memorizzato il numero 65, ossia il suo codice ASCII. Questa funzio-ne è molto utile per leggere singoli caratteri.

La funzione getcharLa funzione getchar() equivale a getc(stdin) e, di conseguenza, legge un carattereda stdin. Nonostante getchar() sia una funzione prevista dallo standard ANSI, ilsuo comportamento può differire a seconda dell’implementazione del compilato-re. In alcune versioni, infatti, restituisce immediatamente il valore del carattereimmesso da tastiera, in altre, invece, attende fino a quando non viene premuto iltasto Invio.

� #include <stdio.h> � int c; � main() � { � c = getchar(); � printf(“\n%d”, c);� system(“PAUSE”);� }

Page 29: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

IL LINGUAGGIO C 29

Le istruzioni di input

La funzione scanfLa 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>)

dove, esattamente come per la funzione printf, la <StringaDiFormato> rappre-senta lo specificatore di formato ed è introdotta dal simbolo %, mentre<Variabile> rappresenta il nome della variabile all’interno della quale dovrà es-sere memorizzato il dato proveniente dalla tastiera. Ad esempio, l’istruzione:

� scanf(“%d”, &a);

legge un valore intero (indicato dallo specificatore di formato %d) e lo memorizzanella variabile a. Notiamo come davanti al nome della variabile è stato posto il sim-bolo & (ampersand o “e commerciale”): esso indica che il valore acquisito dalla ta-stiera deve essere registrato all’indirizzo della variabile a in memoria centrale.Quando il programma durante l’esecuzione raggiunge l’istruzione scanf, si ferma elascia all’utente la possibilità di digitare qualcosa alla tastiera. Il programma nonprosegue fino a che l’utente non ha inserito qualcosa e ha premuto poi il tasto Invio.Una volta acquisito quanto inserito dall’utente, il valore viene memorizzato nella va-riabile a e poi il programma procede con le istruzioni successive. In questo modo, aogni esecuzione l’utente può inserire valori diversi, producendo risultati diversi.Il programma seguente legge un numero da tastiera e lo ristampa a video; abbia-mo utilizzato gli specificatori di formato per scanf() in modo analogo a quello de-scritto per la funzione printf().

� #include <stdio.h>� int i;� main()� {� scanf(“%d \n”, &i);� printf(“%d \n”, i);� system(“PAUSE”);� }

La funzione scanf elabora la stringa di controllo da sinistra a destra e a ogni segna-posto cerca di interpretare i caratteri ricevuti in ingresso in relazione all’identifica-tore (gli identificatori sono gli stessi della funzione printf). Se vengono specificati piùvalori nella stringa di controllo, si presuppone che questi vengano immessi da ta-stiera separandoli con spazi, Invio o il tabulatore. Questo significa che per inseriretre interi è possibile digitare i dati in una delle due forme seguenti:

3 4 5oppure:

345

Per esempio, l’istruzione:

� scanf(“%d %d”,&i,&j);

acquisisce due numeri interi e li memorizza rispettivamente nelle variabili i e j. Idue valori possono essere inseriti separandoli con uno spazio (o un numero qual-sivoglia di spazi), oppure andando a capo ogni volta. Unica eccezione è il caso di%c: viene acquisito un carattere, qualunque esso sia; quindi qualsiasi tasto vengapremuto sulla tastiera, quello è l’unico carattere acquisito.

Page 30: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

30 IL LINGUAGGIO C

Il bloccoIl linguaggio C utilizza quattro istruzioni condizionali principali: if, if..else, ? eswitch. 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 singolariga di codice o una serie di righe che costituiscono un blocco di codice. Quandoall’istruzione condizionale è associata una sola riga di codice, non è necessarioracchiudere l’istruzione da eseguire fra parentesi graffe. Se invece sono associatepiù righe di codice, le stesse (ossia il blocco) dovranno essere racchiuse fra paren-tesi graffe. Volendo, è comunque possibile utilizzare tali parentesi anche quandol’istruzione da eseguire è soltanto una: il compilatore non segnalerà alcun errore.

L’istruzione if..elseLa 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 dellaprogrammazione strutturata, la struttura alternativa può presentarsi con o senzail 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� [{]� <Istruzione/i da eseguire se la condizione è falsa>;� [}]

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>)� [{]� <Istruzione/i da eseguire se la Condizione1 è falsa e la Condizione2 è vera>;� [}]� else if (<Condizione3>)� [{]� <Istruzione/i da eseguire se la Condizione1 è la Condizione2 sono false>;� [}]� ...

Le istruzioni condizionali (o di selezione)

Page 31: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

IL LINGUAGGIO C 31

A titolo di esempio risolviamo un semplice problema: dato in input un numero N,stabilire se è divisibile per 3. Il codice C è il seguente:

� #include <stdio.h>� int n;� main( )� {� printf(“Inserire un numero “);� scanf(“%d”,&n);� if ((n % 3) == 0)� printf(“Il numero inserito e’ divisibile per 3\n”); � else� printf(“Il numero inserito non e’ divisibile per 3\n”);� system(“PAUSE”);� }

All’interno di un’istruzione if è possibile inserire qualsiasi tipo di istruzione, an-che una nuova istruzione if: si parla, in tal caso, di if annidate o nidificate.Quando si utilizzano più istruzioni if annidate, occorre sempre essere sicuri del-l’azione else che verrà associata a una determinata if. Proviamo a capire che cosaaccade nel seguente esempio:

� if (voto < 10)� if (voto < 5) printf( “Sei totalmente insufficiente! \n”);� else printf(“ Forza! Ricomincia a studiare! \n”);

L’assenza di indentazione e la presenza di più istruzioni su una stessa riga nonrendono il codice ben leggibile. In queste circostanze è facile che il programmato-re poco esperto possa avere difficoltà a comprendere il flusso di esecuzione, noncapendo a quale istruzione if fa riferimento l’istruzione else finale. Il principio base, in queste situazioni, stabilisce che un’istruzione else è sempre ri-ferita all’ultima istruzione if presente nel codice. È utile non confondersi troppo leidee con questo principio, poiché ci si potrebbe imbattere in casi in cui compaio-no tante istruzioni if..else annidate, con la conseguenza che la lettura del codicesarebbe davvero difficile per chiunque. Per una buona leggibilità del codice è per-ciò buona norma far sempre uso di una corretta indentazione e, ove necessario,delle parentesi graffe. L’esempio precedente, indentato e corredato di parentesi,diviene:

� if (voto < 10)� {� 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’istruzioneelse è riferita all’istruzione if(voto < 5).

Le istruzioni condizionali (o di selezione)

Page 32: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

32 IL LINGUAGGIO C

ESEMPILe istruzioni condizionali(o di selezione)

Considerata la semplicità degli esercizi proposti, riportiamo solo la codifica in Cevitando l’analisi del problema.

Dati in input tre voti, fornire in output la media in decimi o trentesimiin 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”);� }

Attenzione: nell’istruzione scanf interna al costrutto if abbiamo inserito la se-quenza di escape \n:

� 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 caratterivengono letti dal buffer e portati nella variabile che deve essere letta. Quando si inserisce da tastiera il terzo numero (quello che deve essere inseritonella variabile c), si premono i tasti corrispondenti alle cifre (ad esempio 27), epoi 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 assegnatialla 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 scanfa leggere esplicitamente il carattere ‘invio’, che nel linguaggio C è rappresentatocon ‘\n’. Quindi il codice:

� scanf(“\n%c”,&scelta);

legge il carattere invio e lo scarta, poi legge il carattere successivo e lo assegna allavariabile scelta. Completa l’esercizio inserendo al posto dei puntini le istruzioniper calcolare la media e visualizzarla.

Page 33: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

IL LINGUAGGIO C 33

ESEMPI

Dato in input un numero intero positivo che indica la misura delraggio, 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”);� }

� /* Seconda soluzione – if annidati */� #include <stdio.h>� int r;� float circ;� main()� {� printf(“Inserire la misura del raggio “);� scanf(“%d”, &r);� if (r>=0)� {� if (r<=32767)� {� circ= 2*3.14*r;� printf(“Circonferenza e\’ %3.2f\n”, circ); � }� }� else� printf(“Il valore del raggio deve essere positivo”);� system(“PAUSE”);� }

� /* Terza soluzione – if con condizione composta */� #include <stdio.h>� int r;� float circ;� main()� {� printf(“Inserire la misura del raggio “);� scanf(“%d”, &r);� if ((r>=0) && (r<=32767))� {� circ= 2*3.14*r;� printf(“Circonferenza e\’ %3.2f\n”, circ); � }� else� printf(“Il valore del raggio deve essere positivo”);� system(“PAUSE”);� }

Le istruzioni condizionali (o di selezione)

Page 34: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

34 IL LINGUAGGIO C

Nella risoluzione dei problemi capita molto spesso di dover ripetere molte volteuna 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>;

Al solito, <Istruzione> indica un’istruzione singola o una sequenza di istruzioni(un blocco); in quest’ultimo caso va racchiusa tra parentesi graffe. Ciononostante,può essere utile racchiudere tra parentesi <Istruzione> anche se è una sola.La semantica del costrutto while è la seguente: si valuta <Condizione> e, se essarisulta vera (ossia se è diversa da zero) si esegue <Istruzione>, poi si ripete il tut-to; l’istruzione termina quando la valutazione di <Condizione> fornisce il risul-tato false (ossia assume valore uguale a zero).Vediamo subito un semplice esempio che consente di comprendere l’utilizzo delcostrutto while. Il problema che risolviamo è il seguente: dato in input un nume-

ro, calcolare la somma di tutti i suoi predecessori compreso il numero stesso.

� #include <stdio.h>� int num;� int k;� int sommanumeri;� main( )� {� k = 1; � sommanumeri = 0;� printf(“Inserire un numero positivo “);� scanf(“%d”, &num);� while(k <= num)� { /* le parentesi del blocco potevano essere omesse */� sommanumeri += k++;� }� printf(“La somma dei numeri da 1 a %d e\’ %d \n”, num, sommanumeri);� system(“PAUSE”);� }

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;

Le istruzioni iterative:i costrutti whilee do...while

Page 35: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

IL LINGUAGGIO C 35

� 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”);

� }

Esaminiamo ora il costrutto do..while; la sua sintassi è:

� do� <Istruzione>;� while(<Condizione>);

Ancora una volta, <Istruzione> indica un’istruzione singola o una sequenza diistruzioni (in tal caso va racchiusa tra parentesi graffe).do..while differisce dall’istruzione while in quanto prima si esegue <Istruzione>e poi si valuta <Condizione>: se questa è vera (true) si riesegue il corpo, altri-menti l’istruzione termina. È evidente che il corpo del ciclo do..while viene sem-pre eseguito almeno una volta.Un classico utilizzo di una simile iterazione (detta iterazione postcondizionale) èquello relativo al controllo di validità dei dati di ingresso. Analizziamo il seguenteprogramma, che continua a richiedere in input un numero fino a quando non siinserisce un valore compreso tra 10 e 20.

� #include <stdio.h>� int n;� main( )� {� do� {� printf(“Inserire un valore intero compreso tra 10 e 20: “);� scanf(“%d”, &n);� } while(n < 10 || n > 20);� printf( “Il numero inserito e\’ %d\n”,n);� system(“PAUSE”);� }

Le istruzioni iterative: i costrutti while e do...while

Page 36: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

36 IL LINGUAGGIO C

ESEMPILe istruzioni iterative: i costrutti while e do...while

Dato in input un numero intero positivo che indica la misura delraggio, fornire in output la misura della circonferenzaRiprendiamo questo problema già analizzato precedentemente e vediamo, ora,come fare per accettare in input soltanto valori che soddisfino il problema (nelnostro caso, solo numeri interi positivi). Dal codice si evince, infatti, che dal ciclowhile si esce solo quando l’utente inserisce un valore valido. È un tipico esempiodi 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”);� }

Vediamo, ora, lo stesso esercizio svolto con l’istruzione do..while:

� #include <stdio.h>� int r;� float circ;� main()� {� do� {� 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”);� } while ((r<0) || (r>32767));� circ= 2*3.14*r;� printf(“Circonferenza è %f”, circ);� system(“PAUSE”);� }

Come si vede, si può sempre passare da un ciclo precondizionale a uno postcon-dizionale. In questo caso il ciclo postcondizionale è utile in quanto si deve eseguirealmeno una volta l’operazione di scanf e si evita l’inizializzazione fittizia (r = –1)

Stampare la tabella di conversione Fahrenheit – CelsiusNella scala Celsius delle temperature il punto di congelamento dell’acqua è a 0gradi Celsius, mentre quello di ebollizione è a 100 gradi Celsius. Nella scalaFahrenheit il punto di congelamento dell’acqua è a 32 gradi Fahrenheit, mentre ilpunto di ebollizione si trova a 212 gradi Fahrenheit, suddividendo così la distan-za fra i due estremi in 180 gradi. L’unità di questa scala, il grado Fahrenheit (°F)

Page 37: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

IL LINGUAGGIO C 37

ESEMPI

Le istruzioni iterative: i costrutti while e do...while

è 5/9 di un grado Celsius. Notiamo che la temperatura di 32 °F corrisponde a0°C. Quindi, un metodo per convertire gradi Celsius in gradi Fahrenheit è quellodi moltiplicare per 9/5 e aggiungere 32, mentre per convertire gradi Fahrenheit ingradi 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”);� }

Calcolare il massimo comune divisore di due numeri applicandol’algoritmo euclideo con un programma in CL’algoritmo originale di Euclide è basato sulle sottrazioni successive. Il procedi-mento risolutivo è il seguente. Dati due numeri naturali a e b, si controlla se b èzero. Se lo è, a è il MCD. Se non lo è, si divide a / b e si assegna a r il resto delladivisione (operazione indicata con “a modulo b” in seguito). Se r = 0 allora si puòterminare affermando che b è il MCD cercato, altrimenti occorre assegnare a = b eb = r e ripetere nuovamente la divisione.

� #include <stdio.h>� int x, y, t;� main()� {� do /* Lettura dati di input con controllo di validità */� {� printf(“Inserisci due interi maggiori di zero:\n”);� scanf(“%d %d”, &x, &y);� } while (x <= 0 || y <= 0);� while (x != y) /* Programma in C con algoritmo di Euclide */� {� if (x < y)� {� t = x;� x = y;� y = t;� }� x = x - y;� }� printf(“Il Massimo comun divisore e\’ %d\n”, x);� system(“PAUSE”);� }

Page 38: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

38 IL LINGUAGGIO C

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, ilciclo for rappresenta una specializzazione del ciclo while; tuttavia, nel linguaggioC 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:

Il costrutto for

� for ([<InizializzazioneContatore>] ; [<Condizione>] ; [<IncrementoContatore>])� <Istruzione>;

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 forsarà eseguito fintanto che la condizione si mantiene vera;

• <IncrementoContatore> è solitamente una istruzione di incremento o didecremento 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 siasempre 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 sommadi 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”);� }

for ( i = 0; i < 10; i = i + 1 ) {

printf(“%d”, i);

}

Inizializzazione Test Modifica

Blocco di istruzioni daeseguire ciclicamente

Page 39: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

IL LINGUAGGIO C 39

Il programma, quando incontra l’istruzione for, assegna il valore 1 alla variabile I(la prima espressione del for), quindi controlla se il valore di I è inferiore a 5 (laseconda espressione): poiché l’espressione risulta vera, vengono eseguite leistruzioni inserite nel corpo del ciclo (l’input del numero e l’aggiornamento dellavariabile Somma). Terminate le istruzioni che compongono il ciclo, si esegue l’ag-giornamento di I così come risulta dalla terza espressione contenuta nel for, siripete il controllo contenuto nella seconda espressione e si continua come primafinché il valore di I non rende falsa la condizione.Questo modo di agire del ciclo for è quello comune a tutti i cicli di questo tipomessi a disposizione dai compilatori dei diversi linguaggi di programmazione. Illinguaggio C offre delle opzioni che espandono abbondantemente le potenzialitàdel ciclo for generalizzandolo in maniera tale da inquadrarlo, come abbiamo det-to, quale caso particolare del ciclo while. Il costrutto for, infatti, rappresental’istruzione iterativa universale poiché, a differenza di quanto accade in altri lin-guaggi di programmazione, consente di implementare sia iterazioni definite, siaindefinite. Il programma per la somma di cinque numeri positivi scritto in prece-denza potrebbe, ad esempio, venire riscritto nel seguente modo, che lo rende piùgenerale e molto più potente:

� #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 solavolta) e, subito dopo, controlla se il valore di numero è diverso da zero: nel caso incui 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 ciclofor 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à delprogramma. Con il ciclo for si utilizza spesso la cosiddetta istruzione nulla. Essa contiene soloil ; e può apparire ovunque è consentita un’istruzione; quando viene eseguita nonsuccede sulla. L’istruzione nulla viene utilizzata nei casi in cui è richiesta almenoun’istruzione, ad esempio nei cicli e nelle istruzioni condizionali.Nel seguente caso, ad esempio, l’istruzione for è utilizzata esclusivamente comeun ciclo di ritardo software e, di conseguenza, non è necessario che venga ese-guita alcuna istruzione:

� ...� for(i=0; i < 500000; i++)� ;� ...

Il costrutto for

Page 40: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

40 IL LINGUAGGIO C

ESEMPIIL costrutto for

Dati in input due interi n > 0 e k > 0, stampare i primi n multipli di k.

� #include <stdio.h>� #include <stdlib.h>� int i, n, k, p;� main()� {� do� {� printf(“Inserisci un numero > 0 ”);� scanf(“%d”,&n);� } while (n <= 0);� do� {� printf(“Inserisci un altro numero > 0 ”);� scanf(“%d”,&k);� } while (k <= 0);� for (i=1; i<=n; i++)� {� p = k*i;� printf(“%d\n”, p);� }� system(“PAUSE”);� }

Dati in input due interi n > 0 e k > 0, stampare il risultato della sommatoria k +k2 +k3 +...+kn..

� #include <stdio.h>� #include <stdlib.h>� int i, n, k, p, s;� main()� {� do� {� printf(“Inserisci un numero > 0 ”);� scanf(“%d”,&n);� } while (n <= 0);� do� {� printf(“Inserisci un altro numero > 0 ”);� scanf(“%d”,&k);� } while (k <= 0);� s = 0;� p = 1;� for (i=1; i<=n; i++)� {� p = p*k;� s = s+p;� }� printf(“%d\n”, s);� system(“PAUSE”);� }

Page 41: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

IL LINGUAGGIO C 41

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”);� }

Dati in input 5 numeri, visualizzare il maggiore tra essi, la loro media e la radice quadrata della somma

� #include <stdio.h>� #include <math.h>� int i, a, max, somma;� float r;� main()� {� max = 0;� for (i=0; i<5; i++)� {� printf (“Inserisci il %d° numero: ”,i);� scanf(“%d”,&a);� if(max < a)� max = a;� somma += a;� }� r = somma / 5;� printf (“Il valore massimo inserito e\’: %d\n”, max);� printf (“La radice quadrata della somma e\’: %.3f\n”,� sqrt(somma));� printf (“La media e\’: %.3f\n”, r);� system(“PAUSE”);� }

Il costrutto for

Page 42: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

TrainingPROVE APERTE PER LA VERIFICA DELLE ABILITÀ

42 IL LINGUAGGIO C

Tra le seguenti istruzioni di input è presente una privadi errori mentre le altre presentano ognuna un errore.Sapresti identificare quella corretta e trovare gli erroripresenti nelle altre?

scanf(“%d, k”);

scanf(%d, k);

scanf(“%d, &k);

Scanf(“%d, &k);

scanf(%d, “k”);

scanf(%”d”, $k);

Il seguente programma C non usa l’istruzione if in ma-niera ottimale; inoltre presenta degli errori e non è scrit-to secondo le regole dell’indentazione. Interpreta il pro-gramma e prova a impostarlo in maniera più efficiente.

� #include <stdio.h>� int k;� main( )� {� printf(“Inserisci un numero ”);� scanf(“%d”, &k);� if(k==5)� printf(“\nNumero = 5 \n”);� k++;� printf(“Il valore di k e\’ %d\n”, k); � printf(“Inserisci un numero “);� scanf(“%d”, &k);� if(k==5)� {� printf(“\nNumero = 5\n”);� k++;� }� printf(“Il valore di k e\’ %d\n”, k); � system(“PAUSE”);� }

Il seguente programma C presenta degli errori e non èscritto secondo le regole dell’indentazione. Interpreta ilprogramma e prova a impostarlo in maniera corretta.

� #include <stdio>� int a;� main� {� printf(“Inserisci un numero ”);� scanf(“%d”, &x);� if (x=3);� printf(“Numero uguale a tre”)� system(PAUSE)� }

3.

2.

f

e

d

c

b

a

1. Il seguente programma C presenta degli errori e non èscritto secondo le regole dell’indentazione. Interpreta ilprogramma e prova a impostarlo in maniera corretta.

� #include <stdio.h>;� int h;

� main( )� {� printf(“Inserisci un numero ”);� scanf(“%d”, &x);� if(h=3);� printf(Numero uguale a tre); � x+;� else� printf(Numero diverso da tre); � system(PAUSA)� }

Enuncia il testo del problema relativo al seguente pro-gramma C:

� #include <stdio.h>� int a, i, t;� float r;

� main()� {� t = 0;� i = 0;� printf (“Numeri da inserire: ”);� scanf(“%d”,&a);� while (a >= 0)� {� i++;� t += a;� r = t/i;� printf (“La media attuale e\’: %.3f\n”, r);� printf (“Inserisci un numero: ”);� scanf(“%d”,&a);� }� printf (“La media finale e\’: %.3f\n”, r);� system(“PAUSE”);� }

Quale accorgimento puoi adottare per evitare dirichiedere in input il dato sia fuori dal ciclo, siaall’interno di esso.

5.

4.

Page 43: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

TrainingPROVE APERTE PER LA VERIFICA DELLE ABILITÀ

IL LINGUAGGIO C 43

Enuncia il testo del problema relativo al seguente pro-gramma C:

� #include <stdio.h>� int a, t;� main()� {� t = 0;� printf (“Inserisci un numero: “);� scanf(“%d”,&a);� while (a >= 0)� {� t += a;� printf(“Somma attuale =: %d\n”, t);� printf (“Inserisci un numero: ”);� scanf(“%d”,&a);� }� printf (“Somma finale =: %d\n”, t);� system(“PAUSE”);� }

Enuncia il testo del problema relativo al seguente pro-gramma C:

� #include <stdio.h>� unsigned int x, y, z;� main()� {� scanf (“%u”, &x);� scanf (“%u”, &y);� scanf (“%u”, &z);� if ((x < y + z) && (y < x + z) && (z < x + y))� {� if (x == y && y == z)� {� printf (“Triangolo equilatero”);� }� else� {� if (x == y || y == z || x == z)� {� printf (“Triangolo isoscele”);� }� else� {� printf (“Triangolo scaleno”);� }� }

7.

6.� }� else� {� printf (“Non è un triangolo”);� }� system(“PAUSE”);� }

Ci sono delle righe che potevano essere omesse?Se sì, quali sono?

Quale valore assume la variabile z alla fine del pro-gramma?

� #include <stdio.h>� char c;� int z;� main( )� {� z=0;� c=‘z’;� for (; c < ‘a’; c++)� z++;� printf(“%d\n”, z);� system(“PAUSE”);� }

Enuncia il testo del problema relativo al seguente pro-gramma C:

� #include <stdlib.h>� #include <stdio.h>� int n, i;� long a, b, c;� main()� {� scanf(“%d”, &n);� a = 1;� b = 1;� printf(“%ld %ld “, a, b);� for (i=2; i<n; i++)� {� c = a+b;� printf(“%ld “, c);� a = b;� b = c;� }� system(“PAUSE”);� }

9.

8.

Page 44: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

44 IL LINGUAGGIO C

Nel linguaggio C la componente principale dei codici è costituita da funzioni. Perpoter 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 presoin considerazione. In altri termini, nel linguaggio C le procedure sono funzioniche restituiscono un void. Possiamo riassumere il processo di costruzione e usodi una funzione nelle seguenti tre fasi.

1. Definizione della funzione, cioè scrittura dell’elenco delle operazioni da essasvolte. La definizione specifica nell’ordine il tipo di valore restituito, il nomescelto dal programmatore (valgono le stesse regole viste per l’assegnazione deinomi alle variabili) e, infine, l’elenco dei parametri. All’interno del corpo dellafunzione vengono inserite le dichiarazioni delle variabili della funzione e leistruzioni. La sintassi generale è quindi la seguente:

� [<TipoRestituito>] <NomeFunzione>([<ElencoParametri>])� {� <Istruzioni>� [return [(]<Risultato>[)]]� }

Come si evince dalla sintassi, la specifica del <TipoRestituito> è opzionale: siassume, in sua assenza (per default), che il tipo restituito sia int, sebbene, permotivi di comprensibilità, sia sempre opportuno dichiarare esplicitamente iltipo. Nel caso in cui si desideri implementare una procedura occorre specifica-re come <TipoRestituito> il tipo void. Anche <ElencoParametri>, che tratteremo più avanti, è opzionale: in sua as-senza occorre comunque far seguire il nome della funzione da una coppia di pa-rentesi tonde ( ), oppure inserire la parola chiave void all’interno delle parentesitonde proprio per specificare che nessun parametro viene passato alla funzione.Ad esempio, void Funz() è equivalente a void Funz(void). Ricordiamo che Lo stan-dard C stabilisce che una funzione che non richiede parametri deve utilizzarel’identificatore void in modo esplicito, all’interno delle parentesi.Nel caso in cui <ElencoParametri> sia presente, cioè se la funzione riceve pa-rametri, è necessario specificare il tipo, seguito dal nome del parametro, pro-prio come abbiamo fatto per dichiarare una variabile. Il tipo dei parametri èquello che abbiamo già studiato (int, float e così via). Se a una funzione si pas-sano più parametri, questi dovranno essere separati da una virgola.Le definizioni di funzioni possono essere scritte in qualsiasi punto del pro-gramma: verranno eseguite in seguito alla chiamata, perciò non ha alcuna im-portanza dove siano fisicamente poste. Lo standard ANSI ha però fissato delleconvenzioni secondo le quali è bene codificare le definizioni delle funzionidopo il main. Fra le istruzioni contenute nella definizione della funzione assume una parti-colare importanza return, utilizzata per restituire un valore al chiamante. Lasintassi dell’istruzione prevede di specificare dopo la parola chiave return unvalore costante, o una variabile, o un’espressione compatibile con il tipo resti-tuito dalla funzione. Ad esempio:

� return 2; /* Restituisce il valore 2 – si può anche scrivere (2)*/� return x; /* Restituisce il valore contenuto nella variabile x */� return (a+b); /* Restituisce il risultato dell’espressione specificata */� return; /* Ritorna senza restituire alcun valore */

Non è importante che le definizioni di tutte le funzioni usate in un programmaseguano l’ordine con cui sono chiamate, anche se, per motivi di chiarezza eleggibilità, è opportuno che sia così e che si segua l’ordine specificato in pre-cedenza. In ogni caso, la funzione con il nome main è eseguita per prima, inqualunque punto sia posta, e le funzioni sono eseguite nell’ordine in cui ven-gono chiamate.

Le funzioni

Page 45: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

IL LINGUAGGIO C 45

Le funzioni

2. Dichiarazione del prototipo della funzione. Si tratta di ripetere all’inizio delprogramma, prima della definizione del main, l’intestazione delle funzioni de-finite in seguito. In pratica, si riscrive quanto specificato nella prima riga delladefinizione della funzione, includendo però un punto e virgola alla fine. I pro-totipi sono stati introdotti per consentire al compilatore un maggiore controllosui tipi di parametri: conoscendoli in anticipo, infatti, all’atto della chiamata èpossibile stabilire se i parametri passati sono congruenti con quelli attesi. Nellacostruzione di programmi complessi capita di utilizzare molte funzioni. Inquesto caso le funzioni sono raccolte in librerie e i rispettivi prototipi sono rag-gruppati nei file di intestazione (o file header). Gli header sono file di testo chehanno estensione .h.

3. Chiamata della funzione. Consiste semplicemente nell’indicare, nel punto incui occorre utilizzare l’elaborazione fornita dalla funzione, il nome della fun-zione stessa accompagnato dall’elenco dei parametri da trasmettere. Il pro-gramma chiamante può utilizzare il valore restituito dalla funzione: in tal casoil nome della funzione figurerà, ad esempio, in un’espressione. Il chiamantepuò trascurare il valore restituito anche se non è di tipo void: è sufficiente uti-lizzare la funzione senza assegnare il valore da questa restituito.

Giunti a questo punto del nostro percorso, è doveroso ricordare che anche ilmain è una funzione ed è proprio questo il motivo della presenza della coppiadi parentesi tonde dopo la parola main. È una funzione speciale, poiché vieneeseguita 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 primadi 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.

Vediamo ora un esempio che mostra un prototipo e una funzione in un program-ma: dati in input due numeri interi, fornire in output il loro prodotto.

� #include <stdio.h>� double Moltiplica(); /* questo e’ il prototipo della funzione */� int x, y;� int main( )� { � printf(“Inserire un numero intero “ );� scanf(“%d”, &x);� printf(“\nInserire un altro numero intero “ );� scanf(“%d”, &y);� printf(“Il prodotto e\’ %5.0f\n “, Moltiplica()); /* chiamata della funzione */� system(“PAUSE”);� return 0;� }� double Moltiplica() /* questa è l’intestazione della funzione */� {� /* questo e’ l’inizio del corpo della funzione */� return (x * y);� } /* questa e’ la fine del corpo della funzione */

Non è superfluo far notare che in questo programma la funzione è totalmente inu-tile e può solo moltiplicare interi. L’abbiamo inserita unicamente per mostrarecome si costruisce una funzione.

Page 46: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

46 IL LINGUAGGIO C

ESEMPILe funzioni

Scrivere un programma per il calcolo delle soluzioni di un’equazionedi secondo gradoQuesto problema è stato già risolto precedentemente trattando il costrutto di se-lezione. Ora lo risolviamo con l’ausilio delle funzioni e utilizzando una diversa lo-gica di elaborazione. Partiamo come al solito dall’analisi del problema.Per risolvere un’equazione di secondo grado scritta nella forma canonica:

ax2+bx+c = 0

occorre acquisire i tre coefficienti a, b e c, poiché le soluzioni sono determinatedai valori loro assegnati. Una volta acquisiti, occorre calcolare il discriminante (∆)utilizzando la formula b2 – 4ac. Il valore del discriminante può fare riconosceretre distinte situazioni:• se ∆ < 0 non esistono soluzioni reali;• se ∆ = 0 l’equazione ammette due soluzioni reali e coincidenti;• se ∆ > 0 l’equazione ammette due soluzioni reali e distinte.Nel caso in cui esistano radici reali, queste si ottengono dalla formula:

Affinché il programma possa comprendere tutte le situazioni, è necessario fareattenzione al valore assegnato al coefficiente a, perché nel caso in cui questo siauguale a zero, non solo non sarà possibile applicare la formula, ma non ci si tro-verà più di fronte a un’equazione di secondo grado e occorrerà procedere con larisoluzione di un’equazione di primo grado.L’analisi appena condotta ci porta a individuare cinque sottoprogrammi. Il top-down è pertanto il seguente:

–b± b2 – 4ac2a

Equazionesecondo grado

Main Inserimentodei coefficienti Calcolo Delta

Calcoloe visualizzazione

soluzioni

Risoluzioneequazione

di primo grado

Le variabili che utilizzeremo sono le seguenti:

NOME FUNZIONE TIPO DESCRIZIONE

a I Intero Coefficiente a

a I Intero Coefficiente b

a I Intero Coefficiente c

x1, x2 O Reali Soluzioni dell’equazione di secondo grado

x O Reale Soluzione dell’equazione di primo grado

delta L Reale Valore del discriminante

Page 47: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

IL LINGUAGGIO C 47

ESEMPI

Le funzioni

� #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;� }

Page 48: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

48 IL LINGUAGGIO C

Le funzioni comunicano tra di loro attraverso i parametri. L’operazione attraversola 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 deiparametri attuali prendono il nome di parametri formali.

Il passaggio di parametri (dal chiamante al chiamato) può avvenire secondo duespecifiche 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 chiamatoaccoglierà 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 deallocatoe 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 parametroformale con un nome diverso, ma le locazioni di memoria a cui ci si riferiscesono 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 parametriformali (quelli presenti nell’intestazione della funzione) devono essere entrambecoerenti 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 dellostesso tipo;

• ordine: il passaggio dei parametri è posizionale, nel senso che il primo para-metro attuale invierà il suo contenuto al primo parametro formale, il secondoattuale al secondo formale e così di seguito.

Al fine di chiarire ulteriori dettagli sul passaggio dei parametri, riprendiamol’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 allafunzione 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, risolviamodue semplici problemi. Per la risoluzione del primo ci serviremo di un passaggiodi 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);

Passaggio deiparametri per valore

Page 49: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

IL LINGUAGGIO C 49

� 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 delsottoprogramma, qualsiasi modifica apportata ai parametri formali sarà visibilesolo 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 parametriattuali. 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.

Un ultimo particolare: nella dichiarazione del prototipo della funzione abbiamoscritto:

� long int Potenza(int b, unsigned int e); // il prototipo della funzione

cioè abbiamo indicato i parametri formali completi di tipo e di nome. Nel casoin cui non avessimo inserito i parametri, il compilatore C non avrebbe segnala-to un errore: l’elenco dei parametri, infatti, può essere completo, o può riporta-re solo l’indicazione del tipo. Ciò perché il compilatore non esegue alcun con-trollo sui nomi dei parametri formali del prototipo. A tal proposito,relativamente alla nostra funzione sono validi entrambi i prototipi:

� long int Potenza(int b, unsigned int b); // prototipo valido � long int Potenza(int, unsigned int); // prototipo valido

Passaggio dei parametri per valore

Page 50: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

50 IL LINGUAGGIO C

ESEMPIPassaggio dei parametri per valore

Stampare tutti i numeri primi compresi tra due numeri forniti in inputPer risolvere il problema ci serviamo di due funzioni: la prima, che abbiamo chia-mato Numeriprimi, non fa altro che richiamare la funzione Numeroprimo per ognivalore compreso nell’intervallo [i, j] fornito in input. La funzione Numeroprimocontrolla se il numero passato come parametro è primo. Tale controllo viene ef-fettuato dividendo il valore del parametro ricevuto per tutti i numeri compresi tra2 e il valore del parametro stesso. Nel momento in cui si trova un numero per ilquale 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;� }

� int Numeroprimo(int n) /* verifica se il numero passato come parametro � è primo */� {� int primo, i;� primo = TRUE;� i = 2;� while (primo == TRUE && i<n)� {� if (n%i == 0) � primo=FALSE;� i++;� }� return(primo);� }

� void Numeriprimi(int a, int b) /* Stampa tutti i numeri primi compresi� tra gli interi positivi a e b */� {� int i;� for (i=a; i<=b; i++)� if (Numeroprimo(i)) � printf(“%d e\ numero primo\n”,i);� }

Page 51: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

IL LINGUAGGIO C 51

ESEMPI

Passaggio dei parametri per valore

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);� }

Dati in input il valore della base e dell’esponente,calcolare la potenzaQuesto problema è già stato risolto. Vediamo ora una nuova versione più comple-ta che fa uso del costrutto for e non del costrutto while.

� #include <stdio.h>� #include <stdlib.h>� double Potenza(double base, int esponente);� int main()� { � double base;� int esponente;� printf(“Inserisci la base: ”);� scanf(“%lg”,&base);� printf(“Inserisci l’esponente (intero): ”);� scanf(“%d”,&esponente);� if(esponente<0)� printf(“Solo esponenti positivi sono permessi!\n”);� else if(esponente==0)� {� if(base==0)� printf(“Risultato indeterminato.\n”);� else� printf(“Risultato = 1\n”);� }� else� printf(“Risultato = %g\n”,Potenza(base,esponente));� system(“PAUSE”);� return(0);� }� double Potenza(double base, int esponente)� {� int i;� double risultato;� risultato=1.0;� for(i=1;i<=esponente;i++)� risultato*=base;� return(risultato);� }

Page 52: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

52 IL LINGUAGGIO C

Talvolta la modifica dei parametri formali diviene necessaria per il corretto fun-zionamento del programma. Per esempio il programma seguente, che effettua loscambio 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;� }

� void Scambia(int x, int y)� {� int appoggio;� appoggio = x;� x = y;� y = appoggio;� }

Questi tipi di problemi richiedono che la funzione non operi su una copia localedei dati, ma direttamente sui dati originali. È necessario, quindi, effettuare unpassaggio 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 dimemoria 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 ilvalore 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 indirizzodeve essere in grado di risalire dall’indirizzo della cella di memoria al valore inessa contenuto; per permettere ciò è necessario che i parametri formali sianopreceduti 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 duevariabili, servendoci questa volta del passaggio di parametri per indirizzo.

Passaggio deiparametri per indirizzo

Page 53: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

IL LINGUAGGIO C 53

� #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;� }

Nella terminologia informatica le variabili *x e *y si chiamano puntatori, cioè va-riabili che non contengono un dato, ma l’indirizzo di una locazione di memoria.

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 pervalore) all’interno della funzione non influenza il valore della variabile a, mentrel’incremento della variabile indirizzata da y (trasmesso per indirizzo) modifica ilvalore iniziale della variabile b.

Passaggio dei parametri per indirizzo

Page 54: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

54 IL LINGUAGGIO C

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 diun 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 checontengono tipi di dati diversi (per esempio numeri interi e stringhe, i cosiddettiarray 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.

Gli array

Tutti gli elementi di un array vengono memorizzati uno di seguito all’altro nellamemoria del computer e, cosa importante, l’indice del primo elemento è 0. Ilnome del vettore è un valore costante che rappresenta l’indirizzo di memoria delprimo elemento del vettore stesso.

Dichiarazione di un vettorePer dichiarare un vettore si deve scrivere il tipo degli elementi, seguito da unnome valido e da una coppia di parentesi quadre che racchiudono un’espressio-ne costante. Tale espressione costante definisce le dimensioni dell’array, ossia ilnumero di elementi che esso contiene. La sintassi generale è dunque la seguente:

� <TipoElementi> <NomeArray>[<Dimensione>];

Per esempio:

� int numeri[10]; // Array non inizializzato di 10 interi� char lettere[20]; // Array non inizializzato di 20 caratteri

All’interno delle parentesi quadre non è consentito, in fase di dichiarazione del-l’array, utilizzare nomi di variabili. Per specificare la dimensione di un array è in-vece possibile usare delle costanti definite, come negli esempi:

� #define LIMITE_NUMERI 10� #define LIMITE_LETTERE 20� int numeri[LIMITE_NUMERI];� char lettere[LIMITE_LETTERE];

Inizializzazione di un vettoreUn vettore può essere inizializzato esplicitamente, al momento della creazione,fornendo le costanti di inizializzazione dei dati, oppure durante l’esecuzione delprogramma, assegnando o copiando dati nell’array.

0 1 2 3 4 5 6 7

Valori dell’indice

Valori degli elementi

3 8 150 10 85 90 7 34

Page 55: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

IL LINGUAGGIO C 55

Gli array

Per inizializzare l’array numeri degli esempi precedenti in fase di creazione, condieci numeri interi, scriveremo:

� int numeri[10] = {12, 0, 4, 150, 4500, 2, 34, 5599, 22, 83};

Un metodo alternativo è il seguente:

� int numeri[ ] = {12, 0, 4, 150, 4500, 2, 34, 5599, 22, 83};

In questo secondo modo si crea un array di dimensione pari al numero di ele-menti inseriti. Tutti gli elementi devono essere del tipo dichiarato (nel nostro casoint), altrimenti si avrà un errore in fase di compilazione. Per inizializzare un array durante l’esecuzione del programma occorre invece ac-cedere, generalmente con un ciclo, a ogni elemento dell’array stesso e assegnar-gli un valore. Come abbiamo detto, l’accesso a un elemento di un array avvieneindicando il nome dell’array seguito dall’indice dell’elemento desiderato, in basealla sintassi:

� <NomeArray>[<IndiceElemento>]

dove <IndiceElemento> inizia da 0 e non da 1. Il primo elemento dell’array èquindi <NomeArray>[0], il secondo <NomeArray>[1] e così via. Pertanto, nu-meri[2] indicherà il terzo elemento dell’array numeri e non il secondo.

Rappresentazione in memoria dei vettoriAll’interno della memoria gli elementi di un vettore sono memorizzato in locazio-ni consecutive a partire da quella di indirizzo più basso secondo l’ordine crescen-te del loro indice. Quando si dichiara un array si ottiene solo il riferimento al suoinizio. Alla luce di questa importantissima informazione, supponiamo di avere ache fare con un vettore temperature di 7 elementi di tipo int contenente le tempe-rature medie della settimana. Sapendo che un int occupa 4 byte e ipotizzandoche il primo elemento del vettore venga memorizzato nella cella di memoria diindirizzo 00100, la memorizzazione avverrà nel seguente modo:

Quindi l’indirizzo dell’I-esimo elemento si calcola con la seguente formula:

� <IndirizzoI-esimoEelemento> = <IndirizzoPrimoElemento> + I *<DimensioneElemento>

Array dimensionato

Array non dimensionato

Indirizzo Contenuto

00100 23,5

00104 23,0

00108 22,8

00112 21,6

00116 23,9

00120 20,6

00124 22,9

temperature[0]

temperature[1]

temperature[2]

temperature[3]

temperature[4]

temperature[5]

temperature[6]

Page 56: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

56 IL LINGUAGGIO C

ESEMPIGli array

Caricare un vettore con N elementi interi, con N ≤ 100Questo è un problema di caricamento determinato ossia un caricamento di N va-lori con N noto a priori. Il problema è molto semplice, perciò possiamo passaredirettamente 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);� }

Una variante di questo problema potrebbe prevedere di caricare il vettore con Nelementi interi, utilizzando solo numeri pari. Riportiamo solo il ciclo for del main,poiché il resto è identico all’esempio precedente.

� ...� for (k=0; k < numelementi; k++)� {� printf(“\nInserire l’elemento di posizione %d: “, k);� scanf(“%d”, &vettore[k]);� if (vettore[k] % 2==0) � continue;� k––;� }� ...

Scrivere un programma che chieda in input una serie di numeripositivi (finchè non viene inserito –1) e ne calcoli la somma e lamedia. Il numero inserito deve essere compreso tra 1 e 10000Questo problema ha a che fare con un caricamento indeterminato (ossia con uncaricamento di N valori con N non noto a priori). Lo risolviamo senza l’ausilio disottoprogrammi.

Page 57: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

IL LINGUAGGIO C 57

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 crivellodi EratosteneIl 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 pariperché 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è nonsono 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;� }

Gli array

Page 58: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

TrainingPROVE APERTE PER LA VERIFICA DELLE ABILITÀ

58 IL LINGUAGGIO C

Scrivi in corrispondenza di ogni valore da memorizza-re il tipo di dato più appropriato:

Completa la seguente tabella riportando la descrizio-ne dei vari tipi di dati presenti:

Completa la seguente tabella riportando i byte occu-pati dai singoli tipi di dato:

3.

2.

1. Scrivi le scritture compatte equivalenti alle seguentiistruzioni:

X = X + Y;

X = X – Y;

X = X * Y;

X = X / Y;

X = X % Y;

Trova l’errore presente in ognuna delle seguenti di-chiarazioni di variabili:

� Int a;� Float b;� int a = 12.5;� char parola = “Ciao”;� char lettera = “C”;

Qual è il valore della variabile b al termine dell’esecu-zione del seguente programma?

� #include <stdio.h>� #include <stdlib.h>� int a, b, c;� main()� {� a = 10;� b = 1;� c = 2;� b = a++;� printf(“%d\n”, b);� b = ++a; � printf(“%d\n”, b);� system(“PAUSE”);� }

Qual è il valore della variabile b al termine dell’esecu-zione del seguente programma?

� #include <stdio.h>� #include <stdlib.h>� int a, b, c;� main()� {� a = 10;� b = 1;� c = 2;� b *= a++;� printf(“%d\n”, a);� b *= ++a; � printf(“%d\n”, a);� system(“PAUSE”);� }

7.

6.

5.

4.

Valore Tipo di dato

2

125000000

A

Ab

0.125

125520.25

Tipo Descrizione

caratteri

char

signed char

unsigned char

interi

short intsigned short int

unsigned short int

intsigned int

unsigned int

long intsigned long int

unsigned long int

reali

float

double

long double

Tipo Byte occupati Intervallo di definizione

char da –128 a 127

unsigned char da 0 a 255

short int da –32768 a +32767

int da –21474863648 a+21474863647

long int da 10–309 a 10+308

usigned short da 0 a 65535

unsigned int da 0 a 4294967295

unsigned long notazione IEEE standard

float notazione IEEE standard

double notazione IEEE standard

long double notazione IEEE standard

Page 59: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

TrainingPROVE APERTE PER LA VERIFICA DELLE ABILITÀ

IL LINGUAGGIO C 59

Osservando le porzioni di codice seguenti, scrivi il valo-re contenuto nella variabile c. Il primo caso appare ri-solto, come esempio:

Trova gli errori presenti in ognuna delle seguenti di-chiarazioni di costanti:

� const flot PGRECO = 3.14;� const char C “a”;� const int POSTI = 100,00;� const char[2] MESS = “Buongiorno!”;� #define PGRECO = 3,14;� #define C = ‘a’;� #define POSTI =100;� #define ERRORE “Rilevato errore’

Trova gli errori presenti nel seguente codice:

� #include <iostream.h>� main( )� {� float a, b; /* questo è un � commento corretto.� a = 100; // questo commento è � valido //� b = 10 */ questo commento è valido /*� system(“PAUSE”);� }

Senza usare il compilatore, prova a calcolare il valorerisultante dal seguente frammento di programma:

� 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;

11.

10.

9.

8. Qual è l’output fornito dal seguente programma?

� #include <stdio.h>� #include <stdlib.h>� int a, b;

� main() � {� a=10;� b=3;� printf(“a + b = %d\n”, a + b); � printf(“a - b = %d\n”, a - b); � printf(“-b = %d\n”, -b); � printf(“a * b = %d\n”, a * b); � printf(“a / b = %d\n”, a / b); � printf(“a %% b = %d\n”, a % b); � system(“PAUSE”);� }

Qual è l’output fornito dal seguente programma?

� #include <stdio.h>� #include <stdlib.h>� int a, b;

� main() � {� a = 10;� b = 3; � printf(“a = %d b= %d\n”, a, b); � ++a;� ––b; � printf(“a = %d b= %d\n”, a, b); � a++; � b––;� printf(“a = %d b= %d\n”, a, b); � system(“PAUSE”);� }

13.

12.

Codice Contenuto della variabile cdopo l’esecuzione del codice

int a = –20; c contiene –20int b = 10;int c = (a *= 2, b += 10, c = a + b);

int a = –20;int b = 10;int c = (b = 2, b = a, c = a + b);

int a = –20;int b = 10;int c = (b = 2, b = a++, c = a + b);

int a = –20;int b = 10;int c = (b = 2, b = ++a, c = a + b);

Page 60: Il linguaggio C - Altervista...Il C è un linguaggio di programmazione di alto livello . Progettato e realizzato da Dennis Ritchie nel 1972, fu sviluppato presso gli AT&T Bell Laboratories

TrainingPROVE APERTE PER LA VERIFICA DELLE ABILITÀ

60 IL LINGUAGGIO C

Qual è l’output prodotto dal seguente programma?

� #include <stdio.h>� #include <stdlib.h>� int a, b, c, d;

� main()� {� printf(“Inserisci il primo numero ”);� scanf(“%d”, &a);� printf(““Inserisci il secondo numero ”);� scanf(“%d”, &b);� printf(“Inserisci il terzo numero ”);� scanf(“%d”, &c);� printf(“Inserisci il quarto numero ”);� scanf(“%d”, &d);� printf(“%d\n”, (a>b && c<=d));� printf(“%d\n”, (a>b || c<=d));� printf(“%d\n”, (a<=b && c>d || a));� printf(“%d\n”, (a<=b && (c>d || a)));� system(”PAUSE”);� }

Qual è l’output prodotto dal seguente programma?

� #include <stdio.h>� #include <stdlib.h>� int a,b,c;

� main()� {� printf(“Inserisci un numero ”); � scanf(“%d”, &a);� printf(“++a = %d\n”, ++a);� printf(“a = %d\n”, a); � printf(“a++ = %d\n”, a++);� printf(“a = %d\n”, a);�

� printf(“Inserisci un numero “); � scanf(“%d”, &b);

� c = ++b==3;� printf(“b = %d\n”, b); � printf(“c = %d\n”, c);

� c = b++==3;� printf(“b = %d\n”, b); � printf(“c = %d\n”, c); � system(“PAUSE”);� }

15.

14. Gradi, primi e secondi

Scrivi un algoritmo che, data in input la misura di unangolo in gradi (G), primi (P) e secondi (S), determinila sua ampiezza espressa in secondi.

Media di tre numeri

Scrivi un algoritmo che, dati in input tre numeri,ne determini la media.

Area del cerchio

Scrivi un algoritmo che determini l’area del cerchiocircoscritto a un quadrato.

Perimetro e area del triangolo

Scrivi un algoritmo che, date in input le dimensioniAB e BC del seguente triangolo isoscele, nedetermini perimetro e area.

Età di una persona

Scrivi un algoritmo che, dati in input il cognome,il nome e l’anno di nascita di una persona, forniscain output la sua età.

Equazione di primo grado

Scrivi un algoritmo che calcoli la radicedell’equazione di primo grado ax=b.

Calcolo dei secondi

Dati un numero di giorni, uno di ore, uno di minuti e uno di secondi, calcola il numero di secondicorrispondente.

Esempio: Giorni = 2, Ore = 3, Minuti = 23,Secondi = 7 ? N=184987.

Calcolo litri di vino

Supponiamo di essere andati da un contadino acomprare il vino. Il contadino ci vende il vino a 1,70euro il litro. Costruisci un algoritmo che, ricevuto iningresso il numero di litri acquistati, comunichil’importo da pagare.

Vernici e additivi

Per produrre una vernice sono necessari 10 grammidi additivo ogni chilo di prodotto fino a 10 chili e 5 grammi al chilo per i chili eccedenti. Stabilisci la quantità di additivo necessaria in baseal quantitativo di vernice richiesto.

24

23.

22.

21.

20.

19.

18.

17.

16.

A

B C