INFORMATICA Il linguaggio C
Premessa Fu creato agli inizi degli anni ’70 quale strumento per lo sviluppo del Sistema Operativo UNIX. Si è diffuso molto rapidamente e nel 1989 l’American National Standards Institute (ANSI) completava la definizione del linguaggio producendo il documento noto come  ANSI C , al quale fanno riferimento ormai tutti i compilatori per quel linguaggio. A differenza degli altri linguaggi ad alto livello consente un agevole accesso alla struttura hardware del sistema di elaborazione.
Caratteristiche Generali Il C è un linguaggio:  ad alto livello ... ma anche poco astratto strutturato ... ma con eccezioni fortemente tipizzato ogni oggetto ha un tipo semplice  (!?) poche keyword case sensitive maiuscolo diverso da minuscolo negli identificatori! portabile standardizzato   (ANSI)
Alfabeto Il  vocabolario  base del C è costituito dai seguenti simboli: tutte le lettere dell’alfabeto inglese maiuscole e minuscole: A÷Z,  a÷z le dieci cifre decimali  0 ÷   9 un insieme di caratteri speciali, tra cui: +  *  /  = < >   ( ) [ ] { } . ,   ; :  ” ? ! % # & ˜ ˆ
Identificatori Si riferiscono ad una delle entità del linguaggio: costanti variabili funzioni ecc. Iniziano con un carattere alfabetico oppure con “ _ ”  (underscore)  e possono contenere solamente caratteri alfabetici, cifre e “_” Il C standard prevede che solo i primi 31 caratteri dell'identificatore sono significativi, anche se possono essere usati nomi più lunghi.
Commenti Sono testi liberi inseriti all’interno del programma dal programmatore per descrivere cosa fa il programma. Non sono processati dal compilatore: servono al programmatore, non al sistema! Formato: Racchiuso tra i simboli:  /*  */ Non è possibile annidarli. Esempi: /* Questo è un commento corretto! */ /* Questo /*  risulterà un  */  errore */
Istruzioni Le istruzioni  devono essere scritte rispettando alcune regole sintattiche  e di punteggiatura.   L’istruzione deve sempre essere conclusa con un  ;  (punto e virgola). Si può scrivere più di un’istruzione per riga  purché ognuna sia conclusa col  ; . Un’istruzione può occupare più di una riga .
Parole chiave Riservate! Nel C standard sono 32 : auto double int struct break else long switch case enum register typedef char extern return union c onst float short unsigned continue for signed void default goto sizeof volatile do if static while
Struttura di un programma C Struttura generale: Direttive e parte dichiarativa  globale main ()   { Parte dichiarativa  locale Parte esecutiva }
Struttura di un programma C Tutti gli oggetti, con le loro caratteristiche, che compongono il programma devono essere preventivamente  dichiarati . main è la parola chiave che indica il punto di “ingresso” del programma quando viene eseguito dal S.O.; il suo contenuto è delimitato da parentesi graffe  { … }
Struttura di un programma C Parte dichiarativa  locale : elenco degli oggetti che compongono il  main   ognuno con le proprie caratteristiche. Parte esecutiva: sequenza di istruzioni , ovvero ciò che descriviamo con il diagramma di flusso oppure con lo pseudocodice! Ovvero le istruzioni vere e proprie!
Struttura di un programma C Programma minimo: main()  { } file  prova.c START STOP
I dati
Definizione dei dati In C, tutti i dati devono essere  dichiarati e definiti   prima di essere usati! Definizione di un dato : riserva spazio in memoria; assegna un nome. identifica gli operatori leciti su quel dato Richiede l’indicazione di: nome  (identificatore); tipo ; modalità di accesso  (variabile/costante).
Tipi Il tipo definisce l'insieme dei  valori  che possono essere assunti, la  rappresentazione interna  e l'insieme degli  operatori  che possono agire su quel dato.  Il linguaggio C richiede di definire il tipo dei dati e possiede regole rigide per la loro manipolazione ( tipizzazione forte  ). Permette inoltre al programmatore di definire nuovi tipi astratti. Contemporaneamente permette di “vedere” gli oggetti interni al calcolatore: i registri, la memoria, gli indirizzi (puntatori), ecc.
Tipi base (primitivi)  Sono quelli forniti direttamente dal C. Sono identificati da parole chiave! char caratteri ASCII; int interi (complemento a 2); float reali (floating point singola precisione); double reali (floating point doppia precisione). La dimensione precisa di questi tipi dipende dall’architettura (non definita dal linguaggio). char  = 8 bit sempre Attenzione:  le parole chiave dei tipi base vanno scritte in minuscolo!
INFORMATICA   Cenni sulla Rappresentazione dei dati
char Il tipo  char  (character)  definisce un carattere (attenzione:  un solo carattere !) espresso su 8 bit (1 byte) in codice ASCII. I valori sono interpretati come  numeri interi con segno su 8 bit  (-128  ÷ +127). Un carattere deve essere indicato tra apici, così: ‘ a’
int Il tipo  int  (integer)  definisce i numeri interi con segno.  La rappresentazione interna e l'intervallo dei valori   assunti dipende dal compilatore e dalla macchina usata.  Generalmente si tratta del complemento a 2 e i valori assunti sono compresi nell’intervallo -32768  ÷  32767   su 16 bit oppure, per le macchine a 32 bit, nell’intervallo  -2.147.483.648  ÷  2.147.483.647. Vanno indicati semplicemente così come siamo abituati a scriverli sulla carta, col loro valore (senza il punto decimale):  -2453
float e double Sia il  tipo  float  che il tipo  double  sono rappresentazioni di numeri reali (frazionari). Sono rappresentati secondo la notazione  floating-point , rispettivamente in singola   (32 bit) e doppia (64 bit) precisione.  I valori assunti (rappresentabili) sono: float   ±  3.4E+38  (7 cifre decimali) double   ±  1.7E+308  (17 cifre decimali) La rappresentazione  è normalmente riferita allo standard IEEE P754.
float e double I valori di tipo  float  o  double  vanno indicati con il punto decimale, ad esempio: 14.8743 E’ ammessa anche una notazione simile alla notazione scientifica con il carattere E al posto di 10, così: 0.148743E-02 In alternativa, si può ancora scrivere il numero senza punto decimale  ma seguito dal suffisso  F  oppure  f  (ad esempio,  10F ,  10f  e  10.0  sono equivalenti). Il compilatore concepisce questi valori sempre come di tipo  double .
Modificatori dei tipi base Sono previsti dei modificatori, identificati da parole chiave, da premettere ai tipi base: short long signed unsigned
short / long Il qualificatore  short  si applica al tipo  int  e impone che la rappresentazione degli interi sia su 16 bit (valori assunti: -32768  ÷  32767); il qualificatore  long  si applica sia al tipo  int  che al tipo  double ; long int  impone la rappresentazione degli interi su 32 bit (valori assunti: -2.147.483.648  ÷  2.147.483.647);  long double  forza la rappresentazione dei reali su 80 bit ( ±  1.7E+308 aumentando la precisione a 22 cifre decimali).
signed / unsigned I qualificatori  signed  e  unsigned   si applicano ai tipi  char  e  int .  signed  è ridondante e serve solo a ricordare che un valore è inteso con segno (ma per  int  e  char  è già così!);   unsigned  permette di estendere l'intervallo dei valori non-negativi.  Il tipo  unsigned char   può assumere valori nell'intervallo 0  ÷  255 e il tipo   unsigned int   valori nell'intervallo 0  ÷  65535. I qualificatori possono apparire da soli: nel qual caso si assume che sia   sottinteso il tipo  int . E’ lecito, ad esempio, il tipo  unsigned short  che viene interpretato come  unsigned short int , ecc.
Altri valori interi Per un dato intero, i valori di variabili e costanti possono anche essere espressi in  esadecimale  (specificati col prefisso  0x  oppure  0X , ad esempio,  0xFF = 255 10 ) oppure  ottale  (prefisso  0  (zero), ad esempio  0377 = 255 10 ); per il formato  long  si usa il suffisso  L  oppure  l  ( 255L  o  255l  esprimono entrambi un  long int  con valore  255 10 ); per l' unsigned  si usa il suffisso  U  oppure  u  ( 255U  e  255u  esprimono un  unsigned int  =  255 10  ). I suffissi  u  ed  l  possono apparire entrambi, con ovvio significato.
Valori speciali Il codice ASCII comprende alcuni caratteri non stampabili. Per rappresentarli viene utilizzata la  sequenza di   escape  ( backslash  seguito da un altro carattere). tabulatore vert. \v null \0 tabulatore orizz. \t esadecimale \x ddd return \r ottale \ ddd new line \n backslash \\ pagina nuova \f doppio apice \” backspace \b apostrofo \’ allarme \a Carattere Sequenza Carattere Sequenza
Tabella riassuntiva 1.7E ± 308 (16 cifre) double 1.7E ± 308 (20 cifre) long double 3.4E ± 38 (7 cifre)  float 0 ÷ 4.294.967.295   unsigned long, unsigned long int 0 ÷ 65535 unsigned int, unsigned short int 0 ÷ 255 unsigned, unsigned char, unsigned short 2.147.483.648  ÷  2.147.483.648 signed long,   signed long int 2.147.483.648  ÷  2.147.483.648 long, long int, -32768  ÷  32.767  signed short, signed short int -32768  ÷  32.767  short, short int,  signed short  -32768  ÷  32.767  int, signed ,  signed int  -128 ÷ 127  char, signed char Intervallo dei valori Tipo
Direttive Il C prevede che nel programma, oltre alle istruzioni,  possano esserci anche delle  direttive  che devono essere interpretate   ed eseguite dal compilatore stesso (inserzione di macro, compilazioni condizionate, inclusione di altri sorgenti, ecc.);    il compilatore C esegue una preelaborazione del programma,   detta  Preprocessing , per riconoscere ed eventualmente eseguire le   direttive ; le  direttive  si distinguono dalle istruzioni perché sono inserite sempre in righe individuali e iniziano con il carattere  #  seguito da una parola chiave; ad esempio: #include #define
Definizione di variabili Sintassi: < tipo >  < nome della variabile  >; Più in generale (definizioni multiple): < tipo >  < lista dei nomi delle variabil i  >; < nome >  :   l’identificatore che rappresenta il nome della variabile; < lista dei nomi delle variabili>  : lista di identificatori separati da  ,  (virgola).
Definizione di variabili Esempi: int x; char ch; long int x1 ,x2, x3; double pi; short int stipendio; long y,z; Usiamo nomi significativi! Esempi: int RitenuteOperate, StipendioBase; float OreLavorate; Esempi errati: float Ore Lavorate ;  /* c’è uno spazio  */  int Stip?base;  /* c’è un carattere speciale  */
Definizione di variabili E’ possibile “inizializzare” una variabile, ovvero attribuirgli un valore prima che venga utilizzata per la prima volta, in fase di dichiarazione della stessa. Esempio: int x = 24; char ch = ‘m’; double pi = 124.654;
Definizione di costanti Sintassi: const  < tipo >  < nome della costante > = < valore >; Esempi: const double pigreco =  3.14159; const char  separatore = ‘$’; const float aliquota = 0.2; Convenzione: Identificatori delle constanti tipicamente in MAIUSCOLO   (ma  è una convenzione!). const double PIGRECO = 3.14159;
La direttiva “define” E’ un'altra possibilità di definire valori  costanti  : si introduce un identificatore come sinonimo di una costante: #define identificatore  testo Deve comparire sempre in testa al programma, prima di  main() , e all'inizio della riga.   E’ elaborata dal  preprocessore  del compilatore, che sostituirà in tutto il programma, ovunque appare l'identificatore, il testo di cui è sinonimo.
La direttiva “define” Non essendo un'istruzione non termina con il punto e virgola.   Esempi: #define  PIGRECO  3.1415 #define  DOMENICA  7 #define  VERO  1 #define  Carattere  ‘p’
Stringa Definizione: sequenza di caratteri terminata dal carattere  NULL  (‘ \0 ’); non è un tipo di base del C. memorizzata in posizioni adiacenti di memoria. Formato: “ < sequenza di caratteri >“ Esempi: “ Ciao!” “ abcdefg\n”
Visibilità delle variabili Ogni variabile è definita all’interno di un preciso  ambiente di visibilità (scope). Variabili  globali definite  all’esterno  al  main   sono visibili da tutti i moduli. Variabili  locali definite  all’interno  del  main  (sono visibili solo all’interno del  main ); più in generale, definite all’interno di un blocco (sono visibili solo all’interno del blocco).
Struttura a blocchi In C è possibile aggregare gruppi di istruzioni in  blocchi  racchiudendole tra parentesi graffe; significato:  delimitazione di un ambiente di visibilità di “oggetti” (variabili). Esempio: { int a=2; int b; b=2*a; }  a  e  b  sono definite solo all’interno del blocco!
Visibilità delle variabili - Esempio n, x :  visibili in tutto il file a, b, c ,y :  visibili in tutto il main d, z :  visibili solo nel blocco  int n; double x; main()  { int a,b,c; double y; { int d; double z; } }
Le istruzioni
Assegnazioni Sintassi: < variabile > = < espressione > ; Non è un’uguaglianza ! Significato:  il risultato di < espressione > viene  assegnato  a < variabile >; < variabile >  e  < espressione >  d evono essere “compatibili” (ovvero dello stesso tipo); < variabile >  deve essere stata precedentemente definita! Esempio: int x; float y; x = 3; y = -323.9498;
Assegnazioni In realtà l’ assegnazione  (o  assegnamento ) non è un’istruzione (come accade in tutti gli altri linguaggi); il simbolo  =   è un  operatore  che assegna alla variabile che si trova a sinistra il valore calcolato sull’espressione di destra; nel caso più semplice l’espressione di destra è un semplice valore. Sono pertanto lecite assegnazioni “multiple”: < var 1 > = < var 2 > = < espressione > ;
Istruzioni di I/O Per ora consideriamo solo l’I/O interattivo, quello cioè che si realizza con tastiera e monitor. Sono disponibili diverse forme in base al tipo di informazione letta o scritta: I/O formattato  I/O di caratteri I/O “per righe”
I/O formattato Standard output (scrittura su monitor) istruzione  printf Standard input (lettura da tastiera) istruzione  scanf L’utilizzo di queste funzioni richiede l’inserimento di una  direttiva   #include <stdio.h> all’inizio del file sorgente il cui significato è: “includi il file  stdio.h  ”
L’istruzione  printf Visualizza sul monitor. La  printf  opera utilizzando una stringa, detta  <format> ,   nella quale si devono inserire i comandi che descrivono come devono apparire i dati sul monitor. Al  <format>  deve seguire la lista di variabili che si vuol visualizzare. Sintassi: printf (< format >,< arg1 >,...,< argn >);
L’istruzione  printf < format > : stringa che determina il formato di visualizzazione per ognuno dei vari argomenti. < arg1 >,...,< argn > : lista degli argomenti da visualizzare.  Gli argomenti (opzionali) possono essere costanti, variabili o espressioni.   Se non ci sono argomenti (come quando si vuole visualizzare solo un messaggio) la funzione trasferisce sul video il testo della   stringa di  <format>  e il cursore si posiziona subito dopo l'ultimo   carattere.
L’istruzione  printf Affinché il cursore vada a capo, occorre inserire nella stringa   di  format  il carattere new-line ( \n ).   Esempio: #include <stdio.h> main() { printf (&quot;Stampa di una riga\n&quot;); printf (&quot;Seconda riga\n&quot;); }
Specificatori di formato Generalmente nel  format  sono indicati gli specificatori di formato per le variabili della lista. I principali specificatori di formato sono: %d  o  %i  per il tipo  int , stampa in   notazione decimale;  %o   per il tipo  int , stampa in ottale  senza segno; %x  per il tipo  int , stampa in   esadecimale senza segno;  %u   per il tipo  int , stampa in   decimale senza segno;  %c   per il tipo  char , stampa un carattere; %f  per il tipo  float , stampa   nella notazione virgola mobile   nel formato -d.dddddd   (6 cifre dopo la virgola);  %e  o  %E  per il tipo  float , stampa nella notazione virgola mobile   nel formato esponenziale   -d.dddddde(E)±dd; %s  per le sequenze di caratteri (stringhe).
Specificatori di formato Gli specificatori di formato sono costituiti dal carattere  %  seguito da   un altro carattere che indica il formato da utilizzare per la stampa dell'argomento corrispondente (carattere, numero intero o reale, stringa, ecc.). Quando incontra il primo specificatore di formato il C preleva il primo argomento, effettua la conversione dal formato interno del dato ad una sequenza di caratteri ASCII seguendo le indicazioni del descrittore ed esegue infine l'ouput dei caratteri sul video. Prosegue poi con la stringa del format, ripetendo le azioni prima   descritte per ogni specificatore incontrato e così fino ad esaurire   l'intero format: il numero di specificatori di formato deve essere quindi   pari al numero di argomenti.
Esempio L’associazione tra variabili e specificatori di formato è di tipo ordinale: 1 ° specificatore  1 ª variabile;  2 ° specificatore  2 ª variabile, ecc. Esempi: int x = 2; float z = 0.5; char c = ‘a’; printf (“%d %f %c\n”, x, z, c); printf (“%f***%c***%d\n”, z, c, x); 2 0.500000 a _ 0.500000***a***2 _
Specificatori di formato Tra il carattere % e quello di specificazione può esserci uno o più elementi aggiuntivi: un intero, che fissa la larghezza minima (numero di caratteri) del campo su cui il dato è stampato; un punto seguito da un intero, che stabilisce la precisione con cui   visualizzare il dato (numero di cifre frazionarie); uno di questi modificatori:  h   (per indicare che si tratta di un tipo  short ), l  (per indicare che si tratta di un tipo  long ), L   (per indicare che si tratta di un tipo  long double ).
Esempio (printf) #include <stdio.h> main() { int  a=-57,  b=2,  c=450,  d=33; float  e=1.22E7,  f=-0.1234567,   g=98765.4321,  h=1.0; printf (&quot;a=%4d b=%3d c=%8d d=%1d\n&quot;, a, b, c, d); printf (“e=%9.3f f=%9.3f g=%9.3f h=%9.3f&quot;, e, f, g, h); } Sul video apparirà: a= -57 b=  2 c=  450 d=33 e=12200000.000 f=  -0.123 g=98765.432 h=  1.00
L’istruzione scanf Permette la lettura di dati da tastiera. La  scanf , come la  printf , opera utilizzando un  format ,   cioè un descrittore del formato che devono avere i dati in ingresso   e accetta vari tipi di argomenti: interi, reali, caratteri, stringhe, ecc.   Sintassi: scanf (< format >,< arg1 >,...,< argn >);
L’istruzione scanf <format>  :  è una stringa di caratteri dove compaiono  solo   specificatori di formato  (è bene evitare di inserire degli spazi tra gli specificatori), gli stessi utilizzati per la  printf ; <arg1>,...,<argn>  :  possono essere solo variabili il cui nome deve essere  preceduto dal carattere  & .  ATTENZIONE!!! MPORTANTE i nomi delle variabili vanno sempre precedute dall’operatore   &  che indica l’indirizzo della variabile  Esempio: int x;  float z; scanf(“%d%f“, &x, &z);
L’istruzione scanf Per comprendere il funzionamento della  scanf   si immagini che, man mano che vengono introdotti i caratteri dalla tastiera, il codice di ognuno venga accodato in un contenitore (un  flusso ). Si possono pensare così a delle sequenze di caratteri s ulle quali il programma in esecuzione dispone di un  cursore .   Le modalità con cui opera la  scanf   sono alquanto complesse e dipendono dagli specificatori che compaiono nel  <format> .
L’istruzione scanf Quando deve leggere un  numero intero o reale ( int, float, double ) , il cursore avanza fino al primo carattere diverso da  spazio . Vengono poi letti tutti i caratteri successivi (cifre) fino a raggiungere un carattere di  spazio  oppure un delimitatore di riga (comunque un carattere non numerico), sul quale il cursore si ferma.  Se la sequenza di caratteri così isolata è corretta, viene convertita nella rappresentazione interna ( complemento a 2 oppure floating-point ) e il valore è attribuito alla variabile, altrimenti le operazioni della  scanf  si bloccano.
L’istruzione scanf Nel caso che la stringa contenga più di un descrittore, per ognuno viene attivato l'opportuno meccanismo di lettura e conversione: affinché   la  scanf   si comporti correttamente  ci devono essere tanti descrittori   quanti argomenti. Tra un numero e il successivo possono essere inseriti quanti caratteri separatori si desidera  (spazio, new-line, ecc.):  vengono automaticamente ignorati (come ce ne fosse uno solo!). Se invece si leggono dati di  tipo  char   viene letto un solo carattere, quello  su cui è posizionato il cursore, il quale avanza di una sola posizione!
L’istruzione scanf Per i dati più comuni (numeri e stringhe di caratteri) i valori devono essere introdotti separandoli tra loro da almeno un separatore (spazio, invio, ecc.). Lo specificatore  %* x   provoca il salto della prossima conversione:  viene effettuata la lettura ma il valore non viene assegnato all'argomento.   Lo specificatore  %*  può risultare utile in pratica solo nel caso di lettura di dati da file (come si vedrà più avanti).
Esempio #include <stdio.h> int dato1, dato2, dato3; main() { printf(“\nIntroduci tre numeri interi: &quot;); scanf(&quot;%d%d%d&quot;, &dato1, &dato2, &dato3); printf(“\nHai introdotto: dato1=%d, dato2=%d, dato3=%d”, dato1, dato2, dato3); }
L’istruzione scanf I tre dati interi (da tastiera) possono essere introdotti indifferentemente separandoli tra loro con un semplice  spazio  oppure con il tasto di  invio  oppure ancora con il carattere  tab,  ecc. Ad esempio sono leciti ed equivalenti: 14 674 99000  (su una sola riga) 674 99000  (su una sola riga) 14 674   (su tre righe distinte) 99000
I/O scanf  e  printf  non sono le uniche possibilità che abbiamo per introdurre o visualizzare dati. Esistono numerose altre istruzioni di input sia per la lettura da tastiera, sia per leggere dati da altri periferici (come, ad es., il disco). Sono naturalmente diponibili le rispettive istruzioni di output. Il loro uso è però più complesso e verrà proposto più avanti.
Espressioni Sono c ombinazioni di variabili e operatori. Esistono varie categorie di operatori, applicabili a tipi di dati diversi: operatori aritmetici; operatori relazionali; operatori logici; operatori sui bit: ecc.
Operatori aritmetici Quattro operatori comuni a tutti (numeri reali e interi): + - * / Per i numeri interi, esiste anche l’operatore  %  che ritorna il resto della divisione intera. Stesse regole di precedenza dell’aritmetica ordinaria: ( *,  / )  >  ( + ,  - )  le parentesi tonde alterano la gerarchia. Esempio: int x = 5,  y = 2,  q,  r; q = x / y;  /*  (q = 2, variabili intere! troncamento)  */ r =  x % y;  /*  (r = 1) , resto di 5 / 2  */ q = x + (y * (x – r));  /*  5 + (2 * (5 – 1)) = 13  */
Operatori aritmetici: esempi main() { const double ENEPER = 2.718281; /*  sezione variabili  */ int dato, divintero; double risul, inizio; dato = 12 * 3 - 4 * 5;  /*  equivale a (12*3)-(4*5) = 16  */ dato = dato + 1;   /*  aggiunge 1 a dato: dato = 17  */ divintero = dato % 10;   /*  resto di 17 / 10 (= 7)  */ inizio = dato;  /*  conversione di tipo  */ risul = inizio / ENEPER;  /*  divisione tra numeri reali  */ }
Conversione forzata di tipo (casting) Si può forzare la conversione di tipo anteponendo al dato che si vuole convertire il tipo   posto tra parentesi, secondo questo schema: (tipo) espressione Esempio: int dato_1, dato_2; float dato_real, media; …………………………………… .. dato_real = (float)dato_1 / (float)dato_2; media = (dato_1 + dato_2) / (float)2; L'effetto della conversione mediante l'operazione  cast  è limitato all'espressione in   cui appare: il dato su cui opera resta immutato.
Operatori di assegnamento composti E’ possibile combinare l’istruzione di assegnazione con gli operatori aritmetici. Sintassi: < variabile >  < operatore > =   < espressione > ; Operatori: +=  -=  *=  /=  %=   Significato: assegnazione + operazione. Esempi: x  +=   5; /*  equivalente a x = x + 5  */ y  -=   x; /*  equivalente a y = y – x  */
Operatori di incremento e decremento Per le assegnazioni composte più comuni sono previsti degli operatori espliciti: ++  -- Significato: ++     +=1 --      -=1 Esempi: x++;   /*  equivale a x = x + 1  */ valore--;   /*  equivale a valore = valore – 1 */
Operatori di incremento e decremento Possono essere utilizzati sia in notazione  prefissa  che in notazione  postfissa Prefissa: la variabile viene modificata prima di essere utilizzata nell’espressione Postfissa: la variabile viene modificata solo dopo averla utilizzata nell’espressione Esempio: assumendo  x = 4: Se si esegue  y = x++,  si otterrà come risultato x = 5  e  y = 4; Se si esegue  y = ++x,  si otterrà come risultato x = 5  e  y = 5;
Operatori relazionali Operano su quantità numeriche o di tipo  char  e forniscono un risultato logico o “booleano”. <  <=  >  >=  ==  != Il risultato è sempre di tipo  int:   risultato  = 0   significa  FALSO risultato    0   significa  VERO In C (C89) non esiste un tipo logico o “booleano” !
Esempio main() { float dato1, dato2; int inter1, inter2; short int switch1, flag;   dato1 = 10.5;   dato2 = 3.7; inter1 = 2;   inter2 = 1; switch1 = dato1 < (dato2 * 0.5);  /*  switch1 = 10.5 < 1.85 = FALSO (= 0)  */ flag = inter1 != inter2;   /*  flag = VERO  (   0)  */ }
INFORMATICA Algebra di Boole
Operatori logici Operano su espressioni “booleane” e forniscono un risultato logico o “booleano”. !  &&  || NOT  AND  OR Equivalenti agli operatori Booleani di base. Stesse regole di precedenza NOT > AND > OR Esempi: (x > 0)  &&  (x < 10)   (x compreso tra 1 e 9) (x1  >  x2)  ||  (x1  ==  3)
Esempio #define FALSO 0 #define VERO 1 main() { int dato1,  dato2; short int test, flag, condiz; dato1 = 5; dato2 = 3; flag = VERO; test = !flag;  /*  test = NOT flag cioè FALSO  (= 0)  */ condiz = (dato1  >=  dato2)  &&  test; /*condiz =  VERO  AND FALSO  cioè  FALSO  (= 0) */ }
Operatori di manipolazione dei bit Il C possiede una serie di operatori che possono agire direttamente sui bit delle variabili e costanti di tipo intero o carattere, dichiarate nel programma. Si tratta di 4 operatori derivati direttamente dalle operazioni booleane di base e di altri 2 che eseguono l’operazione di shift (destra e sinistra) di un certo numero di bit. I primi si prestano a “mascherare” o “commutare” i bit, i secondi possono essere utili nelle operazioni di divisione e moltiplicazione per 2. Tranne uno, sono tutti operatori binari,  che agiscono cioè su due espressioni.
Richiamo: operatori Booleani A  AND   B A  OR   B NOT   A A  XOR   B 1 1 1 1 0 0 1 0 A   B 1 0 1 0 0 0 1 0 A   B 0 1 1 0 A 0 1 1 1 0 0 1 0 A   B
Operatori su bit Operatori di manipolazione dei bit: Binario >> Shift a destra Binario << Shift a sinistra ~ ^ | & Unario Binario Binario Binario NOT bit a bit (complemento a 1) XOR bit a bit OR bit a bit AND bit a bit tipo Operatore Operazione
Operatori su bit: esempi char z, x = 3, y = 13;   z = x & y z = ~ x x y y x z x z AND NOT 1 1 0 0 0 0 0 0 1 0 1 1 0 0 0 0 1 1 0 0 0 0 0 0 1 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1
Operatori su bit: esempi z = x | y z = x ^ y NOTA:  Il significato decimale non  è rilevante! OR EXOR 1 1 0 0 0 0 0 0 1 0 1 1 0 0 0 0 1 1 1 1 0 0 0 0 1 1 0 0 0 0 0 0 1 0 1 1 0 0 0 0 0 1 1 1 0 0 0 0
Operatori di shift Equivalenti alla divisione/moltiplicazione per le potenze di 2. Sintassi: <operando>   >>   <num. posizioni> <operando>   <<   <num. posizioni> Significato: fai scorrere  <operando>   a destra/sinistra di un numero di bit pari a  <num. posizioni> Sia  <operando>   che   <num. posizioni>   devono essere valori interi.
Operatori di shift I due operatori operano diversamente a seconda del tipo numerico  Dati  unsigned : equivale allo  shift logico ; <<   inserisce degli ‘ 0 ’ nelle posizioni meno significative >>   inserisce degli ‘ 0 ’ nelle posizioni pi ù significative Dati con segno: equivale allo  shift aritmetico ; <<   aggiunge degli ‘ 0 ’ nelle posizioni meno significative, e mantiene inalterato il bit pi ù significativo (segno) >>  inserisce un valore uguale al bit pi ù significativo (bit di segno) mantenendo pertanto inalterato il segno;
Operatori di shift Esempio: unsigned char x = 15;   /*  x = 00001111  */ x = x << 2     /*  x = 001111 00   (15  x  2 2   = 60)  */ x = x >> 2     /*  x =  00 000011  (15  /  2 2   = 3)  */ char x = -15   /*  x = 11110001  */ x = x <<  2   /*  x = 110001 00   (-15  x  2 2  = - 60)  */ x = x >>  2     /*  x =  11 111100  (-15  /  2 2  = - 4)  */ Anche per questi operatori è consentita la scrittura abbreviata: x  <<= 2  equivale a   x = x <<  2
Operatori di manipolazione dei bit Con questi operatori si possono eseguire operazioni complesse sui singoli bit delle variabili dei programmi. Esempio: char car = ‘m’,  val = 1; ....................  car = car  &  ~  (val <<  5 );   AND  NOT  left shift provoca la trasformazione del carattere  ‘m’  (il cui codice ASCII è  109 ) nel valore intero  77  corrispondente, in codice ASCII al carattere  ‘M’ .
Operatori bit-a-bit: esempio riassuntivo car = car  &  ~  (  val  <<  5 ) Codice binario del numero 1 su 8 bit (variabile  val ) 0 5 4 3 2 1 6 7 0 0 0 0 0 1 0 0
Operatori bit-a-bit: esempio car = car  &  ~  (val <<  5 ) Operazione di shift a sinistra di 5 posizioni sulla variabile  val  (risultato = 32). 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1
Operatori bit-a-bit: esempio car = car  &  ~  (val <<  5 ) Operazione  NOT  sul risultato del precedente shift (risultato = 223 in binario puro). 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0
Operatori bit-a-bit: esempio car = car  &  ~  (val <<  5 ) In  car  vi è il codice di  ‘m’ , cioè 109. 0 0 1 0 1 1 1 1 1 1 1 1 1 1 1 0
Operatori bit-a-bit: esempio car = car  &  ~  (val <<  5 ) Operatore  AND  ( & ): esegue l’operazione logica  AND  tra i bit corrispondenti delle due variabili interessate. bit 0 0 0 1 0 1 1 1 1 1 1 1 1 1 1 1 0 car (val << 5) 1
Operatori bit-a-bit: esempio car = car  &  ~  (val <<  5 ) Operatore  AND  ( & ): esegue l’operazione logica  AND  tra i bit corrispondenti delle due variabili interessate. 0 0 1 0 1 1 1 1 1 1 1 1 1 1 1 0 car (val << 5) 0 1 bit 1
Operatori bit-a-bit: esempio car = car  &  ~  (val <<  5 ) Operatore  AND  ( & ): esegue l’operazione logica  AND  tra i bit corrispondenti delle due variabili interessate. 0 0 1 0 1 1 1 1 1 1 1 1 1 1 1 0 car (val << 5) 0 1 1 bit 2
Operatori bit-a-bit: esempio car = car  &  ~  (val <<  5 ) Operatore  AND  ( & ): esegue l’operazione logica  AND  tra i bit corrispondenti delle due variabili interessate. 0 0 1 0 1 1 1 1 1 1 1 1 1 1 1 0 car (val << 5) 1 0 1 1 bit 3
Operatori bit-a-bit: esempio car = car  &  ~  (val <<  5 ) Operatore  AND  ( & ): esegue l’operazione logica  AND  tra i bit corrispondenti delle due variabili interessate. 0 0 1 0 1 1 1 1 1 1 1 1 1 1 1 0 car (val << 5) 0 1 0 1 1 bit 4
Operatori bit-a-bit: esempio car = car  &  ~  (val <<  5 ) Operatore  AND  ( & ): esegue l’operazione logica  AND  tra i bit corrispondenti delle due variabili interessate. 0 0 1 0 1 1 1 1 1 1 1 1 1 1 1 0 car (val << 5) 0 1 0 1 1 0 bit 5
Operatori bit-a-bit: esempio car = car  &  ~  (val <<  5 ) Operatore  AND  ( & ): esegue l’operazione logica  AND  tra i bit corrispondenti delle due variabili interessate. 0 0 1 0 1 1 1 1 1 1 1 1 1 1 1 0 car (val << 5) 0 1 0 1 1 1 0 bit 6
Operatori bit-a-bit: esempio car = car  &  ~  (val <<  5 ) Operatore  AND  ( & ): esegue l’operazione logica  AND  tra i bit corrispondenti delle due variabili interessate. 0 0 1 0 1 1 1 1 1 1 1 1 1 1 1 0 car (val << 5) 0 0 1 0 1 1 1 0 bit 7
Operatori bit-a-bit: esempio car = car  &  ~  (val <<  5 ) In pratica si è “spento” il bit in posizione 5 di  car Valore finale di  car 0 5 4 3 2 1 6 7 0 0 1 0 1 1 1 1 1 1 1 1 1 1 1 0 car (val << 5) 0 0 1 0 1 1 1 0
Esercizio Scrivere una funzione  bitn   che riceva un valore intero  N   e un altro intero  i  e ritorni il valore dell’i-esimo bit di  N 0 1 0 1 1 1 0 1 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 1<<i (1<<i) & N int bitn (int N, int i) { if (((1 << i) & N) !=  0) return 1; else  return 0; } N
Istruzione composta Una sequenza di istruzioni può essere racchiusa tra le parentesi graffe per costituire quella che è nota come  istruzione composta Il C considera   il blocco di istruzioni che costituiscono l'istruzione composta come se si trattasse di una sola istruzione. main() { .......................... printf (“\nIntroduci due dati interi da elaborare:&quot;); scanf ( &quot;%d%d&quot;, &dato1, &dato2); { coeff = 10.5;  scala = 3; } .......................... }   Lo stesso corpo di un programma può essere considerato come un'unica istruzione composta.
Operatore sizeof Quando si realizzano programmi per i quali “deve” essere garantita la   trasportabilità, può sorgere la necessità di conoscere quanti byte   occupa un certo tipo di dato su una particolare macchina: ad esempio, il tipo  int  può impegnare 2, 4 o 8 byte.   L'operatore  sizeof  può agire o su un tipo, ad esempio,  sizeof (double) o su una variabile, un vettore, un’espressione, una  struct , ad esempio, sizeof (dato_real) in ogni caso restituisce un intero corrispondente al numero di byte occupato dall‘argomento.   In seguito vedremo numerose e importanti applicazioni di questo operatore.
Operatore sizeof Esempio: programma che visualizza il numero di bit sui quali è rappresentato un carattere, un numero   intero, un numero reale, un numero double.   #include <stdio.h> main() { int num_bit; num_bit = sizeof ( char ) * 8; printf (“\n Su questa macchina un char e' su %d bit&quot;, num_bit); printf (“\n  un intero  su %d bit&quot;, (sizeof (int) * 8)); printf (“\n  un float  su %d bit&quot;, (sizeof (float) * 8)); printf (“\n  un double  su %d bit&quot;, (sizeof (double) * 8)); }

