Issuu on Google+

Introduzione al Linguaggio C

Overview „ „

Linguaggio general purpose Procedurale (a differenza di Java che e’ objectoriented) „

„

Applicazioni: compilatori, sistemi operativi, grafica, giochi, sistemi embedded „

„ „

Cosa hanno in comune queste applicazioni?

Limitato set di keyword (32) Da un lato, linguaggio di alto livello „

„

C++ è l’estensione OO del C

Costrutti di controllo del flusso (simile a Java)

Funzionalità di basso livello „ „

Gestione diretta della memoria Manipolazione di indirizzi

1


Linguaggio di per se’ limitato „

Utilizzo di funzioni di libreria „

„

„

„

Assenza di operatori predefiniti per oggetti complessi (stinghe, strutture dati) Utilizzo di funzioni di libreria per l’I/O

Le funzioni piu’ comuni sono contenute in una libreria standard (circa 150 funzioni) Buona portabilità a livello di codice sorgente „ „

Ma questo dipende dalle librerie che usiamo … e dall’uso di dialetti

Perche’ studiare il C (dopo Java)? „ „ „

Linguaggio al tempo stesso di alto e basso livello Maggior controllo degli aspetti di basso livello In generale, migliori performance rispetto a Java „

Anche se Java e’ migliorato tantissimo negli ultimi anni

Pero’: „ Saremo responsabili della gestione della memoria „ Il linguaggio ci lascera’ fare molte cose che Java ci proibiva (e.g. conversioni implicite tra tipi) „ Maggiori possibilita’ di errori

2


Principali similitudini con Java „

Operatori „

Aritmetici „ „

„

Relazionali e logici „ „

„

int i = i+1; i++; i--; i *= 2; +, -, *, /, %, <, >, <=, >=, ==, != &&, ||, &, |, !

Sintassi, strutture di controllo „ „ „ „ „ „

if ( ) { } else { } while ( ) { } do { } while ( ); for(i=1; i <= 100; i++) { } switch ( ) {case 1: … } continue; break;

Cenni storici - I „

„

„

Il linguaggio C è stato sviluppato intorno al 1972 nei Bell Laboratories AT&T americani, Dennis Ritchie. E’ nato come linguaggio di sviluppo del Sistema Operativo UNIX. Gli antenati del C possono essere riuniti in linea genealogica: „ „ „ „ „

Algol 60 CPL BCPL B C

1960 1963 1967 1970 1972

(Comitato Int.) (Cambridge) (Cambridge) (Thompson) (Ritchie)

3


Cenni storici „

Algol „ „

„

CPL (Combined Programming Language) e BCPL „ „

„

Migliorano le caratteristiche di Algol Ancora pero’ molto complessi

B „ „ „

„

Linguaggio modulare e con sintassi regolare Abbastanza complesso

Linguaggio vicino alla macchina Sviluppato per lo UNIX del DEC PDP-7 Non tipato

C „

Include le migliori caratteristiche dei linguaggi sopra citati

Cenni Storici - III „

„

1983: l’American National Standards Institute (ANSI) ha iniziato i lavori per la definizione dell’ANSI C 1983: Bjarne Stroustrup (Bell Labs) sviluppa il C++ a partire da C e Smalltalk „ „

„ „

Paradigma di programmazione a oggetti Nato come preprocessore per il C

1988: nasce l’ANSI C 1999: Versione corrente dell’ANSI C (ANSI C 99) „

„ „ „

Alcune modifiche sostanziali rispetto alle versioni precedenti E.g. dichiarazione variabili in qualsiasi statement Tipi boolean, complex Dichiarazione variabili nelle strutture di controllo

4


Perché programmare in C „ „ „ „ „

Portabilità del codice e del compilatore Codice generato molto efficiente Facilità di accesso al livello “macchina” Interfacciamento completo al S.O. UNIX Non complesso

Struttura dei Programmi - Un programma è formato da uno o più blocchi chiamati funzioni - Una funzione è formata da un insieme di una o più istruzioni Esempio: #include<stdio.h> main() /* esempio di programma C */ { printf(“Hello World!\n”); }

5


Commenti #include<stdio.h> /* */

Direttiva di preprocessore (include file .h) Apertura e chiusura di un commento

main()

Nome di funzione Main e’ la funzione chiamata quando si invoca un programma Inizio corpo funzione

{ printf(“Hello World\n”);

}

Invocazione funzione printf

Fine corpo funzione

Strumenti „

Quello che vi occorre è „ „

