You are on page 1of 36

Dispense su:

Linguaggio di programmazione C
a cura di Angela Scaringella e Sofia Bochicchio

Prefazione
Questa dispensa costituisce il testo di riferimento, in aggiunta agli argomenti trattati nel libro di testo, per la preparazione allesame di base di Informatica, sia per gli studenti di Sociologia Nuovo Ordinamento, sia per gli studenti di Goru, sia per gli studenti di Sociologia Vecchio Ordinamento. Si tratta di una introduzione elementare al linguaggio C che riporta le lezioni e le esercitazioni tenute durante il corso. E destinata soprattutto agli studenti che non hanno potuto frequentare il corso e permette di acquisire gli elementi iniziali della programmazione che sono richiesti per sostenere lesame.

Introduzione
I linguaggi di programmazione sono alla base dellInformatica, perch consentono di generare il software, sia quello di base (sistemi operativi), sia quello applicativo utilizzato nei vari aspetti dellelaborazione di dati, come ad esempio operazioni eseguite da un programma, sequenze di passi eseguiti da una macchina per lautomazione di processi produttivi, controlli e protocolli di telecomunicazione, le interfacce utente, raccolta di dati da Internet, ecc. I linguaggi di programmazione occupano una posizione intermedia tra il linguaggio naturale (tipicamente inglese), comprensibile dalle persone, e quello binario (composto da sequenze delle sole cifre 0 e 1), comprensibili solo dal computer, l'unico linguaggio che pilota direttamente le unit fisiche dell'elaboratore (memoria centrale e cpu). Il linguaggio C, come qualsiasi altro linguaggio di programmazione (confrontare il Cap. 10 del libro di testo), si compone di parole e regole; le prime generate da un dato alfabeto o simboli secondo un metodo prefissato, le seconde costituiscono la portante grammaticale e sintattica del linguaggio che consente di aggregare le parole per formare frasi di senso compiuto, cio ammissibili. I linguaggi di programmazione sono costituiti da un alfabeto, da una sintassi e da una semantica. La sintassi riguarda linsieme di regole che devono essere rispettate per scrivere programmi corretti. Il linguaggio dei programmi C costituito da tutte le stringhe (insiemi di caratteri o simboli) che soddisfano la propriet di poter essere analizzate da un compilatore C, senza che venga rilevato alcun errore sintattico. La costruzione delle stringhe avviene secondo una metodologia che, in informatica nota con il nome Grammatiche formali. Una grammatica formale (come introdotta da Chomsky) un sistema che comprende: variabili terminali, variabili, un insieme di regole di produzione e un insieme di assiomi. La grammatica permette di operare su stringhe di simboli attraverso le regole di produzione che fanno passare da una stringa ad unaltra a partire dagli assiomi. Il linguaggio generato dalla grammatica linsieme di stringhe composte solo da variabili terminali che si possono ottenere a partire dagli assiomi operando con le regole di produzione. In seguito, ogni argomento introdotto supportato da esempi e da esercizi svolti.

Relazione tra i linguaggi di programmazione e il concetto di algoritmo


Si richiama il concetto di algoritmo e dalla sua rappresentazione mediante i diagrammi di flusso, questo ci permetter di gettare una buona base sulla logica sottostante ai linguaggi di programmazione (confrontare il Cap. 1 del libro di testo). I computer, conosciuti anche con il nome di elaboratori elettronici o calcolatori o sistemi di elaborazione dati, sono strumenti dausilio alla risoluzione di una vasta gamma di problemi (non tutti!!, cfr cap.1, par. 1.4 del libro di testo) ed hanno la caratteristica di svolgere un gran numero di operazioni in maniera rapida e corretta. Questa capacit deriva dal fatto che sono macchine programmabili e cio che accettano istruzioni e comandi imposti dalluomo secondo modalit ben precise. I linguaggi di programmazione permettono di tradurre algoritmi interpretabili da un sistema di elaborazione. Un algoritmo scritto in un linguaggio di programmazione viene chiamato programma e il processo di scrittura del programma, a partire dallalgoritmo, viene chiamato codifica. Svolgere unattivit di programmazione (o, brevemente, programmare) significa quindi scrivere programmi che risolvano problemi destinati ad essere eseguiti in maniera automatica su un calcolatore. In generale, necessario definire il problema nel modo pi preciso possibile: tanto pi precisa sar la sua descrizione, tanto pi facile risulter scrivere il programma che lo risolve. E necessario quindi specificare in maniera rigorosa i dati noti e i risultati attesi. Esempio: Dato un importo, denominato imponibile, si deve calcolare un secondo importo, denominato lordo, derivante dallapplicazione dellIVA al 20%. Di seguito riportata la soluzione: 1. Si esegue la moltiplicazione imponibile*20; 2. La cifra ottenuta al passo 1 si divide per 100; 3. Il risultato cercato dato dalla somma della cifra ottenuta al passo 2 con il valore imponibile. Dati iniziali: imponibile e aliquota IVA; risultato atteso: importo lordo. Si osservi che, dato un qualsiasi problema, i dati iniziali vengono sempre trasformati (o meglio,elaborati) al fine di produrre il risultato. Inoltre, con lelencazione dei 3 passi precedenti, abbiamo dato origine ad un algoritmo. Si richiama la definizione di algoritmo: a) E una successione finita di azioni, o passi, che determinano la risoluzione di un problema. Si intuisce che, dati due algoritmi che risolvono lo stesso problema, viene preferito quello col minor numero di passi. b) Le azioni specificate devono essere univocamente interpretabili ovvero devono essere comprensibili senza ambiguit da colui che le esegue (solitamente un computer). c) Se la successione di azioni viene ripetuta in momenti diversi ma con gli stessi dati iniziali, allora deve essere restituito sempre lo stesso risultato; si dice che lalgoritmo deve essere non casuale. d) In ogni istante, la prossima azione da intraprendere deve essere univocamente determinabile a partire dallanalisi del valore di particolari dati. Esistono vari modi di rappresentare un algoritmo e precisamente: - in forma discorsiva per punti (elenco di passi); - mediante uno pseudo-linguaggio di programmazione; - in forma grafica (diagramma a blocchi ) utilizzando simboli standard. 3

Esempio_1 : Consideriamo un gioco con un dado: una volta lanciato un dado, il giocatore vince solo se uscito un numero n maggiore di 3, altrimenti perde. In caso di vincita verr pagato un premio di euro 5*n . - In termini di algoritmo si ha la seguente successione di passi elementari: 1. Calcola un numero naturale n tra 1 e 6; 2. Se n appartiene allinsieme {1,2,3} allora vai al passo 4; 3. n appartiene allinsieme {4,5,6} ed stata vinta la somma di euro 5*n; 4. Il gioco terminato. - In pseudo-codice (simile al linguaggio Pascal) : program Gioco Con Dado: begin {inizio dellalgoritmo} n:=CalcolaUnNumeroNaturaleTra1e6: if n>=4 then { uscito un numero maggiore di 3} begin premio:=n*5{calcola il premio vinto} end end {fine dellalgoritmo}

- Per la forma grafica dobbiamo introdurre i simboli fondamentali dellalgoritmo. La struttura logica della soluzione di un problema pu essere visualizzata mediante un diagramma a blocchi (diagramma di flusso).

Simbolo terminale (Inizio e Fine)

Simbolo di ingresso (Input)

Simbolo di annotazione (Commento)

Simbolo di collegamento

Simbolo di elaborazione (Processo)

Simbolo di decisione (il computer pu decidere solo se vero o falso)

Tornando all esempio_1, possiamo cos graficamente rappresentare lo sviluppo dellalgoritmo:

