Linguaggio C 3
Linguaggio C 3
Caratteristiche principali:
• Elevato potere espressivo:
• Tipi di dato primitivi e tipi di dato definibili dall’utente
• Strutture di controllo (programmazione strutturata,
funzioni e procedure)
Parole chiave:
auto break case const
continue default do double
else enum extern float
for goto if int
long register return short
signed sizeof static struct
switch typedef unsigned void
volatile while
/* questo e‘
un commento
dell’autore */
Caratteri:
Insieme dei caratteri disponibili (e‘ dipendente dalla
implementazione). In genere, ASCII esteso (256 caratteri). Si
indicano tra singoli apici:
’a’ ’A’
Caratteri speciali:
newline \n
tab \t
backspace \b
form feed \f
carriage return \r
codifica ottale \OOO con O cifra ottale 0-7
\041 è la codifica del
carattere !
\' \\ \" \0 (carattere nullo)
Esempi:
printf("Prima riga\nSeconda riga\n");
printf("\\\"/");
Prima riga
Seconda riga
\"/
2 byte 4 byte
base decimale 12 70000, 12L
base ottale 014 0210560
base esadecimale 0xFF 0x11170
Numeri reali
Varie notazioni:
<identificatore>::=<lettera>{<lettera>|<cifra>}
<main> ::=
main() { <parte-dichiarazioni> <parte-istruzioni> }
Formalmente:
scanf("%d%d",&X,&Y);/*p. istruzioni*/
printf("%d",X+Y);
}
Dati:
I dati manipolati da un programma possono essere classificati in:
Operazioni:
Istruzione di assegnamento: (variabile come astrazione della cella
di memoria)
<identificatore-variabile> = <espressione>;
scanf(<stringa-controllo>,<sequenza-elementi>);
printf(<stringa-controllo>,<sequenza-elementi>);
char C ; /* carattere */
Assegnamento:
<identificatore-variabile> = <espressione>
Esempio:
int a;
...
a=100;
V
#include <stdio.h>
main()
{
/* programma che letto un numero a
terminale stampa il valore
della circonferenza del cerchio
con quel raggio */
float X, Y;
scanf("%f",&X);
Y = 2*3.14*X;
printf("%f",Y);
}
#include <stdio.h>
main()
{
/* programma che, letto un numero a
terminale stampa il valore della
circonferenza del cerchio con quel raggio
*/
scanf("%f",&X);
Y = 2*pigreco*X;
printf("%f",Y);
}
In C si possono utilizzare:
tipi di dato
scalari strutturati
• char (caratteri)
• int (interi)
• float (reali)
• double (reali in doppia precisione)
Qualificatori e Quantificatori
+ E` possibile applicare ai tipi primitivi dei quantificatori e dei
qualificatori:
int X; /* X e’ rappresentato da 16
bit */
long int Y; /*Y -> 32 bit */
Ad esempio:
se il numero n di bit a disposizione per la rappresentazione di un
intero è 16, allora il dominio rappresentabile è composto di:
Operatori logici:
si applicano ad operandi di tipo int e producono risultati interi
appartenenti all'insieme {0,1} (valori logici). In particolare
l’insieme degli operatori logici e`:
a b a&&b a||b !a
falso falso falso falso vero
falso vero falso vero vero
vero falso falso vero falso
vero vero vero vero falso
37 / 3 ù 12
37 % 3 ù 1
7<3 ù 0
7 >=3 ù 1
0 || 1 ù 1
0 || -123 ù 1
12 && 2 ù 1
0 && 17 ù 0
!2 ù 0
Overloading:
Il C (come Pascal, Fortran e molti altri linguaggi) operazioni primitive
associate a tipi diversi possono essere denotate con lo stesso
simbolo (ad esempio, le operazioni aritmetiche su reali od interi).
Operatori aritmetici:
+, -, *, /, ++, -- si applicano a operandi reali e producono
risultati reali
Operatori relazionali:
hanno lo stesso significato visto nel caso degli interi:
==, != uguale, diverso
<, >, <=, >=, minore, maggiore etc.
(x / y) *y == x
Ad esempio:
‘a’ ‘b’ ‘A’ ‘0’ ‘2’
Operatori relazionali:
==,!=,<,<=,>=,> per i quali valgono le stesse regole viste
per gli interi
Ad esempio:
char x,y;
x<y se e solo se codice(x) < codice(y)
Operatori aritmetici:
sono gli stessi visti per gli interi.
Operatori logici:
sono gli stessi visti per gli interi.
Regola adottata in C:
• sono eseguibili le espressioni eterogenee in cui tutti i tipi
referenziati risultano compatibili (cioe`: dopo l’applicazione della
regola automatica di conversione implicita di tipo del C risultano
omogenei ).
• non sono eseguibili le espressioni eterogenee se tutti i tipi
referenziati risultano non compatibili (cioe` restano eterogenei
anche dopo l’applicazione della regola automatica di conversione
implicita di tipo del C).
int < long < unsigned< unsigned long < float < double < long double
• passo 2:
tmp / r
• tmp viene convertito nel double corrispondente
• viene applicata la divisione tra reali
ù risultato reale
istruzioni
SEMPLICI STRUTTURATE
<istruzione-assegnamento>::=
<identificatore-variabile> = <espressione>
Ad esempio:
int A, B;
A=20;
B=A*5;
Esempio:
int x;
char y;
double r;
main()
/* intestazione programma */
{
/* segue parte dichiarazioni */
/* parte dichiarazioni variabili */
int X,Y;
unsigned int Z;
float SUM;
/* segue parte istruzioni */
X=27;
Y=343;
Z = X + Y -300;
X = Z / 10 + 23;
Y = (X + Z) / 10 * 10;
/* qui X=30, Y=100, Z=70 */
X = X + 70;
Y = Y % 10;
Z = Z + X -70;
SUM = Z * 10;
/* qui X=100, Y=0, Z=100 , SUM=1000.0*/
}
I tipi scalari vengono inizializzati con una sola espressione che puo`
essere racchiusa tra una coppia di { }.
Esempio:
int x = {10};
char y = ‘a’;
double r = 3.14*2;
Espressioni Aritmetiche:
A seconda del tipo degli operandi, restituiscono valore intero
oppure reale.
int A=10;
Ad esempio:
int A=10, B;
char C=’a’;
int i, j, k;
k = 5;
i = ++k; /* i = 6, k = 6 */
j = i + k++; /* j=12, i=6,k=7 */
j = i + k++; /*equivale a:
j=i+k; k=k+1;*/
k = 5;
j = ++k + k++; /* j=12,k=7 */
Espressioni logiche:
Sono ottenute mediante gli operatori di:
• complemento (not) !
• congiunzione (and) &&
• disgiunzione (or) ||
{vero, falso}
A B A && B A || B !A
_______________________________________________
falso falso falso falso vero
falso vero falso vero vero
vero falso falso vero falso
vero vero vero vero falso
Proprieta‘:
!! A = A (idempotenza)
A || falso = A
A && vero = A
(A && B) && C = A && (B && C)
(A || B) || C = A || (B || C)
(A && B) || C = (A || C) && (B || C)
(A || B) && C = (A && C) || (B && C)
Leggi di De Morgan:
! (A && B) = (! A) || (! B)
! (A || B) = (! A) && (! B)
a+b*c
equivale sempre a
a + (b * c)
a+b+c
equivale sempre a
(a + b) + c
A<=20 || A>=40
! (B=A*2)
A<=B && A<=V
A>=B && A>=V
! (A>=B && A<=V)
! (A>=B) || !(A<=V)
Soluzioni:
A<=20 || A>=40 ù vero {A<20, short cut}
! (B=A*2) ù falso {B=34=17*2}
A<=B && A<=V ù falso {A>V}
A>=B && A>=V ù falso {A<B}
! (A<=B && A<=V) ù vero
! (A>=B) || !(A<=V) ù vero
/ Esercizio:
Determinare, applicando le leggi di De Morgan, se le seguenti
espressioni sono equivalenti:
! (A && B && C) (! A) or (! B) || (! C)
! (! A && ! B) A && B
! (! A || ! B) A && B
! (! A || ! B) A || B
Soluzioni: Nell’ordine: si‘, no, si‘ no.
• Input/Output a caratteri
• Input/Output a stringhe di caratteri
• Input/Output con formato
a 7 1 3.7 b 57 * c 6
testina fine
lettura linea fine file
(EOF)
(ctrl-Z)
Il formato stabilisce:
• come interpretare la sequenza dei caratteri immessi
dal dispositivo di ingresso (nel caso della lettura)
• con quale sequenza di caratteri rappresentare in
uscita i valori da stampare (nel caso di scrittura)
Lettura: scanf
E` una particolare forma di assegnamento: la scanf assegna i
valori letti alle variabili specificate come argomenti (nell'ordine di
lettura).
scanf(<stringa-formato>, <sequenza-variabili>);
printf(<stringa-formato>,<sequenza-elementi>)
Ad esempio:
int X;
float Y;
printf("%d%f", X*X,Y);
scanf("%d",&k);
printf("Quadrato di %d: %d",k,k*k);
}
carattere singolo %c
stringa di caratteri %s
puntatori (indirizzi) %p
Caratteri di controllo:
newline \n
tab \t
backspace \b
form feed \f
carriage return \r
scanf("%c%c%c%d%f", &c1,&c2,&c3,&i,&x);
ABC 3 7.345
le variabili
char c1 ’A’
char c2 ’B’
char c3 ’C’
int i 3
float x 7.345
char Nome=’F’;
char Cognome=’R’;
printf("%s\n%c. %c. \n\n%s\n",
"Programma scritto da:",
Nome,Cognome,"Fine");
ù viene stampato:
Fine
main()
{
float x;
int ret, i;
char name[50];
printf("Inserisci un numero
decimale, ");
printf("un floating ed una stringa
con meno ");
printf("di 50 caratteri e senza
bianchi");
ret = scanf("%d%f%s",&i,&x,name);
printf("%d valori letti %d %f %s",
ret, i, x, name);
}
main()
{
/*dichiarazione dati */
/* leggi i dati di ingresso */
/*calcola l’orario di arrivo */
/*stampa l’orario di arrivo */
}
Codifica:
Come dati occorrono tre variabili intere per l’orario di partenza ed una
variabile intera per i secondi di volo.
/*definizione dati */
unsigned int Ore, Minuti, Secondi;
long unsigned int TempoDiVolo;
main()
{
const float conv= 100.0/30.0;
int voto1, voto2, voto3;
float v1c, v2c, v3c, media;
/* Parte 1: Acquisizione dei dati */
printf(“Immetti il primo voto: “);
scanf(“%d”, &voto1);
printf(“\nImmetti il secondo voto: “);
scanf(“%d”, &voto2);
printf(“\nImmetti il terzo voto: “);
scanf(“%d”, &voto3);
Idea di base:
Caratteristiche:
• Hanno un solo punto di ingresso ed un solo punto di uscita.
• Possono essere interpretate come una singola azione in una
computazione sequenziale.
• I programmi sono più leggibili
I1
I2
I3
In
SULQWI³,QVHULVFLGXHQXPHUL´
^
VFDQIGG ; <
SULQWIG;<
`
Istruzione if:
if (<espressione>)
<istruzione1>
else
<istruzione2>;
(!=0) (==0)
espressione
Istruzione1 Istruzione2
#include <stdio.h>
main()
{
int primo,secondo;
scanf("%d%d",&primo,&secondo);
if (primo>secondo)
printf("%d",primo);
else printf("%d",secondo);
}
Esempio: if
/* Programma che calcola le radici di
un’equazione di secondo grado*/
#include <stdio.h>
#include <math.h> /*lib. matematica*/
main()
{
int a,b,c;
float d,x1,x2;
scanf("%d%d%d",&a,&b,&c);
if ((b*b) < (4*a*c))
printf("%s","radici complesse");
else
{
printf("%d%d%d",a,b,c);
d=sqrt(b*b-4*a*c);
x1=(-b+d)/(2*a);
x2=(-b-d)/(2*a);
printf("%f%f",x1,x2);
};
}
scanf("%d%d%d%\n",&A1,&B1,&C1);
scanf("%d%d%d%\n",&A2,&B2,&C2);
XN = (C1*B2 - C2*B1);
D = (A1*B2 - A2*B1);
YN = (A1*C2 - A2*C1);
if (D == 0)
{if (XN == 0)
printf("sist. indeterm.\n");
else
printf("Nessuna soluz.\n");
}
else
{X= XN/D;
Y= YN/D;
printf("%f%f\n",X,Y);
}
}
if (<e1>)
if (<e2>)
<i1>;
else
<i2>;
(==0) (!=0)
e1
(==0) (!=0)
e2
i2 i1
if (n > 0)
{ if (a > b) n = a; }/*n>0 && a>b */
else
n = b; /* n <= 0 */
Prima specifica:
main()
{
/*dichiarazione dati */
/* leggi le lunghezze dei lati */
/*se triangolo, stampane il tipo */
}
/*dichiarazione dati */
unsigned int primo,secondo,terzo;
Switch:
switch (<EspressioneIntegralType>)
{
case <costante1>: <blocco1>; [break;]
case <costante2>: <blocco2>; [break;]
...
case <costanteN>: <bloccoN>; [break;]
[default: <bloccoDiDefault>;]
}
Significato:
Se l’espressione ha un valore che corrisponde ad una costante (per
esempio <costante1>), si esegue il <blocco1> e tutti i blocchi dei rami
successivi.
Ramo di default:
E` possibile specificare un'etichetta default: essa viene eseguita per
qualunque valore ritornato da selettore.
In pratica, consente di utilizzare una “alternativa” che viene eseguita
se il valore dell'espressione non corrisponde ad alcuna etichetta.
#include <stdio.h>
#define GENNAIO 1
#define FEBBRAIO 2
#define MARZO 3
#define APRILE 4
......
#define OTTOBRE 10
#define NOVEMBRE 11
#define DICEMBRE 12
main()
{
...
switch (mese)
{
case GENNAIO: giorni = 31; break;
case FEBBRAIO:
if (bisestile) giorni = 29;
else giorni = 28;
break;
case MARZO: giorni = 31; break;
...
case DICEMBRE: giorni = 31;
}
switch (mese)
{
case FEBBRAIO:
if (bisestile) giorni = 29;
else giorni = 28;
break;
case APRILE: giorni = 30; break;
case GIUGNO: giorni = 30; break;
case SETTEMBRE: giorni = 30; break;
case NOVEMBRE: giorni = 30; break;
default: giorni = 31;
}
3a soluzione:
switch (mese)
{
case FEBBRAIO:
if (bisestile) giorni = 29;
else giorni = 28;
break;
case APRILE:
case GIUGNO:
case SETTEMBRE:
case NOVEMBRE: giorni = 30; break;
default: giorni = 31;
}
#include <stdio.h>
#define GENNAIO 1
#define FEBBRAIO 2
#define MARZO 3
......
#define OTTOBRE 10
#define NOVEMBRE 11
#define DICEMBRE 12
main()
{
int g1,g2;
int m1,m2;
int a1,a2;
int m, durata;
/* acquisizione dei dati */
printf(“Dammi la data (giorno/mese/anno): “):
scanf(“%d/%d/%d”,&g1,&m,&a1);
m1=m;
#include <stdio.h>
main()
{
int A, B;
char op;
Istruzione while:
while (<espressione>)
<istruzione>;
(==0) (!=0)
Espressione
Istruzione
/* Media di n voti */
#include <stdio.h>
main()
{
int sum,voto,N,i;
float media;
/* Media di n voti*/
#include <stdio.h>
main()
{
int sum,voto,N,i;
float media;
INIZIO
READ:
X,Y
Z:=0
SI
X=0
NO
ciclo
X:=X-1
Z:=Z+Y
WRITE:
Z
FINE
printf(“Dammi i fattori:”);
scanf("%d%d",&X,&Y);
Z=0;
while (X!=0)
{ /* corpo ciclo while */
Z=Z+Y;
X=X-1;
}
printf("%d",Z);
}
/ Esercizio:
Si legga un numero naturale N. Stampare una volta il numero 1,
due volte il numero 2,..., N volte il numero N.
• Dominio di ingresso (0,1,2,...,N)
• Dominio di uscita ((), (1), (1,2,2),(1,2,2,3,3,3)...).
LEGGI:
N
I:=1
SI
I>N
NO
J:=1
STAMPA:
I
J:=J+1
NO
J>I
SI
I := I + 1
FINE
printf(“dammi N:”);
scanf("%d",&N);
I=1;
while (I<=N)
{ /* corpo ciclo esterno */
printf(“Prossimo valore:”);
printf("%d",I);
J=1;
while (J<I)
{ /* corpo ciclo interno */
printf("%d",I);
J=J+1;
}
I=I+1;
}
}
/* Numero primo */
#include <stdio.h>
#include <math.h>
#define true 1
#define false 0
main()
{
int N, I;
float N1;
int primo;
scanf("%d",&N);
N1=sqrt(N);
I=2;primo=true;
while ((I<=N1) && (primo==true))
{if (((N / I) * I) == N)
{primo=false;}
else I=I+1; }
if (primo==true)
printf("numero primo");
else printf("numero non primo");
}
• fattoriale(0) = 1
• fattoriale(N) = N * (N-1)*...*1=fattoriale(N-1)*N
scanf("%d%d",&X,&Y);
Resto=X;
Quoz=0;
while (Resto >= Y)
{ Quoz=Quoz+1;
Resto=Resto-Y; }
printf("%d%s%d%s%d%s%d",
X," diviso ", Y, " = ", Quoz,
" resto ", Resto);
}
Istruzione do:
do
<istruzione>
while (<espressione>);
somma=0; j=1;
while (j <= n)
{ somma = somma + j; j++; }
S1
... do
S1;
S2;
Sn ...
Sn
while Espressione
true
Espressione
false
Con il while:
Car=’ ’;
while (Car==’ ’)
scanf("%c", &Car);
for è equivalente a:
<espressione1>; /* Inizializzazione */
while (<espressione2>) /* Condizione di
Ripetizione */
{
<istruzione>;
<espressione3>; /* InizioNuovoCiclo */
}
somma = 0; /* while */
j = 1;
while (j <= n)
{
somma=somma+j;
j++;
}
con il for:
somma = 0; /* for */
for(j=1;j<=n;j++)
somma = somma + j;
printf(“Dammi N:”);
scanf("%d",&N);
F=1;
for (I=2,I <= N, I++)
{ F=F*I;
I=I+1; }
printf("%s%d","Fattoriale: ",F);
}
Istruzione break:
L’istruzione break provoca l’uscita immediata dal ciclo (o da
un’istruzione switch) in cui è racchiusa
false true
Condizione
Blocco di
Istruzioni
break
Esempio continue:
for (i = N; i > 0; i – – )
{
/* Salta alla prossima ripetizione
se N è multiplo di i */
if (N % i) continue;
/* Esci dal ciclo se i vale 55 */
if (i == 55) break;
...
}
goto label
...
goto errore;
...
errore: ...
...
Usare il goto solo nei rari casi in cui il suo uso rende più leggibile
il codice - ad esempio:
• per uscire dall'interno di strutture molto nidificate
• per convergere in caso di errore, in un unico punto da punti
diversi del programma
Operatore condizionale:
?: condizione ? parteVera : parteFalse
• la parteVera viene valutata solo se la condizione è verificata
(valore diverso da 0)
• la parteFalse viene valutata solo se la condizione non è
verificata (valore uguale a zero)
x = (y != 0 ? 1/y : INFINITY);
k = a < b ? a : b; /* assegna il minore */
k += j /* equivale a k = k + j */
k *= a + b /* equivale a k = k * (a + b) */