Il linguaggio C
Notate che ...
1
Il C è un linguaggio a blocchi
int main (void) {
blocco
}
2
Il C è un linguaggio a blocchi (2)
Non è possibile mischiare dichiarazioni e
comandi !
int main (void) {
Dichiarazione di variabili
locali
Comandi
}
3
Variabili non inizializzate
Le variabili non inizializzate non producono
nessun errore!!!!
int main (void) {
/* ed esempio …. */
int min, max, out;
min = max * out;
…
}
Controllate sempre di aver inizializzato le variabili
prima del loro uso!
4
E se non me lo esegue?
Se avete cercato di eseguire a.out e non ci
riuscite:
$$ a.out
5
E se non me lo esegue?(2)
Se avete cercato di eseguire un file eseguibile
e non ci siete riusciti:
$$ a.out
bash:command not found
Significa che la variabile di ambiente PATH
non contiene la directory corrente quindi
usate il path completo
$$ ./a.out
6
E se non me lo esegue?(3)
Se avete cercato di eseguire un file eseguibile e
non ci siete riusciti:
$$ a.out
bash:command not found
Per settare il PATH
– bash
$$ export PATH=$PATH:.
– csh e tcsh
$$ setenv PATH=${PATH}:.
7
Informazioni sulle funzioni di
libreria
Usare la sezione 3 dei manuali in linea, es:
$$ man 3 printf
8
Informazioni sulle funzioni di
libreria (2)
NAME
printf
SYNOPSIS
#include <stdio.h>
int printf(const char* format,…);
DESCRIPTION
…… cosa fa
EXAMPLES
…… esempi di uso
SEE ALSO
… … altre funzioni simili
9
Le FAQ
Alla pagina
www.di.unipi.it/~susanna/LPS/FAQ.htm
Trovate le domande e risposte più comuni
10
Il linguaggio C
Tipi di dato, costanti, operatori
(parte1)
11
I tipi di dato primitivi
• Interi : short, int, long,
– 2,4,8,16 byte (dipende dalla implementazione)
– segnaposto
• %d rappresentazione decimale
• %x,%o rappresentazione esadecimale o ottale
– costanti intere : 1, -2, 4565
– La funzione predefinita sizeof() fornisce
la lunghezza in byte di un qualsiasi tipo o
variabile C
• es. sizeof(int)
12
I tipi di dato primitivi (2)
• Caratteri :
– char, 1 byte, cod. ASCII, segnaposto %c
– costanti carattere : `a`, `b`, `c`
– i caratteri sono visti da C come interi un po’
speciali : è possibile operare sui caratteri con le
normali operazioni su interi
– es:
char c = `a`;
c++;
putchar(c); /* ???? */
13
I tipi di dato primitivi (3)
• Reali :
– float, double, long double
– 4,8,16 byte,
– rappresentazione in virgola mobile
– segnaposto :
• stampa (es. printf()) %f, %lf
• lettura (es. scanf()) %f (float) , %lf (double),
%Lf (long double),
14
I tipi di dato primitivi (4)
• Libreria matematica (libm)
– fornisce tutte le più comuni operazioni
matematiche per operare sui reali
• es. sqrt()
– per utilizzarla includere il file
• #include <math.h>
– compilare con
gcc … … … -lm
effettua il link esplicito della libreria
15
I tipi di dato primitivi (5)
• Non esistono i tipi byte e bool !!!
• Le stringhe sono rappresentate come array
di caratteri.
• signed/unsigned
– modificatore per i tipi interi e caratteri
– permette di scegliere fra la rappresentazione di
soli interi positivi (es 0-255 su un byte) o quella
in complemento a due (es -128,+127)
• es. unsigned int, signed char
16
I tipi di dato primitivi (6)
• limits.h
– contiene macro che definiscono i massimi ed i
minimi numeri rappresentabili per tutti i tipi
– es. INT_MIN, INT_MAX
– per utilizzarli includere il file limits.h
17
I tipi di dato primitivi (7)
• Conversioni fra tipi diversi :
– sono automatiche in C
– posso scrivere espressioni con operandi di tipo
diverso
int a=0; float b, r=3.1;
b = a + r;
– di solito viene convertito tutto nel tipo più
accurato, le regole p.115 nel testo KP
– conversioni esplicite
r =(float) a / b
18
Il linguaggio C
Funzioni
19
Funzioni C
• Le funzioni C sono l’unico modo per
strutturare i programmi e non si possono
annidare
• Non esistono le procedure
• Non esistono i metodi
• Dichiarazione di funzioni :
– descrive il prototipo della funzione ovvero:
nome della funzione, il tipo del valore restituito
ed il tipo di tutti gli argomenti utilizzati
20
Funzioni C (2)
• Dichiarazione di funzioni :
– es: prototipo della funzione di somma di due
interi
int somma (int, int);
oppure
int somma (int x, int y);
x, y sono inutili, ma vengono convenzionalmente
specificati per documentazione
21
Funzioni C (3)
• Definizione di funzioni :
– la definizione di una funzione è divisa fra :
• una intestazione (head) che fornisce il prototipo
della funzione a i nomi per i parametri formali, ed
• un corpo (body) che specifica le azioni da compiere
– es:
int somma (int x, int y) {
return (x + y);
intestazione
}
22
Funzioni C (4)
• Definizione di funzioni :
– la definizione di una funzione è divisa fra
• una intestazione (head) che fornisce il prototipo
della funzione a i nomi per i parametri formali, ed
• un corpo (body) che specifica le azioni da compiere
– es:
int somma (int x, int y) {
return (x + y);
corpo
}
23
Funzioni C (5)
• La dichiarazione o la definizione di una
funzione deve sempre precedere il suo uso!
– Vedimo la tipica struttura di un programma C
(unico file):
24
Funzioni C (5.1)
/* direttive al preprocessore */
#include …
#define …
/* dichiarazioni di varibili globali*/
int k;
/* dichiarazione di funzioni (prototipi)*/
int somma (int x, int y);
int main (…) {… somma(4,5); … }
/* definizione di funzioni */
int somma (int x, int y) {….}
25
Esempio di funzione
#include <stdio.h>
int max (int a, int b);
int main (void){
printf(“Il massimo è %d \n”, max(10,2));
return 0;
}
int max (int a, int b) {
int tmp;
tmp = (a < b)? b : a
return tmp;
}
26
Funzioni C (6)
• Tutti i parametri sono passati per valore
– una copia viene messa sullo stack all’atto della
chiamata
– la copia viene rimossa qundo la funzione
termina e non è più accessibile
• Scope delle variabili:
– Il corpo di una funzione contiene le variabili
locali
• sono allocate sullo stack,
• sono accessibili solo a quella funzione
• perdono il valore fra un’invocazione e l’altra
27
Esempio di funzione (.1)
#include <stdio.h>
int max (int a, int b);
int main (void){
printf(“Il massimo è %d \n”, max(10,2));
return 0;
}
Parametri attuali
int max (int a, int b) {
copiati sullo stack
int tmp;
tmp = (a < b)? b : a
return tmp; /* definizione */
}
28
Esempio di funzione (.2)
#include <stdio.h>
int max (int a, int b);
int main (void){
printf(“Il massimo è %d \n”, max(10,2));
return 0;
}
Variabili locali
int max (int a, int b) {
sullo stack
int tmp;
tmp = (a < b)? b : a
return tmp; /* definizione */
}
29
Esempio di funzione: il frame (.3)
printf(“Il massimo è %d \n”,
max(10,2));
XX: return 0;
}
stack
stack
int max (int a, int b) {
int tmp;
tmp = (a < b)? b : a
return tmp;
}
30
Esempio di funzione: il frame (.4)
printf(“Il massimo è %d \n”,
max(10,2));
XX: return 0;
}
int max (int a, int b) {
int tmp;
tmp = (a < b)? b : a
return tmp;
}
stack
stack
2
10
XX
31
Esempio di funzione: il frame (.5)
printf(“Il massimo è %d \n”,
max(10,2));
XX: return 0;
}
int max (int a, int b) {
int tmp;
tmp = (a < b)? b : a
return tmp;
&tmp
}
stack
stack
2
10
XX
676186815
32
Esempio di funzione: il frame (.6)
printf(“Il massimo è %d \n”,
max(10,2));
XX: return 0;
}
int max (int a, int b) {
int tmp;
tmp = (a < b)? b : a
return tmp;
&tmp
}
stack
stack
2
10
XX
10
33
Esempio di funzione: il frame (.7)
printf(“Il massimo è %d \n”,
max(10,2));
XX: return 0;
}
stack
stack
int max (int a, int b) {
int tmp;
tmp = (a < b)? b : a
return tmp;
}
34
Funzioni C (7)
• Scope delle variabili (cont.) :
– Le variabili globali sono variabili dichiarate al
di fuori delle funzioni
• sono accessibili all’interno di tutte le funzioni
• sono allocate nell’area dati e vengono deallocate
solo alla terminazione del programma
– Le globali sono sconsigliate a meno di casi
motivati!
• Devono essere sempre adeguatamente documentate
35
Esempio di funzione #2
/* un esempio di var globale */
#include <stdio.h>
int max (int a, int b);
int k = 0;
/* var globale */
int main (void){
printf(“Il massimo è %d \n”, max(10,2));
printf(“Il valore di k è %d \n”, k);
return 0;
}
int max (int a, int b) {
k = k + 1;
/* side effect */
return (a < b)? b : a ;
}
36
Esempio di funzione #2 (.1)
• Risultato esecuzione
> max
Il massimo è 10
Il valore di k è 1
37
Funzioni C (8)
• Scope delle variabili (cont.) :
– Le variabili statiche locali (static)
• sono accessibili all’interno della funzione che le
dichiara
• mantengono il valore fra una invocazione e l’altra
38
Esempio di funzione #3
/* un esempio di var statica */
#include <stdio.h>
int max (int a, int b);
int main (void){
printf(“Il massimo è %d \n”, max(10,2));
/*k non è più accessibile fuori da max*/
return 0;
}
int max (int a, int b) {
static int k = 0;
k++; printf(“Il valore di k è %d \n”,
k);
return (a < b)? b : a ;
}
39
Esempio di funzione #3 (.1)
• Risultato esecuzione (lo stesso di prima)
> max
Il valore di k è 1
Il massimo è 10
40
Funzioni C: commenti
• La nostra convenzione per i commenti per
dichiarazioni e definizioni
– usa le stesse categorie viste a Metodologie
Programmazione, con sintassi un po’ diversa
/* @description -- somma due interi
@param x -- significato del parametro
@require -- (opz) condizioni sui
parametri es. x positivo)
@return x -- descriz valore restituito
(if any)
@modify -- decrizione effetti su
variabili globali, array etc*/
41
Funzioni C: commenti (esempio)
/* @description -- somma due interi
@param a -- intero
@param b -- intero
@return x -- la somma
@modify -- incrementa k, globale*/
int max (int a, int b) {
k = k + 1;
return (a < b)? b : a ;
}
42
Funzioni C: commenti (esempio) (.1)
/* @description -- max di due interi
@param a -- intero
@param b -- intero
@return x -- la somma
@modify -- incrementa k, globale*/
int max (int a, int b) {
extern int k;
k = k + 1;
return (a < b)? b : a ;
}
43
Il linguaggio C
Tipi di dato, costanti, operatori
(parte2)
44
I valori booleani
• Rappresentazione dei valori booleani in C :
– non esiste il tipo bool!
– sono rappresentati con int
– 0 rappresenta FALSO, qualsiasi valore != 0
rappresenta VERO
• es. 456 viene interpretato come VERO
• es.
if (4) printf(“VERO”);
è un condizionale con condizione legale e sempre
vera, che quindi stampa sempre VERO sullo
schermo.
45
Gli operatori di confronto
• ==, !=, (uguale, diverso)
– definiti sui tipi base e sulle struct
– se usati con gli array confrontano solo il
puntatore al primo elemento
– lo stesso vale con le stringhe
• <, <=, >, >=
– definiti sui tipi base (numerici)
– per le stringhe si usano funzioni di libreria (es.
strcmp(), strncmp())
• restituscono sempre un valore di tipo int
46
Gli operatori booleani
• && (and), || (or), ! (not)
– valore : 0 se sono falsi e 1 se sono veri
– restituscono un valore di tipo int
• operatori bit a bit : & (and), | (or), ^ (xor),
<< (lshift), >> (rshift), ~ (complemento)
– es.
1 << 3 // maschera con 1 in terza posizione
a = a & ~ (1 << 3 ) // azzera il quarto bit di a
47
Es operatori bit-a-bit
•
a = a & ~ (1 << 3 )
0
0
0
0
7
6
5 4
0
0
0
1
3 2
1
0
48
Es operatori bit-a-bit (2)
•
a = a & ~ (1 << 3 )
0
0
0
0
0
0
0
1
0
0
0
0
1
0
0
0
49
Es operatori bit-a-bit (3)
•
a = a & ~ (1 << 3 )
0
0
0
0
0
0
0
1
0
0
0
0
1
0
0
0
1
1
1
1
0
1
1
1
50
Es operatori bit-a-bit (4)
•
a = a & ~ (1 << 3 )
0
1
0
1
1
1
0
1
1
1
1
1
0
1
1
1
51
Es operatori bit-a-bit (5)
•
a = a & ~ (1 << 3 )
0
1
0
1
1
1
0
1
1
1
1
1
0
1
1
1
1
52
Es operatori bit-a-bit (6)
•
a = a & ~ (1 << 3 )
0
1
0
1
1
1
0
1
1
1
1
1
0
1
1
1
0
1
53
Es operatori bit-a-bit (7)
•
a = a & ~ (1 << 3 )
0
1
0
1
1
1
0
1
1
1
1
1
0
1
1
1
0
1
0
1
0
1
0
1
Nuovo valore di a
Abbiamo azzerato il bit 3
54
Selezionare l’n-esimo bit di un intero
int bitn (int c, int n){
if (((1<<n) & c)!= 0)
return 1;
else
n
return 0;
0 1 0 1 1 1 0 1
}
1<<n
0
0
0
1
0
0
0
0
(1<<n) & c
0
0
0
1
0
0
0
0
55
Stampare i K bit meno significativi di
un intero
void bitstampa (int c){
int i;
for (i=0; i<K; i++)
if (bitn(c,K-1-i)!= 0)
printf(”1”);
else
printf(”0”);
}
56
Gli array
• Aggregati di variabili dello stesso tipo :
– dichiarazione (array statici):
0 1
int a[4];
1
3
2
3
posizione
7
8
valore
a[1]
– gli indici partono da 0
– non viene effettuato nessun controllo sugli
indici nell’accesso : se cerco di accedere a
a[15]il compilatore non dà errore ed in fase di
esecuzione il risultato dipende dal contenuto
della memoria adiacente ad a
57
Le stringhe
• Sono array di caratteri terminati da ´\0´
– dichiarazione :
char parola[8]=“mango”;
– permette di memorizzare una qualsiasi parola di
al più 7 caratteri (l’ottavo serve per il
terminatore)
– è inizializzata con la parola “mango”
– string.h fornisce tutte le più comuni
funzioni per manipolare stringhe
58
Le strutture (record)
• Aggregati di variabili di tipo diverso
– dichiarazione di una nuova struttura:
struct studente {
char nome[40];
char cognome[40];
double voto;
};
– dichiarazione di variabili di tipo struttura :
struct studente x;
struct studente classe[140];
59
Le strutture (record) (2)
• Ridenominazione tipi :
typedef tipo nome;
– es :
typedef int Intero;
Intero nome[40];
– es :
typedef char stringa40[41];
stringa40 nome;
60
Le strutture (record) (3)
• Ridenominazione tipi :
typedef struct {
char nome[40];
char cognome[40];
double voto;
} studente ;
– così si può eliminare struct dalle dichiarazioni
studente x;
studente classe[140];
61
Le strutture (record) (4)
• Ridenominazione tipi :
typedef struct studente {
char nome[40];
char cognome[40];
double voto;
} studente ;
Opzionale
(serve per i
tipi ricorsivi)
– così si può eliminare struct dalle
dichiarazioni
studente x;
studente classe[140];
62
Le strutture (record) (5)
• Accesso ai campi :
– tramite l’operatore punto (.)
– es :
studente x;
studente classe[140];
classe[i].nome = x.nome;
63
I tipi enumerati
• Rappresentano insiemi finiti:
– giorni: lunedi, martedi, …
– mesi: gennaio, febbraio, …
– bool: true, false.
• Associano un identificatore (costante)
ad ogni elemento dell’insieme
• Sono rappresentati con degli interi
– .. Ma il compilatore controlla che le funzioni
siano chiamate con il tipo giusto (type
checking)
64
I tipi enumerati (2)
• Esempio:
enum giorni {lun,mar,mer,gio,ven,sab,dom};
enum giorni x;
x = lun;
…
/* dichiarazione */
– Si può evitare di ripetere enum con un typedef
– I valori interi assegnati partono da 0 :
• lun == 0,mar == 1,mer == 2,…
65
I tipi enumerati (3)
• Esempio:
typedef enum {true = 1, false = 0} bool;
bool trovato;
trovato = false;
…
/* dichiarazione */
– Si possono scegliere i valori interi assegnati ad
ogni elemento
66
I tipi union
• Nei tipi union più valori di tipi diversi
condividono la stessa zona di memoria
– noti anche come record con varianti
– Esempio:
union numero {
int intero;
long double reale;
struct complex complesso;
};
– solo uno dei tre viene memorizzato ogni volta
67
I tipi union (2)
union numero {
int intero;
/* 4 byte */
long double reale; /* 8 byte */
struct complex complesso; /* 16 byte */
};
union numero n;
• … in memoria ...
&n
16 byte
68
I tipi union (3)
union numero {
int intero;
/* 4 byte */
long double reale; /* 8 byte */
struct complex complesso; /* 16 byte */
};
union numero n;
/* specifico come interpretare n */
n.intero = 5;
0 0 0 5
&n
Parte significativa
69
I tipi union (4)
• Uso tipico:
– in una struct che contenga (oltre alla union) un campo
‘tipo del valore’
typedef enum {INT,REAL,COMPLEX} numtyp;
struct numero {
numtyp tipo;
union {/* union anonima */
int intero;
long double reale;
struct complex complesso; } };
70
I tipi union (5)
• Uso tipico: (cont.)
struct numero x ;
…
switch (x.tipo) {
case INT : ….
x.intero = ...;
case REAL: ….
X.reale = ...;
case COMPLEX: ….
X.complesso = ...;
…..
71
Scarica

PPT