More Related Content

PPTX
Caratteristiche del linguaggio c
PPTX
Identifiers
PDF
loops in C ppt.pdf
PPTX
Introduction to c++
PPTX
C++ decision making
PPSX
Type conversion
PPT
ALU arithmetic logic unit
PPTX
fundamentals of c
Caratteristiche del linguaggio c
Identifiers
loops in C ppt.pdf
Introduction to c++
C++ decision making
Type conversion
ALU arithmetic logic unit
fundamentals of c

What's hot (20)

PPTX
Decision Making Statement in C ppt
PPT
C++ oop
PPTX
Loops c++
DOCX
Inline function(oops)
PDF
Methods and constructors
PPTX
While loop,Do While loop ,for loop
PPTX
Generations of programming_language.kum_ari11-1-1-1
PPTX
Language processor
PPTX
fork join.pptx
PDF
Working Remotely (via SSH) Rocks!
PPTX
Data Types and Variables In C Programming
PPTX
Loops in C
PPTX
Modern Programming Languages - An overview
PPTX
Algorithm and flowchart
PPTX
Looping statements in C
PPTX
Imperative programming
PPSX
C++ Programming Language
PPTX
Java enum
PPT
friend function(c++)
Decision Making Statement in C ppt
C++ oop
Loops c++
Inline function(oops)
Methods and constructors
While loop,Do While loop ,for loop
Generations of programming_language.kum_ari11-1-1-1
Language processor
fork join.pptx
Working Remotely (via SSH) Rocks!
Data Types and Variables In C Programming
Loops in C
Modern Programming Languages - An overview
Algorithm and flowchart
Looping statements in C
Imperative programming
C++ Programming Language
Java enum
friend function(c++)
Ad

