Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
vuoi
o PayPal
tutte le volte che vuoi
X::=A
Dove: ∈
o X VN è un simbolo non terminale, e: ∪
o A è una stringa, ossia una sequenza di simboli ciascuno appartenente all’alfabeto V = VN VT
Questo tipo di grammatica definisce quindi un linguaggio sull’alfabeto terminale VT mediante un meccanismo di
derivazione
Data una grammatica G, si dice perciò Linguaggio L generato da G
G
l’insieme delle frasi di V:
o derivabili dal simbolo iniziale S
o applicando le produzioni P
Le frasi di un linguaggio di programmazione vengono dette programmi di tale linguaggio. 18
Introduzione a C
Il potere espressivo di un linguaggio è caratterizzato principalmente da quali tipi di dati è in grado di rappresentare e
quali istruzioni di controllo mette a disposizione.
Il linguaggio di programmazione C è costituito da un linguaggio di computazione e da un set di librerie standard, le
quali forniscono gli strumenti per rappresentare i dati e comunicare con la memoria
Questo si presenta con alcune caratteristiche nel dettaglio è un linguaggio:
▪ sequenziale, ciò vuol dire che l’accesso ai dati viene fatto in sequenza predeterminata
▪ imperativo, indica che i comandi e le istruzioni sono espressi come una successione di attività sequenziali
▪ strutturato a blocchi; poiché rappresentato da una serie di istruzioni, dichiarazioni e definizioni che sono
inserite in {}
▪ usabile come linguaggio di sistema, in quanto riesce ad operare e a gestire direttamente la memoria che non
sempre però rappresenta un vantaggio.
▪ portabile; ciò implica che è molto più semplice effettuare la scrittura di modifiche, anche definite port
piuttosto che riscrivere l’intero codice
▪ efficiente, è quindi in grado di utilizzare il minor numero di risorse possibili durante la sua esecuzione
▪ sintetico
Inoltre, la caratteristica fondamentale è che questo pone le sue basi sul fatto che utilizza dei concetti elementari quali:
dati, espressioni, definizioni, funzioni, istruzioni, dati.
L'architettura fisica di ogni elaboratore è intrinsecamente capace di trattare vari domini di dati, detti tipi primitivi:
o dominio dei numeri naturali e interi
o dominio dei numeri reali
o dominio dei caratteri
o dominio delle stringhe di caratteri
Concettualmente viene anche introdotto il concetto di tipo di dato il quale ci permettere di raggiungere due obiettivi:
o esprimere in modo sintetico un insieme di valori, la loro rappresentazione in memoria e un insieme di
operazioni ammissibili
o permette di effettuare controlli statici sulla correttezza del programma
In particolare, per quanto riguarda i tipi di dato in C abbiamo:
• caratteri – char caratteri ASCII – unsigned char
• interi con segno – short (int) -32768 ... 32767 (16 bit) – int ??????? – long (int) -2147483648 .... 2147483647
(32 bit)
• naturali (interi senza segno) – unsigned short (int) 0 ... 65535 (16 bit) – unsigned (int) ??????? – unsigned long
(int) 0 ... 4294967295 (32 bit)
• reali – float singola precisione (32 bit) numeri rappresentabili da 10-38 a 1038 circa – double doppia precisione
(64 bit) precisione 15 cifre decimali; numeri rappresentabili da 10-308 a 10308 circa
• boolean – non esistono in C come tipo a sé stante – si usano gli interi: • zero indica FALSO • ogni altro valore
indica VERO – convenzione: suggerito utilizzare uno per VERO
La dimensione di alcuni tipi dipende dal compilatore, in linea di massima è consigliabile utilizzare l’operatore unitario
sizeof (tipo)
è, inoltre, necessario affermare che sussistono delle relazioni che sono sempre vere quali:
o sizeof(signed) = sizeof(unsigned)
o sizeof(char) ≤sizeof(short int) ≤ sizeof(int) ≤ sizeof(long int)
o sizeof(float) ≤ sizeof(double) ≤ sizeof(long double) 19
Definiamo le stringhe come una collezione di caratteri delimitata da virgolette “Hello\n”
In dettaglio per quanto riguarda C, le stringhe sono semplici sequenze di caratteri in cui l’ultimo elemento è sempre
presente in maniera implicita ed è rappresentato da “\0” che viene comunque considerato come un unico carattere.
Per definizione le espressioni sono le notazioni che denotano un valore attraverso un processo di valutazione e
possono essere:
→ Espressioni semplici: sono espressioni semplici le costanti, i simboli di variabili, quelli di funzione e via dicendo;
molto più brevemente sono espressioni semplici tutte quelle che di base non fanno nulle ma ciononostante
sono valide.
→ Espressioni composte; al fine di poter scrivere effettivamente delle espressioni composte ogni linguaggio di
programmazione introduce un insieme di operatori che permettono di aggregare insieme le espressioni e che
facciano riferimento a tipi di dato diversi; è possibile effettuare una classificazione degli operatori:
▪ In base al tipo:
▪ aritmetici
▪ relazionali; considerato che non esistono boolean le
espressioni relazionali denotano un valore intero; dunque:
▪ 0 denota falso
▪ 1 denota vero
▪ Logici; la valutazione dell’espressione cessa nel momento in
cui si è in grado di determinare il risultato, pertanto
il secondo operando è valutato solo se effettivamente necessario; queste situazioni
prendono il nome di valutazione in corto circuito
▪ condizionali; un’espressione condizionale è introdotta da un operatore
ternario, in particolare l’espressione denota:
▪ espr1 se cond è vera
▪ espr2 se condiz è falsa
▪ In base al numero:
▪ unari, operano su un solo operando, come l'operatore di negazione logica "!”
▪ binari, operano su due operandi, come l'operatore aritmetico di addizione "+"
▪ ternari: l'operatore condizionale "? :" che permette di eseguire una delle due espressioni a
seconda che la condizione sia vera o falsa
condiz ? espr 1: espr2
Le espressioni concatenate, permettono di unire due o più stringhe in modo da crearne una nuova; queste vengono
introdotte dall’operatore di concatenazione espr1, espr2,…,esprN
Questo può essere anche definito come un operatore di comodo in quanto permette di scrivere in modo compatto il
codice
Gli operatori possono essere infissi, prefissi o postfissi, a seconda che si trovino tra gli operandi, prima dell'operando
o dopo l'operando; in particolare per quanto riguarda la notazione prefissa e quella postfissa non vi sono dubbi su
quale operatore vada applicato a quali operandi; per quanto riguarda
invece la notazione infissa esistono delle regole di priorità e associatività
che permettano di determinare univocamente quale operatore sia
applicato e a quali operandi
La priorità degli operatori specifica l’ordine degli operatori quando
nell’espressione compaiono operatori infissi diversi mentre
l’associatività degli operatori indica l’ordine di valutazione degli
operatori quando nell’espressione compaiono operatori infissi di uguale
priorità; queste regole possono essere evidenziate mediante l’utilizzo di
parentesi tonde in modo da evitare situazioni di confusione, in
particolare queste ci dicono in che ordine sono valutate le operazioni e
non in che ordine bisogna procurarsi gli operandi; in particolare l’ordine
di valutazione è una regola semantica ma che C non precisa, quindi non
c’è modo di sapere come vengano considerate le operazioni; l’unica
cosa che può essere effettivamente fatta per potersi garantire un ordine
specifico è di andare a serializzare le operazioni e scrivere ad esempio:
1. z1 = f(x)
2. z2 = g(y)
3. (3 + z1) + z2 20
Variabili e funzioni
Il linguaggio C si caratterizza per un approccio strutturato e disciplinato alla progettazione di programmi per computer.
La struttura di un programma C essenzialmente è definita come:
<programma>>: ={<unità di traduzione>}
<main >
{<unità di traduzione>}
La funzione main () è un blocco costituente di un programma ed è l’unica obbligatoria; questa può anche ricevere
informazioni quando viene eseguita; in particolare il void tra parentesi indica che il main non riceve alcun tipo di
informazione; altrimenti se riceve una lista di variabili queste devono essere separate da virgole e sono visibili solo
entro il corpo della funzione.
L’inizio e la fine di un programma sono denotati rispettivamente con {} e il contenuto che troviamo al suo interno viene
anche definito come blocco, un importante costrutto sintattico nel quale sono contenute istruzioni, dichiarazioni e
definizioni.
<dichiarazioni-e-definizioni> introducono i nomi (identificatori) di costanti, variabili, tipi definiti dall’utente
<sequenza-istruzioni> sequenza di frasi del linguaggio ognuna delle quali è un’istruzione.
È necessario che alle variabili vengano definite con un nome ed un tipo di dato prima di poter essere utilizzate; questa
operazione viene effettuata andando ad attribuire ad ogni variabile un identificatore valido il quale può essere
rappresentato da lettere, cifre e trattini bassi; in questo momento è necessario evidenziare il fatto che il C così come
il codice ASCII è case sensitive; pertanto presi in considerazione due caratteri uguali uno maiuscolo e uno minuscolo
questi saranno analizzati come due elementi distinti e separati.
In particolare, per quanto riguarda la notazione degli identificatori nel caso di più parole viene fatta o mediante
l’utilizzo di trattini bassi o attraverso la notazione a cammello ossia QuestoEsempio
In particolare; non essendo gli unici a metter mano sul nostro codice è opportuno andare ad inserire dei commenti
che non vengono presi in considerazione durante l’esecuzione del codice e che possono essere di due tipi.
→ // se viene completamente scritto sulla stessa linea
→ /*…*/ se invece viene scritto su più linee, in questo caso si parla in maniera specifica di commento multilinea
Il <tipoValore> deve coincidere col tipo della funzione denotato dall’espressione che segue la parola chiave return.
Definiamo come variabile un’astrazione della cella di memoria, in maniera formale possiamo distinguere:
- Un simbolo associato a un indirizzo fisico, definito anche L-value il quale risulta essere fisso e immutabile
Un simbolo che va a denotare un valore ossia R-value il quale può variare.
La riga <def di variabile> è una frase che introduce una nuova variabile ed è identificata con un simbolo; in particolare
questa è atta a denotare valori di un tipo ben preciso.
int x; /* x deve denotare un valore intero */
float y; // y deve denotare un valore reale
char ch, ch1; /*