Inizio

Estrai n

n >= 4 ?

si

Hai vinto n*5 euro!

n o

Fine gioco

Vediamo subito un altro esempio per chiarire alcuni punti.

Esempio_2: Uno studente immette il suo voto: se il voto uguale o superiore a 18 lo studente viene promosso, se minore di 18 viene bocciato.

Inizio

Leggi voto

voto >=18 n o

Si

Promosso

Bocciato

Fine

Da notare che non abbiamo dovuto specificare, con un altro controllo, se il voto fosse minore di 18. Se volessimo inserire pi voti ? Mettiamo il caso che: uno studente inserisca 3 voti e che voglia trovare la media. Esempio_3:

Inizio

somma=0; voto; voti ins=0;

Leggi voto

si somma= somma + voto

voti_ins = voti_ins + 1

voti_ins < 3?

no

Media = somma / 3

Fine

Questa la logica lineare da seguire se si vuole sviluppare un algoritmo, ora siamo pronti per introdurre la storia del linguaggio C.

LE BASI DELLAMBIENTE C
Il C e' stato progettato da Dennis Ritchie su UNIX, e discende dal B, ideato nel 1970 da Ken Thompson, e il B a sua volta discende dal BCPL, sviluppato da Martin Richards. Nel 1983 l'Istituto Nazionale Americano per gli Standard (ANSI) ha iniziato una standardizzazione del C, terminata nel 1989 con la definizione dell'ANSI C, che differisce di poco dal C di K&R (Kernigan & Ritchie). In seguito e' stato aggiornato secondo la filosofia della programmazione orientata agli oggetti, in questo caso si parla di C++, e il suffisso dei file solitamente e'.CPP. Il C consente la gestione di bit, byte e indirizzi di memoria, a differenza di altri linguaggi di alto livello come basic e pascal, per questo alle volte e' definito un linguaggio di medio livello, ossia piu' vicino al basso livello, ossia all'assembler. Tra l'altro ha solo 32 parole chiave, ben poche al confronto del basic, che ne ha solitamente piu' di 150. Inoltre il C e' un linguaggio portabile, ossia un listato scritto in ANSI C puo' essere compilato su ogni compilatore standard di ogni sistema operativo. I compilatori C richiedono un listato scritto in formato testo, che si puo' scrivere con un editor qualsiasi o con quello integrato nel compilatore. Il file di testo del programma, che di solito ha come suffisso .c e viene chiamato programma sorgente, viene compilato, cio tradotto e 7

trasformato in un nuovo file chiamato programma oggetto (o modulo), per distinguerli luno dallaltro, il programma trasformato e reso comprensibile solo alla macchina assume un nuovo nome cui bisogna assegnare il suffisso .OBJ. Tutti i sistemi C consistono generalmente di tre parti: lambiente, il linguaggio e la libreria standard del C. I programmi scritti in C passano tipicamente attraverso 6 fasi, prima di essere eseguiti. Queste sono: editare, preelaborare, compilare, linkare (collegare), caricare ed eseguire. La prima fase consiste nella scrittura del codice (editing) in un file: questa si esegue con un programma chiamato editor. Il programmatore scrive un programma in C con leditor e, se necessario, eseguir delle correzioni. Il programma sar quindi immagazzinato in un dispositivo di memoria di massa, come un disco. Il nome del file del programma C dovr terminare con lestensione .c. Ad esempio il blocco note, il vi e lemacs sono editor largamente utilizzati sui sistemi windows e UNIX. In seguito, il programmatore immetter il comando di compilazione del programma. Il compilatore tradurr il programma C nel codice di un linguaggio macchina (detto anche codice oggetto). In un sistema C, prima che incominci la fase di traduzione, sar eseguito automaticamente il programma preprocessore. Il preprocessore del C obbedisce a comandi speciali, chiamati direttive del preprocessore, con le quali si indica che sul programma dovranno essere eseguite determinate manipolazioni,prima della compilazione vera e propria. Tali manipolazioni consistono generalmente nella inclusione di altri file in quello da compilare,e nella sostituzione di simboli speciali con un testo del programma. La quarta fase chiamata linking (collegamento). I programmi scritti in C contengono tipicamente dei riferimenti a funzioni definite altrove,per esempi nelle librerie standard o in quelle di un gruppo di programmatori che lavorano su un particolare progetto. Di conseguenza, il codice oggetto prodotto dal compilatore conterr tipicamente dei buchi dovuti a queste parti mancanti. Il linker collega il codice oggetto con quello delle funzioni mancanti per produrre una immagine eseguibile (senza pezzi mancanti). La fase quinta chiamata caricamento. Prima che possa essere eseguito,un programma dovr essere caricato nella memoria. Questa operazione sar eseguita dal loader (caricatore) che prender limmagine eseguibile dal disco e la trasferir nella memoria. Finalmente, sotto il controllo della sua CPU, il computer eseguir il programma, una istruzione per volta. Quando si scrive il codice buona abitudine indentarlo, ovvero, ad ogni istruzione si va a capo e si lascia una tabulazione orizzontale, questo permette al programmatore una pi chiara lettura di quello che si sta facendo; per commentare pi righe si usano i simboli: /* (Slash asterisco), per aprire il commento, e */ (asterisco slash) per chiudere; // doppio slash per commentare una sola riga. Vediamo subito un programma che visualizzi "Buon giorno!" sullo schermo: #include <stdio.h> /* Include la libreria standard, che non e' altro che un file di testo con delle strutture e macro predefinite. Questi file sono detti Header, infatti terminano con il suffisso .h */ /* Definiamo la funzione main, che non riceve nessun valore come argomento. Il programma iniziera' l'esecuzione a partire da questa funzione, che deve essere presente in ogni programma */ /* Le istruzioni della funzione sono racchiuse tra aperta e chiusa parentesi graffa */ 8

main( )

printf(Buon giorno!\n);

/* Chiamiamo la funzione di libreria printf che si occupa di ,visualizzare sullo schermo. Da notare che \n indica il newLine, ossia serve per andare a capo. Fondamentale: ogni istruzione termina con ; punto e virgola/ /* chiudiamo la funzione principale main( ) */

In questo programma si notano gi degli accorgimenti fondamentali. Innanzitutto la funzione main(), la funzione principale, viene eseguita per prima ed sempre presente in ogni programma. Inoltre si nota che gli argomenti da passare alle funzioni vanno messi tra le parentesi ( ) che si trovano dopo il nome della funzione stessa. Nel caso di main( ), non viene messo alcun argomento, infatti non richiede argomenti. La parentesi graffa aperta { apre il corpo di ogni funzione , la parentesi graffa chiusa } la chiude. La porzione di programma racchiusa in esse anche detta blocco. Quando si chiama la funzione printf( ) della libreria <stdio.h> immettiamo come argomento il testo da stampare tra (doppi apici ), come vuole la sua sintassi. All'interno della stringa di caratteri abbiamo la sequenza di escape \n, che equivale al carattere newline, posiziona il cursore allinizio della riga successiva. Sono disponibili altri caratteri non editabili, ad esempio \t , tabulazione orizzontale, muove il cursore alla tabulazione successiva; \r, ritorno carrello, posiziona il cursore allinizio della riga corrente; \a, allarme, fa suonare il cicalino del sistema; \\ backslash,visualizza un carattere backslash in una istruzione printf; \, apice singolo; \ virgolette.