Un compilatore C (ANSI C compatibile!!) Un editor di testo „ „ „ „

„

Io uso Emacs…. http://www.gnu.org/software/emacs/ http://www.xemacs.org/Download/win32/ Altro editor: VI http://www.vim.org/

GCC – GNU C Compiler „

Distribuito con tutte le distribuzioni di Linux Se avete una macchina con Linux il gioco è fatto…

„

MAC OS – XCode

„

„

„

Alcune distribuzioni consentono il boot da USB stick… http://developer.apple.com/technologies/tools/xcode.html

6


CygWin „

Suite di utility Unix per sistema operativo Windows „ „

„

Inclusa una shell Unix Incluso il compilatore GCC

Download all’indirizzo http://www.cygwin.com/

Cygwin - Download

7


Cygwin - Download

Cygwin - Download

8


Cygwin - Download

Cygwin - Download

9


Eclipse CDT „ „ „

„

http://www.eclipse.org/cdt/ Ambiente integrato Syntax highlighting, debugger integrato nell’editor… Appropriato se siete gia’ abituati a lavorare con Eclipse (JDT) „

„

Sovrapponibile.. scaricate versioni compatibili (Helios) di entrambi e scompattateli nella stessa dir…

Abituatevi anche e soprattutto ad usare compilatore e altri strumenti da riga di comando!!!

Eclipse CDT

10


Programmare in C in <120 min. Viewer discretion is advised

Compilazione di un programma C Source code Hello.c

„

Preprocessore „

Preprocessed code Hello.i

Il codice sorgente può essere altamente portabile La compilazione produce un eseguibile „

Compilatore Assembly code Hello.s

„

Assemblatore Object module Hello.o

Altri object module Librerie

Linker Executable Hello / Hello.exe

Informazioni di rilocazione

„

In linguaggio macchina, quindi eseguito direttamente dalla macchina Dipendente dall’architettura e dal S.O.

Invece, Java produce bytecode „

„

Eseguito dalla Java Virtual Machine Indipendente dall’architettura e dal S.O.

11


Il preprocessore „

„

Trasforma il file sorgente iniziale processando direttive del preprocessore Iniziano con “#”, eg. „ „ „

#define definizione di costanti/macro #include inclusione di altri sorgenti #if #else #endif compilazione condizionale

Compilazione ed esecuzione „

cc ciao.c „ „

„

O anche gcc ciao.c Spesso cc e’ un link simbolico (alias) di gcc

Produrra’ il file eseguibile a.out „

a.exe con Cygwin

Per eseguirlo: „ ./a.out Hello World „

12


Alcune opzioni GCC gcc –Wall –pedantic –ansi ciao.c –o ciao.out „

„

-Wall produce tutti I possibili warning (usatelo!) -ansi evita che usiate codice non-ANSI „

„

„

e.g. parte del dialetto GCC

-pedantic visualizza tutti i warning circa la compliance ISO C -o file_output specifica il nome del file eseguibile

Ritorno a capo „

La funzione printf non genera un carattere di ritorno a capo al termine della stringa „

„ „

Come System.out.print, non come System.out.println

Occorre stampare esplicitamente un carattere speciale ‘\n’ Qual’e’ la differenza tra questi due programmi? main() { printf(“ciao”); printf(“mondo”); printf(“\n”); }

main() { printf(“ciao mondo \n”); }

13


Un programma (un po’) piu’ complesso… „

Conversione da °C a °F „

°C = (5/9)(°F-32)

Output 1 -17 20 -6 40 4 60 15 80 26 100 37 120 48 140 60 160 71 180 82 200 93 220 104 240 115 260 126 280 137 300 148

14


Dichiarazione di variabili „ „

„

„

int fahr, celsius; int lower, upper, step; Nome del tipo seguito da lista di nomi di variabili (identificatori) Tipo int: intero „

„

Numero di bit machine dependent, spesso 16 bit [-32768, +32767] Che tipo di rappresentazione numerica è usata?

printf.. printf("%d\t%d\n", fahr, celsius) „ „ „ „

„ „

Stampa Stampa Stampa Stampa

il valore della variable fahr un carattere \t (tabulazione) il valore della variable celsius un ritorno a capo \n

"%d\t%d\n“ e’ una stringa di formattazione %d in posizione i-esima indica che va prodotto l’output (come decimale intero) della i-esima variabile nella lista dopo la stringa di formattazione

15


Giustificazione numeri… „ „

L’output prodotto in precedenza conteneva printf("%3d %6d\n", fahr, celsius); „

