


















































































Studia grazie alle numerose risorse presenti su Docsity
Guadagna punti aiutando altri studenti oppure acquistali con un piano Premium
Prepara i tuoi esami
Studia grazie alle numerose risorse presenti su Docsity
Prepara i tuoi esami con i documenti condivisi da studenti come te su Docsity
Trova i documenti specifici per gli esami della tua università
Preparati con lezioni e prove svolte basate sui programmi universitari!
Rispondi a reali domande d’esame e scopri la tua preparazione
Riassumi i tuoi documenti, fagli domande, convertili in quiz e mappe concettuali
Studia con prove svolte, tesine e consigli utili
Togliti ogni dubbio leggendo le risposte alle domande fatte da altri studenti come te
Esplora i documenti più scaricati per gli argomenti di studio più popolari
Ottieni i punti per scaricare
Guadagna punti aiutando altri studenti oppure acquistali con un piano Premium
appunti di programmazione che contengono: nozioni di base per approcciarsi alla programmazione basi del linguaggio C basi del linguaggio Java definizioni dei vari paradigmi di programmazione, introduzione ai costrutti, variabili, assegnamenti, ecc.
Tipologia: Appunti
1 / 90
Questa pagina non è visibile nell’anteprima
Non perderti parti importanti!



















































































Con linguaggio si intende la capacità d’uso e l’uso stesso di un sistema fatto di simboli, con la finalità di
comunicare.
Esistono 2 accezioni di linguaggio:
o Un linguaggio scritto è un l’insieme delle sequenze di simboli presi da un alfabeto. Non tutte
le combinazioni però fanno parte del linguaggio.
L’obbiettivo della linguistica è quello di dare una rigorosa descrizione di un linguaggio.
Definire un linguaggio
Un linguaggio oltre che un insieme di caratteri e segni ha delle regole che permettono di associare un
significato ad ogni sequenza di simboli. Queste regole si distinguono su 3 livelli:
o Sintattico , ovvero le regole che specificano in quali modi i simboli possono essere combinati.
o Semantico , ovvero le regole che permettono di dare significato alle stringhe.
o Pragmatico , ovvero le regole che permettono di capire se il linguaggio è quello adatto.
Alfabeto e stringhe
L’ alfabeto è un insieme finito di elementi che possono essere lettere o simboli.
Una stringa invece è una sequenza finita di simboli appartenenti ad un alfabeto.
Caratteristiche delle stringhe
La cardinalità di una stringa viene definita come la lunghezza di una stringa, quindi il numero di caratteri che
la compone. Questa viene indicata con |S|
o Per esempio, 001101 ha cardinalità |6|.
o La stringa vuota è una stringa che non ha nessun simbolo, viene indicata con 𝜖 e ha cardinalità |0|.
La chiusura di Kleene (detta anche Kleene star), indicata con 𝛴*, che indica l’insieme di tutte le possibili
stringhe scrivibili su 𝛴.
. Da notare che viene considerata anche la stringa vuota.
Una sottostringa è una qualsiasi parte di simboli consecutivi della stringa s.
Operazioni sulle stringhe
La concatenazione di due stringhe avviene come unione delle due stesse. Esistono inoltre concatenazioni
multiple, che vengono espresse con notazioni esponenziali. (𝑎
𝑛
Linguaggio formale
Formalmente un linguaggio è un insieme di parole su un alfabeto. Questo si basa su simboli e token che sono
definiti come gli atomi costituenti di un linguaggio, ovvero i simboli stessi che compongono un alfabeto.
Una parola è formalmente una stringa di un alfabeto.
Esistono linguaggi vuoti che non contengono parole.
Caratteristiche dei linguaggi
La cardinalità di un linguaggio indica il numero di stringhe che lo compongono.
La chiusura L*, indica invece l’insieme ottenuto dall’unione di tutte le potenze n-esime di L.
Operazioni sui linguaggi
La concatenazione consiste nell’unione di due linguaggi, quindi, 𝐿 𝑐
1
2
La potenza n-esima consiste invece nell’insieme delle stringhe ottenute concatenando n stringhe di L, per
esempio, se:
0
1
2
Codice
Il codice è un linguaggio in cui ogni parola si può creare in modo unico, come sequenza di simboli su un
linguaggio.
Proprietà di un codice
Un codice è univocamente decifrabile quindi data una parola esiste solo un modo di ottenerla come prodotto
di simboli dell’alfabeto L. Ogni parola di conseguenza non può essere prefisso di nessun’altra.
▪ Linguaggio formato da (0, 10) è un codice, perché se scrivo 10010100 si può comporre in un solo
modo.
▪ Linguaggio formato da (ab, aba, bab) non è un codice, perché se scrivo ababab si può comporre in
diversi modi, come per esempio la ripetizione di 3 volte di ab o aba + bab.
Appartenenza ad un linguaggio
Per riconoscere se una stringa fa parte o meno di un linguaggio esistono due approcci:
facendo solitamente uso di un algoritmo.
determinato linguaggio, spesso facendo riferimento alle grammatiche.
Dando una lettera come riferimento ad ogni azione possiamo costruire una stringa che indica la soluzione,
ovvero: PBLPCBP
Questa è sempre una stringa che rappresenta una macchina a stati, dato che come prima un processo viene
svolto dopo averne concluso un altro e il problema viene risolto dopo una serie di istruzioni.
Questa però è solo una delle possibili soluzioni, infatti in una macchina a stati le possibilità di risoluzione sono
infinite, dato che posso ripetere infinite volte le stesse operazioni.
Sta al programmatore creare il programma più veloce ed efficiente per risolvere il problema.
Automi a stati finiti
Un automa a stati finiti è una macchina a stati che ha un programma che si ripete ogni volta che gli viene
impresso di fare un’azione.
Questi si dividono in:
o Automi a stati deterministici , in cui il risultato è sempre certo, ed esiste una e una sola transizione.
o Automi a stati non deterministici, in cui il risultato e le transizioni possono cambiare, solitamente su
un valore percentuale. (esempio le slot machine).
Un automa è una macchina a stati finiti che si basa su una quintupla formata da:
Alan Mathison Turing, fu un matematico britannico, considerato uno dei padri dell’informatica.
Fu uno dei più importanti decifratori che operavano durante la Seconda guerra mondiale.
Decifrò il codice usato dai sottomarini tedeschi.
Morì mangiando una mela al cianuro.
Una macchina a stati ha un sistema che ha due mancanze:
Turing risolse i problemi di una macchina a stati nella sua macchina, aggiungendo:
o Un nastro, diviso in celle dove la testina può leggere e scrivere.
o Una testina che può leggere e scrivere sul nastro.
La testina di lettura – scrittura può muoversi di una posizione sia a destra che a sinistra e può scrivere e
leggere un simbolo nella cella che si presenta sotto di essa. Il dispositivo si trova in ogni istante in un insieme
finito di stati.
A seconda dell’input la macchina cambia stato ed esegue una delle azioni di elaborazione.
Elaborazione della macchina di Turing
La macchina di Turing funziona per quintuple di elementi:
Utilizzi della macchina di Turing
La macchina di Turing è in grado di risolvere una classe di problemi molto vasta, tanto che si arrivò a dire che
non esiste un problema computabile non risolvibile con una macchina di Turing.
Oggi sappiamo però di problemi risolvibili con la macchina di Turing, come il problema dell’arresto.
Con il problema dell’arresto si ipotizzò una macchina di Turing universale, quindi in grado di eseguire
programmi di qualsiasi tipo.
Tipologie di problemi
I problemi che si affrontano possono essere di diversi tipi, tra i quali:
lunghezza?)
percorso minimo)
Non tutti i problemi sono però di natura computazionale, cioè non per tutti è possibile definire una soluzione
esprimibile in un algoritmo che consenta di ottenere sempre risultati. La scienza degli algoritmi si occupa solo
di problemi computazionali.
Flusso
La sequenza di passaggi tra gli stati di un algoritmo rappresentano il flusso. La differenza tra algoritmo e il
flusso è che l’algoritmo risolve il problema in generale , quindi ha diramazioni per ogni possibilità.
Le possibilità di diramazioni di un algoritmo rappresentano i possibili flussi.
Controllo del flusso
Il flusso è controllato da:
Soluzioni
Per trovare la soluzione ad un problema ci si può approcciare ad un problema con la “forza bruta”, ovvero
continuando a tentare finché non si trova la soluzione.
Flow chart
I flow chart, anche detti diagrammi di flusso , sono un formalismo grafico che definisce gli algoritmi,
rappresentandoli con blocchi collegati tra loro.
Questo sistema ha il privilegio di mettere in evidenza la presenza di cicli, salti, biforcazioni, ecc.
Per descrivere un flusso tramite flow chart si utilizzano:
o Rettangoli per i dati.
o Rombi per le decisioni.
o Frecce per indicare la direzione del flusso.
Le BNF vengono utilizzate per definire le grammatiche di tutti i linguaggi di programmazione. In questo
formalismo si utilizzano:
o ::= per indicare assegnamenti.
o Simboli non terminali rappresentati all’interno di < >.
o Simboli terminali racchiusi tra virgolette.
o Il simbolo | che viene letto come oppure.
Carte sintattiche
La carta sintattica è come il diagramma di flusso, ma rappresenta una BNF, quindi:
sequenza lecita di simboli.
Variabili
La variabile è un contenitore di un dato che può essere modificato durante l’esecuzione di un programma.
Gli algoritmi operano sulle variabili per far cambiare stato al programma ed alla macchina. Le variabili
risiedono nella memoria RAM ed hanno associato un identificatore.
Macchina ad accesso casuale (macchina RAM)
La macchina ad accesso casuale è il modello computazionale più comune. Essa è in grado di eseguire istruzioni
in sequenza.
Questa macchina ha 4 componenti:
o Memoria , capace di salvare un valore.
o Programma , formato da una sequenza di istruzioni.
o Flusso di input.
o Flusso di output.
Teorema di Böhm Jacopini
Questo teorema recita: Dato un programma proprio P è possibile costruire un programma strutturato S(P)
equivalente a P.
Questo permise di dimostrare ai sostenitori dei programmi non strutturati, che affermavano che senza goto
non si poteva avere la potenza computazionale, che i programmi strutturati non sono inferiori a quelli non
strutturati.
Il programma strutturato per sostituire i salti viene costituito da tre oggetti logici fondamentali:
o Sequenza , ovvero eseguire un’operazione dopo l’altra in ordine.
o Selezione , ovvero biforcare lo scenario, scegliere un’operazione piuttosto che un’altra.
o Iterazione , ovvero ripete più volte le stesse operazioni.
Queste espressioni permettono di rendere egualmente efficaci i programmi strutturati quanto quelli non
strutturati.
Asserzione e invariabile
L’asserzione è una variabile vera o falsa circa lo stato della computazione.
L’invariante è un’asserzione vera in qualunque momento del programma, quindi una certezza in qualunque
momento.
Variabile
In una variabile sono definiti:
o Nome, che identifica il riferimento.
o Tipo, ovvero l’insieme dei possibili valori che possono essere assunti dalla variabile.
o Valore, ovvero il valore attualmente assunto dalla variabile.
La variabile è un contenitore di valori che variano durante l’esecuzione del programma.
L’identificatore di una variabile corrisponde ad un’area della memoria che contiene il valore dell’oggetto.
Il rapporto tra identificatore e valore è dinamico, mentre quello tra identificatore e l’area di memoria è
statico. Infatti in una variabile varia il valore ma non la posizione in cui la variabile si trova nella memoria.
Il tipo
Il tipo di una variabile specifica:
Programma vuol dire macchina
Un programma è una macchina che trasforma dati in risultati attraverso una sequenza di operazioni.
Le operazioni del programma sono:
Programma non vuol dire codice
Un programma non è il codice che lo rappresenta, infatti in passato realizzare un programma voleva dire:
Collegare ingranaggi.
o Collegare cavi.
o Collegare schede.
Oggi realizzare un programma vuol dire:
Programmare non significa imparare un linguaggio
I linguaggi si estinguono, il programmatore no, conoscere più linguaggi, tra l’altro è una grande abilità.
L’algoritmo è un programma utile
L’algoritmo risolvente trasforma un’istanza di un problema in una soluzione, attraverso una sequenza di
operazioni.
Esempi di problemi
Alcuni esempi tipici di problemi affrontati con la programmazione sono:
o Istanza: testo corrotto
o Soluzione: testo ricostruito
I vantaggi del C
o È un linguaggio molto espressivo, usando diverse sequenze di soluzioni si possono descrivere tutte
le soluzioni per il problema.
o Possiamo definire funzioni e procedure.
o Produce un codice rapido e compatto.
o Offre accesso diretto al basso livello, quindi gestire singoli bit.
o Ha poche parole chiave dal significato ben chiaro.
o La struttura favorisce uno sviluppo “top – down”, quindi che parte dall’alto livello, e via via risolve
sempre più piccoli problemi.
o Ha molte librerie che permettono di ampliare lo spettro delle operazioni descritte dal linguaggio.
Gli svantaggi del C
Il C si usa molto perché
o Permette di agire su istruzioni ad alto livello.
o Permette di controllare meccanismi a basso livello.
o Quindi può gestire funzioni vicine all’hardware ma anche lontane.
Primo esempio
Hello word è il primo programma che si illustra per capire come si scrive un codice.
Struttura di un programma C
Il linguaggio C ha una struttura modulare, questa struttura ha delle caratteristiche, per esempio:
se scritto in linguaggio ad alto livello.
Insiemi di questi brani di codice vengono chiamati librerie.
I brani di codice però non corrispondono ad un programma funzionante ma vengono ricollegati ad un altro
codice per essere usati.
Compilazione
La compilazione è un processo di traduzione che avviene:
o Dal codice, in linguaggio di alto livello.
o Al programma, in linguaggio macchina.
La compilazione attraversa 3 fasi:
descrizione ad alto livello vengano fuse per creare altre parti più complete.
.c è l’estensione dei file in linguaggio C.
.h (header) è l’estensione di file di istruzioni aggiuntive al codice.
.o è l’estensione degli oggetti.
Struttura dei listati C (lista delle istruzioni)
Un listato scritto in C ha una struttura regolare, che presenta:
o Parte dichiarativa, dichiara quali elementi saranno utilizzati.
o Parte descrittiva, che dice come gli elementi si combinano tra loro.
Commenti
I commenti sono uno strumento importante, sono indirizzati solamente alle persone che leggono il codice e
che devono comprendere il codice.
Il precompilatore li scarta, infatti il programma non li calcola.
Queste spiegazioni sono racchiuse tra /* e */, oppure tra // e la fine della riga nello standard C99 (non nel
Questi commenti sono essenziali per il lavoro di gruppo , ma anche per i programmatori solitari per
comprendere un codice istantaneamente dopo molto tempo.
Esistono strumenti software che documentano il programma partendo dai commenti.
Funzione main
int main (int argc, char *argv[])
{
char b;
int l;
/* Stampa il bordo superiore */
StampaCarattere(BORDO,LARGHEZZA);
ACapo();
/* Stampa il bordo laterale sinistro */
StampaCarattere(BORDO,1);
StampaCarattere(SPAZIO,1);
/* Stampa il saluto */
StampaStringa(SALUTO);
/* Stampa il bordo laterale destro */
StampaCarattere(SPAZIO,1);
StampaCarattere(BORDO,1);
ACapo();
/* Stampa il bordo inferiore */
b = BORDO;
l = LARGHEZZA;
StampaCarattere(b,l);
return 0;
}
L’intestazione presenta:
La sequenza di istruzioni che il programma deve svolgere è racchiusa fra parentesi graffe {}.
Questa sequenza viene divisa in due parti:
char b;
int l;
La parte dichiarativa introduce le variabili, ovvero gli oggetti manipolati dal programma.
Le variabili sono risultati parziali, di ognuna di esse si specifica:
o Tipo , ovvero l’insieme dei valori che essa può assumere, e le operazioni che possiamo compiere con
essa.
o Nome , ovvero un identificatore simbolico usato per manipolarla.
Ogni dichiarazione di variabile termina con ;
Più variabili di tipo identico possono essere dichiarate insieme. Per esempio:
int l1, l2; equivale a: int l1;
int l2;
/* Stampa il bordo superiore */
StampaCarattere(BORDO,LARGHEZZA);
ACapo();
/* Stampa il bordo laterale sinistro */
StampaCarattere(BORDO,1);
StampaCarattere(SPAZIO,1);
/* Stampa il saluto */
StampaStringa(SALUTO);
/* Stampa il bordo laterale destro */
StampaCarattere(SPAZIO,1);
StampaCarattere(BORDO,1);
ACapo();
/* Stampa il bordo inferiore */
b = BORDO;
l = LARGHEZZA;
StampaCarattere(b,l);
return 0;
La parte esecutiva introduce le istruzioni, ovvero le operazioni compiute dal programma.
Le istruzioni possono essere:
Ogni istruzione termina con un punto e virgola ;
Procedure
/* Stampa la stringa di caratteri "s" */
void StampaStringa (char *s)
{
printf("%s",s);
}
/* Stampa il carattere "c"
ripetuto "num" volte */
void StampaCarattere (char c, int num)
{
int i;
for (i = 1; i <= num; i++)
printf("%c",c);
}
/* Va a capo */
void ACapo ()
{
printf("\n");
}
Nelle procedure si definiscono i brani di codice preannunciati nel prototipo.
2. Scrivere E sul video viene scomposto in: - “Scrivere ***** sul video” - Ecc…
A loro volta questi sotto problemi possono essere ancora scomposti in altri sotto problemi, come:
“Scrivere * * sul video”, può essere scomposto in:
o “Scrivere * sul video”
o “Scrivere spazio sul video”
o “Scrivere spazio sul video”
o “Scrivere spazio sul video”
o “Scrivere * sul video”
In questo modo il problema sarà scrivere un carattere, che come si può intuire è un compito elementare,
molto semplice.
Il problema a questo punto segue questo schema:
Approccio bottom – up
L’approccio bottom – up, complementare dell’approccio top – down, consiste nel partire da un problema più
elementare ed andare a risolverlo attraverso un problema più complesso.
Quindi partire dal cuore del problema per poi aggiungere dettagli ecc.…
Questo approccio è spesso la strategia sbagliata per affrontare un problema.
I vantaggi della struttura modulare
I vantaggi della struttura modulare, che riflette un approccio top – down, sono:
1. Il codice viene strutturato in modo da essere gestibile. 2. Si scompone il codice in moduli o blocchi strutturati. 3. Si rendono i blocchi comprensibili adottano convenzioni, come: - Dichiarazioni. - Nomi auto esplicativi per le funzioni, detti macro e variabili. - Corrispondenze biunivoche tra variabili ed oggetti. - Uso di spazi per chiarire il senso e rendere visibili istantaneamente i blocchi. - Commenti, che chiariscono lo scopo delle funzioni.
o Definendoli in modo che abbiano poche interazioni tra loro.
o Esplicitando i requisiti di ogni blocco. (dati e risultati che si vogliono avere)
Lo scopo della programmazione a struttura modulare vuole avere gli obiettivi di:
Nei linguaggi di programmazione i valori non sono quasi mai costanti, in genere i valori che si danno alle
variabili vengono espressi con delle espressioni.
Blocco
Il blocco è un insieme di istruzioni, che:
contemporaneamente.
Ogni blocco può contenere altri blocchi al suo interno. Nel linguaggio C, ogni blocco è racchiuso tra parentesi
graffe. { }
Variabile
La variabile conserva un risultato parziale, ogni blocco ha una parte dichiarativa, dove si dichiarano le
variabili, comprese di:
o Nome.
o Tipologia.
Es. char b;