Dichiarazione di variabili
Gli elementi di base di un programma sono le variabili e le costanti. In C le variabili devono essere dichiarate prima di essere usate e allinizio del programma. Si possono definire molti tipi di variabili numeriche, ad esempio con int si indicano variabili che possono contenere solo numeri interi, con float variabili che possono contenere numeri con la virgola. Ecco una tabella riassuntiva dei tipi di dati definibili: Tipo unsigned char char unsigned int short int int unsigned long long float double long double Lungh. 8 bits 8 bits 16 bits 16 bits 16 bits 32 bits 32 bits 32 bits 64 bits 80 bits Range (valori minimi e massimi) 0 fino 255 -128 "" 127 0 "" 65,535 -32,768 "" 32,767 -32,768 "" 32,767 0 "" 4,294,967,295 -2,147,483,648 "" 2,147,483,647 3.4 * (10**-38) "" 3.4 * (10**+38) 1.7 * (10**-308) "" 1.7 * (10**+308) 3.4 * (10**-4932) "" 1.1 * (10**+4932)

Come si vede i tipi interi (char, int, long) possono essere unsigned, ossia solo positivi, in questo modo contengono il doppio di valori positivi, risparmiandosi di supportare quelli negativi. I tipi a virgola mobile, ossia float, double e long double, sono comunque signed. Se si va fuori del raggio di azione di una variabile, ad esempio se si aggiunge 100 ad una variabile int che vale gia' 32700, il risultato e' -32736! Questo per l'aritmetica in complemento a 2, che per semplificare fa ricominciare dal numero pi basso quando si supera quello pi alto, dato che non e' segnalato alcun errore e il risultato erroneo pu essere usato, attenzione a non far eccedere mai i tipi! Per dichiarare una variabile basta scrivere il tipo seguito dal nome che decidiamo per la variabile stessa, ad esempio: int numero; float numero; /*nel caso in cui volessi inserire un numero intero */ /*nel caso in cui volessi inserire un numero con la virgola */

Nel primo caso abbiamo dichiarato una variabile di tipo intero e di nome numero. Da notare che abbiamo terminato la dichiarazione con un ;. Il nome da dare alla variabile e' a piacere, le uniche limitazioni sono: non pu iniziare con un numero, ne con simboli come &,/,!,... , non si possono dare come nomi le parole chiave di comandi del C, come if, else, int, float... Il C case sensitive, ovvero, le lettere maiuscole e quelle minuscole sono differenti in C, per cui NUMERO e' diverso da Numero o da NumeRO. Le parole chiave come printf() devono essere scritte in minuscolo, e solitamente anche le variabili sono scritte con caratteri minuscoli, nonostante si possano usare anche caratteri maiuscoli. La regola quindi sarebbe di scrivere le variabili a lettere minuscole, e se si vuole si pu usare il carattere _. Per esempio, si pu fare: int numero_1; int prova1_prova; Come assegnare un valore ad una variabile: numero = 1000; abbiamo introdotto l'operatore di assegnamento = , che assegna il valore ad una variabile. In questo caso abbiamo dato a numero il valore 1000. Da notare che scrivere: numero = 500+500; numero = (250+250)+500; equivalente, infatti si pu mettere anche unespressione, che sar risolta in fase di precompilazione, dato che si assegna sempre 1000. A questo punto ci manca di sapere come stampare il valore di una variabile a video con la funzione printf( ). Abbiamo gi visto che per stampare un testo normale basta includerlo tra ,virgolette. Per inserire una variabile nella stringa occorre aggiungere un %d nel punto che ci interessa, e mettere il nome della variabile dopo la chiusura delle , in questo modo: printf (Il valore di Numero e' %d.,numero);

10

Al momento della stampa il %d sar sostituito dal valore della variabile numero. Da notare la virgola che separa i doppi apici dalla variabile. La specifica di conversione %d usata in una stringa di controllo del formato di una funzione printf per indicare che sar visualizzato un intero, mentre in una stringa di controllo del formato di una funzione scanf per indicare che sar immesso un intero. La funzione scanf della libreria standard stdio.h utilizzata per leggere i dati della tastiera. Andiamo ora a semplificare le cose con un esempio: #include<stdio.h> main() { int num1; //dichiarazioni variabili int num2; int somma; num1=5; //inizializzazione num2=0; somma=0; printf(Inserisci un numero:\n); //prompt scanf(%d, &num2); /* legge un intero, il valore digitato sar immesso nella posizione di memoria alla quale il nome num2 stato assegnato */ somma=num1+num2; //assegnamento delladdizione alla somma printf(La somma del numero inserito da tastiera e del numero dato dal computer : %d,somma); //visualizza la somma return ; /* indica che il programma terminato con successo */ } Listruzione scanf (%d,&num2); utilizza scanf per ottenere un valore dallutente. La funzione scanf prende i dati in ingresso dallo standard input che di solito la tastiera. Questa scanf ha due argomenti: %d e &num2. Il primo argomento, la stringa di controllo del formato, indica il tipo di dato che dovr essere immesso dallutente. La specifica di conversione %d indica che il dato dovr essere un intero ( d sta per intero decimale). Il secondo argomento incomincia con una E commerciale &, detta in C operatore di indirizzo, seguita dal nome della variabile. La E commerciale, o ampersand, quando combinata con il nome della variabile , indica alla scanf la locazione di memoria in cui immagazzinata la variabile num2. Il computer quindi immagazziner il valore della variabile num2 in quella locazione. Ogni qualvolta un valore sistemato in una posizione di memoria, esso si sostituisce al valore contenuto in precedenza in quella locazione. Dato che questa informazione precedente sar distrutta, il processo di scrittura in una locazione di memoria detto scrittura distruttiva. Cos come abbiamo visto per la variabile somma, prima inizializzata a 0 e poi sostituita dal valore dato dalla somma di num1 e num2. Quando il valore sar letto da una locazione di memoria, il valore in quella locazione sar preservato, questo processo detto lettura non distruttiva. Per semplicit, immaginate la locazione della memoria come un cassettone, ad ogni cassetto (la dimensione dipende dal tipo della variabile) corrisponde un nome, allinterno troveremo il nostro valore. E buona abitudine inizializzare a 0 la variabile (come se volessimo ripulire il cassetto) per evitare risultati poco probabili durante lesecuzione. 11

Listruzione return 0; restituisce il valore 0 allambiente del sistema operativo in cui il programma stato eseguito. In questa tabella sono riportate le specifiche di conversione per printf e scanf: Tipi di dato long double double float unsigned long int long int unsigned int int short char Laritmetica del C Gli operatori aritmetici sono: Operazione Parentesi Moltiplicazione Divisione Modulo Addizione Sottrazione Operatore () * / % + Ordine di valutazione (priorit) Sono valutate per prime Sono valutate per seconde Sono valutate per seconde Resto di una divisione intera. Sono valutate per seconde Sono valutate per ultime Sono valutate per ultime Specifiche di conversione per printf per scanf %Lf %f %f %lu %ld %u %d %hd %c %Lf %lf %f %lu %ld %u %d %hd %c

Gli operatori di uguaglianza e relazionali: Operatori di uguaglianza == != Operatori relazionali > < >= <= maggiore minore maggiore o uguale minore o uguale 12 uguale diverso (not uguale)

Tutti questi operatori, a eccezione di quello di assegnamento =, associano da sinistra a destra. Loperatore di assegnamento associa da destra a sinistra. Es.: somma = num1 + num2 ;

Gli operatori di assegnamento


Il C fornisce diversi operatori di assegnamento per abbreviare le relative espressioni. Per esempio listruzione a=a+b; pu essere abbreviata con loperazione di assegnamento addizione += come in: a+=b; Loperatore += aggiunge il valore dellespressione alla destra delloperatore alla variabile alla sua sinistra, immagazzinando il risultato in questultima. += -= *= /= %= Addiziona Sottrae Moltiplica Divide Da il resto