Viewers also liked (7)

PDF
Seminario Drupal 2012
PDF
Da Windows a Linux: è tempo di migrare
PDF
Come dove perchè? Ubuntu!
PPT
Riepilogo Java C/C++
PDF
Seminario Raspberri Pi - Parte 2 - GULP
PPT
Spring 2.5
PDF
Seminario Raspberri Pi - Parte 1 - GULP
Seminario Drupal 2012
Da Windows a Linux: è tempo di migrare
Come dove perchè? Ubuntu!
Riepilogo Java C/C++
Seminario Raspberri Pi - Parte 2 - GULP
Spring 2.5
Seminario Raspberri Pi - Parte 1 - GULP
Ad

Similar to 3 Linguaggioc (20)

PDF
Lezione 21 (2 maggio 2012)
PDF
Lezione 11 (26 marzo 2012)
PDF
Lezione 11 (26 marzo 2012)
PPT
Corso c++
PPSX
Modulo 1 - Lezione 1
PPT
05 2 integrali-conversioni-costanti-preproc-inclusione
PDF
Le basi di Pytthon 3 - Fondamenti n.1
PPT
05 1 intro-struttura
PDF
13 - Programmazione: Compendio C - C++
PPT
9 Altre Istruzioni Di I O
PDF
T4 tipizzazione
PPT
13 Puntatori E Memoria Dinamica
PDF
7. MATLAB - Parte 2 (IO, cicli, funzioni).pdf
PDF
Laboratorio Programmazione: Visibilita' e tipi di dato
PPT
Linguaggio assembly del processore 8086 (ita) 1
PPT
Corso java base
PPT
Analizzatori di programmi in C
PPT
Java Lezione 1
PDF
ECDL modulo 1 ud1: algoritmi rappr informazione
Lezione 21 (2 maggio 2012)
Lezione 11 (26 marzo 2012)
Lezione 11 (26 marzo 2012)
Corso c++
Modulo 1 - Lezione 1
05 2 integrali-conversioni-costanti-preproc-inclusione
Le basi di Pytthon 3 - Fondamenti n.1
05 1 intro-struttura
13 - Programmazione: Compendio C - C++
9 Altre Istruzioni Di I O
T4 tipizzazione
13 Puntatori E Memoria Dinamica
7. MATLAB - Parte 2 (IO, cicli, funzioni).pdf
Laboratorio Programmazione: Visibilita' e tipi di dato
Linguaggio assembly del processore 8086 (ita) 1
Corso java base
Analizzatori di programmi in C
Java Lezione 1
ECDL modulo 1 ud1: algoritmi rappr informazione

More from guest60e9511 (11)

PPT
2 Rappresentazione Dei Dati
PDF
Codifica
PPT
12 Struct
PPT
11 I File
PPT
10 Typedef Enum
PPT
8 Algoritmi
PPT
6 Vettori E Matrici
PPT
7 Sottoprogrammi
PPT
5 Strutture Iterative
PPT
4 Strutture Condizionali
PPT
4 Algebra Di Boole
2 Rappresentazione Dei Dati
Codifica
12 Struct
11 I File
10 Typedef Enum
8 Algoritmi
6 Vettori E Matrici
7 Sottoprogrammi
5 Strutture Iterative
4 Strutture Condizionali
4 Algebra Di Boole

3 Linguaggioc

  • 2. Premessa Fu creato agli inizi degli anni ’70 quale strumento per lo sviluppo del Sistema Operativo UNIX. Si è diffuso molto rapidamente e nel 1989 l’American National Standards Institute (ANSI) completava la definizione del linguaggio producendo il documento noto come ANSI C , al quale fanno riferimento ormai tutti i compilatori per quel linguaggio. A differenza degli altri linguaggi ad alto livello consente un agevole accesso alla struttura hardware del sistema di elaborazione.
  • 3. Caratteristiche Generali Il C è un linguaggio: ad alto livello ... ma anche poco astratto strutturato ... ma con eccezioni fortemente tipizzato ogni oggetto ha un tipo semplice (!?) poche keyword case sensitive maiuscolo diverso da minuscolo negli identificatori! portabile standardizzato (ANSI)
  • 4. Alfabeto Il vocabolario base del C è costituito dai seguenti simboli: tutte le lettere dell’alfabeto inglese maiuscole e minuscole: A÷Z, a÷z le dieci cifre decimali 0 ÷ 9 un insieme di caratteri speciali, tra cui: + * / = < > ( ) [ ] { } . , ; : ” ? ! % # & ˜ ˆ
  • 5. Identificatori Si riferiscono ad una delle entità del linguaggio: costanti variabili funzioni ecc. Iniziano con un carattere alfabetico oppure con “ _ ” (underscore) e possono contenere solamente caratteri alfabetici, cifre e “_” Il C standard prevede che solo i primi 31 caratteri dell'identificatore sono significativi, anche se possono essere usati nomi più lunghi.
  • 6. Commenti Sono testi liberi inseriti all’interno del programma dal programmatore per descrivere cosa fa il programma. Non sono processati dal compilatore: servono al programmatore, non al sistema! Formato: Racchiuso tra i simboli: /* */ Non è possibile annidarli. Esempi: /* Questo è un commento corretto! */ /* Questo /* risulterà un */ errore */
  • 7. Istruzioni Le istruzioni devono essere scritte rispettando alcune regole sintattiche e di punteggiatura. L’istruzione deve sempre essere conclusa con un ; (punto e virgola). Si può scrivere più di un’istruzione per riga purché ognuna sia conclusa col ; . Un’istruzione può occupare più di una riga .
  • 8. Parole chiave Riservate! Nel C standard sono 32 : auto double int struct break else long switch case enum register typedef char extern return union c onst float short unsigned continue for signed void default goto sizeof volatile do if static while
  • 9. Struttura di un programma C Struttura generale: Direttive e parte dichiarativa globale main () { Parte dichiarativa locale Parte esecutiva }
  • 10. Struttura di un programma C Tutti gli oggetti, con le loro caratteristiche, che compongono il programma devono essere preventivamente dichiarati . main è la parola chiave che indica il punto di “ingresso” del programma quando viene eseguito dal S.O.; il suo contenuto è delimitato da parentesi graffe { … }
  • 11. Struttura di un programma C Parte dichiarativa locale : elenco degli oggetti che compongono il main ognuno con le proprie caratteristiche. Parte esecutiva: sequenza di istruzioni , ovvero ciò che descriviamo con il diagramma di flusso oppure con lo pseudocodice! Ovvero le istruzioni vere e proprie!
  • 12. Struttura di un programma C Programma minimo: main() { } file prova.c START STOP
  • 14. Definizione dei dati In C, tutti i dati devono essere dichiarati e definiti prima di essere usati! Definizione di un dato : riserva spazio in memoria; assegna un nome. identifica gli operatori leciti su quel dato Richiede l’indicazione di: nome (identificatore); tipo ; modalità di accesso (variabile/costante).
  • 15. Tipi Il tipo definisce l'insieme dei valori che possono essere assunti, la rappresentazione interna e l'insieme degli operatori che possono agire su quel dato. Il linguaggio C richiede di definire il tipo dei dati e possiede regole rigide per la loro manipolazione ( tipizzazione forte ). Permette inoltre al programmatore di definire nuovi tipi astratti. Contemporaneamente permette di “vedere” gli oggetti interni al calcolatore: i registri, la memoria, gli indirizzi (puntatori), ecc.
  • 16. Tipi base (primitivi) Sono quelli forniti direttamente dal C. Sono identificati da parole chiave! char caratteri ASCII; int interi (complemento a 2); float reali (floating point singola precisione); double reali (floating point doppia precisione). La dimensione precisa di questi tipi dipende dall’architettura (non definita dal linguaggio). char = 8 bit sempre Attenzione: le parole chiave dei tipi base vanno scritte in minuscolo!
  • 17. INFORMATICA Cenni sulla Rappresentazione dei dati
  • 18. char Il tipo char (character) definisce un carattere (attenzione: un solo carattere !) espresso su 8 bit (1 byte) in codice ASCII. I valori sono interpretati come numeri interi con segno su 8 bit (-128 ÷ +127). Un carattere deve essere indicato tra apici, così: ‘ a’
  • 19. int Il tipo int (integer) definisce i numeri interi con segno. La rappresentazione interna e l'intervallo dei valori assunti dipende dal compilatore e dalla macchina usata. Generalmente si tratta del complemento a 2 e i valori assunti sono compresi nell’intervallo -32768 ÷ 32767 su 16 bit oppure, per le macchine a 32 bit, nell’intervallo -2.147.483.648 ÷ 2.147.483.647. Vanno indicati semplicemente così come siamo abituati a scriverli sulla carta, col loro valore (senza il punto decimale): -2453
  • 20. float e double Sia il tipo float che il tipo double sono rappresentazioni di numeri reali (frazionari). Sono rappresentati secondo la notazione floating-point , rispettivamente in singola (32 bit) e doppia (64 bit) precisione. I valori assunti (rappresentabili) sono: float ± 3.4E+38 (7 cifre decimali) double ± 1.7E+308 (17 cifre decimali) La rappresentazione è normalmente riferita allo standard IEEE P754.
  • 21. float e double I valori di tipo float o double vanno indicati con il punto decimale, ad esempio: 14.8743 E’ ammessa anche una notazione simile alla notazione scientifica con il carattere E al posto di 10, così: 0.148743E-02 In alternativa, si può ancora scrivere il numero senza punto decimale ma seguito dal suffisso F oppure f (ad esempio, 10F , 10f e 10.0 sono equivalenti). Il compilatore concepisce questi valori sempre come di tipo double .
  • 22. Modificatori dei tipi base Sono previsti dei modificatori, identificati da parole chiave, da premettere ai tipi base: short long signed unsigned
  • 23. short / long Il qualificatore short si applica al tipo int e impone che la rappresentazione degli interi sia su 16 bit (valori assunti: -32768 ÷ 32767); il qualificatore long si applica sia al tipo int che al tipo double ; long int impone la rappresentazione degli interi su 32 bit (valori assunti: -2.147.483.648 ÷ 2.147.483.647); long double forza la rappresentazione dei reali su 80 bit ( ± 1.7E+308 aumentando la precisione a 22 cifre decimali).
  • 24. signed / unsigned I qualificatori signed e unsigned si applicano ai tipi char e int . signed è ridondante e serve solo a ricordare che un valore è inteso con segno (ma per int e char è già così!);   unsigned permette di estendere l'intervallo dei valori non-negativi. Il tipo unsigned char può assumere valori nell'intervallo 0 ÷ 255 e il tipo unsigned int valori nell'intervallo 0 ÷ 65535. I qualificatori possono apparire da soli: nel qual caso si assume che sia sottinteso il tipo int . E’ lecito, ad esempio, il tipo unsigned short che viene interpretato come unsigned short int , ecc.
  • 25. Altri valori interi Per un dato intero, i valori di variabili e costanti possono anche essere espressi in esadecimale (specificati col prefisso 0x oppure 0X , ad esempio, 0xFF = 255 10 ) oppure ottale (prefisso 0 (zero), ad esempio 0377 = 255 10 ); per il formato long si usa il suffisso L oppure l ( 255L o 255l esprimono entrambi un long int con valore 255 10 ); per l' unsigned si usa il suffisso U oppure u ( 255U e 255u esprimono un unsigned int = 255 10 ). I suffissi u ed l possono apparire entrambi, con ovvio significato.
  • 26. Valori speciali Il codice ASCII comprende alcuni caratteri non stampabili. Per rappresentarli viene utilizzata la sequenza di escape ( backslash seguito da un altro carattere). tabulatore vert. \v null \0 tabulatore orizz. \t esadecimale \x ddd return \r ottale \ ddd new line \n backslash \\ pagina nuova \f doppio apice \” backspace \b apostrofo \’ allarme \a Carattere Sequenza Carattere Sequenza
  • 27. Tabella riassuntiva 1.7E ± 308 (16 cifre) double 1.7E ± 308 (20 cifre) long double 3.4E ± 38 (7 cifre) float 0 ÷ 4.294.967.295 unsigned long, unsigned long int 0 ÷ 65535 unsigned int, unsigned short int 0 ÷ 255 unsigned, unsigned char, unsigned short 2.147.483.648 ÷ 2.147.483.648 signed long, signed long int 2.147.483.648 ÷ 2.147.483.648 long, long int, -32768 ÷ 32.767 signed short, signed short int -32768 ÷ 32.767 short, short int, signed short -32768 ÷ 32.767 int, signed , signed int -128 ÷ 127 char, signed char Intervallo dei valori Tipo
  • 28. Direttive Il C prevede che nel programma, oltre alle istruzioni, possano esserci anche delle direttive che devono essere interpretate ed eseguite dal compilatore stesso (inserzione di macro, compilazioni condizionate, inclusione di altri sorgenti, ecc.);   il compilatore C esegue una preelaborazione del programma, detta Preprocessing , per riconoscere ed eventualmente eseguire le direttive ; le direttive si distinguono dalle istruzioni perché sono inserite sempre in righe individuali e iniziano con il carattere # seguito da una parola chiave; ad esempio: #include #define
  • 29. Definizione di variabili Sintassi: < tipo > < nome della variabile >; Più in generale (definizioni multiple): < tipo > < lista dei nomi delle variabil i >; < nome > : l’identificatore che rappresenta il nome della variabile; < lista dei nomi delle variabili> : lista di identificatori separati da , (virgola).
  • 30. Definizione di variabili Esempi: int x; char ch; long int x1 ,x2, x3; double pi; short int stipendio; long y,z; Usiamo nomi significativi! Esempi: int RitenuteOperate, StipendioBase; float OreLavorate; Esempi errati: float Ore Lavorate ; /* c’è uno spazio */ int Stip?base; /* c’è un carattere speciale */
  • 31. Definizione di variabili E’ possibile “inizializzare” una variabile, ovvero attribuirgli un valore prima che venga utilizzata per la prima volta, in fase di dichiarazione della stessa. Esempio: int x = 24; char ch = ‘m’; double pi = 124.654;
  • 32. Definizione di costanti Sintassi: const < tipo > < nome della costante > = < valore >; Esempi: const double pigreco = 3.14159; const char separatore = ‘$’; const float aliquota = 0.2; Convenzione: Identificatori delle constanti tipicamente in MAIUSCOLO (ma è una convenzione!). const double PIGRECO = 3.14159;
  • 33. La direttiva “define” E’ un'altra possibilità di definire valori costanti : si introduce un identificatore come sinonimo di una costante: #define identificatore testo Deve comparire sempre in testa al programma, prima di main() , e all'inizio della riga.   E’ elaborata dal preprocessore del compilatore, che sostituirà in tutto il programma, ovunque appare l'identificatore, il testo di cui è sinonimo.
  • 34. La direttiva “define” Non essendo un'istruzione non termina con il punto e virgola.   Esempi: #define PIGRECO 3.1415 #define DOMENICA 7 #define VERO 1 #define Carattere ‘p’
  • 35. Stringa Definizione: sequenza di caratteri terminata dal carattere NULL (‘ \0 ’); non è un tipo di base del C. memorizzata in posizioni adiacenti di memoria. Formato: “ < sequenza di caratteri >“ Esempi: “ Ciao!” “ abcdefg\n”
  • 36. Visibilità delle variabili Ogni variabile è definita all’interno di un preciso ambiente di visibilità (scope). Variabili globali definite all’esterno al main sono visibili da tutti i moduli. Variabili locali definite all’interno del main (sono visibili solo all’interno del main ); più in generale, definite all’interno di un blocco (sono visibili solo all’interno del blocco).
  • 37. Struttura a blocchi In C è possibile aggregare gruppi di istruzioni in blocchi racchiudendole tra parentesi graffe; significato: delimitazione di un ambiente di visibilità di “oggetti” (variabili). Esempio: { int a=2; int b; b=2*a; } a e b sono definite solo all’interno del blocco!
  • 38. Visibilità delle variabili - Esempio n, x : visibili in tutto il file a, b, c ,y : visibili in tutto il main d, z : visibili solo nel blocco int n; double x; main() { int a,b,c; double y; { int d; double z; } }
  • 40. Assegnazioni Sintassi: < variabile > = < espressione > ; Non è un’uguaglianza ! Significato: il risultato di < espressione > viene assegnato a < variabile >; < variabile > e < espressione > d evono essere “compatibili” (ovvero dello stesso tipo); < variabile > deve essere stata precedentemente definita! Esempio: int x; float y; x = 3; y = -323.9498;
  • 41. Assegnazioni In realtà l’ assegnazione (o assegnamento ) non è un’istruzione (come accade in tutti gli altri linguaggi); il simbolo = è un operatore che assegna alla variabile che si trova a sinistra il valore calcolato sull’espressione di destra; nel caso più semplice l’espressione di destra è un semplice valore. Sono pertanto lecite assegnazioni “multiple”: < var 1 > = < var 2 > = < espressione > ;
  • 42. Istruzioni di I/O Per ora consideriamo solo l’I/O interattivo, quello cioè che si realizza con tastiera e monitor. Sono disponibili diverse forme in base al tipo di informazione letta o scritta: I/O formattato I/O di caratteri I/O “per righe”
  • 43. I/O formattato Standard output (scrittura su monitor) istruzione printf Standard input (lettura da tastiera) istruzione scanf L’utilizzo di queste funzioni richiede l’inserimento di una direttiva #include <stdio.h> all’inizio del file sorgente il cui significato è: “includi il file stdio.h ”
  • 44. L’istruzione printf Visualizza sul monitor. La printf opera utilizzando una stringa, detta <format> , nella quale si devono inserire i comandi che descrivono come devono apparire i dati sul monitor. Al <format> deve seguire la lista di variabili che si vuol visualizzare. Sintassi: printf (< format >,< arg1 >,...,< argn >);
  • 45. L’istruzione printf < format > : stringa che determina il formato di visualizzazione per ognuno dei vari argomenti. < arg1 >,...,< argn > : lista degli argomenti da visualizzare. Gli argomenti (opzionali) possono essere costanti, variabili o espressioni. Se non ci sono argomenti (come quando si vuole visualizzare solo un messaggio) la funzione trasferisce sul video il testo della stringa di <format> e il cursore si posiziona subito dopo l'ultimo carattere.
  • 46. L’istruzione printf Affinché il cursore vada a capo, occorre inserire nella stringa di format il carattere new-line ( \n ). Esempio: #include <stdio.h> main() { printf (&quot;Stampa di una riga\n&quot;); printf (&quot;Seconda riga\n&quot;); }
  • 47. Specificatori di formato Generalmente nel format sono indicati gli specificatori di formato per le variabili della lista. I principali specificatori di formato sono: %d o %i per il tipo int , stampa in notazione decimale; %o per il tipo int , stampa in ottale senza segno; %x per il tipo int , stampa in esadecimale senza segno; %u per il tipo int , stampa in decimale senza segno; %c per il tipo char , stampa un carattere; %f per il tipo float , stampa nella notazione virgola mobile nel formato -d.dddddd (6 cifre dopo la virgola); %e o %E per il tipo float , stampa nella notazione virgola mobile nel formato esponenziale -d.dddddde(E)±dd; %s per le sequenze di caratteri (stringhe).
  • 48. Specificatori di formato Gli specificatori di formato sono costituiti dal carattere % seguito da un altro carattere che indica il formato da utilizzare per la stampa dell'argomento corrispondente (carattere, numero intero o reale, stringa, ecc.). Quando incontra il primo specificatore di formato il C preleva il primo argomento, effettua la conversione dal formato interno del dato ad una sequenza di caratteri ASCII seguendo le indicazioni del descrittore ed esegue infine l'ouput dei caratteri sul video. Prosegue poi con la stringa del format, ripetendo le azioni prima descritte per ogni specificatore incontrato e così fino ad esaurire l'intero format: il numero di specificatori di formato deve essere quindi pari al numero di argomenti.
  • 49. Esempio L’associazione tra variabili e specificatori di formato è di tipo ordinale: 1 ° specificatore 1 ª variabile; 2 ° specificatore 2 ª variabile, ecc. Esempi: int x = 2; float z = 0.5; char c = ‘a’; printf (“%d %f %c\n”, x, z, c); printf (“%f***%c***%d\n”, z, c, x); 2 0.500000 a _ 0.500000***a***2 _
  • 50. Specificatori di formato Tra il carattere % e quello di specificazione può esserci uno o più elementi aggiuntivi: un intero, che fissa la larghezza minima (numero di caratteri) del campo su cui il dato è stampato; un punto seguito da un intero, che stabilisce la precisione con cui visualizzare il dato (numero di cifre frazionarie); uno di questi modificatori: h (per indicare che si tratta di un tipo short ), l (per indicare che si tratta di un tipo long ), L (per indicare che si tratta di un tipo long double ).
  • 51. Esempio (printf) #include <stdio.h> main() { int a=-57, b=2, c=450, d=33; float e=1.22E7, f=-0.1234567, g=98765.4321, h=1.0; printf (&quot;a=%4d b=%3d c=%8d d=%1d\n&quot;, a, b, c, d); printf (“e=%9.3f f=%9.3f g=%9.3f h=%9.3f&quot;, e, f, g, h); } Sul video apparirà: a= -57 b= 2 c= 450 d=33 e=12200000.000 f= -0.123 g=98765.432 h= 1.00
  • 52. L’istruzione scanf Permette la lettura di dati da tastiera. La scanf , come la printf , opera utilizzando un format , cioè un descrittore del formato che devono avere i dati in ingresso e accetta vari tipi di argomenti: interi, reali, caratteri, stringhe, ecc. Sintassi: scanf (< format >,< arg1 >,...,< argn >);
  • 53. L’istruzione scanf <format> : è una stringa di caratteri dove compaiono solo specificatori di formato (è bene evitare di inserire degli spazi tra gli specificatori), gli stessi utilizzati per la printf ; <arg1>,...,<argn> : possono essere solo variabili il cui nome deve essere preceduto dal carattere & . ATTENZIONE!!! MPORTANTE i nomi delle variabili vanno sempre precedute dall’operatore & che indica l’indirizzo della variabile Esempio: int x; float z; scanf(“%d%f“, &x, &z);
  • 54. L’istruzione scanf Per comprendere il funzionamento della scanf si immagini che, man mano che vengono introdotti i caratteri dalla tastiera, il codice di ognuno venga accodato in un contenitore (un flusso ). Si possono pensare così a delle sequenze di caratteri s ulle quali il programma in esecuzione dispone di un cursore . Le modalità con cui opera la scanf sono alquanto complesse e dipendono dagli specificatori che compaiono nel <format> .
  • 55. L’istruzione scanf Quando deve leggere un numero intero o reale ( int, float, double ) , il cursore avanza fino al primo carattere diverso da spazio . Vengono poi letti tutti i caratteri successivi (cifre) fino a raggiungere un carattere di spazio oppure un delimitatore di riga (comunque un carattere non numerico), sul quale il cursore si ferma. Se la sequenza di caratteri così isolata è corretta, viene convertita nella rappresentazione interna ( complemento a 2 oppure floating-point ) e il valore è attribuito alla variabile, altrimenti le operazioni della scanf si bloccano.
  • 56. L’istruzione scanf Nel caso che la stringa contenga più di un descrittore, per ognuno viene attivato l'opportuno meccanismo di lettura e conversione: affinché la scanf si comporti correttamente ci devono essere tanti descrittori quanti argomenti. Tra un numero e il successivo possono essere inseriti quanti caratteri separatori si desidera (spazio, new-line, ecc.): vengono automaticamente ignorati (come ce ne fosse uno solo!). Se invece si leggono dati di tipo char viene letto un solo carattere, quello su cui è posizionato il cursore, il quale avanza di una sola posizione!
  • 57. L’istruzione scanf Per i dati più comuni (numeri e stringhe di caratteri) i valori devono essere introdotti separandoli tra loro da almeno un separatore (spazio, invio, ecc.). Lo specificatore %* x provoca il salto della prossima conversione: viene effettuata la lettura ma il valore non viene assegnato all'argomento. Lo specificatore %* può risultare utile in pratica solo nel caso di lettura di dati da file (come si vedrà più avanti).
  • 58. Esempio #include <stdio.h> int dato1, dato2, dato3; main() { printf(“\nIntroduci tre numeri interi: &quot;); scanf(&quot;%d%d%d&quot;, &dato1, &dato2, &dato3); printf(“\nHai introdotto: dato1=%d, dato2=%d, dato3=%d”, dato1, dato2, dato3); }
  • 59. L’istruzione scanf I tre dati interi (da tastiera) possono essere introdotti indifferentemente separandoli tra loro con un semplice spazio oppure con il tasto di invio oppure ancora con il carattere tab, ecc. Ad esempio sono leciti ed equivalenti: 14 674 99000 (su una sola riga) 674 99000 (su una sola riga) 14 674 (su tre righe distinte) 99000
  • 60. I/O scanf e printf non sono le uniche possibilità che abbiamo per introdurre o visualizzare dati. Esistono numerose altre istruzioni di input sia per la lettura da tastiera, sia per leggere dati da altri periferici (come, ad es., il disco). Sono naturalmente diponibili le rispettive istruzioni di output. Il loro uso è però più complesso e verrà proposto più avanti.
  • 61. Espressioni Sono c ombinazioni di variabili e operatori. Esistono varie categorie di operatori, applicabili a tipi di dati diversi: operatori aritmetici; operatori relazionali; operatori logici; operatori sui bit: ecc.
  • 62. Operatori aritmetici Quattro operatori comuni a tutti (numeri reali e interi): + - * / Per i numeri interi, esiste anche l’operatore % che ritorna il resto della divisione intera. Stesse regole di precedenza dell’aritmetica ordinaria: ( *, / ) > ( + , - ) le parentesi tonde alterano la gerarchia. Esempio: int x = 5, y = 2, q, r; q = x / y; /* (q = 2, variabili intere! troncamento) */ r = x % y; /* (r = 1) , resto di 5 / 2 */ q = x + (y * (x – r)); /* 5 + (2 * (5 – 1)) = 13 */
  • 63. Operatori aritmetici: esempi main() { const double ENEPER = 2.718281; /* sezione variabili */ int dato, divintero; double risul, inizio; dato = 12 * 3 - 4 * 5; /* equivale a (12*3)-(4*5) = 16 */ dato = dato + 1; /* aggiunge 1 a dato: dato = 17 */ divintero = dato % 10; /* resto di 17 / 10 (= 7) */ inizio = dato; /* conversione di tipo */ risul = inizio / ENEPER; /* divisione tra numeri reali */ }
  • 64. Conversione forzata di tipo (casting) Si può forzare la conversione di tipo anteponendo al dato che si vuole convertire il tipo posto tra parentesi, secondo questo schema: (tipo) espressione Esempio: int dato_1, dato_2; float dato_real, media; …………………………………… .. dato_real = (float)dato_1 / (float)dato_2; media = (dato_1 + dato_2) / (float)2; L'effetto della conversione mediante l'operazione cast è limitato all'espressione in cui appare: il dato su cui opera resta immutato.
  • 65. Operatori di assegnamento composti E’ possibile combinare l’istruzione di assegnazione con gli operatori aritmetici. Sintassi: < variabile > < operatore > = < espressione > ; Operatori: += -= *= /= %= Significato: assegnazione + operazione. Esempi: x += 5; /* equivalente a x = x + 5 */ y -= x; /* equivalente a y = y – x */
  • 66. Operatori di incremento e decremento Per le assegnazioni composte più comuni sono previsti degli operatori espliciti: ++ -- Significato: ++  +=1 --  -=1 Esempi: x++; /* equivale a x = x + 1 */ valore--; /* equivale a valore = valore – 1 */
  • 67. Operatori di incremento e decremento Possono essere utilizzati sia in notazione prefissa che in notazione postfissa Prefissa: la variabile viene modificata prima di essere utilizzata nell’espressione Postfissa: la variabile viene modificata solo dopo averla utilizzata nell’espressione Esempio: assumendo x = 4: Se si esegue y = x++, si otterrà come risultato x = 5 e y = 4; Se si esegue y = ++x, si otterrà come risultato x = 5 e y = 5;
  • 68. Operatori relazionali Operano su quantità numeriche o di tipo char e forniscono un risultato logico o “booleano”. < <= > >= == != Il risultato è sempre di tipo int: risultato = 0 significa FALSO risultato  0 significa VERO In C (C89) non esiste un tipo logico o “booleano” !
  • 69. Esempio main() { float dato1, dato2; int inter1, inter2; short int switch1, flag;   dato1 = 10.5; dato2 = 3.7; inter1 = 2; inter2 = 1; switch1 = dato1 < (dato2 * 0.5); /* switch1 = 10.5 < 1.85 = FALSO (= 0) */ flag = inter1 != inter2; /* flag = VERO (  0) */ }
  • 71. Operatori logici Operano su espressioni “booleane” e forniscono un risultato logico o “booleano”. ! && || NOT AND OR Equivalenti agli operatori Booleani di base. Stesse regole di precedenza NOT > AND > OR Esempi: (x > 0) && (x < 10) (x compreso tra 1 e 9) (x1 > x2) || (x1 == 3)
  • 72. Esempio #define FALSO 0 #define VERO 1 main() { int dato1, dato2; short int test, flag, condiz; dato1 = 5; dato2 = 3; flag = VERO; test = !flag; /* test = NOT flag cioè FALSO (= 0) */ condiz = (dato1 >= dato2) && test; /*condiz = VERO AND FALSO cioè FALSO (= 0) */ }
  • 73. Operatori di manipolazione dei bit Il C possiede una serie di operatori che possono agire direttamente sui bit delle variabili e costanti di tipo intero o carattere, dichiarate nel programma. Si tratta di 4 operatori derivati direttamente dalle operazioni booleane di base e di altri 2 che eseguono l’operazione di shift (destra e sinistra) di un certo numero di bit. I primi si prestano a “mascherare” o “commutare” i bit, i secondi possono essere utili nelle operazioni di divisione e moltiplicazione per 2. Tranne uno, sono tutti operatori binari, che agiscono cioè su due espressioni.
  • 74. Richiamo: operatori Booleani A AND B A OR B NOT A A XOR B 1 1 1 1 0 0 1 0 A B 1 0 1 0 0 0 1 0 A B 0 1 1 0 A 0 1 1 1 0 0 1 0 A B
  • 75. Operatori su bit Operatori di manipolazione dei bit: Binario >> Shift a destra Binario << Shift a sinistra ~ ^ | & Unario Binario Binario Binario NOT bit a bit (complemento a 1) XOR bit a bit OR bit a bit AND bit a bit tipo Operatore Operazione
  • 76. Operatori su bit: esempi char z, x = 3, y = 13; z = x & y z = ~ x x y y x z x z AND NOT 1 1 0 0 0 0 0 0 1 0 1 1 0 0 0 0 1 1 0 0 0 0 0 0 1 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1
  • 77. Operatori su bit: esempi z = x | y z = x ^ y NOTA: Il significato decimale non è rilevante! OR EXOR 1 1 0 0 0 0 0 0 1 0 1 1 0 0 0 0 1 1 1 1 0 0 0 0 1 1 0 0 0 0 0 0 1 0 1 1 0 0 0 0 0 1 1 1 0 0 0 0
  • 78. Operatori di shift Equivalenti alla divisione/moltiplicazione per le potenze di 2. Sintassi: <operando> >> <num. posizioni> <operando> << <num. posizioni> Significato: fai scorrere <operando> a destra/sinistra di un numero di bit pari a <num. posizioni> Sia <operando> che <num. posizioni> devono essere valori interi.
  • 79. Operatori di shift I due operatori operano diversamente a seconda del tipo numerico Dati unsigned : equivale allo shift logico ; << inserisce degli ‘ 0 ’ nelle posizioni meno significative >> inserisce degli ‘ 0 ’ nelle posizioni pi ù significative Dati con segno: equivale allo shift aritmetico ; << aggiunge degli ‘ 0 ’ nelle posizioni meno significative, e mantiene inalterato il bit pi ù significativo (segno) >> inserisce un valore uguale al bit pi ù significativo (bit di segno) mantenendo pertanto inalterato il segno;
  • 80. Operatori di shift Esempio: unsigned char x = 15; /* x = 00001111 */ x = x << 2 /* x = 001111 00 (15 x 2 2 = 60) */ x = x >> 2 /* x = 00 000011 (15 / 2 2 = 3) */ char x = -15 /* x = 11110001 */ x = x << 2 /* x = 110001 00 (-15 x 2 2 = - 60) */ x = x >> 2 /* x = 11 111100 (-15 / 2 2 = - 4) */ Anche per questi operatori è consentita la scrittura abbreviata: x <<= 2 equivale a x = x << 2
  • 81. Operatori di manipolazione dei bit Con questi operatori si possono eseguire operazioni complesse sui singoli bit delle variabili dei programmi. Esempio: char car = ‘m’, val = 1; .................... car = car & ~ (val << 5 ); AND NOT left shift provoca la trasformazione del carattere ‘m’ (il cui codice ASCII è 109 ) nel valore intero 77 corrispondente, in codice ASCII al carattere ‘M’ .
  • 82. Operatori bit-a-bit: esempio riassuntivo car = car & ~ ( val << 5 ) Codice binario del numero 1 su 8 bit (variabile val ) 0 5 4 3 2 1 6 7 0 0 0 0 0 1 0 0
  • 83. Operatori bit-a-bit: esempio car = car & ~ (val << 5 ) Operazione di shift a sinistra di 5 posizioni sulla variabile val (risultato = 32). 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1
  • 84. Operatori bit-a-bit: esempio car = car & ~ (val << 5 ) Operazione NOT sul risultato del precedente shift (risultato = 223 in binario puro). 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0
  • 85. Operatori bit-a-bit: esempio car = car & ~ (val << 5 ) In car vi è il codice di ‘m’ , cioè 109. 0 0 1 0 1 1 1 1 1 1 1 1 1 1 1 0
  • 86. Operatori bit-a-bit: esempio car = car & ~ (val << 5 ) Operatore AND ( & ): esegue l’operazione logica AND tra i bit corrispondenti delle due variabili interessate. bit 0 0 0 1 0 1 1 1 1 1 1 1 1 1 1 1 0 car (val << 5) 1
  • 87. Operatori bit-a-bit: esempio car = car & ~ (val << 5 ) Operatore AND ( & ): esegue l’operazione logica AND tra i bit corrispondenti delle due variabili interessate. 0 0 1 0 1 1 1 1 1 1 1 1 1 1 1 0 car (val << 5) 0 1 bit 1
  • 88. Operatori bit-a-bit: esempio car = car & ~ (val << 5 ) Operatore AND ( & ): esegue l’operazione logica AND tra i bit corrispondenti delle due variabili interessate. 0 0 1 0 1 1 1 1 1 1 1 1 1 1 1 0 car (val << 5) 0 1 1 bit 2
  • 89. Operatori bit-a-bit: esempio car = car & ~ (val << 5 ) Operatore AND ( & ): esegue l’operazione logica AND tra i bit corrispondenti delle due variabili interessate. 0 0 1 0 1 1 1 1 1 1 1 1 1 1 1 0 car (val << 5) 1 0 1 1 bit 3
  • 90. Operatori bit-a-bit: esempio car = car & ~ (val << 5 ) Operatore AND ( & ): esegue l’operazione logica AND tra i bit corrispondenti delle due variabili interessate. 0 0 1 0 1 1 1 1 1 1 1 1 1 1 1 0 car (val << 5) 0 1 0 1 1 bit 4
  • 91. Operatori bit-a-bit: esempio car = car & ~ (val << 5 ) Operatore AND ( & ): esegue l’operazione logica AND tra i bit corrispondenti delle due variabili interessate. 0 0 1 0 1 1 1 1 1 1 1 1 1 1 1 0 car (val << 5) 0 1 0 1 1 0 bit 5
  • 92. Operatori bit-a-bit: esempio car = car & ~ (val << 5 ) Operatore AND ( & ): esegue l’operazione logica AND tra i bit corrispondenti delle due variabili interessate. 0 0 1 0 1 1 1 1 1 1 1 1 1 1 1 0 car (val << 5) 0 1 0 1 1 1 0 bit 6
  • 93. Operatori bit-a-bit: esempio car = car & ~ (val << 5 ) Operatore AND ( & ): esegue l’operazione logica AND tra i bit corrispondenti delle due variabili interessate. 0 0 1 0 1 1 1 1 1 1 1 1 1 1 1 0 car (val << 5) 0 0 1 0 1 1 1 0 bit 7
  • 94. Operatori bit-a-bit: esempio car = car & ~ (val << 5 ) In pratica si è “spento” il bit in posizione 5 di car Valore finale di car 0 5 4 3 2 1 6 7 0 0 1 0 1 1 1 1 1 1 1 1 1 1 1 0 car (val << 5) 0 0 1 0 1 1 1 0
  • 95. Esercizio Scrivere una funzione bitn che riceva un valore intero N e un altro intero i e ritorni il valore dell’i-esimo bit di N 0 1 0 1 1 1 0 1 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 1<<i (1<<i) & N int bitn (int N, int i) { if (((1 << i) & N) != 0) return 1; else return 0; } N
  • 96. Istruzione composta Una sequenza di istruzioni può essere racchiusa tra le parentesi graffe per costituire quella che è nota come istruzione composta Il C considera il blocco di istruzioni che costituiscono l'istruzione composta come se si trattasse di una sola istruzione. main() { .......................... printf (“\nIntroduci due dati interi da elaborare:&quot;); scanf ( &quot;%d%d&quot;, &dato1, &dato2); { coeff = 10.5; scala = 3; } .......................... }   Lo stesso corpo di un programma può essere considerato come un'unica istruzione composta.
  • 97. Operatore sizeof Quando si realizzano programmi per i quali “deve” essere garantita la trasportabilità, può sorgere la necessità di conoscere quanti byte occupa un certo tipo di dato su una particolare macchina: ad esempio, il tipo int può impegnare 2, 4 o 8 byte.   L'operatore sizeof può agire o su un tipo, ad esempio, sizeof (double) o su una variabile, un vettore, un’espressione, una struct , ad esempio, sizeof (dato_real) in ogni caso restituisce un intero corrispondente al numero di byte occupato dall‘argomento.   In seguito vedremo numerose e importanti applicazioni di questo operatore.
  • 98. Operatore sizeof Esempio: programma che visualizza il numero di bit sui quali è rappresentato un carattere, un numero intero, un numero reale, un numero double.   #include <stdio.h> main() { int num_bit; num_bit = sizeof ( char ) * 8; printf (“\n Su questa macchina un char e' su %d bit&quot;, num_bit); printf (“\n un intero su %d bit&quot;, (sizeof (int) * 8)); printf (“\n un float su %d bit&quot;, (sizeof (float) * 8)); printf (“\n un double su %d bit&quot;, (sizeof (double) * 8)); }