Riserva 3 cifre per fahr e 6 per celsius

Problema „ „

„ „

Le temperature °F sono interi a intervalli di 20 Le conversioni °C sono troncate all’intero inferiore → non molto precise Dobbiamo utilizzare variabili floating point float fahr, celsius „

Tipicamente a 32 bit

16


Programma rivisitato #include <stdio.h> main() { float fahr, celsius; float lower, upper, step; lower = 0; /* lower limit of temperatuire scale */ upper = 300; /* upper limit */ step = 20; /* step size */ fahr = lower; while (fahr <= upper) { celsius = (5.0/9.0) * (fahr-32.0); printf("%3.0f %6.1f\n", fahr, celsius); fahr = fahr + step; } }

Cosa notiamo di diverso? „ „

float fahr, celsius; float lower, upper, step; „

„ „ „ „

celsius = (5.0/9.0) * (fahr-32.0); Perche’ 5.0 9.0 32.0? Come vedremo, il C effettua una conversione implicita 5 e 9 sarebbero trattate come costanti intere „

„

Il risultato di 5/9 sarebbe troncato all’intero inferiore (0)

Se scrivevamo fahr-32? „ „ „ „

„

Dichiarazione di variabili di tipo float

fahr e’ float 32 intero In questo caso il C avrebbe convertito tutto al tipo float (+ preciso di int) Quindi andava bene, ma meglio far vedere esplicitamente che 32 e’ float

Questo problema sarà affrontato in dettaglio piu’ avanti nel corso…

17


printf: stringhe di formattazione per numeri printf("%3.0f %6.1f\n", fahr, celsius); „

„

%3.0f fahr e’ stampato utilizzando spazio x 3 caratteri di ampiezza senza decimali %6.1f celsius e’ stampato utilizzando spazio x 6 caratteri di ampiezza, incluso 1 decimale

printf: riepilogando… „ „ „ „ „

„

„

%d %4d %f %.2f %6.2f

Intero in notazione decimale Intero in notazione decimale, 4 caratteri Float Float, 2 caratteri dopo il punto decimale Float 6 caratteri di cui 2 dopo il punto decimale

Ve ne sono altre (%o ottale, %x esadecimale, %c carattere, %s stringa) Usate printf(“%%”) per stampare un carattere “%”

18


Il costrutto FOR #include <stdio.h> main() { int fahr; for (fahr = 0; fahr <= 300; fahr = fahr + 20) printf("%3d %6.1f\n", fahr, (5.0/9.0)*(fahr-32)); }

„

Come funziona la struttura iterativa FOR? „

Ricordate da Java…

Dichiarazione di costanti „

Utilizzo della direttiva di preprocessore #define

#define nome testo_da_sostituire „

Il preprocessore analizza il programma e rimpazza ogni occorrenza di nome con testo_da_sostituire

#include <stdio.h> #define LOWER 0 /* lower limit of table */ #define UPPER 300 /* upper limit */ #define STEP 20 /* step size */ /* print Fahrenheit-Celsius table */ main() { int fahr; for (fahr = LOWER; fahr <= UPPER; fahr = fahr + STEP) printf("%3d %6.1f\n", fahr, (5.0/9.0)*(fahr-32)); }

19


Output preprocessore „ „

„

gcc -E fahr4.c –o fahr4.i Esegue solo lo step di preprocessore del compilatore (ricordate?) e produce il file fahr4.i Output (la parte superiore contiene stdio.h)

… main() { int fahr; for (fahr = 0; fahr <= 300; fahr = fahr + 20) printf("%3d %6.1f\n", fahr, (5.0/9.0)*(fahr-32)); }

Lettura e scrittura di caratteri

„

Impariamo a realizzare semplici “filtri” Programmi che leggono una sequenza di caratteri e producono in output una sequenza di caratteri

„

c=getchar()

„

„

„

Legge un carattere dal canale standard di input

putchar(c) „

Scrive il carattere c sul canala standard di output

20


Copia di un file leggo un carattere; while(il carattere letto non è il carattere di fine file) { stampo il carattere; leggo il carattere successivo; }

„

In C (libreria stdio.h) il carattere di fine file è rappresentato mediante EOF

Copia di un file - Implementazione #include <stdio.h> main() { int c; c = getchar(); while (c != EOF) { putchar(c); c = getchar(); } } „

Notate qualcosa di strano?

21


int c? „

Assegniamo un carattere a una variabile int? „

In realtà, in C esiste il tipo char „ „

„ „

„ „ „