Gli operatori logici


Gli operatori logici dellalgebra booleana (confronta Cap. 3 del libro di testo, par. 3.2) possono essere utilizzati per formare condizioni pi complesse, combinando quelle semplici. Questi sono: && ( AND logico), || (OR logico) e ! (NOT logico detto anche negazione logica). (condizione 1) && (condizione 2) , la condizione sar vera se e solo se entrambe le condizioni semplici saranno vere. (condizione 1) || (condizione 2) , la condizione sar vera se una o entrambe le condizioni semplici saranno vere.

Gli operatori di incremento ++ e di decremento - Il C fornisce anche loperatore di incremento ++ unario e loperatore di decremento unario. Quindi, qualora volessi incrementare di 1 una variabile, anzich scrivere: a= a+1 o a+=1 Si pu scrivere a++ ++a Incrementa la variabile a di 1 e quindi utilizza il nuovo valore di a nellespressione in cui essa occorre. a++ Utilizza il valore corrente di a nellespressione in cui essa occorre e quindi incrementa a di 1. --a Decrementa a di 1 e quindi utilizza il nuovo valore di a nellespressione in cui essa occorre. a-Utilizza il valore corrente di a nellespressione in cui essa occorre e quindi decrementa a di 1. Quando gli operatori di incremento o di decremento sono sistemati prima di una variabile, si dicono rispettivamente operatori di preincremento o di predecremento. Quando sono sistemanti dopo una variabile, si dicono rispettivamente operatori di postincremento o di postdecremento.

13

STRUTTURE DI CONTROLLO
La maggior parte dei programmi richiede delle iterazioni o cicli. Un ciclo (loop) un gruppo di istruzioni che il computer eseguir ripetutamente, finch una certa condizione di continuazione del ciclo rimarr vera. Tutti i programmi possono essere scritti in termini di tre sole strutture di controllo: la struttura di sequenza, la struttura di selezione, e la struttura di iterazione. Queste strutture di controllo con un ingresso e una uscita singoli semplificano la costruzione dei programmi. Le strutture di controllo possono essere attaccate luna allaltra, collegando il punto di uscita di una di esse con quello di entrata con una successiva: accatastamento delle strutture di controllo; oppure possono essere innestate: nidificazione delle strutture di controllo. Strutture di sequenza: le istruzioni sono eseguite nellordine in cui sono state scritte. Strutture di selezione: sono di tre tipi: - IF , nel caso in cui una condizione sia vera eseguir una certa azione, mentre la ignorer nel caso sia falsa. Chiamata struttura di selezione singola. - IF/ELSE , nel caso in cui una condizione sia vera eseguir una certa azione, nel caso in cui sia falsa eseguir unaltra differente azione. Detta struttura di selezione doppia. - SWITCH , sceglier ed eseguir una tra tante differenti azioni secondo il valore assunto da una data espressione. Consiste di una serie di etichette case (caso) e di un caso opzionale default. Detta struttura di selezione multipla. Strutture di iterazione: sono di tre tipi: - WHILE , consente al programmatore di specificare che una azione dovr essere ripetuta finch alcune condizioni rimarranno vere. - DO/WHILE , stesso controllo del WHILE fatto per dopo aver eseguito almeno una volta il corpo del loop (ciclo). - FOR , gestisce automaticamente tutti i dettagli di una iterazione controllata da un contatore. Utilizziamo ora i diagrammi di flusso per visualizzare il funzionamento delle strutture di sequenza, selezione e ripetizione con un ingresso e una uscita singoli . Sequenza Selezione Struttura if (selezione singola)

vero fa ls o

14

Struttura if/else (selezione doppia)

falso

vero

Struttura switch (selezione multipla)

vero

vero

vero

15

Iterazione Struttura do/while

vero f

Struttura while

vero f

16

Struttura for

vero

Vediamo due tipi di iterazione: Literazione controllata da un contatore; Literazione controllata da un valore sentinella. Literazione controllata da un contatore detta a volte iterazione definita, perch conosciamo esattamente in anticipo il numero di volte che il ciclo sar eseguito. Literazione controllata da un valore sentinella detta a volte iterazione indefinita, perch non noto in anticipo il numero di volte che il ciclo sar eseguito. I valori sentinella sono utilizzati per controllare una iterazione quando il numero preciso delle iterazioni non noto in anticipo e il ciclo include delle istruzioni che otterranno dei dati ogni volta che questultimo sar eseguito. Il valore sentinella indica la fine dei dati e sar immesso dallutente dopo che tutti i veri elementi informativi saranno stati forniti dal programma. Nella iterazione controllata da un contatore, utilizzata una variabile di controllo per contare il numero delle iterazioni. La variabile di controllo sar incrementata (di solito di 1) ogni volta che sar eseguito il gruppo di istruzioni. Il ciclo terminer quando il valore della variabile di controllo indicher che sar stato eseguito il numero corretto di iterazioni; a quel punto, il computer potr continuare con listruzione successiva alla struttura di controllo. Una iterazione controllata da un contatore richiede: il nome di una variabile di controllo; il valore iniziale della stessa; lincremento (o decremento) con cui la variabile di controllo sar modificata ogni volta nel corso del ciclo; la condizione che verificher il valore finale della variabile di controllo (ovverosia, quella che determiner se il ciclo dovr continuare).

17

Esempio_4 Iterazione controllata da un contatore (while): #include<stdio.h> main( ) { int contatore = 1;

/* dichiarazione e inizializzazione, posso dargli un qualsiasi nome e valore */ while ( contatore < = 10 ) // condizione di iterazione { printf (%d Buon giorno!\n,contatore); contatore++; // incremento } return ;

} Questo programma conta quante volte ( 10 nel nostro esempio) ho richiamato la funzione printf e ripete la frase : Buon giorno! ogni volta. La condizione di iterazione la posso prendere dallesterno del programma e quindi richiederla allutente e memorizzarla in una variabile dappoggio. Vedremo come nel prossimo esempio. La struttura di iterazione for gestisce automaticamente tutti i dettagli di una iterazione controllata da un contatore. Riscriviamo il programma dellesempio_4 con il for aggiungendo anche una variabile dappoggio: Esempio_5 (for): include<stdio.h> main( ) { int i ; // contatore int appoggio = 0; // variabile dappoggio printf (Digita quante volte vuoi ripetere la frase Buon giorno: ); scanf (%d,&appoggio); /* inizializazione, condizione di iterazione e incremento sono tutti inclusi nella intestazione della struttura for */ for (i=1; i <= appoggio; i++) { printf (%d Buon giorno\n,i ); } return ; }

18

Proseguiamo con altri esempi sulle strutture di controllo. Esempio_6 (if/else): Inserire un numero e vedere se pari o dispari. #include<stdio.h> void main(void) { int numero; // dichiaro variabile printf("Inserisci un numero:\n"); // visualizzo su schermo scanf("%d",&numero); // leggo numero if(numero%2==0) // condizione printf("Il numero inserito pari"); else printf("Il numero inserito dispari"); }

/* void sta a significare che la funzione main non riceve e non restituisce alcun valore, come abbiamo gi visto, si pu omettere */

Esempio_7 (if/else if/else): Inserire un voto. Se il voto dello studente >= 90 visualizza "a", altrimenti se il voto >= 80 visualizza "b", altrimenti se il voto >= 70 visualizza "c", altrimenti visualizza "d". #include<stdio.h> void main(void) { int voto; printf("Inserisci voto: "); scanf("%d",&voto); if(voto>=90) printf("\n a"); else if (voto>=80) printf("\n b"); else if(voto>=70) printf("\n c"); else printf("\n d"); } /* if appeso */ /* costruzione annidata */ /* avendo una sola istruzione non ha bisogno delle parentesi graffe*/

19

Esempio_8 (while/if/else): Inserisci un numero e vedere se un numero primo. #include<stdio.h> void main (void) { int num, i=2, div=0; // posso dichiarare ed inizializzare pi variabili insieme printf("Inserisci un numero:\n"); scanf("%d",&num); while(i<num) // due strutture di controllo luna dentro laltra { if(num%i==0) { div=div+1; //div++; i=i+1; } else { i++; // uguale a i=i+1 } } if(div==0) printf("\n%d un numero primo",num); else printf("\n%d non un numero primo",num); } Esempio_9 (if/while/while): Scrivere un programma C che legga il lato di un quadrato e lo disegni sullo schermo utilizzando degli "*".Il programma dovr funzionare con tutti i quadrati con lati compresi tra 1 e 20. esempio lato: 3 *** *** *** se lato < 1 o lato > 20 visualizzare "errore" #include<stdio.h> void main(void) { int lato,contatore1,contatore2; printf("Inserisci il lato del quadrato: "); scanf("%d",&lato); if((lato>=1) && (lato<=20)) /* && sta per loperatore and, se entrambe le condizioni sono vere il programma seguita la lettura nella funzione */ { contatore1=0; while(contatore1<lato) { printf("\n*"); 20

contatore1++; contatore2=1; while(contatore2<lato) { printf("*"); contatore2++; } } } else printf("\nErrore!"); } Esempio_10 (switch) Scrivere un programma che calcoli l'area del quadrato, del rettangolo, del triangolo e del cerchio. #include<stdio.h> void main (void) { int figura; float base, altezza, area, raggio, p=3.14159; printf("Per calcolare l'area del:\n quadrato digita 1\n rettangolo digita 2\n triangolo digita 3\n cerchio digita 4"); printf("\n\n Digita numero: "); scanf("%d",&figura); switch(figura) { case 1: printf("Inserisci base: "); scanf("%f",&base); area=base*base; break; //esce dallo switch case 2: printf("Inserisci base e altezza separati da spazio: "); scanf("%f %f",&base,&altezza); area=base*altezza; break; case 3: printf("Inserisci base e altezza separati da spazio: "); scanf("%f %f",&base,&altezza); area=(base*altezza)/2; break; case 4: printf("Inserisci il raggio: "); scanf("%f",&raggio); area=raggio*raggio*p; break;

21

default: printf("Che ho detto? o 1 o 2 o 3 o 4...Guarda che hai inserito!"); } printf("L'area della figura geometrica che hai scelto : %.4f ",area); // %.4f mi visualizza un numero float con solo 4 cifre dopo la virgola } Le istruzioni break e continue sono utilizzate per alterare il flusso di controllo. Listruzione break, qualora sia eseguita in una struttura while, for, do/while o switch, provocher luscita immediata da quella struttura. Lesecuzione del programma continuer con la prima istruzione successiva alla struttura. Lutilizzo tipico dellistruzione break per anticipare luscita da un ciclo, oppure per ignorare la parte rimanente di una struttura switch. In assenza del break sarebbero eseguiti insieme tutti i case di una istruzione switch. Qualora non sia stata riscontrata nessuna occorrenza, sar eseguito il caso default e sar visualizzato un messaggio di errore. Ogni case pu contenere una o pi azioni. La struttura switch differente da tutte le altre strutture, poich in un case di switch non sono necessarie le parentesi graffe intorno alle azioni multiple. Qualora sia eseguita in una struttura while, for o do/while, listruzione continue far in modo che quelle rimanenti nel corpo della struttura siano ignorate e che sia eseguita literazione successiva del ciclo. Esempio: for ( x=1; x<=10; x++) { if ( x ==5) continue; printf (%d ,x); } Il risultato sar: 1 2 3 4 6 7 8 9 10 Se avessi messo break al posto di continue il risultato sarebbe stato: 1234 Il C fornisce loperatore condizionale ( ? : ) che strettamente correlato con la struttura if/else. Quello condizionale lunico operatore ternario del C, in altre parole, accetta tre operandi. Gli operandi, insieme alloperatore condizionale, formano una espressione condizionale. Il primo operando una condizione, il secondo operando il valore che assumer lintera espressione condizionale, qualora la condizione sia vera, mentre il terzo operando il valore che assumer lintera espressione condizionale, qualora la condizione sia falsa. Per esempio listruzione printf printf ( %s, voto >= 18 ? Promosso : Bocciato); contiene unespressione condizionale che restituir la stringa letterale Promosso, qualora la condizione voto >= 18 risulti vera, mentre restituir la stringa letterale Bocciato, qualora la condizione risulti falsa. La specifica di conversione %s serve per visualizzare una stringa di caratteri. I valori in una espressione condizionale possono anche essere delle azioni da eseguire. Otteniamo lo stesso risultato se scriviamo: voto >= 18 ? printf (Promosso) : printf (Bocciato);

/* senza parentesi per la if perch contiene ununica istruzione */

22

