...

ppt

by user

on
Category: Documents
74

views

Report

Comments

Description

Transcript

ppt
Programmazione Mod A - Cap 3 prof. Burattini
1
Metodo dei raffinamenti successivi
1- Capire bene il problema
input : di quale informazione si dispone,
output: che cosa esattamente si vuole ottenere,
risolvibilità: convincersi che è possibile implementare una soluzione al problema
2- Descrivere una successione di azioni che possono risolvere il problema
Azione: una serie di operazioni, che, se effettuate, producono un risultato previsto e
ben determinato e che si compiono in un certo intervallo di tempo. Ogni azione
modifica lo stato di uno o più oggetti: ci rendiamo conto che l’azione ha
prodotto un risultato proprio dal cambiamento di stato dell’oggetto stesso.
Istruzioni di un programma sorgente: descrizione di azioni per mezzo di un
linguaggio formale.
3- La successione di azioni proposta risolve veramente il problema?
Se la risposta è positiva allora abbiamo trovato un algoritmo che risolve il problema,
altrimenti:
4- Applicare i passi 2) e 3) ad ognuna delle azioni di cui è composto l’algoritmo.
Possiamo interrompere il processo dei raffinamenti successivi quando ogni azione o
è già ridotta ad una istruzione elementare del C++ o può essere facilmente
riducibile ad una breve successione di istruzioni elementari. Si dice che un
algoritmo di questo tipo è scritto
in pseudo-codice
Programmazione
Mod A - Cap 3 - per sottolineare la sua 2
somiglianza al linguaggio oggettoprof. Burattini
Il metodo dei raffinamenti successivi può essere così schematizzato:
1. Attenta lettura iniziale del problema per convincersi che ammette
soluzione.
2. Se esiste almeno una soluzione, descrivere in modo sommario le
azioni da eseguire per poter determinare tale soluzione.
3. Se la successione di azioni porta alla soluzione allora possiamo
raffinare ogni azione in altre azioni più dettagliate.
4. Il passo 3 termina quando il dettaglio è tale che ogni azione
corrisponde ad una istruzione del linguaggio utilizzato (C++ nel
nostro caso), o può essere facilmente tradotta in una breve
successione di istruzioni in C++ .
Programmazione Mod A - Cap 3 prof. Burattini
3
ESEMPIO
Dati un capitale iniziale C ed un tasso di interesse annuo T calcolare e stampare l’interesse maturato ed il
capitale risultante dopo un anno dopo due anni e dopo tre anni.
La stampa deve essere del tipo:
Anno Capitale
Tasso %
Interesse
Totale
1
1.000
10
100
1.100
2
1.100
10
110
1.210
3
1.210
10
121
1.331
Primo raffinamento:
leggi( Capitale, Tasso)
stampa l’intestazione
calcola e stampa interesse e totale dopo il primo anno
calcola e stampa interesse e totale dopo il secondo anno
calcola e stampa interesse e totale dopo il terzo anno
Noto che : Interessi=capitale*tasso/100 ; Totale=Somma del capitale e degli interessi,
Dobbiamo effettuare un ciclo di operazioni da ripetere tre volte aggiornando la variabile capitale alla fine
di ogni ciclo.
Secondo raffinamento:
leggi(capitale,tasso)
stampa l’intestazione
for (i=1;i<=3;i++)
interessicapitale*tasso/100
totalecapitale+interessi
stampa(i,capitale,tasso,interessi,totale)
Programmazione Mod A - Cap 3 prof. Burattini
capitaletotale
4
#include <iostream>
#include <cstdlib>
using namespace std;
int main () {
float Totale, Capitale, Tasso, Interesse;
cout << "Inserisci il Capitale iniziale."<<endl;
cout << "Capitale=";
cin >> Capitale;
cout <<"Inserisci il Tasso d'interesse."<<endl;
cout <<"Interesse%=";
cin >>Tasso;
cout <<"Anno
Capitale Tasso % Interesse
Totale"<< endl;
for(int i=1;i<=3; i++)
{
Interesse=Capitale*Tasso/100;
Totale=Capitale +Interesse;
printf("%3d %10.2f %6.2f %10.2f %12.2f\n", i,
Capitale,Tasso, Interesse,Totale);
Capitale=Totale;
}
system("pause");
}
Programmazione Mod A - Cap 3 prof. Burattini
eser3.1
5
Esempio
Calcolare la somma di due frazioni n1/d1, n2/d2 e ridurla ai minimi termini.
Primo raffinamento:
leggi(n1,d1,n2,d2)
calcola il numeratore, num, ed il denominatore, den, della somma
riduci num e den ai minimi termini
stampa(num e den)
I quattro numeri in input non possono essere quattro interi qualsiasi perché un
denominatore non può mai essere zero.
Quindi precondizioni: d1≠0 e d2≠0
Per ridurre num e den ai minimi termini dobbiamo prima trovare il massimo comun
divisore k, e successivamente effettuare le operazioni numnum/k, denden/k.
Secondo raffinamento:
leggi(n1,d1,n2,d2) (precondizione: d1≠0 e d2≠0)
dend1*d2
numn1*d2+n2*d1
Calcola k, massimo comun divisore di num e den
numnum/k
denden/k
Programmazione Mod A - Cap 3 prof. Burattini
6
Terzo raffinamento:
leggi(n1,d1,n2,d2) (precondizione: d1>0,d2>0)
dend1*d2
numn1*d2+n2*d1
n=num
d=den
while d!=0
temp=n%d
nd
dtemp
k=n
numnum/k
denden/k
Programmazione Mod A - Cap 3 prof. Burattini
7
ESERCIZI
1) Un commerciante, per vendere di più un suo prodotto, il cui prezzo è di 15,75 €,
propone uno sconto del 12% per i clienti che ne acquistano più di 500 unità.
Scrivere un programma che calcoli il ricavo effettivo per un acquisto di x unità.
2) Quali sono i cambiamenti da apportare al programma dell’esercizio precedente nel
caso in cui il commerciante applichi uno sconto ulteriore del 10% quando un cliente
acquisti almeno 1000 unità?
3) Scrivere un programma che chieda in input esattamente N numeri interi relativi
compresi tra 100 e -100 e li stampi. Utilizzando tale programma scrivere un altro
programma che stampi
la quantità di numeri positivi e negativi generati;
il massimo ed il minimo dei valori generati;
la differenza massima in valore assoluto tra ogni termine ed il precedente (escluso il
primo)
la differenza minima in valore assoluto tra ogni termine ed il precedente (escluso il
primo)
4) Scrivere un programma che determini se un numero intero positivo è primo ( deve
scrivere vero se è primo, falso altrimenti )
5) Scrivere un programma che assegnato un numero intero positivo stampi la somma dei
suoi divisori ( escluso se stesso )
Programmazione Mod A - Cap 3 prof. Burattini
8
6) Scrivere un programma che assegnato un numero intero positivo stampi vero se il
numero è perfetto, falso altrimenti ( un numero è perfetto se e solo la somma dei
suoi divisori, escluso se stesso, è uguale al numero stesso: 6=1+2+3 è perfetto
8=1+2+4 non lo è ).
7) Per produrre una vernice sono necessari 10 grammi di un certo additivo per ogni chilo
di prodotto fino a 10 chili e 5 grammi al chilo per i chili eccedenti. Scrivere un
programma che fornisca la quantità di additivo necessaria in base al quantitativo di
vernice richiesto.
8) Dati due numeri, stabilire se non hanno divisori comuni.
9) Una macchina distributrice automatica offre oggetti del costo di 30 centesimi e
accetta monete da 5, 10, 20 e 50 centesimi. Assegnato il numero di oggetti richiesto
ed il numero di monete immesso per ogni taglio, calcolare il resto o fornire un
opportuno messaggio negli altri casi.
10) Una ditta produce pacchi di pasta. Tali pacchi devono contenere 0,5 Kg di pasta con
una tolleranza di ± 0,7%. Costruire un programma che, data in ingresso la
sequenza dei pesi dei pacchi (che termina con 0), restituisca:
- Il numero di pacchi di peso corretto, sottopeso e sovrappeso.
- Il peso totale della merce nei pacchi a norma ed il peso totale nei pacchi fuori
norma.
11) Ad ogni gara di tiro con l’arco partecipano 10 concorrenti, ognuno identificabile con
un nome diverso. Ogni concorrente ha a disposizione 8 frecce con cui colpire un
bersaglio. Costruire un programma che, assegnato nome e numero di bersagli
colpiti da ogni arciere, restituisce
il nomeMod
ed A
il -numero
Programmazione
Cap 3 - di colpi messi a segno dal
9
prof. Burattini
primo e secondo classificato.
ASTRAZIONE PROCEDURALE
L’astrazione procedurale consiste nel descrivere a parole tutti i sottoproblemi in cui
un problema è descrivibile sostituendo poi a queste descrizioni una chiamata ad
un sottoprogramma, non ancora scritto, il cui compito sarà quello di risolvere il
corrispondente sottoproblema.
Il sottoprogramma dovrà ricevere tutta l’informazione (i dati) necessari per poter
risolvere il problema. E’ necessario precisare quale è lo stato del sistema all’atto
della chiamata del sottoprogramma (le precondizioni) e quale sarà lo stato del
sistema dopo l’esecuzione del sottoprogramma (le postcondizioni), essendo
sicuri che l’esecuzione dei vari sottoprogrammi nell’ordine e nelle modalità
descritte porta effettivamente alla risoluzione del problema originale.
A questo punto si scrive lo pseudo codice per ognuno dei sottoprogrammi.
Naturalmente può accadere che qualcuno dei sottoprogrammi sia ancora così
complesso da richiedere a sua volta la sua scomposizione in ulteriori
sottoprogrammi.
Programmazione Mod A - Cap 3 prof. Burattini
10
Esistono due tipi di sottoprogrammi: le procedure e le funzioni. Entrambe sono
genericamente chiamate function.
Una chiamata a procedura costituisce a tutti gli effetti un enunciato di un
programma.
Ad esempio se abbiamo definito una procedura di nome minmax, per cercare in un
insieme di interi il minimo e il massimo, se nel main, min e max sono due
variabili di tipo intero, allora minmax(min, max) è un enunciato il cui risultato
complessivo dopo l’esecuzione della procedura è di fornire in min il minimo e
in max il massimo dei valori dati in ingresso.
Una funzione invece restituisce un valore .
Ad esempio sia MCD il nome di una funzione che dati due interi assume il valore del
massimo comun divisore. Se n1 ed n2 sono due variabili di tipo intero definite
nel main la chiamata MCD(n1,n2) può solo apparire all’interno di una
espressione, del tipo: k=MCD(n1,n2).
In C e in C++ una procedura è definita come una function che non assume alcun
Programmazione
Mod Anel
- CapC++
3 - standard).
11
valore (o meglio che ritorna
il valore void
prof. Burattini
Riprendiamo il problema di trovare la somma di due frazioni ridotta ai minimi termini.
La prima versione scritta informalmente del nostro algoritmo era:
leggi(n1,d1,n2,d2)
calcola il numeratore, num, ed il denominatore, den, della somma
riduci num e den ai minimi termini
stampa(num e den)
Usando la tecnica dell’astrazione procedurale scriviamo il seguente algoritmo:
leggi(n1,d1,n2,d2) (post: d1<>0,d2<>0)
calcolasomma(n1,d1,n2,d2,num,den)
(pre:n1,d1 e n2,d2 sono coppie di interi rappresentanti numeratore e
denominatore di due funzioni,
post: num e den rappresentano la somma delle due funzioni)
riduci(num, den)
(pre: num e den rappresentano numeratore e denominatore di una funzione,
post: num e den rappresentano la stessa frazione ridotta ai minimi termini)
stampa(num,den)
Programmazione Mod A - Cap 3 -
Abbiamo quindi ridotto il nostro algoritmo
alla chiamata di quattro procedure.
prof. Burattini
12
leggi: precondizioni, le quattro variabili devono essere di tipo intero;
postcondizioni le quattro variabili hanno ricevuto i valori che l’utente ha
inserito e d1 e d2 devono essere dei numeri diversi da zero.
calcolasomma: precondizione: n1,d1,n2,d2 devono avere i valori inseriti
dall’utente,
postcondizione num e den devono rappresentare il numeratore ed il
denominatore della somma.
riduci: precondizione num e den rappresentano numeratore e denominatore di una
frazione,
postcondizione num e den rappresentano il numeratore ed il denominatore
della stessa frazione ma ridotta ai minimi termini.
stampa: precondizione num e den sono i valori della frazione ridotta ai minimi
termini
postcondizione che questi siano stampati a video.
Per le prime tre procedure dopo la loro chiamata lo stato del sistema cambia mentre
per l’ultima l’insieme delleProgrammazione
variabili delMod
sistema
non subisce alcun
A - Cap 3 13
cambiamento.
prof. Burattini
I parametri passati ad una procedura possono essere di input, di output oppure di
input-output.
parametro di input: parametro indispensabile per effettuare i calcoli;
parametro di output: variabile non inizializzata che assume un valore determinato al
termine della procedura;
parametro di input-output: una variabile che ha un suo valore prima della chiamata
della procedura e che al termine della procedura può assumere un valore diverso.
Nella procedura leggi i quattro parametri della procedura sono tutti di output.
Nella procedura calcolasomma gli stessi sono invece parametri di input mentre num
e den sono parametri di output.
Nella procedura riduci num e den sono parametri di input-output.
Nella procedura stampa sono parametri di input.
Programmazione Mod A - Cap 3 prof. Burattini
14
Sintassi della chiamata e della definizione di una function
La sintassi in C++ di una chiamata ad una function è
identificatore(lista dei parametri effettivi);
dove identificatore è il nome della function ed ogni parametro è un’espressione se
rappresenta un parametro di input, una variabile se rappresenta un parametro di
output o di input-output.
Nella procedura calcolasomma le variabili n1,d1,n2,d2 si riferiscono al loro valore
(right value), mentre le variabili num e den al loro indirizzo (left value).
Affinchè il compilatore possa riconoscere il nome di una function occorre che
questa sia stata definita in precedenza.
Una definizione di function è formata da una intestazione seguita da un blocco
racchiuso al solito tra parentesi graffe. L’intestazione ha la forma:
tipo identificatore(lista dei parametri formali)
dove tipo è il tipo del valore restituito se si tratta di una funzione, la parola riservata
void se si tratta di una procedura, seguono il nome della function e la lista dei
suoi parametri formali separati da virgole, racchiusa tra parentesi. Nella lista
Programmazione Mod A - Cap 3 15
ogni parametro formale deve essere
preceduto
dal
suo
tipo.
prof. Burattini
Nella chiamata di procedura per ogni parametro di output o di input-output, il
nome di una variabile è preceduto dall’operatore di riferimento &.
Così l’intestazione di riduci sarà:
void riduci(int &n, int &d)
dove n e d sono degli alias per num e den allorché riduci sarà chiamata.
Anche il programma principale main obbedisce alle regole formali di una function:
la sua intestazione è int main() poiché non restituisce alcun valore e non ha
parametri che gli possono essere passati da un altro processo.
Programmazione Mod A - Cap 3 prof. Burattini
16
Passaggio dei parametri
Scriviamo ora il codice corrispondente a leggi e stampa, ed inoltre, essendo il
denominatore della somma pari al prodotto dei denominatori, facciamo a meno di
calcolasomma il cui corpo contiene solo due enunciati di assegnazione.
Per cui il nostro algoritmo diventa:
La procedura riduci sarà data da:
void riduci(int &n, int d&)
kmcd(n,d)
nn/k
dd/k
leggi(n1,d1,n2,d )
dend1*d2
numn1*d2+n2*d1
riduci(num,den)
stampa(num,den)
Osserviamo che nello scrivere lo pseudo-codice per la function riduci abbiamo:
•
•
introdotto una nuova variabile k che è usata solo in riduci e che quindi dovrà
essere definita nel corpo di questa function come variabile locale.
introdotto una chiamata alla funzione mcd che deve calcolare il massimo comun
divisore tra i due parametriProgrammazione
della procedura.
Mod A - Cap 3 17
prof. Burattini
Scrivere lo pseudo-codice per la funzione mcd è semplice:
int mcd(p, q)
while (q !=0)
tempq
qp%q
ptemp
return p
Si noti che abbiamo esplicitamente introdotto una nuova (pseudo)-istruzione
corrispondente all’istruzione return del C. Essa ha il formato:
return espr
dove espr è una espressione il cui tipo deve coincidere con il tipo con cui inizia la
intestazione della funzione, nel nostro caso il tipo intero.
Questa istruzione deve essere presente in ogni dichiarazione di funzione.
Quando essa deve essere eseguita l’espressione viene valutata, l’esecuzione della
funzione termina ed al processo
chiamante
restituisce,
nel punto della 18
Programmazione
Mod Asi- Cap
3prof. Burattini
chiamata alla funzione, il valore così
calcolato.
#include<cstdlib>
#include<iostream>
using namespace std;
//
DEFINIZIONE DELLE FUNZIONI
//calcola il massimo comun divisore di due interi
int mcd(int p,int q)
{
int temp;
while (q != 0)
{
temp=q;
q=p%q;
p=temp;
}
return p;
}
void riduci(int &n,int &d) /* prec: int e num sono il numeratore ed il denominatore di
una frazione.
postc: int e num sono il denominatotore e numeratore
ridotti ai minimi termini*/
{
int k=mcd(n,d);
n=n/k;
Programmazione Mod A - Cap 3 19
d=d/k;
prof. Burattini
}
//
MAIN
int main()
{
int n1,d1,n2,d2,num,den;
cout<<"scrivere numeratore e denominatore della prima frazione"<<endl
<<"numeratore: ";
cin>>n1;
cout<<" denominatore ( !=0): ";
cin>>d1;
cout<<endl;
cout<<"scrivere numeratore e denominatore della seconda frazione" <<endl
<<"numeratore: ";
cin>>n2;
cout<<" denominatore ( !=0): ";
cin>>d2;
cout<<endl;
den=d1*d2;
num=n1*d2+n2*d1;
riduci(num,den);
cout<<"numeratore ="<<num<<" denominatore ="<<den<<endl;
system("pause");
}
Programmazione Mod A - Cap 3 prof. Burattini
eser3.2
20
Record di
Attivazione
per mcd
Record di
Attivazione
per riduci
main
int mcd(int p,int q)
{
int temp;
while (q != 0)
{
temp=q;
q=p%q;
p=temp;
}
return p;
}
5
150
12
360
n
d
k
void riduci(int &n,int &d)
{
int k=mcd(n,d);
n=n/k;
d=d/k;
}
1505
12
360
30
?
n1
d1
n2
d2
num
den
?3
?12
?5
?30
150
? 5?
360
?12?
Programmazione Mod A - Cap 3 prof. Burattini
int main()
{
int n1,d1,n2,d2,num,den;
cin>>n1;
cin>>d1;
cin>>n2;
cin>>d2;
den=d1*d2;
num=n1*d2+n2*d1;
riduci(num,den);
cout<<num<<den;
21
}
Interfacciamento: fase durante la quale avviene il passaggio dei parametri effettivi
del processo chiamante ai parametri formali della function.
Il passaggio dei parametri avviene attraverso due modalità:
Passaggio per valore: al parametro formale è assegnata una copia del valore del
parametro effettivo. La function può quindi anche modificarne il valore senza
che nessuna delle variabili del processo chiamante ne risulti modificata.
Passaggio per riferimento ( per indirizzo): al parametro formale, che deve essere un
riferimento, è passato l’indirizzo della corrispondente variabile del parametro
effettivo. Il parametro formale si comporta come un sinonimo o alias del
corrispondente parametro effettivo. Ogni modifica apportata al parametro
formale è in realtà una modifica apportata al corrispondente parametro effettivo.
Al termine della function ed al ritorno nel processo chiamante solo le variabili di
quest’ultima corrispondenti ai parametri effettivi passati per indirizzo
risulteranno modificati.
Per questi motivi tutto ciò che serve ad una procedura per poter effettuare i suoi
calcoli, cioè i parametri di input, deve essere passato per valore, mentre tutte
le variabili dichiarate nel processo chiamante che la procedura deve modificare
o inizializzare , ovverosia iProgrammazione
parametri di
input-output ed i parametri di 22
Mod A - Cap 3 output devono essere passati perprof.
riferimento.
Burattini
Viene segnalato un errore in corrispondenza della chiamata:
riduci(int &n,int &d)
riduci(num+1,den);
Infatti num+1 è un’espressione cui dovrebbe corrispondere nella intestazione
della function un parametro per passaggio di valore mentre il primo
argomento di riduci è un riferimento.
Una soluzione può essere:
num++;
riduci(num,den);
E’ sempre possibile trasformare una funzione in una procedura avente tutti i
parametri della funzione più un ulteriore parametro di output dello stesso
tipo del valore di ritorno della funzione.
Ad esempio una funzione la cui intestazione sia del tipo:
int calcola(int p,…float q,int &r,…,float &s)
può essere sostituita dalla procedura:
void calcola(int p,…,float q,int &r,…,float &s, int &t)
dove t è una nuova variabile.
Il corpo della procedura si ottiene dal corpo della funzione ( e viceversa)
Programmazione Mod A - Cap 3 23
sostituendo ogni enunciato
del prof.
tipoBurattini
return espr; con l’enunciato t=espr;
Regola
Scrivere una function che ritorna un valore solo se si tratta di una funzione, cioè
quando tutti suoi parametri devono essere passati per valore.
In tutti gli altri casi scrivere una procedura.
Programmazione Mod A - Cap 3 prof. Burattini
24
Ricordiamo che il minimo comune multiplo (mcm) di due interi a e b è il
più piccolo intero positivo che è multiplo sia di a che di b. Se non esiste
un intero positivo con queste proprietà, cioè se a = 0 o b = 0, allora
mcm(a, b) è definito uguale a zero.
Se a e b non sono entrambi nulli, il minimo comune multiplo può essere
calcolato usando il Massimo Comune Divisore (MCD) di a e b e la
formula seguente:
mcm(a,b)=
a*b .
MCD(a,b)
Programmazione Mod A - Cap 3 prof. Burattini
25
Dichiarazione di FUNCTION.
Nell’esempio precedente se volessimo prendere come denominatore della
somma delle due frazioni il minimo comune multiplo dei denominatori,
sarebbe ragionevole introdurre una function dedicata alla risoluzione di
questo problema. Un suo algoritmo è il seguente:
void calcolasomma(int n1, int d1,int n2,int d2,int &n,int &m)
int Mmcm(d1,d2) ;
d M
nn1*M/d1 +n2*M/d2
Abbiamo introdotto una nuova funzione che serve per il calcolo del minimo
comune multiplo tra due numeri.
In pseudo-codice abbiamo:
int mcm(int m1, int m2)
Mmcd(m1, m2)
return m1*m2/M
Nello scrivere questi algoritmi ci siamo conformati alla metodologia suggerita,
scrivendo secondo le regole formali del C++ l’intestazione delle due
Mod A - Cap 3la
- prima deve essere una
26
function di cui, secondo laProgrammazione
Regola precedente,
prof. Burattini
procedura e la seconda una variabile.
Volendo passare alla codifica dell’algoritmo dovremmo scrivere
definizione di mcd,
definizione di riduci
definizione di mcm
definizione di calcolasomma .
Questo rende complicata la lettura del programma perché si sarebbe
continuamente costretti, leggendo il main, a spostare l’attenzione dal main
all’elenco delle dichiarazioni delle function per cercare quella che serve.
La situazione sarebbe ben peggiore in un programma con una dozzina o più di
function.
Programmazione Mod A - Cap 3 prof. Burattini
27
Il C++ permette di risolvere questo problema tramite il ricorso alla
dichiarazione di function (da non confondersi con la sua definizione).
Una dichiarazione di function è costituita dalla sola intestazione della function.
Volendo si possono omettere i nomi dei parametri. Nel nostro caso per
calcolasomma avremo:
void calcolasomma(int n1, int d1,int n2,int d2,int &n, int &m)
oppure :
void calcolasomma(int , int ,int ,int ,int&,int&)
Basta premettere al main le dichiarazioni di tutte le function usate e scrivere
dopo il main tutte le definizioni nell’ordine top down in cui sono chiamate,
rendendo così il programma molto più leggibile.
Il programma avrà la formaProgrammazione
(layout) seguente.
Mod A - Cap 3 prof. Burattini
28
#include<cstdlib>
#include<iostream>
using namespace std;
//
DICHIARAZIONI DI FUNCTION
void calcolasomma(int , int ,int ,int ,int&,int&)
int mcm(int,int)
int mcd(int,int)
void riduci(int&,int&)
//
MAIN
int main() {
int n1,d1,n2,d2,num,den;
cout<<"scrivere numeratore e denominatore della prima frazione"<<endl<<"numeratore: ";
cin>>n1;
cout<<" denominatore (>0): "; cin>>d1; cout<<endl;
cout<<"scrivere numeratore e denominatore della seconda frazione"<<endl <<"numeratore: "
cin>>n2;
cout<<" denominatore (>0): "; cin>>d2; cout<<endl;
//
CHIAMATA DI FUNCTION
calcolasomma(n1,d1,n2,d2,num,den)
riduci(num,den);
cout<<"numeratore ="<<num<<" denominatore ="<<den<<endl;
system("pause");
}
Programmazione Mod A - Cap 3 29
prof. Burattini
//
DEFINIZIONI DI FUNCTION
void calcolasomma(int n1, int d1,int n2,int d2,int &n,int &d) //somma num e den
(* prec: n1 e n2, numeratori di due frazioni, d1 e d2 i loro denominatori
postc: d( minimo comune multiplo fra d1 e d2) denominatore e n numeratore
della loro somma*)
{
int M=mcm(d1,d2) ;
d=M;
n=n1*M/d1 +n2*M/d2;
}
int mcm(int m1,int m2) //calcola il minimo comune multiplo
{
int m=mcd(m1,m2);
return m1*m2/m;
}
Programmazione Mod A - Cap 3 prof. Burattini
30
int mcd (int p,int q) //calcola il massimo comun divisore di due interi
{
int temp;
while (q != 0)
{ temp=q;
q=p%q;
p=temp;
}
return p;
}
void riduci(int &n,int &d) //riduce una frazione ai minimi termini
/* prec:int e num sono il numeratore ed il denominatore di una frazione.
postc:int e num sono il denominatotore e numeratore ridotti ai minimi
termini*/
{
int k=mcd(n,d);
n=n/k;
d=d/k;
eser3.3
}
Programmazione Mod A - Cap 3 prof. Burattini
31
ESEMPIO
Assegnata una certa quantità di centesimi in euro suddividerla nel numero
minimo di monete da 50, 20, 10, 5, 2, 1.
Primo raffinamento
Mostra Istruzioni
Calcola quante monete servono da 50 cent
Calcola quante monete servono da 20 cent
………………………………………………
Stampa i risultati
Costruiamo una procedura che accetti in ingresso i centesimi e il valore della
moneta e ci restituisca in uscita sia il numero di pezzi di tale tipo di moneta
che il numero di centesimi rimasti (dato in input 74 centesimi e 20 come
valore della moneta, ci fornisca in uscita 3 ed il numero di centesimi rimasti
14).
In questa procedura il valore della moneta è un parametro di input, i centesimi
iniziali rappresentano un
parametro di input-output mentre il numero
di
Programmazione Mod A - Cap 3 32
pezzi è un parametro di output.
prof. Burattini
/*Assegnati i centesimi iniziali, determina il minimo numero di
monete di taglio maggiore da restituire in cambio */
#include <iostream>
#include <stdlib.h>
using namesapace std;
//
DICHIARAZIONI DI FUNCTION
void CalcolaPezzi (int, int &, int &);
void StampaDati (int,int, int, int, int, int);
//
MAIN
int main () {
int Centesimi,Pezzi50 Pezzi20, Pezzi10, Pezzi5, Pezzi2, Pezzi1;
cout << "Inserisci i centesimi =";
cin >> Centesimi;
CalcolaPezzi (50,Centesimi,Pezzi50);
CalcolaPezzi (20,Centesimi,Pezzi20);
CalcolaPezzi (10,Centesimi,Pezzi10);
CalcolaPezzi (5,Centesimi,Pezzi5);
CalcolaPezzi(2,Centesimi,Pezzi2);
Pezzi1=Centesimi;
StampaDati (Pezzi50, Pezzi20, Pezzi10, Pezzi5, Pezzi2, Pezzi1);
system(“pause”);
Programmazione Mod A - Cap 3 prof. Burattini
}
33
//
DEFINIZIONI DI FUNZIONI
void CalcolaPezzi( int Tpezzo, int &Cent, int &Npezzi)
{
/* prec:Cent è la quantità di centesimi che deve essere cambiata in monete
aventi valore Tpezzo.
postc: Cent è la quantità di centesimi dopo il cambio, NPezzi è il numero di
monete di valore Tpezzo date in cambio */
}
void StampaDati (int Pezzi50, int Pezzi20, int Pezzi10, int Pezzi5, int Pezzi2, int
Pezzi1)
{
/* prec: il numero dei vari tipi di moneta dato in cambio
postc: stampa dei dati */
}
Programmazione Mod A - Cap 3 prof. Burattini
34
Osservazioni:
Calcolaprezzi potrebbe essere una funzione ma la presenza di centesimi che è un
parametro di input-output impone di scrivere una procedura, v. Regola.
Abbiamo visto un altro uso molto comune dei sottoprogrammi. Codificando
direttamente l’algoritmo iniziale avremmo dovuto scrivere più volte del
codice sostanzialmente simile. L’utilizzo della procedura CalcolaPezzi ce lo
ha evitato.
Si sarebbero potuto anche fondere in una unica procedura CalcolaPezzi e
Stampa, la quale, dopo aver calcolato Npezzi, provvedesse anche a
stamparlo. Tuttavia così come è scritta CalcolaPezzi risulta più facilmente
riutilizzabile in un altro programma.
Non abbiamo ancora scritto il corpo delle due function . Ma questo programma
incompleto può essere compilato. Inoltre introducendo nel corpo delle
function un opportuno messaggio di stampa si può verificare se il flusso del
programma è quello voluto. Ad esempio si potrebbe inserire in stampa:
cout<<”sono in stampa”
ed in CalcolaPezzi:
cout<<Tpezzo
stub : una definizione diProgrammazione
function contenente
un blocco vuoto o incompleto.
Mod A - Cap 3 35
prof. Burattini
Dalle osservazioni precedenti possiamo scrivere in questo modo le due
procedure da inserire nel programma:
void CalcolaPezzi( int Tpezzo, int &Cent, int &Npezzi)
// Calcola il numero di pezzi
{
Npezzi = Cent / Tpezzo;
Cent = Cent % Tpezzo;
}
void StampaDati (int Pezzi50, int Pezzi20, int Pezzi10, int Pezzi5, int Pezzi2, int
Pezzi1)
// Stampa i dati
{
cout << "Pezzi da 50=" << Pezzi50 <<endl;
cout << "Pezzi da 20=" << Pezzi20 <<endl;
cout << "Pezzi da 10=" << Pezzi10 <<endl;
cout << "Pezzi da 5 =" << Pezzi5 <<endl;
eser3.4
cout << "Pezzi da 2 =" << Pezzi2 <<endl;
cout << "Pezzi da 1 =" <<Programmazione
Pezzi1 <<endl;
Mod A - Cap 3 36
}
prof. Burattini
Parametri array
Ricordiamo che di solito è buona norma dichiarare un array nel seguente modo:
…
// DICHIARAZIONI
void scambia(&int,&int)
int const Max=100;
// MAIN
int main();
{
int A[Max];
…
scambia(A[i],A[j]);
…
…
}
…
//
DEFINIZIONI
Se una function ha bisogno di operare su
singoli elementi di un array basta
semplicemente passarli come parametri
effettivi nella chiamata.
void scambia(int &a,int &b);
{
int temp=a;
a=b;
b=temp;
Programmazione Mod A - Cap 3 prof. Burattini
}
37
Spesso è necessario passare l’intero array come parametro della function:
Esempio:
Dato un array A contenente N elementi ed un intero k, si vuole scrivere una
function per costruire un altro array che contenga i prodotti di k per ognuno
degli elementi di A.
Da un punto di vista matematico si tratta di una funzione, ma in C++ il tipo di
ritorno di una funzione non può essere un array. Ciò non deve meravigliare
perché come abbiamo già detto nel capitolo precedente una variabile di tipo
array non può far parte di una espressione.
Occorrerà quindi scrivere una procedura che avrà come parametri di input
l’array iniziale con il numero n di elementi effettivamente presenti ed il
coefficiente k, mentre il nuovo array da costruire sarà un parametro di
output.
Programmazione Mod A - Cap 3 prof. Burattini
38
Se moltiplica è il nome della function che risolve il problema, una sua chiamata
sarà semplicemente del tipo:
moltiplica ( A, B, n, k );
dove A è l’array di input, B quello di output, n il numero degli elementi presenti
in A, k il numero dato.
Alle variabili A e B corrisponde un indirizzo di memoria (in effetti l’indirizzo
del primo elemento dell’array), ne consegue che di fatto ogni array è sempre
passato per indirizzo.
Quindi l’intestazione della funzione non può essere:
void moltiplica(int a1, int a2, int n, int k);
perché il parser sintattico si aspetta che a1 ed a2 siano due interi passati per
valore. Occorre invece segnalare esplicitamente al parser che si tratta di
due array nel seguente modo:
void moltiplica(int a1[],int a2[],int n,int k);
Quindi la definizione di questa function sarà:
void moltiplica(int a1[], int a2[], int n, int k);
{
for (i=0;i<n;i++)
a2[i]=k*a1[i];
Programmazione Mod A - Cap 3 prof. Burattini
}
39
Ricapitolando:
Nel prototipo o dichiarazione di una function, per indicare che un argomento è
un array i cui elementi hanno tipo type si scrive type [], per esempio
int [], float [], char []
Invece nella corrispondente definizione le due parentesi quadre devono
apparire vicine all’identificatore; per esempio
void funzione ( int v[], int n )
Il passaggio di un array ad una function come argomento avviene sempre per
riferimento, anche se nell’intestazione della funzione non si fa uso del
simbolo & (indirizzo di).
L’argomento v[] della lista dei parametri formali della funzione è un array, ma,
per come gli array sono memorizzati, è sufficiente passare alla funzione solo
l’indirizzo del primo elemento: conoscendolo, il compilatore è in grado di
calcolare gli indirizzi di tutti gli elementi successivi. Quando il nome di un
array è usato in una procedura
tale nome è interpretato come l’indirizzo
Programmazione Mod A - Cap 3 40
base dell’array.
prof. Burattini
In linguaggi che permettono la chiamata per valore di un vettore, l’intero vettore
deve essere ricopiato nell’area di memoria del sottoprogramma, tuttavia,
tranne che per array di piccole dimensioni, ovvie ragioni di efficienza
consigliano di utilizzare lo stesso la chiamata per indirizzo in quanto:
• il programma non perde tempo nel copiare elemento per elemento tutti i
dati dell’array dalla memoria principale a quella dedicata alla procedura;
• il programma non spreca memoria per conservare due volte gli stessi dati.
Per questo motivo la chiamata per valore di un array non è prevista nel C++ .
Si potrebbe obiettare che, leggendo la sola lista dei parametri nella definizione di
una function contenente un vettore come parametro, se essa non è
accompagnata da documentazione non si capirebbe se il vettore è un
parametro di input oppure no.
Il C++ però permette di evitare questo inconveniente dichiarando const la
variabile array.
Programmazione Mod A - Cap 3 prof. Burattini
41
Il termine const davanti ad una qualsiasi variabile passata come parametro in una
procedura o funzione, vieta alla stessa di modificarne il contenuto.
Ad esempio,nella function moltiplica il primo array è un parametro di input poiché
non deve essere modificato ma solo adoperato nei calcoli. Si scriverà pertanto:
void moltiplica (const int a1[], int a2[], int n )
l’array a1 non potrà essere modificato: il compilatore segnala un errore durante la
compilazione ad ogni tentativo di modifica dei parametri attuali. La
corrispondente dichiarazione della function sarà:
void moltiplica (const int [],int [], int )
L’uso del termine const nel passaggio di parametri è utile per tre ragioni:
• guardando il prototipo (dichiarazione) della funzione si comprende come il
parametro con la clausola const non sia modificabile all’interno della
function.
• modifiche accidentali dovute ad errori di programmazione non sono
consentite;
• allorché un parametro è passato come const non può che essere un
Programmazione Mod A - Cap 3 42
parametro di input.
prof. Burattini
Driver di una function
Dato un array di interi contenente n elementi ed un intero k, si vuole cancellare
dall’array ogni occorrenza di k.
Ad esempio se l’array in questione contiene i sette elementi: (10,2,8,7,6,8,1)
e l’elemento da cancellare è 8, l’array si trasformerà in
(10,2,7,6,1).
Sappiamo che ogni volta che si deve eliminare un elemento da un array occorre
spostare tutti gli elementi che lo seguono di un posto verso l’alto. Nel nostro
caso, però, per cancellare il primo 8 è inutile spostare verso l’alto il secondo 8
che comunque dovrà essere in seguito cancellato. L’idea è di ‘riscrivere’ l’array
A a partire da un indice j inizialmente uguale a zero, inserendo in A[j] il primo
elemento diverso da 8 che incontriamo e incrementando j di una unità e
ripetendo la stessa operazione per ogni elemento di A.
Proviamo dunque a scrivere questa function: l’array A è evidentemente un
parametro di input-output, k un parametro di input ed n, il numero di elementi
presenti in A prima della cancellazione è un parametro di input-output.
.
Infatti se n venisse passato per valore non sapremmo più quanti elementi sono
Mod A - Cap 3 43
effettivamente rimasti in Programmazione
A dopoprof.
l’esecuzione
della
function.
Burattini
void cancella(int k,int &n, int A[]) {
int j=-1;
for(i=0;i<n;i++) {
if (A[i] != k) {
j++; A[j]=A[i];
}
}
n=j;
}
Si noti che il corpo dell’if poteva anche ridursi a A[j++]=A[i];.
Per verificare se questa function si comporta correttamente basta scrivere un piccolo
main, un driver, il cui corpo sarà del tipo:
cin>>k>>n;
for(i=0;i<n ; i++)
cin>>A[i];
cancella(k,n,A)
cout<<”elementi rimasti “<<n<<endl
for (I=0,I++,I<n)
cout<<A[I]<<endl;
driver: un main scritto con l’unico scopo di verificare se una function si
Programmazione Mod A - Cap 3 comporta correttamente.
prof. Burattini
44
Regola generale per la scrittura di un driver per una procedura.
Supponiamo che la definizione di procedura contenga come
parametri di input x1,..,xn,
parametri di input-output y1,…,ym
parametri di output z1,…zr.
Allora il corpo del driver sarà:
cin>>x1>>…>>xn>>y1>>…>>ym;
f(x1,…,xn,y1,…,ym,z1,…,zr) ;
cout<<,y1<<…<<ym<<z1…<<zr ;
In altri termini il driver leggerà tutti i parametri di input e di input-output e stamperà
tutti i parametri di input-output e di output.
Nel caso invece di una funzione del tipo:
float: f(x1,x2,…,xn)
il corpo del driver sarà:
cin>>x1>>…>>xn ; Programmazione Mod A - Cap 3 cout<<f(x1,x2,…xn);
prof. Burattini
45
Variabili locali e globali
Scope di una variabile
Nei nostri esempi abbiamo quasi sempre utilizzato le dichiarazioni di tipo
all’inizio del programma, ma in C++, niente ci vieta di dichiarare delle
variabili in qualsiasi punto del programma.
In questo modo può essere difficile individuare il campo d’azione (scope) di una
variabile, cioè la parte di programma che ‘conosce’ quella variabile.
Per esempio, una variabile v può essere utilizzata soltanto all’interno della
funzione o procedura in cui è definita.
Qual è lo scope di una variabile v definita in un qualsiasi punto del programma?
Il C++ fornisce la seguente regola:
Il campo d’azione (o scope) di una variabile o di una costante è dato dalla più
piccola istruzione composta (gruppo di istruzioni racchiuso tra due parentesi
graffe) che include la sua dichiarazione.
Programmazione Mod A - Cap 3 prof. Burattini
46
Per questo motivo la variabile i definita in un for ha come scope solo il blocco o
la singola istruzione che segue il for ed è sconosciuta all’esterno.
Es.
for (int i=0; i<n; i++)
{
cout<<“ N° “<<i<<endl;
}
Sempre per questo motivo il parametro di una function può avere lo stesso
nome del parametro effettivo del processo chiamante.
Possiamo definire anche delle variabili globali e delle costanti globali: esse vanno
dichiarate all’esterno di qualsiasi function, compreso il main.
Il loro scope comprende tutto il programma sorgente in cui è presente.
Se una variabile v viene definita come globale e poi dichiarata nuovamente
locale in una funzione, si dice che
Programmazione Mod A - Cap 3 -
la variabile locale v nasconde la prof.
variabile
Burattiniglobale v.
47
ESEMPIO
……….
int v;
int main () {
……….. }
void f( int a) {
int v;
……..
}
La prima dichiarazione di v la rende globale,
perché definita al di fuori di ogni funzione.
La seconda dichiarazione di v, definita
localmente all’interno di una function nasconde
la v globale, nel senso che tutte le assegnazioni
che avvengono in questo contesto, riguardano
solo la variabile v locale.
Programmazione Mod A - Cap 3 prof. Burattini
48
L’uso di variabili globali è sconsigliabile per il seguente motivo:
se una function altera al suo interno il valore di una variabile globale, essa perde
una proprietà fondamentale e cioè che al ritorno nel processo chiamante gli
unici valori alterati sono i parametri passati per riferimento;
si ha in tal caso un side effect ed i side effect possono dare luogo ad errori
estremamente difficili da individuare.
Invece non si corre alcun rischio nel dichiarare una costante come globale, anzi
spesso ciò può essere utile quando, ad esempio, si debba cambiare la
dimensione di un array, allora è più facile trovare subito la sua dichiarazione,
piuttosto che cercarla in tutto il programma.
REGOLA
Non adoperare variabili globali.
Adoperare delle costanti globali invece non può arrecare alcun danno, visto che
ogni tentativo di modificarne il valore provoca un errore in fase di
compilazione.
Programmazione Mod A - Cap 3 prof. Burattini
49
Parametri di default. Passaggio di funzioni
E’ possibile evitare di indicare sempre tutti i parametri necessari per le
procedure o le funzioni, quando alcuni di essi vengono utilizzati spesso.
Ad esempio una funzione potenza, pot, che ha lo scopo di calcolare la potenza di
un numero intero può scriversi come segue.
int pot(int p,int n)
{
int ris=1;
for(int i=0;i<n;i++)
ris*=p;
return ris;
}
Programmazione Mod A - Cap 3 prof. Burattini
50
Poichè la maggior parte delle volte la potenza da calcolare è un quadrato allora
il C++ consente di usare la tecnica dei parametri di default.
E’ sufficiente cambiare il prototipo (dichiarazione) della funzione pot nel modo
seguente:
int pot (int , int = 2)
L’uso di questa funzione può allora essere
Z = pot(x)
è equivalente a scrivere z= pot (x,2) cioè z=x2
Z = pot (x,5)
ha il significato di z=x5
Programmazione Mod A - Cap 3 prof. Burattini
51
Possono esistere anche più parametri di default purché ci si attenga alle
seguenti considerazioni:
scrivendo sia il prototipo (dichiarazione) che la definizione, i valori di default
devono essere scritti soltanto nel prototipo,
se un parametro ha un valore di default, anche tutti gli eventuali parametri
successivi che appaiono nella lista formale devono avere un valore di
default.
Nella lista dei parametri formali delle funzioni possiamo inserire altre funzioni
o procedure.
Possiamo utilizzare la funzione pot nella lista di un’altra funzione;
ad esempio:
int prova(int h, int pot(x,h), int pot(x,k))
può essere richiamata con l’istruzione
y = prova(int 4, int
Programmazione Mod A - Cap 3 pot(7,4), int
prof.pot(3,5))
Burattini
52
Supponiamo di avere scritto la seguente procedura presentazione:
void presentazione () {
cout<<”Questo programma è stato scritto da”<<endl;
cout<<”Pinco Pallino”<<endl; }
Una qualsiasi funzione o procedura può richiamare la procedura presentazione;
Ad esempio:
int prova2(int h, void presentazione())
Programmazione Mod A - Cap 3 prof. Burattini
53
La procedura
cin.getline(s,n)
usa i parametri di default: il suo prototipo (dichiarazione) ha una struttura del
tipo
cin.getline(tipo-stringa s, int n, char =’\n’)
il primo parametro rappresenta la stringa di input,
il secondo il numero massimo di caratteri digitati,
il terzo il carattere di terminazione.
L’input della stringa termina o quando si è raggiunto il numero massimo n di
caratteri inseriti o quando si è digitato il carattere finale che, se omesso, è
rappresentato da invio. Quindi, se scriviamo
cin.getline(s,100)
il terzo parametro è di default ed è il tasto Invio, mentre scrivendo
cin.getline(s,n,’\t’)
l’input terminerà digitando
Programmazione Mod A - Cap 3 il tasto TAB.
prof. Burattini
54
Funzioni sovraccaricate (overloaded functions)
Il C++ consente di definire più funzioni con lo stesso nome purchè le due funzioni
differiscano o per il tipo o per il numero di parametri formali che appaiono nella lista.
Il compilatore, secondo il tipo o il numero di parametri passati dalla funzione, decide
quali funzioni attivare.
Nell’esempio seguente sono definite due funzioni potenza, entrambe nominate pot con
diversa tipologia di parametri: il compilatore sceglie la funzione più adatta allo scopo.
#include <iostream>
int pot(int p,int n) { // DEFINIZIONI
#include <stdlib.h>
int ris=1,i=0;
using namespace std;
while (i<n) {
int pot(int, int =3); //DICHIARAZIONI
i++;
float pot(float, int);
ris*=p; }
// MAIN
return ris;
main () {
}
int x; float f;
float pot(float p,int n) {
cout<<”Inserisci Numero intero=”;
float ris=1.0;
cin>>x;
int i=0;
cout<<”Cubo="<<pot(x)<<endl;
while (i<n) {
cout<<"Inserisci numero decimale=";
i++;
cin>>f;
ris*=p;
cout<<"Quadrato="<<pot(f,2)<<endl;
}
system(“pause”);
Programmazione Mod A -return
Cap 3 - ris;
55
}
// continua a lato prof. Burattini}
Namespace.
All’inizio del corso abbiamo introdotto il termine namespace e la clausola using,
osservando che in questo modo potevamo liberamente utilizzare i nomi della
libreria standard di input/output
using namespace std.
Con l’introduzione delle funzioni abbiamo anche descritto il concetto di scope
(ambito di visibilità di una variabile). Poiché il namespace è “lo spazio dei
nomi”, definire un namespace significa raggruppare sotto un nome comune
un insieme di elementi (funzioni, classi, variabili) tra loro correlati,
mantenendo separati quegli elementi che appartengono a namespace diversi.
Gli spazi dei nomi si rivelano molto utili quando creiamo librerie di funzioni.
Programmazione Mod A - Cap 3 prof. Burattini
56
Possiamo definire uno “spazio dei nomi”, o namespace, dichiarandolo ed
utilizzarlo per richiamare quella particolare funzione o classe.
ESEMPIO.
namespace Nome1 {
class primo {
…………};
int func(int a, int b) {
………………}
}_______________
namespace Nome2 {
class primo {
…………};
int func(int a, int b) {
………………}
}
All’interno del namespace, vengono definite
delle classi e delle funzioni a cui si può accedere
attraverso il risolutore del campo d’azione ::
(due punti doppi) detto anche operatore di scope.
Possiamo utilizzare anche funzioni con lo stesso
nome, purché abbiano un namespace diverso. Le
due funzioni func definite nello spazio dei nomi,
Nome1 e Nome2, sono distinte pur avendo la
stessa struttura, stessi parametri formali e
restituendo lo stesso tipo.
La funzione func può essere richiamata da un qualsiasi programma purchè si usi il
nome completo
Nome1::func(a,b)
se si vuole utilizzare la funzione definita nel namespace Nome1, con
Nome2::func(a,b)
Programmazione
- Cap 3 57
se si vuole utilizzare la funzione
definitaMod
nelAnamespace
Nome2.
prof. Burattini
Se pensiamo di servirci più spesso delle funzioni contenute nel namespace
Nome1, allora, subito dopo l’include del file contenente le definizioni
relative a Nome1, possiamo assegnare il comando
using namespace Nome1;
in tal caso tutte le funzioni contenute in Nome1 potranno essere scritte
semplicemente con il proprio nome, mentre quelle contenute in Nome2
potranno essere richiamate soltanto con il loro nome completo.
Programmazione Mod A - Cap 3 prof. Burattini
58
Semplici regole per la scrittura di buoni programmi.
Tutte le variabili globali possono essere richiamate da ogni funzione o
procedura ma non è consigliabile utilizzare le variabili globali così che ogni
procedura è autosufficiente, nel senso che non ha bisogno di altre variabili
oltre le locali e quelle di input/output assegnate nella lista dei parametri
formali.
Se tutte le procedure di un programma sono autosufficienti, il programma si
dice modulare.
Un programma modulare non ha effetti collaterali (side-effects).
Scrivere del codice senza effetti collaterali è molto semplice: basta fare in modo
di servirsi soltanto di variabili che fanno riferimento a termini che o sono
dichiarati localmente o sono definiti nella lista dei parametri formali,
non deve essere richiamata nessuna variabile globale.
Programmazione Mod A - Cap 3 prof. Burattini
59
I parametri formali che appaiono nell’intestazione di una procedura possono
essere:
INPUT: il passaggio dei parametri avviene per valore; i parametri attuali
possono essere espressioni o variabili;
INPUT/OUTPUT: rappresentano i valori cambiati dalla procedura; il
passaggio di parametri avviene per riferimento; i parametri attuali
possono essere soltanto delle variabili;
OUTPUT: rappresentano i valori restituiti dalla procedura; il passaggio
di parametri avviene per riferimento; i parametri attuali possono
essere soltanto delle variabili;
Programmazione Mod A - Cap 3 prof. Burattini
60
Non usare la chiamata per valore di una variabile se il valore di
questa variabile non è stato istanziato almeno una volta prima
della chiamata.
In questa procedura il valore conservato nella variabile Numero
viene perso
void ChiamataSbagliata(int Numero………)
{
cin>>Numero:
}
Non usare la chiamata per riferimento se il valore in uscita non
viene usato nel resto del programma chiamante.
Quando si scrive una procedura è necessario prima progettare e
scrivere la dichiarazione e poi il contenuto della procedura.
Programmazione Mod A - Cap 3 prof. Burattini
61
Per assegnare i nomi delle funzioni e procedure conviene attenersi
alle seguenti regole:
Poiché la funzione restituisce un valore è consigliabile assegnare
un nome che ricorda tale valore ( per esempio Potenza() ,
Massimo() , MCD() , .. );
Nel caso di una procedura (void e nome funzione) è meglio
assegnare un verbo che indichi l’azione svolta (per esempio
CalcolaPezzi(), StampaDati() )
Programmazione Mod A - Cap 3 prof. Burattini
62
ESERCIZIO.
Negli esercizi seguenti strutturare il programma in funzioni o
procedure:
Supponiamo di volere cambiare un assegno di una certa cifra
in moneta contante. Supponiamo siano assegnati i tagli
delle monete: 1, 2, 5, 10, 20, 50, 100 euro.
Vogliamo sapere in quali e quanti tagli di monete sarà
convertita la cifra assegnata (max 3000 euro)
Programmazione Mod A - Cap 3 prof. Burattini
63
Librerie standard
Il C++ è un linguaggio ricco di librerie che possono essere
opportunamente caricate con la direttiva include del compilatore.
La libreria contenuta nel file cctype o ctype.h contiene tutte le
routine di controllo; per esempio, verifica se un carattere è una
lettera, una cifra od un carattere di controllo.
Alcune di esse sono riportate di seguito e, comunque, ritornano un
intero e non un booleano (anche se resta inteso che un valore
nullo sta per false ed un valore diverso da zero sta per true).
Programmazione Mod A - Cap 3 prof. Burattini
64
File <cctype>
isalnum (int c);
Controlla se c è una cifra o una lettera
int isalpha (int c);
Controlla se c è una lettera
int isdigit (int c);
Controlla se c è una cifra
int iscntrl (int c);
Controlla se c è un carattere di controllo
int isspace (int c);
Controlla se c è un separatore
int isxdigit (int c);
Controlla se c è una cifra esadesimale
int tolower (int c);
Se c è una lettera, restituisce la sua versione
minuscola, altrimenti restituisce c inalterato
int toupper (int c);
Se c è una lettera, restituisce la sua versione
minuscola, altrimenti restituisce c inalterato
Programmazione Mod A - Cap 3 prof. Burattini
65
File <cstdlib>
int atoi (const char s [ ]);
Converte la stringa C contenuta nell’array s
in un intero.
void itoa(int n, char sn[],int b)
Converte il numero intero n in una stringa C,
copiata nell’array sn.
double atof (const char s [ ]);
Converte la stringa C contenuta nell’array s
in un double. La funzione restituisce 0 se la
stringa non contiene un numero reale valido.
int rand ();
Genera un numero pseudocasuale.
void srand (unsigned int seme);
rand ().
Genera un punto di partenza per la funzione
void exit (int CodiceDiUscita);
Provoca l’immediata terminazione del
programma e fornisce il CodiceDiUscita al
sistema operativo.
int system (const char cmd [Programmazione
]); InviaMod
la stringa
A - Cap 3 -cmd all’interprete dei 66
prof.
Burattinidel sistema operativo.
comandi
File <ctime>
double time ()
double localtime ()
suddivisa
double asctime ()
double ciftime ()
double clock ()
Restituisce il tempo assoluto in secondi
Converte il tempo assoluto nella rappresentazione
Converte in stringa il tempo memorizzato in una
struttura tm
Calcola intervalli di tempo
Restituisce il tempo trascorso dall’inizio dell’esecuzione
del programma
Struct tm
{
int tm_sec;
//secondi 0..59
int tm_min;
//minuti 0..59
int tm_hour;
//ora
0..23
int tm_mday;
//giorno 1..31
int tm_mon;
//mese 0..11
int tm_year;
//anno 0..anno-1900
int tm_wday;
//secondi 0..6
int tm_yday;
//secondi 0..365
Programmazione Mod A - Cap 3 67
int tm_isdst;
//diverso
da
zero
se
l’ora
è
legale
prof. Burattini
La funzione rand() genera in maniera casuale un numero intero compreso tra 0 e
32767 (il massimo intero rappresentabile con 2 byte). Il termine casuale sta ad
indicare che l’istruzione
n = rand();
può assegnare ad n un numero incluso tra 0 e 32767 e che ogni valore su indicato ha
la stessa probabilità di essere scelto.
Volendo simulare il lancio di un dado, dobbiamo attribuire ad n un intervallo
diverso, compreso tra 1 e 6; in tal caso possiamo scrivere
n=rand() % 6 +1; dove rand() % 6 restituisce un valore tra 0 e 5.
Se eseguiamo un programma contenente l’istruzione rand() possiamo verificare che
i valori che man mano vengono generati sono sempre gli stessi.
La procedura srand(seme) ha lo scopo di cambiare il valore iniziale e quindi tutta la
serie secondo il valore introdotto nella variabile seme. A questo punto ci viene in
aiuto l’istruzione time() che restituisce il tempo assoluto espresso in secondi;
quindi scrivere srand(time(0)) all’inizio di ogni programma contenente
l’istruzione rand() consente di far ripartire la successione di valori random da un
Programmazione Mod A - Cap 3 68
numero ogni volta diverso.
prof. Burattini
Libreria personale
Nella scrittura di programmi accade spesso di dover utilizzare le stesse
operazioni: un tipico esempio è dato dalle istruzioni di input/output.
A questo scopo conviene progettare una sola volta le funzioni che ci
servono per poi tenerle pronte per un possibile riutilizzo.
Costruiamo una funzione per l’inserimento dei numeri interi.
Il file, che chiameremo InsertNumero.h potrà essere richiamato da
qualsiasi programma.
Programmazione Mod A - Cap 3 prof. Burattini
69
Per costruire una funzione che restituisca solo numeri interi osserviamo che:
1.
conviene accettare l’input sotto forma di stringa per poi trasformarlo in numero
intero con la funzione di sistema atoi(stringa) contenuta nell’header <stdlib.h>;
2.
la funzione atoi(stringa) si comporta in questo modo:
a- se il primo carattere non è né una cifra, né il segno + o – allora restituisce il
valore 0; per esempio se digitiamo aa321 restituisce zero; per evitare che ogni
digitazione errata corrisponda al valore zero dobbiamo controllare se il primo
carattere inserito è 0;
b- se il primo carattere è una cifra oppure è un segno + o – allora restituisce solo
il numero corrispondente alle prime cifre digitate; per esempio, se inseriamo
° 124-33 la funzione fornisce il valore 124
° 343a2 la funzione fornisce il valore 343;
3.
considerare la possibilità che il numero inserito sia incluso tra due valori assegnati
(per default supporremo che questi valori siano compresi tra –2 miliardi e +2
miliardi).
Programmazione Mod A - Cap 3 prof. Burattini
70
Pseudocodice
Inserisci stringa INT1
Numero=atoi(INT1)
// controlla se il numero è compreso tra i due limiti assegnati
if ((Numero>=limiteinferiore) AND (Numero<=limitesuperiore))
il valore è accettabile
//controlla che il valore digitato sia soltanto lo zero
if (Numero==0 AND il primo carattere è diverso da zero)
il valore NON è accettabile
Se includiamo il codice nelle nostre librerie per richiamarlo basterà scrivere
#include “InsertNumero.h”
Se il nome del file header viene posto tra “ ” allora il compilatore si aspetta di
trovarlo nella stessa directory del file chiamante, mentre se viene posto tra
parentesi angolari <> lo cerca nella libreria include (in genere settabile come
parametro di variabile d’ambiente nel compilatore).
Programmazione Mod A - Cap 3 prof. Burattini
71
Se il file viene richiamato più volte nel corso di un programma, per evitare problemi
è possibile utilizzare la direttiva condizionale del compilatore #ifndef .
Scrivere ad esempio
#ifndef INSERT_NUMERO_H
#define INSERT_NUMERO_H
……istruzioni
#endif
significa segnalare al compilatore che in questo programma, con l’istruzione
#define INSERT_NUMERO_H
viene definita la costante INSERT_NUMERO_H; la direttiva
#ifndef
avverte il preprocessore di controllare se è già stata definita la costante
INSERT_NUMERO_H
se tale costante non é stata ancora definita, allora devono essere compilate tutte le
istruzioni comprese tra #ifndef e #endif, altrimenti quella stessa parte di codice
non deve essere presa in considerazione.
Programmazione Mod A - Cap 3 prof. Burattini
72
// InsertNumero.h
// Controlla se un valore inserito è effettivamente un numero compreso tra -2000000000 e
+2000000000
#ifndef INSERT_NUMERO_H
#define INSERT_NUMERO_H
#include <iostream>
#include <stdlib.h>
using namespace std;
// PROTOTIPO
int NumeroIntero(const char[], float=-2e9, float=2e9);
// DEFINIZIONE
int NumeroIntero(const char INTEST[],float inf, float sup)
{
char INT1[12];
#include <iostream>
int i,m;
#include "InsertNumero.h"
bool OKint=false;
using namespace std;
do {
int main () {
cout<<INTEST;
int n;
cin>>INT1;
n=NumeroIntero ("Inserire un numero intero:");
m=atoi(INT1);
cout<<n<<endl;
if (m>=inf && m<=sup)
system("pause");
OKint=true;
}
if (INT1[0]!='0' && m==0)
OKint=false;
} while(!(OKint));
return m;
Programmazione Mod A - Cap 3 73
}
insertNumero.h
eser3.6
prof. Burattini
Il file InsertArray.h è composto da due procedure:
LeggeVettore, ritorna un vettore di interi di lunghezza n; i parametri formali sono:
int [] Vet  Vet è il vettore restituito (per un vettore non è necessario introdurre
l’operatore & )
const int n  n rappresenta la lunghezza del vettore assegnato come parametro in input
char nome  nome è un carattere che rappresenta il nome del vettore
int nr  tutti i valori generati dal computer sono compresi nell’intervallo (-nr; nr)
estremi esclusi
bool Acaso Acaso è un valore booleano che, se vale true, assegna a caso i valori del
vettore, se false aspetta che siano immessi da tastiera; notiamo che esso è un
parametro di default, bool=true nel prototipo (dichiarazione), per cui se non viene
inserito si sottintende true.
La procedura LeggeVettore può essere così descritta:
se Acaso è vero allora
genera un punto di partenza per la funzione rand()
crea n valori, da 0 a n-1, a caso compresi tra 0 e 50
altrimenti
insertArray.h
chiedi in input gli n valori del vettore
StampaVettore stampa il vettore sul monitor; i parametri formali sono:
const int[] a  a è il vettore da stampare (che può anche essere un vettore costante)
const int n  rappresenta la lunghezza
del Mod
vettore
assegnato
come parametro in74input
Programmazione
A - Cap
3prof. Burattini
char nome  un carattere che rappresenta
il nome del vettore
INPUT E STAMPA DI VETTORI
// InsertArray.h
#ifndef INSERT_ARRAY_H
#define INSERT_ARRAY_H
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <ctime>
using namespace std;
void LeggeVettore (int [],const int, char, int=100, bool=true);
void StampaVettore (const int [], const int, char);
void LeggeVettore (int vet[],const int n, char nome, int nr, bool Acaso) {
int i;
if (Acaso){
srand(time(0));
for (i=0; i<n; i++) {
vet[i]=rand() % nr - nr/2;
cout<<nome<<"["<<i<<"]="<<vet[i]<<" ";
eser 3.7
}
cout<<endl;}
void StampaVettore (const int a[], const int n, char nome) {
else {
int i;
for (i=0; i<n; i++) {
for (i=0; i<n; i++) {
cout<<nome<<"["<<i<<"]="<<a[i]<<endl;
cout<<nome<<"["<<i<<"]=";
}
cin>>vet[i];
}
}
Programmazione Mod A - Cap 3 75
#endif
}
prof. Burattini
}
Sia assegnato un vettore di interi (max 255) VettIn ed un numero intero ind. Si
progetti un algoritmo OrdSubVet che riceve in input il vettore VettIn e l'intero ind e
restituisca come output lo stesso vettore VettIn dopo averne ordinato
in senso crescente le sole componenti comprese tra 0 e ind (incluso).
-----------------------------------------------------------------------------------------------------------Esempio
INPUT:
VettIn = 6 5 7 2 1 9 13 5
ind = 4
OUTPUT:
VettIn = 1 2 6 5 7 9 13 5
-----------------------------------------------------------------------------------------------------------PSEUDO CODICE
LeggiDati(int [],int&, int&);
OrdSubVet(int [],int,int,int&);
StampaDati(int [],int, int);
OrdSubVet(int V[], int N, int K, int &j)
// ordina i numeri minori o uguali a K
for(int i=1;i<N;i++) //cicla su tutto il vettore
if (V[i]<=K)
//ogni volta che trovi un valore <=K
scambia(V[i],V[j]); //scambialo di posto con il primo non ordinato
Programmazione
A - Cap 3al
- posto giusto il valore trovato
76
ordina(V,j,j-1);//risali
il vettoreMod
inserendo
prof. Burattini
j
0
3
i
1
5
2
2
3
j
2
1
3
i
j
2
5
3
6
6
6
4
7
7
7
5
1
1
5
6
8
8
7
9
9
i
Programmazione Mod A - Cap 3 prof. Burattini
8
9
77
// DEFINIZIONI
void scambia(int &a,int &b)
// DEFINIZIONI
{
void StampaDati(int V[],int N, int h)
int temp=a;
{ cout<<"\nI numeri ordinati sono"<<endl;
a=b;
for(int i=0;i<=h;i++)
b=temp;
// PROTOTIPI
cout<<V[i]<<" | ";
}
void StampaDati(int [],int, int);
cout<<" ";
void ordina(int V[],int r,int s)
void LeggiDati(int [],int&, int&);
for(int i=h+1;i<N;i++)
{
void scambia(int& ,int&);
cout<<V[i]<<" | ";
while ((s>=0)&&(V[r]<V[s]))
void ordina(int [],int,int);
cout<<endl;
{
void OrdSubVet(int [],int,int,int&);
}
scambia(V[r],V[s]);
void LeggiDati(int V[],int &N,int &K)
r--;
{
s--;
// MAIN
cout<<"Quanti numeri vuoi inserire?(max
}
int main()
cin>>N;
}
{
cout<<"Il programma ordinera' i soli valor
void OrdSubVet(int V[], int N, int K, int &j)
int Vett[M], n, j=0, k;
ed\nil valore che inserirai adesso: "
for(int i=1;i<N;i++)
LeggiDati(Vett, n, k);
cin>>K;
{
OrdSubVet(Vett, n,k, j);
cout<<"Inserisci i numeri separati da uno
if (V[i]<=K)
StampaDati(Vett, n, j);
for (int i=0; i<N;i++)
{
system("PAUSE");
cin>>V[i];
j++;
return EXIT_SUCCESS;
cout<<" Fine inserimento "<<endl;
scambia(V[i],V[j]);
Programmazione Mod A - Cap
3
78
}
}
ordina(V,j,j-1);
prof. Burattini
#include <cstdlib>
#include <iostream>
using namespace std;
const int M=100;
Alcune funzioni e procedure per l’uso delle stringhe.
Con gli strumenti che abbiamo è per ora difficile gestire le stringhe in stile C.
Abbiamo, quindi, la necessità di scrivere delle funzioni che utilizzano l’array di
caratteri.
Le procedure sono le seguenti tre :
bool paragona (const char[], const char[]);
int lung(const char[]);
void concat(const char[], const char[], char s3[]);
La prima confronta due stringhe e ritorna un valore booleano, true se le
stringhe sono uguali, false altrimenti.
La seconda funzione restituisce la lunghezza della stringa;
La terza, rappresentata da una procedura, concatena le prime due stringhe e
restituisce il risultato nella terza.
Programmazione Mod A - Cap 3 prof. Burattini
79
Utilizziamo la parola chiave const per tutte le variabili di input nella lista dei
parametri formali: in questo modo anche una stringa costante può essere
passata come parametro.
La prima funzione paragona confronta due stringhe; per verificarne
l’uguaglianza è necessario confrontarle carattere per carattere: se due
caratteri sono distinti allora le stringhe non sono uguali e la funzione deve
restituire false, true altrimenti.
Pseudocodice
Codice
Finché i due caratteri i-esimi
sono uguali
Se la stringa è terminata
restituisci TRUE
Incrementa l’indice i
Se esce dal ciclo allora i due
caratteri sono diversi e quindi
restituisci FALSE
bool paragona (const char s1[],
const char s2[]) {
int i=0;
while (s1[i]==s2[i]) {
if (s1[i]=='\0')
return true;
i++;
}
return false;
}
Programmazione Mod A - Cap 3 prof. Burattini
80
La seconda funzione lung calcola il numero di caratteri racchiusi in
una stringa: è sufficiente scandire la stringa inserendo un contatore
nel ciclo (per eliminare il tipico errore off by one viene restituito un
valore decrementato di una unità):
int lung(const char s1[]) {
int i=0;
while (s1[++i]!='\0');
return i--;
}
Programmazione Mod A - Cap 3 prof. Burattini
81
L’ultima funzione concat concatena due stringhe S1 ed S2 in S3.
A questo scopo, si copiano in S3 prima tutti i caratteri di S1,
successivamente tutti quelli di S2 ed, infine, si aggiunge il
carattere di fine stringa ‘\0’.
void concat(const char s1[], const char s2[], char s3[])
{
int i=0,j=0;
while (s1[i]!='\0') {
s3[i]=s1[i];
i++;
}
while (s2[j]!='\0') {
s3[i++]=s2[j++];
}
s3[i]='\0'; // inserisce il simbolo di fine stringa
}
Programmazione Mod A - Cap 3 82
prof. Burattini
Le funzioni sono inserite in un file, stringhearray.h, da utilizzare
come libreria personale.
// stringhearray.h
#ifndef stringhe_array_h
#define stringhe_array_h
#include <iostream>
using namespace std;
// PROTOTIPI
bool paragona (const char[], const char[]);
int lung(const char[]);
void concat(const char[], const char[], char[]);
// DEFINIZIONI
qui vanno inserite le implementazioni delle funzioni
#endif
Programmazione Mod A - Cap 3 prof. Burattini
stringarray.h
83
Il programma seguente rappresenta un semplice esempio di utilizzo della
libreria stringhearray.h.
Ricordiamo che tale file di libreria deve stare nella stessa cartella del file che lo
utilizza, altrimenti è necessario fornire il path completo.
#include <iostream>
#include <stdlib.h>
#include "stringhearray.h"
using namespace std;
int main () {
char t[10],s[10],z[20];
cout<<"stringa s ="; cin>>s;
cout<<"stringa t ="; cin>>t;
cout<<"Lunghezze s = "<<s<<"
"<<lung(s)<<" t ="<<t<<"
"<<lung(t)<<endl;
concat(s,t,z);
cout<<"stringa s concatenata a t ="<<z<<endl;
if (paragona(s,t))
cout<<"Le due stringhe sono uguali\n";
else
cout<<"Le due stringhe NON sono uguali\n";
system("pause");
return 0;
Programmazione Mod A - Cap 3 prof. Burattini
}
eser3.8
84
ESEMPIO
Data una stringa qualsiasi verificare se è palindroma.
Una stringa è palindroma quando ha uguali i caratteri che hanno la stessa
distanza dal centro della stringa. Per esempio
Sono stringhe palindrome
ANNA
ADA
DEOED
baccdccab
NON sono stringhe palindrome
AMARA
AROMA
ODE
abcab
baccdccab
0123456789
Analizzando, ad esempio, la parola baccdccab dobbiamo verificare che il primo
carattere è uguale all’ultimo, il secondo è uguale al penultimo, e così via.
Quindi, detta n la lunghezza della stringa otteniamo
s[i]=s[n-i] cioè s[0]=s[n-1] , s[1]=s[n-2] ……… e così via
Programmazione Mod A - Cap 3 prof. Burattini
85
i=0; Ok=true;
while Ok è verificata e i<(n-1)/2
se l’elemento i-esimo è diverso da quello
n meno i-esimo allora la condizione non è
soddisfatta e quindi
Ok=false;
incrementa i;
if (Ok)
output “stringa palindroma”
else output “stringa NON palindroma”
i=0; Ok=true;
while (Ok) & (i<(n-1)/2)
if (s[i]!=s[n-i-1])
Ok=false;
i++;
if (Ok)
output “stringa palindroma”
else
output “stringa NON palindroma”
Programmazione Mod A - Cap 3 prof. Burattini
eser3.9
86
ESERCIZIO
Scrivere il codice e provarlo nei casi seguenti:
•
•
•
•
•
Stringa nulla o massima consentita
Numero di caratteri pari o dispari
Tutti caratteri uguali
Tutti caratteri diversi
Sono uguali solo il primo e l’ultimo
Programmazione Mod A - Cap 3 prof. Burattini
87
Esercizi.
Usando le funzioni LeggeVettore e StampaVettore e le funzioni sulle stringhe
risolvere i seguenti esercizi.
1) Generato in modo random un vettore contenente N interi relativi compresi
tra –M ed M mediante una procedura, risolvere i seguenti problemi :
• scrivere un programma che stampi tutti i numeri positivi e la loro posizione
• scrivere un programma che stampi tutti i numeri minori o uguali a zero
• scrivere un programma che stampi il più grande ed il più piccolo e le loro
posizioni
• scrivere un programma che stampi tutti i numeri superiore ad un valore
assegnato e le loro posizioni
• scrivere una procedura che restituisca tutte le posizioni dei numeri negativi
2) Definire una funzione Uguali2 che prenda in input un vettore V di interi di
lunghezza n, e restituisca:
- “true” se il vettore contiene almeno due numeri uguali
- “false” altrimenti.
Esempi.
Se V= [1,22,13,24,5] è Uguali2(V) = false
Programmazione
Mod A - Cap 3 88
Se invece V= [1,2,6,24,2] è Uguali2(V)
= true
prof. Burattini
3) Definire una procedura PrecSegueX che abbia in input un vettore V di interi
di lunghezza n, ed un numero X, e:
- inserisca all’inizio di V i valori di V minori o uguali ad X (conservando
l’ordine in cui si trovavano in V);
- inserisca in seguito tutti i valori di V maggiori di X (conservando ancora
l’ordine in cui si trovavano in V).
Esempio.
Sia V= [56,35,4,2,22]. L’output di PrecSegueX(V,40) deve essere:
V=[35,4,2,22,56].
4) Definire una funzione ContaCifre che prenda in input un Vettore V di interi
di lunghezza N, ed un numero X e conti quante volte tutte le cifre di X siano
contenute negli elementi che compongono il vettore.
eser3.10b
Esempi.
Siano V=[484,325,12,8489,48,12487,1284] ed X=48 ; ContaCifre(V,7,48) = 4
(sono evidenziati i numeri che contengono al loro “interno” il numero 48).
5) Definire una procedura GoDestra, che, assegnato un vettore V di n elementi
ed un intero m, 0<=m<=n, sposti verso destra di m passi tutti gli elementi
del vettore V.
Esempi.
Programmazione Mod A - Cap 3 89
Sia V=[7,8,9,0] ed n=4 otteniamo GoDestra(V,3)
fa diventare V=[8,9,0,7]
prof. Burattini
6) Scrivere una procedura Comuni, che assegnati due vettori V1, V2 di
dimensioni rispettivamente n1 ed n2, ponga in un altro vettore V3 tutti e
soli gli elementi di V1 che compaiono anche in V2, conservando l’ordine
con cui compaiono in V1.
Esempio. Siano V1=[1,2,3,4,5], V2=[5,0,3,0,1], V3 qualunque. Eseguiamo
Comuni(V1, V2,V3). Allora V3 diventa [1,3,5].
7) Definire una procedura PariDispari che dato un vettore V di interi di
lunghezza n:
- ponga all’inizio di V i valori di V pari, nello stesso ordine in cui si trovavano in
V;
- li faccia quindi seguire dai valori di V dispari, di nuovo nello stesso ordine in
cui si trovano in V.
Esempio. Sia:
V= [5,3,4,2,1]
Dopo aver eseguito la procedura PariDispari si deve avere: V = [4,2,5,3,1].
8) Scrivere una funzione che dato un array V di interi di dimensione n
restituisce true se nell’array V c’è un valore che è uguale alla somma di
tutti i valori che lo precedono, false altrimenti.
Programmazione
Mod A - Cap
3 - perché a[3]=9=1+4+490
Esempio. V=[1, 4, 4, 9, 3] la funzione
restituisce
true
prof. Burattini
V =[1,3,5,8,3]
la funzione restituisce false
9) Scrivere una procedura che dati 2 array di interi V1 e V2 di dimensione n
restituisce nell’array V3 gli elementi che appartengono a V1 ma non a V2
non ripetuti e in N3 il numero di tali elementi.
Esempio.
V1= [2, 4, 4, 5, 3] e V2= [7, 3 ,10 ,6 ,7] si deve ottenere V3= [ 2, 4, 5] con N3 =3
10) Scrivere una funzione che data una stringa s ed un carattere car restituisce
il numero massimo di caratteri car consecutivi presenti nell’array.
Esempio.
S = ‘abcaacaaabaa’ car=’a’ la funzione deve restituire 3
11) Scrivere una procedura che dato un array a ordinato di dimensione N
inserisce nell’array il valore x in modo tale che l’array dopo l’inserimento
sia ancora ordinato.
Esempio.
Siano a = [2, 3, 7, 11, 24] e x =5 si deve ottenere a = [2, 3, 5, 7, 11,24 ]
12) Scrivere un programma che, dati due vettori di interi di dimensione N, ne
costruisca un terzo di dimensione 2N i cui elementi di posizione pari siano
gli elementi del primo vettore e gli elementi di posizione dispari siano gli
Programmazione
Mod A il
- Cap
3elementi del secondo vettore.
Strutturare
programma
in procedure e91
prof. Burattini
funzioni.
13) Scrivere un programma che, dato un vettore V1 di reali di dimensione N, ne
generi un altro V2 così definito: il primo elemento di V2 è dato dal prodotto
degli elementi 1 e 2 di V1, il secondo elemento di V2 è dato dal prodotto
degli elementi 3 e 4 di V1, e così via.
14) Scrivere una procedura che genera un vettore V di numeri reali di
dimensioni N (con N<=100). Utilizzando tale procedura scrivere un
programma che
• stampi prima tutti gli elementi di posto dispari e poi quelli di posto pari,
• letto un indice h stampi l’indice ed il valore del più piccolo fra i numeri
maggiori di V[h];
• stampi l’indice ed il valore dei numeri di valore dispari massimo e minimo;
• si costruisca e quindi si stampi un secondo array di N elementi tali che il
primo elemento contenga la somma di tutti gli N numeri, il secondo la
somma dei numeri dal secondo in poi, il terzo la somma dal terzo in poi e
così via;
• si stampi l’indice ed il valore dell’elemento massimo fra gli elementi di
posto dispari, quindi l’indice ed il valore del minimo fra gli elementi di
posto pari;
• letto un indice h, si costruisca e quindi si stampi un array di N elementi tali
che il primo sia quello specificato dall’indice, il secondo sia quello
precedente e così fino al primo,
poi proseguendo
Programmazione
Mod A - Cap 3 - dall’ultimo retrocedendo
92
prof. Burattini
fino a completare l’array.
15) Scrivere un programma che prenda in input un vettore già ordinato di
interi e stampi in output l’istogramma delle occorrenze di ogni elemento del
vettore.
Per esempio, dato il vettore V=[1,1,1,3,5,5,7,7,7,7,10,10], deve stampare:
1 ***
3 *
5 **
7 ****
10 **
eser3.12
Programmazione Mod A - Cap 3 prof. Burattini
93
Fly UP