Ambiente di Sviluppo
- Per lo svolgimento degli esercizi proposti in questa ed altre lezioni viene utilizzato l’ambiente visuale DevC++ (Free Software)
- DevC++ per Windows è un ambiente di sviluppo integrato (IDE, ovvero Integrated Development Environment) che utilizza il compilatore MinGW (“Minimalistic GNU for Windows”)
- MinGW è un compilatore C/C++ a linea di comando basato sul progetto GNU GCC
- Lo studente è libero in ogni caso di utilizzare l’ambiente che preferisce, a patto che supporti il C++ standard
DevC++ Download e documentazione (in inglese)
Definizione di “Free Software” (in inglese)
Il mio primo programma C/C++ (I)
Il mio primo programma C/C++ (II)
Editing
- Editare tutte le linee di codice in un file sorgente, esattamente come le vedete nel lucido precedente
Commento al codice (continua)
#include <iostream>
#include <stdlib.h>
- Le due istruzioni precedenti devono essere presenti quando si utilizzano programmi forniti dalla libreria standard. In questo caso il nostro primo programma utilizza:
- cout (istruzione di uscita) e l’operatore << per stampare a video, presenti nella libreria C++ iostream
- system(“PAUSE”) presente nella libreria C che ha l’effetto di chiedere all’utente di premere un tasto della tastiera per continuare
Il mio primo programma C/C++ (III)
Commento al codice (continua)
using namespace std;
- Questa istruzione è necessaria se si vuole utilizzare la libreria standard del C++ (notare la presenza del ; al termine dell’istruzione)
int main(int argc, char *argv[])
- Prima istruzione eseguibile del programma. main è una parola chiave del linguaggio e serve appunto ad identificare l’istruzione da cui iniziare l’esecuzione del programma (il registro PC conterrà l’indirizzo di via del programma corrispondente all’indirizzo in memoria di questa istruzione espressa – ovviamente – in linguaggio macchina).
- Nel suo complesso questa è in realtà l’intestazione del programma principale che è concepito come una funzione (sottoprogramma). Sarà pertanto più chiaro cosa rappresentano gli elementi che vi compaiono quando studieremo le procedure e le funzioni.
Il mio primo programma C/C++ (IV)
Commento al codice
L’intestazione del programma principale è seguita da una coppia di parentesi graffe che definisce il blocco contenente le istruzioni del programma:
{
cout << “Ciao Mondo!”;
system(“PAUSE”);
return 0;
}
- L’istruzione di uscita cout stampa a video la sequenza di caratteri (stringa) tra i doppi apici
- Il programma di libreria system è utilizzato per “fermare” l’esecuzione del programma in modo da poter vedere l’output prodotto a video (provare a commentare questa istruzione per verificare l’effetto)
- return 0; è una istruzione di salto il cui effetto in questo punto è la terminazione del programma. Terminando il programma “comunica” il valore 0 al sistema operativo.
Il mio primo programma C/C++ (V)
Compilazione
- A questo punto il programma è completo.
- Salvare il file (ad esempio con nome primo.cpp)
- Compilare (“compila” dal menù “esegui”)
Il mio primo programma C/C++ (VI)
Esecuzione
Trattandosi di un semplice programma, sviluppato su un unico file sorgente, viene prodotto dall’ambiente direttamente l’eseguibile primo.exe
Eseguire il programma
- Dall’ambiente (“esegui” dal menù esegui)
- Da sistema operativo, cliccando due volte su primo.exe
- Premendo un tasto la finestra in cui il programma è eseguito si chiude e l’esecuzione è terminata
Esempi di Programmi con strutture di selezione
Nel seguito si suppone che i programmi proposti vengano editati compilati ed eseguiti con le stesse modalità presentate precedentemente.
ESEMPIO 1:
- Specifica del problema: Scrivere un programma che forniti in ingresso da tastiera due numeri interi diversi tra loro determini quale è il maggiore dei due.
- Si suppone che l’ingresso effettuato da chi utilizza il programma sia corretto (che i due dati in ingresso sono numeri interi e sono diversi).
- L’algoritmo per la risoluzione di questo problema è molto semplice. I due numeri (chiamiamoli A e B) vengono confrontati. Se A è maggiore di B viene stampata a video la frase “A è maggiore di B”, altrimenti viene stampata a video la frase B è maggiore di A”
Esempio 1
- L’elaborazione è Y=F(X)
- Dati iniziali X= A, B interi da confrontare
- Dati finali Y= maggiore tra i due valori
- Abbiamo bisogno quindi di due variabili per memorizzare i valori da confrontare di tipo intero
- In questo semplice esempio ci limitiamo a stampare il risultato del confronto.
Esempio 1 – Soluzione
Esempio 1: esecuzione e test
Una volta realizzato, il programma deve essere testato per individuare eventuali malfunzionamenti ed assicurarsi che sia corretto rispetto alle sue specifiche
- Pertanto devono essere definiti tutti i possibili casi di test e il programma deve essere eseguito su ognuno di essi
- In concreto si tratta di identificare gli insiemi di ingressi che determinano tutte le possibili sequenze dinamiche
- In questo caso le possibile sequenze dinamiche sono due. E sono determinate dai due rami dell’if
- I due esempi di esecuzione mostrano che il programma si comporta correttamente sia nel caso che A sia minore di B, sia nel caso che A sia maggiore di B
Esempio 2
- Specifica del problema: Scrivere un programma che forniti in ingresso da tastiera tre numeri interi diversi tra loro, determini quale è il minore dei tre.
- Si suppone che l’ingresso effettuato da chi utilizza il programma sia corretto (in ingresso sono forniti tre interi e sono tre numeri diversi tra loro).
- L’algoritmo per la risoluzione di questo problema può essere descritto mediante il diagramma di flusso già presentato nella lezione sulle istruzioni strutturate e riportato nel prossimo lucido
- La determinazione dei casi di test ed il test della soluzione proposta è lasciata per esercizio
Esempio 2
L’algoritmo quindi può essere implementato utilizzando due costrutti if-then-else innestati
- L’elaborazione è Y=F(X)
- Dati iniziali X= A, B, C interi da confrontare
- Dati finali Y= minimo tra i tre valori
- Abbiamo bisogno quindi di tre variabili per memorizzare i valori da confrontare di tipo intero
- In questo semplice esempio ci limitiamo a stampare il risultato del confronto.
Osservazioni
Il secondo costrutto if-then-else è innestato nel primo ed è precisamente l’istruzione che deve essere eseguita nel caso in cui la condizionerisulti falsa.
La condizione logica (A<B && A<C) è composta: cioè è costituita da due relazioni in AND (l’operatore &&). Ciò significa che entrambe devono risultare vere affinchè globalmente la condizione risulti vera. Se anche una sola delle due relazioni risulta falsa, allora la valutazione della condizione produce come risultato falso.
Le istruzioni che devono essere eseguite nel ramo then (notate che in C/C++ la parola then non è espressa esplicitamente) e nel ramo else di un costrutto if-then-else devono essere chiuse in un blocco se sono più di una, mentre è possibile omettere le parentesi graffe se c’è una unica istruzione da eseguire.
Un costrutto globalmente preso è considerato come un’unica istruzione (infatti non c’è bisogno delle parentesi prima e dopo l’if innestato).
Esempio 3
- Specifica del problema: Scrivere un programma che realizzi un semplice menù: l’utente fornisce in ingresso due numeri interi A e B ed ha la possibilità di scegliere tra tre opzioni. In corrispondenza della prima viene effettuata la somma A+B, in corrispondenza della seconda viene effettuato il prodotto A*B, in corrispondenza della terza viene effettuata la differenza A-B
- Si suppone che l’ingresso effettuato da chi utilizza il programma sia corretto (in ingresso sono forniti due interi e l’opzione è del tipo richiesto dal programma).
- L’algoritmo per la risoluzione di questo problema è molto semplice e può essere realizzato mediante l’uso del costrutto di selezione a più vie (case)
- Tale costrutto in C/C++ è reso dall’istruzione switch e mediante l’opportuno utilizzo dell’istruzione di salto break
Esempio 3: esecuzione e test
Osservazioni
- Il costrutto di selezione a più vie in C/C++ utilizza le parole chiave switch e case. Inoltre il suo corpo costituisce un blocco, cioè deve essere racchiuso tra parentesi graffe
- Dopo lo switch viene valutata l’espressione tra parentesi (in questo caso il valore della variabile scelta) che deve assumere valore in un insieme discreto e finito. Tutti i possibili valori che l’espressione può assumere devono essere noti a priori
- A ciascun case corrisponde uno dei possibili valori (espressi come costanti del loro tipo e seguiti dai :) e le istruzioni da eseguire in corrispondenza del presentarsi di tale valore
- Non sono necessarie le parentesi graffe per racchiudere le istruzioni di un singolo case
- Il costrutto switch prevede la possibilità di esprimere un default: cioè le istruzioni che devono essere eseguite nel caso che la valutazione dell’espressione produca un valore diverso da quelli previsti
- Per ottenere un comportamento equivalente al costrutto di selezione descritto in maniera generale nella lezione precedente, è necessario utilizzare al termine di ogni case l’istruzione di salto break che non appartiene al costrutto switch e anzi provoca l’uscita dallo switch: il controllo passa all’istruzione successiva allo switch
- ESERCIZIO: ELIMINARE i break ed eseguire gli stessi casi di test. Qual’è il comportamento del costrutto switch?
- ESERCIZIO: Realizzare lo stesso programma utilizzando degli if innestati e/o degli if in cascata (uno dopo l’altro, senza innestarli)
Esempi di Programmi con cicli
ESEMPIO 4:
- Specifica del problema: scrivere un programma che fornito in ingresso da tastiera un numero intero N non negativo calcola il fattoriale di N.
- Si suppone che l’ingresso effettuato da chi utilizza il programma sia corretto (viene introdotto un numero intero)
- L’algoritmo per la risoluzione di questo problema ricalca il procedimento per il calcolo del fattoriale, che può essere iterativo o ricorsivo. La ricorsione non è affrontata in questo corso, pertanto esamineremo solo la soluzione iterativa.
Esempio 4
- La procedura iterativa per il calcolo del fattoriale è la seguente:
- Se N è uguale a 0 il fattoriale di N per convenzione è 1
- Altrimenti se N è maggiore di 0 il fattoriale di N si calcola così:
- Ad esempio, supponiamo che N sia uguale al valore 4:
- L’algoritmo per la risoluzione di questo problema richiede quindi che venga generata una sequenza di interi 1,2,3,4 … da 1 a N. Ogni elemento della sequenza deve essere moltiplicato per i precedenti. Abbiamo bisogno quindi di memorizzare i prodotti man mano che vengono effettuati. In effetti è lo stesso procedimento mentale che adottiamo se vogliamo calcolare a mente 4!:****
-
- 2 x 3= 6 (e ricordiamo 6)
-
- 6 x 4 = 24 il fattoriale di 4 è 24
Esempio 4
- L’elaborazione è Y=F(X)
- Dati iniziali X= valore intero di cui calcolare il fattoriale
- Dati finali Y= il fattoriale del valore X
- Abbiamo bisogno quindi di una variabile per memorizzare il valore di cui calcolare il fattoriale e di una variabile per contenere il risultato: chiamiamole rispettivamente N e fattoriale. Saranno di tipo intero perchè N deve essere intera e il prodotto di numeri interi è un intero.
- Abbiamo bisogno poi di variabile di algoritmo (non sono dati di iniziali o finali ma servono per portare avanti l’elaborazione): una variabile per contare il numero di iterazioni e una variabile per memorizzare i risultati parziali, chiamiamole rispettivamente i e parziale. Saranno ovviamente di tipo intero.
- parziale deve contenere di volta in volta i risultati dei prodotti effettuati, QUINDI DEVE ESSERE INIZIALIZZATA all’elemento NEUTRO per il prodotto (altrimenti il suo valore iniziale sarà indefinito, e verrà moltiplicato per il valore calcolato ottenendo così un risultato SBAGLIATO): parziale=1
Esempio 4: Algoritmo
- parziale=1
- i=1 // primo elemento della sequenza di numeri 1,2,3,…N
- ripeti finchè i<=N :
- i=i+1 // genera il numero successivo nella sequenza
- fattoriale = parziale //
- L’ultimo dei risultati parziali è evidentemente il risultato finale.
- Questo è l’algoritmo per il calcolo del fattoriale. Bisogna però considerare i casi particolari:
- se N inizialmente vale 0 oppure 1
- altrimenti
- esegui l’algoritmo per il calcolo del fattoriale
- Bisogna inoltre considerare che N deve rispettare delle condizioni, per definizione di fattoriale infatti deve essere un numero non negativo.
- Questo controllo può essere aggiunto prima di effettuare il calcolo del fattoriale, ad esempio:
- se N<0 stampa un messaggio di errore
- altrimenti calcola il fattoriale di N
Esempio 4: Algoritmo
- In definitiva:
- se N<0 stampa un messaggio di errore
- altrimenti
- se N inizialmente vale 0 oppure 1
-
- i=1 // primo elemento della sequenza di numeri 1,2,3,…N
-
-
- i=i+1 // genera il numero successivo nella sequenza
-
- fattoriale = parziale // L’ultimo dei risultati parziali è evidentemente il risultato finale.
- Ora possiamo tradurre l’algoritmo in linguaggio C/C++ aggiungendo la definizione delle varialbili e le istruzioni di ingresso (lettura di N) e di uscita (stampa del risultato)
- Il ciclo viene espresso mediante un for (ciclo a conteggio)
- ESERCIZIO: implementare il programma utilizzando in vece del ciclo for il ciclo while
- ESERCIZIO: realizzare il diagramma di flusso del presente algoritmo
Osservazioni
Il secondo costrutto if-then-else è innestato nel primo ed è precisamente l’istruzione che deve essere eseguita nel caso in cui il controllo sull’input abbia esito positivo. Pertanto il calcolo del fattoriale costituisce il ramo else dell’if più esterno.
La condizione logica (N==0 || N==1) è composta: cioè è costituita da due relazioni in OR (l’operatore ||). Ciò significa che almeno una di esse deve risultare vera affinchè globalmente la condizione risulti vera. Se entrambe le relazioni risultano false, allora la valutazione della condizione produce come risultato falso.
Attenzione. La relazione di uguaglianza è espressa dall’operatore ==. Un errore comune è utilizzare per distrazione l’operatore di assegnazione = al posto dell’operatore ==. La sostituzione non provoca errori in compilazione, perché il left value viene modificato e la condizione così espressa è la seguente: “se il valore assunto dal left value è vero”,
Le istruzioni che devono essere eseguite nel ramo else del primo if costituiscono un blocco. Nel blocco vi sono le seguenti 3 istruzioni: 1. un if-then-else (che a sua volta contiene un for nel ramo else), 2. una assegnazione e 3. una istruzione di uscita (la stampa del risultato).
Notare ancora una volta che a) un costrutto globalmente preso è considerato come un’unica istruzione; b) se il corpo di un ciclo o un ramo di un if contengono una sola istruzione le parentesi graffe non sono necessarie.
ESEMPIO 5:
- Specifica del problema: modificare l’esempio 4 in modo che dopo la prima esecuzione sia possibile effettuare eventualmente ulteriori esecuzioni consecutive, a scelta dell’utente
- Vuole essere un semplice esempio di utilizzo del ciclo a condizione finale. Per realizzare il comportamento descritto dalla specifica infatti è necessario che il calcolo del fattoriale venga effettuato almeno una volta, dopo la prima esecuzione all’utente viene chiesto se desidera calcolare un altro fattoriale o meno.
- Il programma sviluppato per l’esempio 4 deve essere quindi il corpo di un ciclo a condizione finale. Il valore di verità della condizione è determinato dalla scelta dell’utente.
- Si noti, eseguendo il programma riportato nella prossima slide, che l’istruzione system (“PAUSE”) non è più necessaria
Esempio 5: esecuzione e test
Prossima lezione
Linee guida per lo sviluppo di un semplice programma
- Specifica
- Procedimento per raffinamenti successivi
- Prova “penna e carta”
- Casi di test e test