LE FUNZIONI
Il modo migliore per sviluppare e amministrare un programma corposo di costruirlo partendo da pezzi pi piccoli o moduli ognuno dei quali sia pi maneggevole del programma originale. Questa tecnica detta dividi e conquista (divide et impera). I moduli in C sono chiamati funzioni. Le funzioni possono essere: predefinite, quelle preconfezionate disponibili nella libreria standard del C (es. #include<stdio.h> , file gi compilato, #include<math.h>,); o definite dallutente. Le funzioni sono invocate da una chiamata di funzione. Questa specifica il nome della funzione e fornisce delle informazioni (gli argomenti ) di cui la funzione chiamata ha bisogno. Un capo (la funzione chiamante) chiede a un operaio (la funzione chiamata) di eseguire un compito e tornare indietro a riferire, quando il lavoro sar stato eseguito. Il prototipo di funzione indica al compilatore il tipo del dato restituito dalla funzione, il numero dei parametri che quella funzione si aspetta di ricevere, il tipo dei parametri e lordine in cui questi sono attesi. Il compilatore utilizzer i prototipi per convalidare le chiamate di funzione. Il formato di una definizione di funzione : tipo_del_valore_di_ritorno nome_della_funzione (lista_dei_parametri) { dichiarazioni; istruzioni; return; } Esempio_11: Trovare la radice quadrata di un numero chiesto allutente. Utilizzare una funzione predefinita contenuta nella libreria matematica. #include<stdio.h> #include<math.h> /* includo il file di intestazione matematico, utilizzando la direttiva del preprocessore #include<math.h>, quando utilizzo le funzioni della libreria matematica. */ void main (void) { double x=0; printf("Inserisci il valore: "); scanf("%lf",&x); printf("La radice quadrata di %.2f %.2f",x , sqrt(x)); /* chiamo la funzione all'interno della printf , in alternativa avrei potuto dichiarare unaltra variabile, assegnarle il risultato della radice quadrata e poi visualizzarla a video. */ }

23

Esempio_12: Trovare il quadrato di un numero chiesto allutente. Utilizzare una funzione personalizzata. #include<stdio.h> int funzione_1 (int valore); /* prototipo di funzione. Nel prototipo posso omettere il nome della variabile che vado a passare, avrei potuto scrivere: int funzione_1 (int);*/ main( ) { int numero=0; /* numero e risultato sono variabili locali. int risultato=0; printf("Inserisci un numero:\n"); scanf("%d",&numero); risultato=funzione_1(numero); /*chiamo la funzione passandogli un argomento, la variabile numero, il valore intero di ritorno lo assegno alla variabile dappoggio risultato */ printf(" %d elevato al quadrato %d", numero, risultato); return; } int funzione_1 (int valore) { int num; num=valore*valore; /* avrei potuto ottimizzare la scrittura del codice con ununica istruzione: return valore * valore; senza cos utilizzare la variabile dappoggio num. */ return num; } Posso scegliere un qualsiasi nome per la funzione. Il prototipo di funzione: int funzione_1 (int valore); sta ad indicare che la funzione_1 ricever come argomento una variabile di tipo int e che mi restituir unaltra variabile di tipo int. Se alla funzione non passassi alcun argomento e se non mi restituisse alcun valore scriverei: void funzione_1 (void); Tutte le variabili dichiarate nelle definizioni di funzione sono variabili locali : esse sono note soltanto in quella in cui sono state definite. Quelle dichiarate allesterno delle funzioni, anche dal main, sono dette variabili globali : sono note a tutto il programma. /* Se chiudessi la funzione con ; il programma non leggerebbe il blocco di istruzioni. */ /* Nota: non ho bisogno di inizializzare la varibile valore Potrei utilizzare lo stesso nome della variabile numero, ma bene capire che sono due variabili distinte! */

24

Esempio_13: Vedo come varia il valore di una variabile utilizzando due diverse funzioni. #include<stdio.h> void funz1 (int); //prototipo di funzione int funz2 (int, int); //prototipo di funzione void main (void) //funzione principale { int num; num=999; printf("Sono nel main.num vale %d\n",num); funz1(num); //chiamata di funz1, passo un solo argomento num=funz2(10,12); // chiamata di funz2, passo 2 argomenti (valori) da me scelti. printf ("Sono di nuovo nella funzione main! num vale %d",num); } int funz2 (int a, int b) //funz2 { printf("Sono nella funzione 2. a=%d e b=%d\n",a,b); return a+b; } void funz1 (int x) //funz1 { printf("Sono nella funzione 1. num vale %d\n",x); } Invocare le funzioni: chiamata per valore e per riferimento Esistono due modi per invocare le funzioni: la chiamata per valore e la chiamata per riferimento. Quando gli argomenti saranno passati in una chiamata per valore, sar preparata una copia dei loro valori e questa sar passata alla funzione chiamata. Le modifiche effettuate alla copia non interessano il valore originale della variabile definita nel chiamante. Quando un argomento sar passato in una chiamata per riferimento, il chiamante consentir effettivamente alla funzione chiamata di modificare il valore originale della variabile. Le classi di memoria Per dichiarare una variabile abbiamo sempre utilizzato il nome, il tipo e il valore, questi sono detti attributi. Una variabile una locazione (posizione) della memoria in cui un valore pu essere immagazzinato perch possa essere utilizzato da un programma . Un nome di variabile in C qualsiasi identificatore valido. Un identificatore una serie di caratteri,comprendente lettere,numeri e caratteri di sottolineatura (_),che non comincia con un numero. Un identificatore pu avere qualsiasi lunghezza, ma soltanto i primi 31 caratteri devono essere riconosciuti dal compilatore C, in accordo con lo standard dell

25

ANSI C. Il C case sensitive,ovvero, le lettere maiuscole e quelle minuscole sono differenti in C, perci a1 e A1 sono identificatori distinti. Ora utilizzeremo gli identificatori anche come nomi per le funzioni definite dallutente. In realt, ogni identificatore in un programma ha anche altri attributi che includono: la classe di memoria, la permanenza (o durata) in memoria, la visibilit e il collegamento. Il C fornisce quattro classi di memoria indicate dalle specifiche di classe di memoria: auto, register, extern e static. La permanenza in memoria di un identificatore il periodo durante il quale quellidentificatore esiste in memoria. Alcuni identificatori esistono per un tempo limitato, altri sono creati e distrutti ripetutamente, mentre altri ancora esistono durante lintera esecuzione del programma. La visibilit di un identificatore il punto del programma in cui si pu far riferimento allidentificatore. Il collegamento di un identificatore determina se un identificatore sia noto solo in quello corrente o in qualsiasi altro file sorgente che abbia le dichiarazioni appropriate. Le quattro specifiche di classe di memoria possono essere suddivise in due tipi di permanenza: la permanenza automatica in memoria e la permanenza statica in memoria. Le parole chiave auto e register sono utilizzate per dichiarare variabili con permanenza automatica in memoria, queste ultime saranno create ogniqualvolta si entrer nel blocco in cui sono state dichiarate,esisteranno finch quello rester attivo e saranno distrutte quando si uscir dallo stesso. Le variabili locali hanno per default una permanenza automatica nella memoria. I dati per i calcoli e le altre elaborazioni,nella versione in linguaggio macchina di un programma, sono caricati normalmente nei registri. La specifica di classe di memoria register potr essere inserita prima della dichiarazione di una variabile automatica,per suggerire al compilatore di conservare la variabile in uno dei registri hardware ad alta velocit del computer. Esistono due tipi di identificatori con permanenza statica nella memoria: gli identificatori esterni (come le variabili e i nomi di funzione globali) e le variabili locali dichiarate con la specifica di classe di memoria static. Le variabili e i nomi di funzioni globali sono definiti per default con la classe di memoria extern. La visibilit di un identificatore la porzione del programma in cui quello potr essere oggetto di riferimenti. I quattro tipi di visibilit possibili per un identificatore sono: prototipo di funzione, visibilit nella funzione, visibilit nel file, visibilit nel blocco e visibilit nel prototipo di funzione. Generazione di numeri casuali Lelemento della casualit pu essere introdotto nelle applicazioni per computer utilizzando la funzione rand della libreria standard del C. Listruzione: i = rand ( ) ; genera un numero compreso tra 0 e RAND_MAX (costante simbolica definita nel file di intestazione <stdlib.h> ). Lo standard dellANSI stabilisce che il valore di RAND_MAX debba essere almeno 32767,che anche il valore massimo per un intero di due byte. Il prototipo per la funzione rand pu essere ritrovato in <stdlib.h>. Utilizzeremo loperatore modulo (%) in congiunzione con rand nel modo seguente: rand ( ) % 6 ; per generare degli interi compresi nellintervallo da 0 a 5. Questa operazione si chiama riduzione in scala,mentre il numero 6 detto fattore di scala.

26

La funzione rand genera in realt dei numeri pseudocasuali. Richiamando ripetutamente rand, si produrrebbe una sequenza di numeri che sembra essere casuale. In realt, la sequenza si ripeter ogni volta che il programma sar eseguito. Una volta che il programma sar stato completamente messo a punto,potr essere condizionato in modo da produrre una sequenza diversa di numeri casuali ad ogni sua esecuzione. Questa operazione detta in gergo randomizzazione, ed eseguita con la funzione srand della libreria standard. La funzione srand riceve un argomento intero unsigned e insemina la funzione rand, in modo da indurla a generare una diversa sequenza di numeri casuali ad ogni esecuzione del programma. ( Un unsigned int di due byte pu contenere soltanto valori positivi compresi nellintervallo da 0 a 65535.) Listruzione: srand ( time ( NULL ) ) ; porta il computer a leggere il suo orologio interno per ottenere automaticamente un valore per il seme. La funzione time restituisce lora corrente del giorno espressa in secondi. Questo valore sar convertito in un intero senza segno e utilizzato come seme per il generatore di numeri casuali. La funzione time ricever un argomento NULL (normalmente time in grado di fornire al programmatore una stringa che rappresenta lora del giorno; il NULL disabilita appunto questa capacit per una chiamata specifica di time). Il prototipo di funzione per time in <time.h>. (esempio: dado.c) E se volessimo finalmente scrivere il nostro esempio_1 in linguaggio C? #include<stdio.h> #include<stdlib.h> #include<time.h> main( ) { int numero; srand(time(NULL)); numero=1+rand( )%6; // librerie standard del C // funzione principale // apro blocco istruzioni // dichiaro la variabile int /* Con laggiunta di +1 estraggo un numero casuale da 1 a 6 */

printf(E uscito il numero %d\n,numero); if(numero>=4) /* struttura di controllo. Tra parentesi c la condizione da rispettare. if, simbolo di decisione: se il numero che io utente ho inserito > o = 4 la lettura del codice seguta allinterno del blocco istruzioni e salta la else */

{ printf(Hai vinto %d*5 euro,numero); /*In questo caso abbiamo una sola istruzione*/ } else { printf(Non hai vinto!); } /* Altrimenti, implica quindi che il numero < di 4, salta la if e seguta la lettura dellelse */

27

printf(Fine gioco!); /*A fine programma visualizzer la scritta: Fine gioco! */ return ; // Fine programma

I VETTORI
Un vettore un gruppo di posizioni (o locazioni) di memoria correlate dal fatto che tutte hanno lo stesso nome e tipo di dato.Il primo elemento di ogni vettore lelemento zero. I vettori sono entit statiche, giacch manterranno le proprie dimensioni durante lesecuzione del programma. Il numero di posizione contenuto allinterno delle parentesi quadre pi formalmente noto come indice. Un indice deve essere un intero o unespressione intera. DICHIARAZIONE DEI VETTORI int vett[10]; questa riga di istruzioni specifica il tipo elementare di ogni elemento della struttura dati di tipo vettore e il numero richiesto per la grandezza del vettore in modo tale che il computer possa riservare lappropriata quantit di memoria. Invece la sequente riga di istruzioni: int vett[ ]={2,4,7,4,8}; creer un vettore di tipo int di nome vett di 5 elementi. int vett[SIZE]; Nella dichiarazione posso utilizzare la costante simbolica SIZE , direttiva del preprocessore #define. Una costante simbolica un identificatore che sar sostituito con il testo di sostituzione dal preprocessore C, prima che il programma sia compilato.Utilizzare le costanti simboliche per specificare le dimensioni dei vettori render i programmi pi scalabili. Una costante simbolica non una variabile, il compilatore non le riserva nessuno spazio di memoria. int vett[5]={1,2,3,4,5,6}; provocher un errore di sintassi. INIZIALIZZARE A ZERO GLI ELEMENTI DI UN VETTORE Tre modi: int v[10]={0,0,0,0,0,0,0,0,0,0}; int v[10]={0}; for(i=0;i<10;i++) v[i]=0; Esempio_14: Chiedere all'utente 10 valori interi, il programma deve visualizzare il max. #include <stdio.h> void main (void) { int i, vettore[10], max = 0; for(i=0;i<10;i++) 28

{ printf("Inserisci un numero: "); scanf("%d",&vettore[i]); if(vettore[i]>max) max=vettore[i]; } printf("Il maggiore %d",max); } Esempio_15: Tabellina del 2. #include<stdio.h> #define N 10 main() { int v[N]={0},i; for(i=0;i<N;i++) v[i]=2+2*i; printf("%s%13s\n","Elemento","Valore"); for(i=0;i<N;i++) printf("%7d%13d\n",i,v[i]); return; } Come esercizio, si potrebbe chiedere allutente di introdurre un qualsiasi numero e poi visualizzare la tabellina. Esempio_16: Scrivere un programma che chieda allutente di introdurre 10 valori. Visualizzare prima tutti i valori pari e poi tutti i valori dispari. #include<stdio.h> main() { int v[10]={0},i; printf("Digita 10 numeri:\n"); for(i=0;i<10;i++) scanf("%d",&v[i]); printf("Valori pari:\n"); for(i=0;i<10;i++) if(v[i]%2==0) printf("%d ",v[i]); 29