tipicamente 8 bit di fatto è trattato come intero

Il C consente assegnazioni tra tipi eterogenei Cosa accade? „

int c=‘a’;

„

char c=‘a’;

0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 0 1 1 0 0 0 0 1

IlIlcodice codice ASCII ASCII didi‘a’ ‘a’èè97 97

(Le costanti char si sono rappresentate da caratteri tra singoli apici) printf(“%d”,’a’) stampa il valore 97 Come vedete.. è possibile fare di tutto… a vostro rischio e pericolo

Quindi… „ „

Quindi meglio dichiarare char c? Beh… il fatto è che EOF è una costante int che indica la fine del file „

„ „

In alcune architetture la dimensione dell’int potrebbe essere >255 Quindi è safer utilizzare int Anche se nella maggior parte dei casi char va bene

22


Versione compatta! #include <stdio.h> main() { int c; while ((c = getchar()) != EOF) putchar(c); }

Come lo usiamo? „

„

„

In una shell Unix, se invochiamo un comando seguito da <filename → il comando considera come canale di input standard il file Se invochiamo un comando seguito da >filename → il comando produce l’output su file ./copyfile <file1 >file2

23


Confronto (!=) ha precedenza su assegnazione (=) #include <stdio.h> main() { int c; while (c = getchar() != EOF) putchar(c); } „ „ „

„

Cosa accade? c = getchar() != EOF equivale a c = (getchar() != EOF) Il risultato di un’ espressione booleana è 0 se falso, 1 se vero… Quale sarà l’output del programma?

Ora provate voi… „

Scrivete un programma per il conteggio dei caratteri contenuti in un file…

24


Altro esercizio… „

Stampiamo i codici ASCII di tutti i caratteri contenuti in un file…

Stampiamo tutte le ‘a’ contenute in un file #include <stdio.h> main() { int c; while ((c = getchar()) != EOF){ if(c==‘a’) putchar(c); } }

25


Esercizio „ „

Contiamo le righe di un file Come? „

Ogni riga termina col carattere di ritorno a capo ‘\n’

Vettori (array) in C „

Dichiarazione array: „

„

Esempio: „

„

„

tipo identificatore[dimensione] int ndigit[10]

Come in Java l’accesso agli elementi del vettore avviene mediante indici interi ndigit[0], ndigit[1], … , ndigit[9]

26


Esempio „

„

Contiamo cifre, spazi bianchi e altri caratteri in un testo Ci occorrono: „

Una variabile per contare gli spazi bianchi „

„

Una per contare gli altri caratteri „

„

int nwhite; int nother;

10 variabili per contare 0, 1,…9, „ „

Beh, un vettore di 10 interi… int ndigit[10];

Codice… #include <stdio.h> main() { int c, i, nwhite, nother; int ndigit[10]; nwhite = nother = 0; for (i = 0; i < 10; ++i) ndigit[i] = 0; while ((c = getchar()) != EOF) if (c >= '0' && c <= '9') ++ndigit[c-'0']; else if (c == ' ' || c == '\n' || c == '\t') ++nwhite; else ++nother; printf("digits ="); for (i = 0; i < 10; ++i) printf(" %d", ndigit[i]); printf(", white space = %d, other = %d\n", nwhite, nother); }

27


Inizializziamo le variabili

nwhite = nother = 0; for (i = 0; i < 10; ++i) ndigit[i] = 0; „ „

L’inizializzazione è fondamentale in C A differenza di Java, l’inizializzazione a zero non è garantita!

Leggiamo I caratteri fino alla fine del file while ((c = getchar()) != EOF) if (c >= '0' && c <= '9') ++ndigit[c-'0']; else if (c == ' ' || c == '\n' || c == '\t') ++nwhite; else ++nother; „

„ „

„

if (c >= '0' && c <= '9') restituisce true se il carattere è compreso tra 0 e 9 C-’0’ vale 0 se c==‘0’, 1 se c==‘1’, etc. Quindi ndigit[c-’0’] punta all’elemento del vettore corrispondente alla cifra ++ndigit[c’-0’] incrementa il numero di cifre… „ Che differenza c’e’ tra ++ndigit[c-’0] e ndigit[c-’0]++?

28


Infine.. „

Stampiamo il risultato:

printf("digits ="); for (i = 0; i < 10; ++i) printf(" %d", ndigit[i]); printf(", white space = %d, other = %d\n", nwhite, nother);

Object-oriented programming… „

Avete studiato Java „ „

