












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 presi a lezione integrati con la dispensa e le slide, relativi alla parte teorica del corso
Tipologia: Appunti
1 / 20
Questa pagina non è visibile nell’anteprima
Non perderti parti importanti!













negativo) nel modo seguente:
o la sequenza di cifre: cn- 1 cn- 2 … c1 c
o rappresenta in base B=2 il valore: cn-1XBn- 1 + cn- 2 xBn- 2 + … + c1xB1 + c0xB0 dove: c di i
appartiene a 0, 1, 2, …, B- 1 per ogni 0 <= i <= n- 1
es: 231bin = 2x2^2+3x2^1+1x2^
le varie basi: (es. numero 29)
! base decimale: B=10 A= {0,1,2,3,4,5,6,7,8,9} 29 dec
! base ottale: B=8 A={0,1,2,3,4,5,6,7} 29 dec
= 3x
! base esadecimale: B=16 A={0,1,2,3,4,…,9,A,B,C,D,E,F} 29 dec
= 1x
! base binaria: B=2, A={0,1} 29 dec
= 1x
+1x
+1x
+1x
codiche notevoli: esadecimale 16
(16), ottale 8
(8), binaria 2
usata dal calcolatore per la codifica di tutte le informazioni, codifica in BIT ("BInary digiT”), è
l#unità elementare dell#informazione. {0,1} possono essere associati a due stati opposti
nella codifica binaria classica con 1Byte = sequenza di 8 BIT si possono rappresentare tutti i
numeri che vanno da: 0 = 00000000 bin
a 255 dec
bin
A. conversioni:
da dec → bin : metodo dei resti :
nb! se il numero è dispari termina con 1, se pari termina con 0
nb! aggiungere uno zero in fondo = moltiplicare il numero per la base, se aggiungo un 1 in
fondo = moltiplicare il numero per la base e aggiungere 1 (es 9 dec
bin
bin
9x dec
dec
bin
= 9x dec
dec
da bin→dec: sommatoria : ∑=c n- 1
x
n- 1
+c n- 2
x
n- 2
+...+c 0
x
(es. bin
=1x
+0x
+0x
+1x
+1x
—>conversioni rapide, notazione abbreviata con errore ≤10% (approssimato per difetto
nel caso bin → dec, approssimato per eccesso o difetto nel caso dec → bin):
Mi=
Gi=
si può utilizzare per scomporre potenze di 2 elevate a partire dalle prime 9 :
(es.
x
~128x
B. Operazioni sui numeri binari
predefinite, nessun bit può essere vuoto (se il numero è più corto di 8 bit allora è preceduto
da tutti zeri);
algoritmo di addizione a propagazione dei riporti :
0+0 = 0, 1+0 = 1, 1+1=0 con riporto di 1, eseguo una semplice somma addendo per
addendo.
Se il riporto è sull#ultima colonna allora significa che tale numero non è rappresentato su 8
bit (max 255) → ottengo errore! un risultato errato, riporto perso = ho overow :
superamento del limite di rappresentazione, il valore del risultato non può essere
rappresentato con le cifre a disposizione
log2 valore Numero di bit per rappresentare il valore
es: log2 (8)= 3 – servono 3 bit per rappresentare il valore 8
C. numeri interi in modulo e segno , m&s : il primo bit a sx rappresenta il segno ed è
applicato al numero, togliendo il primo bit si ottiene il valore assoluto
0 segno positivo, 1 segno negativo es.
0 00001000m&s = +2^3=+8dec 1 00001000m&s= - 2^3=-8dec
D. numeri interi in complemento a due C2 :
primo bit a sx è detto bit di segno ed è interpretato con valore negativo(-1)→(-b n- 1
)x
n-
+b n- 2
x
n- 2
+...+b 0
x
, il bit di segno non è separabile dagli altri bit ma è integrato ed
infatti ha anche valore di modulo.
0 = segno positivo, 1= segno negativo
permette di rappresentare sia interi positivi sia interi negativi, i bit rimangono comunque 8,
però questa volta si potranno rappresentare solo numeri da: - 128 a +127 (- 2
n- 1
< n <
n- 1
)
—>l# inverso addittivo (o opposto) di un numero n codificato in C2 si ottiene
invertendo (negando) ogni bit del numero
sommando uno alla posizione a dx tenendo conto di eventuali riporti.
(es 11011 C
dec
dec
—> conversione dec → C2 :
se dec > 0 : converto il decimale in binario naturale e aggiungo in bit 0 davanti a sx (es
dec
bin
se dec < 0 : converto in binario naturale come se fosse un numero positivo, aggiungo il bit
0 davanti ed eseguo l’inverso additivo
—> Estensione del segno: replicando in modo progressivo il bit di segno a sinistra, il
ott
→ due tre sei cinque tre tre → 010 011 110 101 011 011 → 010011110101011011
da bin →
hex: 010011110101011011 → 0001 0011 1101 0101 1011 → uno tre tredici cinque undici →
hex
hex → bin:
hex
→ dieci sette undici quattro zero dodici → 1010 0111 1011 0100 0000 1100
esponente negativo, la porzione intera e frazionaria sono costanti.
es. 0, bin
=0x
, 1x
dec
dec
virgola fissa
A. conversione dec → bin: converto la parte intera con il metodo dei resti + parte frazionaria
con il metodo dei prodotti
metodo dei prodotti :
Posso ottenere anche un
numero periodico se nelle
moltiplicazioni i resti si
ripetono, i periodo sono le
moltiplicazioni che intercorrono tra i due resti
es: 0,675dec 0,101(0110)bin
si possono rappresentare con pochi bit numeri molto grandi oppure valori frazionari molto
piccoli (cioè con molti decimali). N°bit=bit M+ bit E
La rappresentazione si basa sulla relazione
virgola mobile
= M x B
M = mantissa numero frazionario rappresentante le cifre significative dopo la virgola, m≥ 1 bit
B = base 2, E = esponente, n≥ 1 bit
sia mantissa (solitamente in m&s) che esponente possono essere negativi
numero più grande è l#errore dell#approssimazione), sono rischiose lo operazioni tra numeri
aventi ordini di grandezza molto diversi
quasi tutti i calcolatori oggi adottano lo standard aritmetico IEEE 754, che definisce:
1 - i formati di rappresentazione: binario naturale, C2 e virgola mobile;
2 - gli algoritmi somma, sottrazione, prodotto, ecc.. per tutti i formati previsti;
3 - i metodi di arrotondamento per i numeri frazionari;
4 - la gestione degli errori (overflow, divisione per 0, rad quadrata di numeri negativi, ...).
la definizione dello standard IEEE 754 permette di trasportare programmi tra calcolatori diversi
senza mutare risultati o precisione di calcolo.
ciascuno un carattere;
7 bit e comprende 128 caratteri pensati per la lingua inglese.
(ASCII Esteso a 8 bit, 256 caratteri, comprende anche caratteri speciali e lettere
accentate necessarie alle lingue europee) il codice comprende: spazi, tabulazione,
sound bell (e altri caratteri non stampabili), punteggiatura, caratteri alfa-numerici
LATIN) → poi è stato esteso a UNICODE per creare una codifica universale
testi → sequenze di carattere (seq. di bit)
immagini → bitmap con sequenze di pixel (puntini di n colori), jpeg, gif, etc musica →
mid, wav, mp3, etc
video → seq. di immagini + suoni
contenere sequenze di n ≥ 1 bit, n = 8, 16, 32 o 64 bit) = celle che compongono la
memoria a ciascuna delle quali corrisponde un indirizzo.
Ciascuna parola di memoria può memorizzare un elemento d#informazione diverso: un
carattere (o più), un numero bin naturale o in C2, un numero frazionario con virgola
mobile.
Alcuni bit della parola possono non essere utilizzati.
(es. parole di memoria:)
serve per formalizzare attraverso operazioni logiche le operazioni del calcolatore.
L#algebra booleana utilizza due operandi logici:
—> operatori logici binari:
OR (somma logica)
AND (prodotto logico)
—> operatore logico unario:
NOT (negazione o inversione ) e rispettive tabelle di verità
dischi a memorizzazione ottica (DVD e Blu-ray) in cui però la velocità di accesso non è
uniforme in tutte le parti del disco. I più efficaci sono tuttavia le memorie a stato solido,
(SSD (Solid State Drive)) che garantiscono una velocità di accesso ai dati
indipendentemente dalla loro posizione in memoria.
operativo, che li divide e organizza per tipo attraverso indici (estensioni .pfd .png etc)
che ne garantisce un accesso veloce.
- area di memoria contenente dati e programmi (in linguaggio macchina) su cui la CPU
può operare, e ha tempi di accesso molto brevi rispetto a mm.
sono successivamente caricate in uno dei registri della CPU (= piccole unità di
memoria volatile).
spegne allo spegnimento della macchina
insieme ordinato di parole di memoria (=celle) a parola = n elementi binari (8, 16, 32,
64 bit)
la posizione di ciascuna cella è definita da un indirizzo —> la capacità di indirizzamento
della ram è definita dalle dimensione di bus indirizzi e registro indirizzi
a. LA RAM (RANDOM ACCESS MEMORY)
le celle, indipendentemente dalla posizione
b. LA ROM (READ ONLY MEMORY)
- costituita dalla stessa tecnologia della Memoria di massa
della produzione e non modificabili
nb! all#accensione del pc la RAM contiene una sequenza casuale di 01 mentre la ROM
contiene il bootstrap, programma contenente le prime istruzioni che la CPU deve
svolgere.
—> Indirizzamento della RAM
gli indirizzi i di ciascuna parola corrispondono a un valore numerico intero positivo
espresso in binario su un certo numero di bit
=> k bit possono indirizzare 2
k
celle (es. con 10 bit indirizzo 2
= 1024 celle, 20 bit un
mega di parole, 30 bit un giga, 40 bit un tera).
All#interno della CPU vi è un registro indirizzi che contiene tutti gli indirizzi i delle celle
da cercare, quindi l#indirizzo i della cella viene scritto sul registro indirizzi e da qui viene
mandato tramite il bus indirizzi alla ram.
contiene gli elementi circuitali che regolano il funzionamento della macchina
formata da:
a. UNITÀ DI CONTROLLO (UC) = responsabile della decodifica ed esecuzione delle
istruzioni, dirige l#azione delle altre parti.
—>Il formato delle istruzioni è il linguaggio macchina
è costituito da sequenze di 01
contiene:
il campo codice operativo che specifica l#istruzione da eseguire
il campo operandi che indica, per valore o indirizzo, i dati da utilizzare (possono
essere 0, 1, 2).
formato istruzione =
b. UNITÀ ARITMETICO-LOGICA (ALU) = esegue le operazioni aritmetico logiche fra
registri A e B in ingresso, non ha facoltà di scelta
c. REGISTRI = piccole memorie velocemente accessibili utilizzate per memorizzare
dati temporanei, dati di controllo e risultati parziali durante le operazioni di calcolo
L#insieme dei contenuti dei registri in un dato istante è detto contesto.
d. OROLOGIO DI SISTEMA (CLOCK) = elemento di sincronizzazione che
temporarizza le varie operazioni del calcolatore.
—> LOAD (lettura da MC)
alla memoria via bus indirizzi
la CPU invia il comando di read memory sul bus di controllo
la memoria trasmette sul bus dati il contenuto della parola verso il registro dati
la memoria segnala al processore sul bus di controllo che l’operazione è stata
completata con successo: il dato si trova nel registro dati
—>STORE (scrittura da MC)
indirizzi e lo trasmette alla memoria via bus indirizzi
la CPU carica nel registro dati la parola da scrivere in memoria
la CPU invia il comando di write memory sul bus di controllo
la CPU trasmette sul bus dati il contenuto del registro dati verso l’indirizzo di
memoria segnalato
eseguita con successo: il dato si trova nella parola di memoria destinazione
consentono la comunicazione con l#ambiente esterno (anche se non sempre con utente
umano).—> le periferiche dati sono collegate al bus tramite interfacce : dispositivi
(elettronici o elettromeccanici) che traducono elementi periferici per il collegamento con
l#elaboratore tramite il bus.
Le interfacce contengono:
bus di controllo
(es. pronta, occupata, errore).
per macchine più moderne:
supporto per la programmazione
meccanismi di ingresso e uscita
gestione archivi (file).
—> da codice in C a in assembler (?)
nb! il compilatore deve decidere prima quanto spazio allocare per le variabili.
nb! la corrispondenza posizionale tra i %d e le variabili di traduce in un preciso ordine di
istruzioni READ in assembler
ogni espressione ha : un TIPO ed un VALORE
ARRAY = variabile strutturata in cui si memorizzano più valori tutti dello stesso tipo
inizializzazione —> v[5]={1,2,3,4,5} 5=num elementi, 1 ha indice zero..
MATRICI = array bidimensionali
dati organizzati per righe ‘i' e colonne ‘j’, elementi anche qui specificati prima
mat[4][5] 4=riga, 5=colonna
prodotto tra matrici <=> numero di colonne di prima mat è uguale a numero di righe della
seconda mat
risultato è matrice con stesso numero di righe e colonne
es:
1 2 3 x 1 1 = 1x1+2x1+3x0 1x1+2x5+3x2 = 3 17
0 1 3 2 5 0x1+1x2+3x0 0x1+1x5+3x2 2 11
matrice quadrata<=> i=j
trasposta - > inverto elementi di colonna con quelli di riga intorno a diagonale principale
si ha trasposta solo di mat quadrata
se matrice=matrice trasposta - > mat è simmetrica
STRINGHE = array di caratteri
es. char a[ ]=“parola” —> array di 7 eletti= 6caratteri+ termine tappo—>’\ 0 ’ che termina la
stringa
dove “r” è una striga costante mentre ‘r’ è una costante di tipo char
—> non sono un tipo base di dato => aggiungere propria libreria #string.h
viene considerato - > per leggere tutta stringa usare getchar()
—> il nome dell’array rappresenta l’indirizzo del suo primo elemento perciò con scanf non
necessario una & es. scanf(“%s”, stringa)
—> se scanf acquisisce stringa troppo lunga, questa è memorizzata oltre la fine dell’array =
errore grave
array => collezioni di variabili omogenee
struct => collezioni di variabili eterogenee
STRUCT = variabile strutturata in cui si memorizzano più valori (dati , che in struct sono
chiamati campi) di tipo differente
struct data { //data è un nuovo tipo di dato che si può usare nel main
int giorno;
char mese[ ];
int anno;
—> per accedere ai campi della struttura usare ‘.’
esempio (nel main)
struct data oggi;
oggi.giorno=25;
oggi.anno=2020;
oggi.mese=“dicembre”
quindi
printf (“%d”, oggi.anno) stamperà 2020
—> posso copiare elementi di una struct in un’altra struct (solo se sono dello stesso tipo)
attraverso = —> esempio:
struct data oggi;
struct data compleanno;
compleanno=oggi; //assegna valori di oggi a compleanno
typedef int {intero}; nel main posso definire con nuovo tipo—> intero numero;
typedef struct{
char nome[20];
char cognome[20];
int annoNascita;
int codiceFiscale[30];
} persona;
typedef char {
ventiCaratteri [20]
ventiCaratteri nome, cognome; = nome e cognome sono di tipo ventiCaratteri, ovvero due
array di 20 char
sono delle variabili abilitate a contenere un indirizzo
es. &a = restituisce l’indirizzo di memoria della variabile a
contenuto dell’oggetto puntato, perciò estrae il valore contenuto nella cella puntata (permette
di andare a modificare il valore del puntatore)
variabili di tipoBase —> puntatore è un tipo derivato perché occorre specificare a che
indirizzo punta
es. int *p => p punta ad un intero
se ho void *p => non viene specificato il tipo di indirizzo di memoria a cui punta, può puntare
a qualsiasi variabile
int x=
int *p
p= &x //è analogo a scrivere int *p = &x
//il valore di p corrisponde all’indirizzo di x => p contiene l’indirizzo di x
printf (“il valore di x è %d”, *p) //il valore stampato è 3 quindi dopo l’assegnazione p= &x *p
e x sono perfettamente equivalenti
—> l#indirizzo della cella i-esima è: v + i //la dereferenziazione di tale valore permette di
accedere al contenuto della cella i-esima
—> differenza tra array e puntatori:
Essendo array di tipo int *const il suo indirizzo non può essere modificato durante l#esecuzione
del programma. Quello di punt può invece essere modificato liberamente.
—> Con la seguente dichiarazione:
int a[5], i, *p;
a[i] //equivale a *(a + i);
p = a; //equivale a p = &a[0];
p = a + 1; //equivale a p = &a[1];
a = p; //è un ERRORE !!
a = a + 1; //è un ERRORE !!
A è il nome di un array, quindi un puntatore costante. L#indirizzo dell#array non può essere
modificato.
—> Se p e q puntano a due diversi elementi di uno stesso array:
int v[5] = {14, 16, 8, 9, 12};
int *p = &v[3], *q = &v[1];
la differenza: p – q dà la distanza tra gli elementi puntati espressa in numero di celle dell#array
valori in uscita
tipo_funzione nome_funzione (tipo_variabile variabile1, tipo_variabile variabile2) {
dove tipo_funzione corrisponde al tipo che viene restituito, mentre tipo_variabile corrisponde al
tipo che viene inserito
! Dichiaro la funzione prima del main (dichiarazione)
! Specifico i passaggi della funzione in { } (definizione ). La funzione restituisce un valore
(return valore;) dello stesso tipo della funzione. Le funzioni che non restituiscono valori sono
di tipo void (dette anche procedure ) —> l#istruzione del return è assente, la funzione termina
quando il flusso di esecuzione arriva alla } finale.
! Invocazione: quando uso la funzione all#interno del main.
formali = parametri presenti nella definizione (es. variabile1, variabile2)
attuali = parametri dati al momento dell’invocazione nel main —> i tipi devono corrispondere
funzione all’interno dell’ambiente chiamante occorre utilizzare i puntatori => ovvero uso i
puntatori quando non ho un valore di ritorno e scopo è modificare un parametro nel main e
non restituire un valore
Void modifica_dato (int *dato) {
*dato=4; //il valore della cella puntata da dato è 4
int nuovo_dato (int dato) {
Dato=1;
Return dato; }
Int main () {
Int dato =0;
printf("dato: %d\n”, dato);
nuovo_dato(dato); //il valore della variabile nel main rimane zero, perché non ho
assegnato il valore di ritorno della funzione a nessuna variabile.
printf("dato: %d\n”, dato); //stampa zero
dato = nuovo_dato(dato); //ho assegnato il valore di ritorno della funzione alla variabile.
Quindi la mia variabile ha cambiato valore.
printf("dato: %d\n”, dato); //stampa 1
modifica_dato (&dato); //modifico il dato anche senza avere un valore di ritorno e senza
assegnare a nessuna variabile il mio valore di ritorno (è una funzione void). (Quindi posso
andare a modificare il valore di una variabile senza assegnare a questa un valore di ritorno)
printf("dato: %d\n”, dato); //qui il dato si modifica —> stampa 4. Il dato è stato modificato nel
main
//quando io uso i puntatori modifico la variabile a livello globale (nel main).
—> per modificare i parametri attuali con i puntatori
(&varLocale)
parametro (*p)
caratteristiche:
memorizzazione persistente dei dati, non limitata dalle dimensioni della memoria centrale.
Ogni programma vede il file come una sequenza di componenti (record logici), terminata da
una "marca” di fine file (End Of File —> EOF).
= sono degli archivi che:
permettono il salvataggio persistente dei dati su un supporto fisico
il caricamento dei dati su un supporto fisico in momenti successivi al salvataggio
—>libreria necessaria per interagire con file: stdio.h
tipo:
binario => sequenza di byte
testo => sequenza di caratteri
restituisce il file pointer (infatti il valore di ritorno della funzione viene assegnato alla
variabile fp), che viene associato a nomeFile.txt
return-1}
—>modalità di utilizzo:
“r” = read => permette di leggere elementi del file, la testina (=indicatore della posizione
corrente nel file) è posizionata all’inizio del file
“w” = write => permette di scrivere su file, gli elementi precedentemente contenuti vengono
eliminati e la testina è posizionata all’inizio del file (per scrivere su file senza cancellare
elementi precedenti usare “a” = append)
—> descrittore:
programma e non prima
#include <stdlib.h> —> permette di utilizzare funzioni per l#allocazione e il rilascio dinamico
di memoria
void* malloc (n°di byte da allocare di un certo tipo);
—> il tipo non viene specificato, ma è compito del programmatore determinarne il tipo
—> restituisce un puntatore di tipo void che punta alla memoria allocata (una variabile senza
nome, che può essere utilizzata solo tramite il suo puntatore)
—> la funzione malloc crea in memoria una variabile di un certo tipo e restituisce l’indirizzo del
byte riservato in memoria alla variabile
es. pi = (int *) malloc(sizeof(int)) —> l’istruzione alloca dinamicamente in memoria una
quantità tale da poter accogliere un intero ; questo intero allocato dinamicamente e di cui non
si conosce il nome, può essere raggiunto solo tramite il puntatore pi.
In particolare (int *) permette di assegnare l’indirizzo del primo byte dell’intero a pi, dopo
aver convertito il tipo void* (ritornato da malloc) nel tipo int* —> chiamo cast (=conversione da
un tipo ad un altro)
—> se non vi è più memoria disponibile malloc restituisce NULL
dalla memoria, tramite free:
void free (void *ptr);
—> libera la memoria precedentemente allocata per il puntatore ptr
es:
char *ptr
ptr = (char*) malloc(sizeof(char))
*ptr = ‘a’ // scrivo nella memoria riservata da malloc ‘a’
printf (“%c”, *ptr)
free (ptr) //non viene eliminato ptr ma il valore presente nella memoria a cui puntava ptr,
quindi ora in memoria non sarà più presente ‘a’
! produzione di garbage => si verifica quando memoria allocata dinamicamente è
inaccessibile (es non uso la free prima di far puntare puntatore che puntava a memoria
dinamica ad un’altra variabile, quindi quella variabile occupata un’area di memoria che
risulta essere inutilizzabile)
! puntatori fluttuanti => che puntano ad aree di memoria che sono già state deallocate
! dangling refereces (riferimenti fluttuanti): creazione di riferimenti fasulli a zone di memoria
inesistenti. – più rischiosa
elementi numEle elementi di dimensione eleDim