printf("\nValori dispari:\n"); for(i=0;i<10;i++) if(v[i]%2!=0) printf("%d ",v[i]); return; } Esempio_17: Scrivere un programma che chieda allutente di introdurre 10 valori. Visualizzare prima tutti i valori di posizione pari e poi tutti i valori di posizione dispari. #include<stdio.h> main() { int v[10]={0},i; printf("Digita 10 numeri:\n"); for(i=0;i<10;i++) scanf("%d",&v[i]); printf("Valori di posizione pari:\n"); for(i=0;i<10;i+=2) printf("%d ",v[i]); printf("\nValori di posizione dispari:\n"); for(i=1;i<10;i+=2) printf("%d ",v[i]); return; }

PASSARE I VETTORI ALLE FUNZIONI Indicherete il nome del vettore senza parentesi quadre per passare ad una funzione un argomento di quel tipo. Per esempio, se il vettore vett fosse stato dichiarato come int vett[10]; listruzione per la chiamata della funzione somma(vett,10); passerebbe il vettore vett, il nome, e la sua dimensione alla funzione somma. Quando si passa a una funzione un vettore, spesso sar passata anche la sua dimensione, in modo che la funzione possa elaborare il numero specifico degli elementi inclusi nel vettore. Il C passa i vettori alle funzioni utilizzando automaticamente una chiamata per riferimento simulata: la funzione chiamata potr modificare i valori degli elementi inclusi nel vettore originale del chiamante. Il nome del vettore in realt lindirizzo del suo primo elemento! vett e &vett[0] hanno lindirizzo equivalente.

30

Di conseguenza, quando allinterno del suo corpo la funzione chiamata modificher gli elementi del vettore, essa star modificando effettivamente quelli del chiamante direttamente nelle loro locazioni di memoria originarie. funz( vett[3]); cos ho passato un solo elemento del vettore ad una funzione.

Il C fornisce lo speciale qualificatore di tipo const per prevenire, allinterno di una funzione, la modifica dei valori contenuti in un vettore. Quando un parametro di tipo vettore sar preceduto dal qualificatore const, i suoi elementi diventeranno delle costanti nel corpo della funzione e ogni tentativo di modificarli, in quel contesto, provocher un errore in fase di compilazione. Esempio_18: Inserisco 10 numeri e trovo il massimo. Stesso esercizio dellesempio_14 ma utilizzando una funzione per trovare il max. #include<stdio.h> #define N 10 int maxvet (int v[ ]); main() { int i,vet[N]; printf("Inserisci %d numeri:\n",N); for(i=0;i<N;i++) scanf("%d",&vet[ i ]); printf("Il massimo : %d",maxvet(vet)); return; } int maxvet (int v[ ]) { int j, max =0; for(j=0;j<N;j++) { if(v[ j ]>max) max=v[ j ]; } return max; // restituisco un intero } Esempio_19: Cerco un valore allinterno di un vettore di 10 elementi. #include<stdio.h> #define N 10 void inserimento (int vet[ ]); void cerca (int vettore[ ], int numero); void stampa (int vettoreee[ ]); main() { int v[N],num=0; inserimento(v); 31