Linguaggio OO Il funzionamento di un programma avveniva mediante scambio di messaggi tra oggetti op

op

op

obj

obj obj

op

op op

obj obj

op

29


Linguaggio procedurale… „

C è un linguaggio procedurale „

„

„

Il programma è costituito da un insieme di unità funzionali dette funzioni Funzioni in Fortran, procedure in Pascal

Una funzione: „ „

riceve zero o piu’ parametri in ingresso Esegue un task specificato da una sequenza di statement (come nel caso di un metodo) „

„

Eventualmente invocando altre funzioni

Infine, termina „ „

Eventualmente, ritornando un risultato in uscita Eventualmente, modificando i parametri in ingresso

Programmazione procedurale

bar() foo() main()

fun()

ff()

30


Esempio #include <stdio.h> Dichiarazione funzione power

int power(int m, int n);

Definizione funzione main main() { int i; for (i = 0; i < 10; ++i) printf("%d %d %d\n", i, power(2,i), power(-3,i)); return 0; }

int power(int base, int n) { int i, p; p = 1; for (i = 1; i <= n; ++i) p = p * base; return p; }

Definizione funzione power

Call graph

power() main()

printf()

31


Definizione funzione tipo_ritorno nome_funzione(parametro1, parametro2,…) { statement… } „

Se ometto tipo_ritorno, si assume che sia int

„

Una funzione potrebbe non avere tipo di ritorno

„

„

„

Infatti main ritorna int…

In tal caso come dovrei dichiarare la funzione?

Posso omettere i parametri tipo_ritorno funzione() { }

Dichiarazione funzione „

„

In C le funzioni devono essere dichiarate prima di poter essere usate Siccome power è definita dopo main, il compilatore non l’avrebbe trovata durante la compilazione di main „

„

„

Anche se tale dichiarazione è opzionale nei compilatori ANSI 99 Warning visibili solo con -Wall

Quindi, è necessaria una dichiarazione „ „

tipo_ritorno nome_funzione(lista_parametri); Nota anche come prototipo della funzione

32


Prototipo funzione „

„

„ „

Lista parametri può essere tipo1 nome1, tipo2 nome2… ..oppure è lecito anche scrivere tipo1, tipo2.. e.g. int power(int, int) Ma è meno comprensibile

Return „

Sintassi „ „

return espressione; return; „

„

Non ritorna nulla…

Anche la funzione main può ritornare un valore „ „ „

Infatti è definita come funzione con tipo di ritorno int Valore usato dal sistema operativo Diverso da zero → codice di errore

33


Passaggio parametri per valore „

„

Parametri passati alle funzioni tramite variabili provvisorie Possono essere usate come variabili locali nella funzione „

„

„

E quindi modificate

Ma la variabile passata nella funzione chiamante resta inalterata Vi sono eccezioni „

„

Quando passo un vettore, passo l’indirizzo del primo elemento Le vedremo in seguito

Passaggio parametri - esempio #include <stdio.h> int fact(int n); main() { int i; for (i = 0; i < 5; ++i) printf("%d e' il fattoriale di %d\n", fact(i),i); return 0; } „

int fact(int n) { int result=1; while(n>0) { result*=n; n--; } return result; }

„

„

i viene stampato dopo aver invocato fact Ma il parametro n è decrementato dentro fact No problem, il valore di i non cambia in main!

34


Vettori di caratteri „ „ „

A differenza di Java il C non ha un tipo stringa Le stringhe sono trattate come array di caratteri char msg[10]; /*array di caratteri, lunghezza 10*/ C

„

I

A

O

char [] = “Ciao Mondo” /* Inizializzazione con una stringa costante */ „ Notare l’assenza di dimensione

Carattere di fine stringa „

„

„

„

„

Molte funzioni richiedono stringhe (array di caratteri) come input Problema: come facciamo a conoscere la lunghezza della stringa? Non esiste una funzione che ci dica la lunghezza di un array (come length in Java!) Inoltre, quando accedo ai singoli elementi, C non mi proibisce di andare oltre il limite!

→ Per convenzione, quando creiamo una stringa in C aggiungiamo un carattere di terminazione ‘\0’ al termine dell’array C

„

I

A

O

\0

Quando assegniamo una costante stringa a un array ciò avviene automaticamente

35


Stampa di una stringa… „

„ „ „ „

#include<stdio.h> main(){ char str[] = "Ciao Mondo!"; printf("%s\n",str); }

Esercizio „

Scriviamo un programma che calcoli la lunghezza di una stringa

36


Introduzione al c