Skip to content
This repository has been archived by the owner on Jun 16, 2023. It is now read-only.

Commit

Permalink
lezione-9
Browse files Browse the repository at this point in the history
  • Loading branch information
mc-cat-tty committed Oct 21, 2021
1 parent a662ca6 commit 6b3eef6
Show file tree
Hide file tree
Showing 12 changed files with 227 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
esempi/*.out
esercitazioni/*.out

40 changes: 40 additions & 0 deletions 9_best_practice_funzioni.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Best practice funzioni

## Input variabili
È meglio prendere in input le variabili necessarie nella funzione o utilizzare un parametro formale?
La soluzione migliore è la seconda, perchè rende il codice più modulare e riutilizzabile.

## Output variabili
Analogamente a quanto sopra detto, anche per l'output è meglio ritornare i valori delle funzioni, così da non replicare il codice.

## Chiamate incrociate
In questi casi è necessario dichiarare la funzione prima di definirla. Dal punto in cui viene dichiarata la funzione in poi è possibile usare la stessa.

### Prototipi e definizioni
Dichiarazione o prototipo di funzione: sola intestazione di una funzione seguita da punto e virgola (niente graffa). Nel prototipo di una funzione non è necessario l'identificatore dei parametri formali (al compilatore basta sapere il tipo di parametro che è possibile passare).

Il prototipo:
- è un "avviso ai naviganti"
- non causa produzione di codice eseguibile, è un mero avviso al compilatore
- può essere ripetuto più volte all'interno del programma, l'importante è che le varie dichiarazioni non siano in contraddizione tra loro

La definizione:
- contiene il codice della funzione
- non può apparire più volte
- il nome dei parametri formali è obbligatorio

-> il prototipo può comparire più volte (per esempio su più file header), ma la definizione deve essere unica.

### Controlli compilatore
Il compilatore controlla che l'invocazione sia *sintatticamente* corretta:
- numero parametri (formali e attuali devono coincidere)
- tipo di ciascun parametro formale
- tipo valore di ritorno

Il compilatore segnala solamente errori sintattici. Per ottenere più warning (sensibilità più alta da parte del compilatore) possiamo usare il flag `-Wall` e `--pedantic`.
Eg: è possibile passare un bool ad un parametro formale di tipo int (dal punto di vista della memoria sono la stessa cosa)

Il compilatore sostituisce ogni chiamata a funzione con un'istruzione di salto (in codice macchina).



4 changes: 4 additions & 0 deletions 9_codice_di_qualità.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Scrivere codice di qualità
First law of programming: error=mc^2 => more code al quadrato :)

Programmare per micro-fasi. Ogni versione parziale del codice deve essere immediatamente collaudata. In questo modo si possono identificare gli errori, che potrebbero amplificare il proprio effetto (accumularsi). Al posto di scrivere tutto il codice da zero.
36 changes: 36 additions & 0 deletions 9_debugging.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Debugging
=> ricerca di bug (logici o di altro tipo) in un programma

## Debugger
Utile ma difficile da usare

## Testing
Testo (teoricamente) tutti i possibili input e verifico che l'output sia quello desiderato.

Due tipi di testing:
> white box
Il programmatore si mette nei panni del compilatore, per controllare che sia formalmente corretto, e dell'esecutore (CPU), per controllare che il programma venga eseguito come pensato.
> black box
Faccio finta di non conoscere il codice sorgente del programma e lo testo con vari input (possibilmente tutti i valori possibili)
Scelgo input agli estremi del dominio e input al di fuori di esso, per accertarmi che il programma sia robusto.

Cosa succede se il test fallisce?
Due tipi di fallimento:
- il programma crasha. Esso viene terminato forzatamente dal SO a causa di un operazione illegale (come la divisione per zero)
- il programma termina correttamente ma il risultato è scorretto. Errore logico contenuto nel programma. Questo tipo di errore viene chiamato *bug* o *baco*. Le tarme/cimici un tempo bloccavano l'esecuzione dei relé e delle valvole, causando problemi nel funzionamento dei computer.

Hint: non programmare mai al 100% delle tue capacità intellettuali, perchè debuggare un codice può diventare 5 volte più complicato di scriverlo.

## Analisi statica del codice
=> rilettura accurata del codice nell'ottica di trovare gli errori.

### Duck programming
=> prendere una paperella e spiegarle il funzionamento del programma.

### Pair programming
=> una persona scrive il codice, mentre un'altra guarda il codice scritto ed, evenutalmente, evidenzia errori logici.

## Tracing
=> tracciare l'evoluzione del valore delle variabili per individuare dove avviene una lettura/scrittura non desiderata.

Il tracing di cicli viene spesso "rallentato" utilizzando delle `cin`, che attendono un qualche input da stdin.
23 changes: 23 additions & 0 deletions 9_tipi_passaggio.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Tipi passaggio dei parametri
=> tipo di inizializzazione dei parametri formali a partire dai parametri attuali.
- passaggio per valore
- passaggio per riferimento (no in C (?))

## Passaggio per valore o passaggio per copaia
La locazione di memoria di ogni parametri formale viene inizializzata copiando il valore di ciscun parametro attuale.
L'area di memoria dei parametri formali viene deallocata dopo il termine della funzione. I parametri formali sono privati alla funzione, ne consegue che ogni loro modifica è locale alla funzione (tempo di vita coincide con quello della funzione stessa).
In questo caso i valori dei parametri attuali non vengono mai modificati.
Modificare i parametri formali è una cattiva abitudine [vedi esercizio somma da 1 a n]. Si rende il codice poco leggibile, si creano effetti collaterali se il passaggio avviene per riferimento, la distinzione logica tra variabile ausiliaria, di ingresso e di uscita viene rotta. La modifica

### Vantaggi
- variabili del chiamante e del chiamato sono *disaccoppiate* -> ragionare per compartimenti stagni

### Svantaggi
- non posso modificare le variabili del chiamante _a priori_
- operazione costosa (soprattutto per dati di grosse dimensioni)

### const
=> qualificatore che non consente di modificare i parametri formali

Attenzione: const può creare una divergenza tra il prototipo della funzione e la sua definizione.

Binary file added esempi/a.out
Binary file not shown.
17 changes: 17 additions & 0 deletions esercitazioni/funzione_fattoriale.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include <iostream>

using namespace std;

const int fattoriale(const int n) {
int res = 1;
for (int i=1; i<=n; i++)
res*=i;
return res;
}

int main() {
int val;
cout << "Numero: "; cin >> val;
cout << "Fattoriale: " << fattoriale(val) << endl;
return 0;
}
16 changes: 16 additions & 0 deletions esercitazioni/funzione_max.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include <iostream>

using namespace std;

int ritorna_massimo(int a, int b) {
if (a>b)
return a;
return b;
}

int main() {
int x, y;
cout << "Valori: "; cin >> x >> y;
cout << "Massimo: " << ritorna_massimo(x, y) << endl;
return 0;
}
24 changes: 24 additions & 0 deletions esercitazioni/funzione_prime.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#include <iostream>
#include <cmath>

using namespace std;

bool is_prime(const int n) { // is_prime è snake-case, isPrime è camel-case
if (n>0 && n<=3)
return true;
if (n%2 == 0)
return false;

for (int i=3; i<=static_cast<int>(sqrt(n)); i+=2) {
if (n%i == 0)
return false;
}
return true;
}

int main() {
int val;
cin >> val;
cout << is_prime(val);
return 0;
}
25 changes: 25 additions & 0 deletions esercitazioni/funzione_primi_gemelli.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include <iostream>
#include <cmath>

using namespace std;

bool is_prime(const int n) { // is_prime è snake-case, isPrime è camel-case
if (n>0 && n<=3)
return true;
if (n%2 == 0)
return false;

for (int i=3; i<=static_cast<int>(sqrt(n)); i+=2) {
if (n%i == 0)
return false;
}
return true;
}

int main() {
int val1, val2;
cin >> val1 >> val2;
if ((abs(val1-val2) == 2) && is_prime(val1) && is_prime(val2))
cout << "Primi gemelli";
return 0;
}
16 changes: 16 additions & 0 deletions esercitazioni/funzione_sqrt.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include <iostream>

using namespace std;

inline const int my_sqrt(const int n) {
int i;
for (i=1; i*i<=n; i++);
return i-1;
}

int main() {
int val;
cin >> val;
cout << my_sqrt(val) << endl;
return 0;
}
25 changes: 25 additions & 0 deletions esercitazioni/somma_quadrati.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include <iostream>

using namespace std;

const int ricerca_j(const int n, const int i) {
int j;
for (j=i; j <= n-1 && i*i+j*j != n; j++);

if (i*i+j*j == n)
return j;
return -1;
}

int main() {
int n;
cin >> n;
for (int i=1, j; i <= n; i++) {
j = ricerca_j(n, i);
if (j != -1) {
cout << "i: " << i << " j: " << j << endl;
return 0;
}
}
return 1;
}

0 comments on commit 6b3eef6

Please sign in to comment.