printf("\nDigita un numero:"); scanf("%d",&num); cerca(v,num); stampa(v); return; } void inserimento (int vet[ ]) { int i; printf("Inserisci %d numeri\n",N); for(i=0;i<N;i++) scanf("%d",&vet[i]); } void cerca (int vettore[ ], int numero) { int i,f=0; for(i=0;i<N;i++) if(vettore[i]==numero) { f=1; printf("Il numero %d nella posizione %d\n",numero,i+1); } if(f==0) printf("Il numero %d non nel vettore\n",numero); } void stampa (int vettoreee [ ]) { int i; for(i=0;i<N;i++) printf("%d\n",vettoreee[i]); }

La Struttura Dati MATRICE


I vettori in C possono anche avere pi di un indice. Un utilizzo tipico dei vettori multidimensionali la rappresentazione di tabelle di valori formate da informazioni organizzate in righe e colonne. Per identificare un particolare elemento della tabella, dovremo specificare due indici: il primo identificher per convenzione la riga dellelemento, mentre il secondo ne identificher la colonna. Le tabelle o i vettori che per identificare un particolare elemento richiedono due indici sono detti vettori bidimensionali o matrici. Osservate che i vettori multidimensionali possono avere pi di due indici. Lo standard ANSI stabilisce che i sistemi ANSI C debbano supportare per i vettori un minimo di 12 indici. Colonna 0 Riga 0 M[0][0] Riga 1 M[1][0] Riga 2 M[2][0] Colonna 1 M[0][1] M[1][1] M[2][1] Colonna 2 M[0][2] M[1][2] M[2][2] Colonna 3 M[0][3] M[1][3] M[2][3] 32

Matrice M con 3 righe e 4 colonne, matrice 3 per 4. Esempio_20: /* MATRICE */ #include<stdio.h> #define R 4 #define C 6 /* righe */ /* colonne */

void riempiMx (int Mat[R][C]); /* utilizzo le funzioni */ void stampaMx (int Matrice[R][C]); void main (void) { int Mx[R][C]={0}; riempiMx(Mx); stampaMx(Mx); }

/* dichiaro e inizializzo matrice */ /* chiamata funzione */

void riempiMx (int Mat[R][C]) /* inserisco i valori nella matrice */ { int i,j; printf("Inserisci valori:\n"); for(i=0;i<R;i++) /* utilizzo un doppio ciclo for */ for(j=0;j<C;j++) scanf("%d",&Mat[i][j]); } void stampaMx (int Matrice[R][C]) /* stampo i valori */ { int i,j; for(i=0;i<R;i++) { printf("\n"); /* va a capo dopo aver visualizzato una riga */ for(j=0;j<C;j++) printf("%4d",Matrice[i][j]); } }

La Struttura Dati PUNTATORE


I puntatori sono delle variabili che come valore contengono degli indirizzi di memoria. Una variabile contiene direttamente un valore specifico; un puntatore, invece, contiene lindirizzo di una variabile nella quale immagazzinato quel valore specifico.

33

Es.: num 7 num, nome variabile, fa direttamente riferimento ad una variabile il cui valore 7. numPtr X numPtr fa indirettamente riferimento ad una variabile il cui valore 7. Per questo motivo il riferimento a un valore per mezzo di un puntatore detto deriferimento. DICHIARAZIONE int num, *numPtr ; * (asterisco) indica che la variabile dichiarata sar un puntatore. Possono essere dichiarati in modo da far riferimento a oggetti di qualsiasi tipo di dato. Posso inizializzare il puntatore nella dichiarazione o con una istruzione di assegnamento, come una variabile normale. & operatore di indirizzo, restituisce lindirizzo del suo operando int y = 5 ; int *yPtr ; yPtr = &y ; assegner al puntatore yPtr lindirizzo della variabile y * operatore di deriferimento o operatore di risoluzione del riferimento, restituisce il valore delloggetto puntato dal suo operando ( cio dal puntatore ) printf ( %d , *yPtr ) ; visualizzer il valore della variabile y, 5. Esempio_21: Inserisco un numero e lo modifico mediante un passaggio alla funzione del suo puntatore: #include<stdio.h> void modifico (int *); // riceve come argomento un puntatore main() { int a; printf("Inserisci un valore intero:\n"); scanf("%d",&a); modifico(&a); // chiamo la funzione e le passo un puntatore printf("Il valore di a = %d\n ",a); /* ho modificato la variabile a senza che la funzione mi restituisse un valore */ return; } void modifico (int *x) { if(*x>10) (*x)-=5; /* se il valore > di 10 gli sottraggo 5 (numero preso a 34

else (*x)+=5; }

caso */ // se il valore < di 10 gli addiziono 5

La Struttura Dati STRINGA Nel linguaggio C una stringa in realt un vettore di caratteri che termina con il carattere nullo (\0). Per accedere a una stringa si utilizzer un puntatore che far riferimento al suo primo carattere. Il valore di una stringa corrisponde allindirizzo del suo primo carattere. Ne consegue che nel linguaggio C corretto affermare che una stringa un puntatore: in effetti, un puntatore al primo carattere della stringa. In questo senso le stringhe sono come i vettori, poich anche questi sono puntatori al loro primo elemento. Una stringa potr essere utilizzata in una dichiarazione per inizializzare un vettore di caratteri: char colore [ ] = rosso; uguale scrivere: char colore [ ] = {r,o,s,s,o,\0}; // i caratteri sono tra apici singoli

Assicurarsi che il vettore sia grande a sufficienza per immagazzinare la stringa e il carattere NULL di terminazione. La dichiarazione creer il vettore colore di 6 elementi. char colore [6]; FUNZIONI PER LA MANIPOLAZIONE DELLE STRINGHE TRATTE DALLA LIBRERIA PER LA GESTIONE DELLE STRINGHE Libreria: <stdlib.h> strcpy ( s1 , s2 ) strcat ( s1 , s2 ) strcmp ( s1 , s2 ) copia la stringa s2 nella stringa s1 accoda s2 a s1 confronta le stringhe s1 e s2 La funzione restituir 0 se sono uguali < 0 se s1 minore di s2 > 0 se s1 maggiore di s2 N.b. Per comprendere < o > si consideri il processo di sistemazione in ordine alfabetico (es. per cognomi ). strlen ( s ) determina la lunghezza della stringa s. Restituisce il numero di caratteri che precedono il NULL di terminazione. strerror ( nomestringa ) traduce in una stringa di testo dipendente dal sistema printf ( %s \n , strerror ( Sbagliato! ) ; visualizzer: Error Sbagliato!

35

Nel caso di strncpy, strncat, strncmp posso copiare, accodare, comparare un massimo di n caratteri dalla stringa s2 nel vettore s1. Es.: strncpy ( s1 , s2 , 4 ) ; Per strcpy s1 deve avere uguale o maggiore dimensione di memoria di s2. Dopo aver copiato una stringa bisogna aggiungere il carattere nullo di terminazione s1 [ strlen ( s1 ) ] = \0 ; Esempio_22: Chiedo allutente di inserire delle parole, il programma termina se si inserisce la parola "fine" e visualizza le stringhe fino ad ora inserite. #include<stdio.h> #include<string.h> main() { char s[5]="fine"; char s1[20]=" ",s2[20]=" ",s3[200]=" "; //dichiaro ed inizializzo a 0 tre stringhe printf("Digita basta per terminare\n\n"); printf("Inserisci una parola:\n"); gets(s1); //stessa funzione dello scanf, legge in input. while(strcmp(s,s1)<0 || strcmp(s,s1)>0) { strcat(s3,s1); strcat(s3," "); /*inserisco uno spazio tra una parola e l'altra*/ printf("Inserisci una parola:\n"); gets(s2); strcpy(s1,s2); s1[strlen(s1)]='\0'; } printf("%s",s3); return; }

36

You might also like