Skip to content
Snippets Groups Projects
Unverified Commit 1183da48 authored by Andrea Trentini's avatar Andrea Trentini
Browse files

lab07

parent abfcb020
Branches
No related tags found
No related merge requests found
......@@ -47,3 +47,20 @@ Byte e rune, operazioni con caratteri. Il pacchetto unicode. Il tipo string. Il
## 9 novembre 2023 - Lab05 - Switch e funzioni
### Materiale e link
## 16 novembre 2023 - Lab06 - puntatori, struct e array
## 23 novembre 2023 - Lab07 - slice e array e bufio
## 30 novembre 2023 - Lab08
## 14 dicembre 2023 - Lab09
## 21 dicembre 2023 - Lab10
## 11 gennaio 2024 - Lab11
\ No newline at end of file
Lab07.md 0 → 100644
# Lab 07 - slice e array e bufio
## sorgenti (inclusi nomi sbagliati) consegnati: 66
## quanti di ogni esercizio:
```
10 punto_bis.go
10 array.go
8 countdown.go
7 usaStandard.go
7 estraiData_bis.go
7 dado_bis.go
3 scambio.go
3 conta_cifre.go
3 carte.go
2 puntatori.go
2 clessidra.go
1 usastandard.go
1 puntatore2.go
1 estraiDATA_bis.go
1 black_jack.go
```
## errori compilazione
```
./punto_bis.go:24:23: not enough arguments in call to newPunto have (unknown type) want (float64, float64)
./punto_bis.go:24:23: undefined: punto
./punto_bis.go:24:5: no new variables on left side of :=
./punto_bis.go:26:16: undefined: punto
./punto_bis.go:26:23: Punto (type) is not an expression
./punto_bis.go:27:14: undefined: punto
./punto_bis.go:50:14: undefined: x
./usaStandard.go:52:34: syntax error: unexpected literal ", " at end of statement
```
---
# Consegne del Lab 06 - osservazioni e correzioni
- Punto: passaggio di parametri vs lettura da stdin
```go
func NewPunto(x,y float64) Punto {
var p3 Punto
fmt.Scan(&x) <<<<<<<<<
fmt.Scan(&y) <<<<<<<<<
p3.x=x
p3.y=y
fmt.Print("punto p3:") <<<<< NO
return p3
}
```
- Data: un po' troppi riferimenti annidati
```go
func stringGMA2GMA(data string) (int, int, int) {
giorno, _ := strconv.Atoi(data[:strings.Index(data, "/")])
mese, _ := strconv.Atoi(data[strings.Index(data, "/") + 1:strings.LastIndex(data, "/")])
anno, _ := strconv.Atoi(data[strings.LastIndex(data, "/") + 1:])
return giorno, mese, anno //da sostituire con il codice per questa funzione
```
- Data: meglio questa soluzione, *se avete visto le slice*
```go
func stringGMA2GMA(data string) (int, int, int) {
parti:= strings.Split(data, "/")
g, _:=strconv.Atoi (parti[0])
m, _:=strconv.Atoi (parti[1])
a, _:=strconv.Atoi (parti[2])
return g, m, a
}
```
- Array: for + if?
```go
func reverse(array *[DIM]int){
for i:=0;i<DIM;i++{
if i<=DIM/2{ <<<<<<<
array[i],array[(DIM-1)-i]=array[(DIM-1)-i],array[i]
}
}
}
```
- Array: c'è l'assegnamento multiplo!!!
```go
x:=array[(DIM-1)-i]
array[(DIM-1)-i]=array[i]
array[i]=x
```
- inizializzazione di un array
```go
var array[DIM] int
array[0]=4
array[1]=5
array[2]=6
array[3]=7
array[4]=8
```
vs
```
arr:=[DIM]int{27, 7, 3, 13, 17}
```
- array vs slice
```go
dim := 5
a := make([]int, dim)
```
- Array: reverse (posizionale!) con Sort?!?
- Array: nell'array stesso?
```go
func reverse (v *[DIM]int) {
var tmp [DIM]int <<<<<<<<<<
for i:=len(*v)-1; i>=0; i-- {
tmp[int(math.Abs(float64(i-4)))]=(*v)[i]
}
*v=tmp
}
```
- Carta: iterazione vs ricorsione!
```go
func estraiCarta() Carta {
numeroCasuale := rand.Intn(numCarte)
carta, valido := carta(numeroCasuale)
if !valido {
return estraiCarta() //<<<<<<< chiamata ricorsiva
}
return carta
}
```
- Countdown: != vs </>
```go
if (*clock).sec==0 && ((*clock).hour!=0 ||(*clock).min!=0 )
```
- Countdown: evitare i doppi controlli
```go
func countdown (clock *Clock) {
if (*clock).sec==0 && ((*clock).hour!=0 ||(*clock).min!=0 ){ <<<<<<<<<<
func main() {
for {
countdown(&clock)
.....
if clock.hour==0 && clock.min==0 && clock.sec==0 { <<<<<<<<<<
break
}
```
- Countdown d.c. <<<
divisione dei compiti (ad es. downMin aggiorna anche i secondi)
```go
func downHour(time Clock) {
time.min = 59
time.hour--
}
```
- Dado: cosa fa?
```go
for i := 0; i < n; i++ {
lancio = rand.Intn(NFACCE) + 1
frequenza[lancio]++
for i:=0; i<n; i++ {
fmt.Printf("%d: %d (%d%%)\n", i, frequenza[i], frequenza[i]*100/n)
}
}
```
---
## Note iniziali
- Go test: vedi indicazioni in Lab06.md
### Interruzioni forzate
Ci sono tre diversi livelli in cui è possibile dare istruzioni di **interruzione forzata**, da non confondere assolutamente:
- a livello di **ciclo for** con l'istruzione "**break**": <ins>l'esecuzione del programma prosegue</ins> con l'istruzione subito dopo la chiusa graffa del for;
- a livello di **funzione** con un'istruzione di "**return**": <ins>l'esecuzione del programma prosegue</ins> nella funzione chiamante con l'istruzione in cui la funzione è stata chiamata, o, se è completata, con quella subito dopo;
- a livello di **programma**, e quindi di funzione main, con l'istruzione "**return**" o invocando la funzione "**os.Exit**": <ins>l'esecuzione del programma termina</ins>.
---
### Funzioni e I/O
Quando volete implementare una parte della soluzione attraverso una **funzione**, chiedetevi:
1. se la funzione vi serve principalmente per **spezzare il codice** in moduli più piccoli, che potreste mettere insieme senza modifiche o quasi in un unico main;
1. se la funzione deve **ricevere** da e / **o fornire** al resto del programma dei **valori**.
Nel **primo caso**, tra le parti che potete voler impacchettare in una funzione potrebbe esserci anche la **lettura** dell'input e/o la **stampa** dell'output.
Nel **secondo caso**, invece, è meglio passare valori alla funzione per mezzo di **parametri**, facendo leggere altrove i dati dall'esterno (tipicamente nel main). Analogamente è meglio passare per mezzo di **valori di ritorno** (*return values*) i risultati calcolati dalla funzione, delegandone, tipicamente al main, la eventuale stampa.
In generale, cercate di evitare funzioni con tutti e due i ruoli (ma, come sempre, ci possono essere eccezioni).
E in ogni caso, in generale evitate funzioni con solo un paio di righe di codice o una sola. In questi casi mettete l'istruzione, o le istruzioni, direttamente al posto dell'invocazione di funzione (ma, come sempre, ci possono essere eccezioni).
---
### La slice os.Args
Un programma ha accesso agli argomenti passati da linea di comando per mezzo della slice `os.Args`, una variabile del pacchetto `os`.
In `os.Args` vengono salvati automaticamente, come stringhe, gli argomenti passati da linea di comando a un programma.
Il primo elemento di questa slice, os.Args[0], contiene sempre il path del programma, mentre os.Args[1:] contiene gli argomenti veri e propri passati al programma da linea di comando.
Ad esempio, se lancio l'esecuzione di myProgram così:
```
./myProgram arg1 arg2 arg3
```
os.Args conterrà "arg1", "arg2", e "arg3", in particolare "arg1" in os.Args[1], "arg2" in os.Args[2], e così via.
---
## Brevi richiami sulle slice
#### Dichiarazione di una slice (viene creata una slice nulla, cioè nil):
sintassi:
```go
var nomeSlice []type
```
esempio:
```go
var mySlice []int
```
Nota. Le funzioni builtin len, cap e append funzionano anche con slice nil.
#### Creazione/inizializzazione di una slice con lunghezza/capacità fissate
sintassi:
```go
nomeSlice := make([]type, length, capacity)
nomeSlice := make([]type, length) //la capacità può non essere specificata
nomeSlice := []type{} // tra {} ci può essere una lista di valori
```
esempi:
```go
mySlice := make([]int, 4, 5)
mySlice := make([]int, 4)
mySlice := []int{}
mySlice := []int{1, 2, 3, 4}
```
#### Stampa di una slice
```
mySlice := []int{1, 2, 3, 4}
fmt.Println(mySlice)
```
produce in output:\
[1 2 3 4]
#### Subslicing
```go
mySlice[3] //elemento di indice 3
mySlice[:3] //gli elementi fino a quello di indice 3 escluso
mySlice[3:] //gli elementi da quello di indice 3 incluso all'ultimo
mySlice[3:7] //gli elementi da quello di indice 3 a quello di indice 6 (cioè a quello di indice 7 escluso)
```
#### Funzioni built-in per slice
(vedi documentazione packages, sotto builtin)
```go
func append(nomeSlice []Type, elems ...Type) []Type
```
esempi:
```go
mySlice = append(aSlice, elem1, elem2)
mySlice = append(aSlice, anotherSlice...) // i ... fanno parte della sintassi
```
```go
func copy(dest, src []Type) int
```
Nota: se dest è più piccola di src, solo una parte verrà copiata.
esempio:
```go
//esempio con lunghezze uguali:
myCopy = make([]int, len(mySlice))
copy(myCopy, mySlice)
```
---
## Esercizi Go per il Lab 07 - slice e array e bufio
### Esercizi di avvio all'uso delle slice
### Esercizio 1 - progettazione: memorizzazione in slice vs elaborazione/stampa immediata
Problemi con domande sull'uso o meno di slice, a [questo link](https://forms.gle/rPqGNkNyjuMFmiMRA).
Rispondere alle domande del form.
### Esercizio 2 - implementazione
Scrivete i programmi per i problemi n. 2, 7, 8, 10, 12 dell'esercizio 1 e caricateli su upload (con i nomi es2.go, es7.go, es8.go, ecc.).
### Esercizio 3 - comprensione
Esercizio di associazioni frammenti di codice - descrizioni di operazione su slice, a questo [link](https://forms.gle/QWYktEU6G9dyD5FN6) (esercizio propedeutico all'esercizio 4).
### Esercizio 4 - operazioni su slice
Scrivere un programma usoLeSlice.go che
- legge da linea di comando una lista di almeno 3 parole;
- legge da standard input un'altra lista di parole (anche almeno 3).
Quindi fa le seguenti operazioni e man mano stampa il risultato ottenuto:
1. delle due liste fa un'unica lista (slice), da elaborare e a cui, se serve, ci riferiremo con "mySlice"
2. mette in ordine alfabetico (lessicografico) la slice ottenuta (usare una funzione di libreria) e poi la stampa
3. cancella l'ultima parola dalla slice
4. rimuove dalla slice gli elementi di indice dal 2 (incluso) al 4 (escluso)
5. crea una nuova slice con "aa", "bb" e "cc"
6. la inserisce in posizione 1 della vecchia slice (mySlice)
7. legge una nuova parola e la inserisce in posizione 2 della slice mySlice
8. legge una nuova parola e la inserisce in fondo alla slice mySlice
9. estende la slice mySlice con una nuova slice di lunghezza 2 (di stringhe vuote)
10. inserisce alla posizione 3 di mySlice una nuova slice di lunghezza 3 (di stringhe vuote)
11. copia in una nuova slice la slice mySlice ottenuta fin qui
12. dalla copia rimuove l'ultimo elemento e stampa sia la slice mySlice che la copia.
Esempio di esecuzione:
```
$ ./usoLeSlice.go uno due tre
scrivi almeno 3 parole (seguite da ctrl D)
4 5 6 7
1. [uno due tre 4 5 6 7]
2. [4 5 6 7 due tre uno]
3. [4 5 6 7 due tre]
4. [4 5 due tre]
5. [aa bb cc]
6. [4 aa bb cc 5 due tre]
scrivi una parola: pos2
7. [4 aa pos2 bb cc 5 due tre]
scrivi una parola: lastPos
8. [4 aa pos2 bb cc 5 due tre lastPos]
9. [4 aa pos2 bb cc 5 due tre lastPos ]
10. [4 aa pos2 bb cc 5 due tre lastPos ]
11. [4 aa pos2 bb cc 5 due tre lastPos ]
12. [4 aa pos2 bb cc 5 due tre lastPos ]
[4 aa pos2 bb cc 5 due tre lastPos ]
```
nomefile: usoLeSlice.go
### Esercizio 5 - da stringhe a slice
(uso delle funzioni strings.Fields, strings.Split e strings.SplitAfter e delle conversioni []byte() e []rune())
Scrivere una programma `strings2slice.go` che legge da linea di comando:
- una stringa in formato CSV (del tipo: \<nome\>,\<cognome\>,\<matricola\>), ne estrae i valori salvandoli in una slice e stampa la slice;
- della stessa stringa estrae i valori compresa la virgola separatore salvandoli in una slice e stampa la slice;
- una frase tra "" di parole separate anche da più spazi e tab, ne estrae le parole salvandole in una slice e stampa la slice;
- un numero intero non negativo e stampa la slice dei codici ASCII delle cifre che lo formano, nello stesso ordine da sinistra a destra;
- una stringa di lettere accentate e stampa la slice dei codici unicode delle lettere che la formano;
- un orario nel formato h:m:s, ne estrae ore, minuti e secondi salvandoli in una slice e stampa la slice.
## Esercizi sulle slice e su bufio
(os.Arg, slice restituite da funzioni di libreria, slice create nel programma)
### Esercizio - Quadrati (con TEST)
Scrivere una programma `quadrati.go` che legge da linea di comando una sequenza di numeri interi non negativi e stampa solo quelli che sono dei quadrati (1, 4, 9, ecc.). Il programma deve essere dotato di una funzione
`isSquare(n int) bool`
che restituisce true se *n* è un quadrato, false altrimenti.
nomefile: quadrati.go
### Esercizio - Ordini (con TEST)
Scrivere un programma ordini.go che legge da standard input una serie di stringhe che descrivono ordini nel formato
`prezzo#quantità#sconto`
e stampa il totale finale da pagare.
Prezzo, quantità e sconto sono float; prezzo indica il prezzo unitario del prodotto, quantità indica la quantità acquistata e sconto è lo sconto applicato per quel prodotto, espresso come float tra 0 e 1 (ad esempio 0.2 indica uno sconto del 20%).
Il programma termina la lettura quando incontra EOF (ctrl D su riga nuova).
nomefile: ordini.go
### Esercizio - Stampa alternata (con TEST)
Scrivere un programma stampaAlternata.go che legge da standard input del testo su più righe (terminato da EOF) e stampa prima le righe pari e poi le righe dispari (considerate la prima riga del testo la riga 1 (e non 0)).
nomefile: stampaAlternata.go
### Esercizio - Polinomio (con TEST)
Scrivere un programma `polinomio.go` che legge da standard input una riga che contiene dei numeri a, b, ....
Il programma calcola il valore in x del polinomio\
a + bx + cx^2 + dx^3 ....\
corrispondente alla sequenza dei numeri letti tranne l'ultimo; l'ultimo valore della sequenza è il valore di x.
Ad esempio,
3 2 0 7 5
corrisponde al polinomio 3 + 2x + 7x^3 da valutare per x = 5
nomefile: polinomio.go
### Esercizio - extractions (con TEST)
Scrivere un programma `extractions.go` con due funzioni:
- `estraiPari(in []int) (out []int)` che prende una slice di interi e ne restituisce una che contiene solo i numeri di quella in ingresso che sono numeri pari.
- `rimuoviMultipli(m int, in []int) (out []int)` che prende un intero e una slice di interi e ne restituisce una senza i multipli del numero passato di quella in ingresso. Es.: `rimuoviMultipli(5, in)` restituisce, a partire da `in`, una slice senza i multipli di 5.
Nota: non ci sono specifiche per la funzione main.
nomefile: extractions.go
## Esercizi su array
### Esercizio - giorni della settimana
Scrivere un programma `giornoSettimana.go`, dotato di un array giorniDellaSettimana\
```[7]string{"lun", "mart", "merc", "giov", "ven", "sab", "dom"}```\
che legge da linea di comando il nome del giorno della settimana del 1° gennaio di un dato anno. Se il giorno non è fra "lun", "mart", "merc", "giov", "ven", "sab", "dom", il programma avvisa e termina. Altrimenti poi accetta da standard input dei numeri interi (tra 1 e 365), corrispondenti a giorni di quell'anno, e per ciascuno stampa il giorno della settimana corrispondente. Il programma termina quando l'utente digita -1.
nomefile: giornoSettimana.go
### Esercizio - conteggio delle lettere in un testo (con TEST)
Scrivere un programma `contaLettere.go` che legge un testo (da stdin) e stampa quante volte (anche 0) appare nel testo ciascuna lettera minuscola dell'alfabeto ('a'-'z').
Il programma è dotato di una costante\
`const LEN_ALFABETO = 26`\
e di una funzione\
`func aggiornaConteggi(s string, contaMinu *[LEN_ALFABETO]int)`\
che, data una stringa *s*, aggiorna i conteggi delle lettere minuscole di *s*.
Si consiglia di usare la ridirezione dell'input per provare il programma.
Ad esempio (attenzione che il risultato potrebbe cambiare in funzione del contenuto del file, cioè i numeri sono esemplificativi):
```
$ ./contaLettere < questeSpecifiche
a 35
b 1
c 15
d 11
e 38
f 3
g 18
h 4
i 27
j 1
k 1
l 15
m 10
n 29
o 24
p 11
q 2
r 23
s 16
t 28
u 14
v 4
w 1
x 1
y 1
z 3
```
Esempio minimale:
```
$ echo abc | ./contaLettere
a 1
b 1
c 1
d 0
e 0
f 0
g 0
h 0
i 0
j 0
k 0
l 0
m 0
n 0
o 0
p 0
q 0
r 0
s 0
t 0
u 0
v 0
w 0
x 0
y 0
z 0
```
nomefile: contaLettere.go
File added
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment