Sei sulla pagina 1di 6

Quinta esercitazione (funzioni)

Esercizio 1 (svolto)
Esercizio 2 (svolto)
Esercizio 3
Esercizio 4
Esercizio 5

Esercizio 1

Cominciamo con una funzione che non comunica con il resto del programma:
#include <iostream>
using namespace std;

void hello() {
cout << "Questa e' la mia prima funzione" << endl;
}

int main() {
hello();
return 0;
}

Proviamo ora a passare un parametro alla funzione:


#include <iostream>
using namespace std;

void sum(double a, double b) {


double c;
c = a + b;
cout << "La somma vale " << c << endl;
}

int main() {
double v1,v2;
cout << "Valore di v1:"; cin >> v1;
cout << "Valore di v2:"; cin >> v2;
sum(v1,v2);
return 0;
}

Proviamo ora ad utilizzare il valore di ritorno della funzione


#include <iostream>
using namespace std;
double sum(double , double ); // prototipo della funzione

int main() {
double v1,v2,v3;
cout << "Valore di v1:"; cin >> v1;
cout << "Valore di v2:"; cin >> v2;
v3=sum(v1,v2);
cout << "La somma di v1 e v2 vale " << v3 << endl;
cout << "La somma di v1 e v2 vale " << sum(v1,v2) << endl;
return 0;
}

double sum(double a, double b) {


double c;
c = a + b;
return c;
}

Vediamo ora come modificare il parametro passato alla funzione (passaggio del puntatore)
#include <iostream>
using namespace std;
void sum(double , double ,double *); // prototipo della funzione

int main() {
double v1,v2,v;
cout << "Valore di v1:"; cin >> v1;
cout << "Valore di v2:"; cin >> v2;
sum(v1,v2,&v);
cout << "La somma di v1 e v2 vale " << v << endl;
return 0;
}

void sum(double a, double b, double *c) {


*c = a + b;
}

Un altro modo, esclusivo del C++, per modificare un parametro è passarlo per riferimento senza
l'aiuto del puntatore
#include <iostream>
using namespace std;
void sum(double , double , double &);

int main() {
double v1,v2,v;
cout << "Valore di v1:"; cin >> v1;
cout << "Valore di v2:"; cin >> v2;
sum(v1,v2,v);
cout << "La somma di v1 e v2 vale " << v << endl;
return 0;
}

void sum(double a, double b, double &c) {


c = a + b;
}

Tipi struct

Una struttura dati è un insieme di tipi diversi di dati raggruppati in un'unica dichiarazione. La forma
della dichiarazione è la seguente:
struct nome_tipo {
tipo1 nome_elemento1;
tipo2 nome_elemento2;
tipo3 nome_elemento3;
.
.
};

int main(){
struct nome_tipo nome_oggetto;
...
...
return 0;
}

in cui nome_tipo è un nome per il tipo di struttura: tra le parentesi graffe {} sono indicati i tipi e i
rispettivi sub_identificatori degli elementi che compongono la struttura.
nome_oggetto indifica un singolo oggetto del tipo nome_tipo
Dato un oggetto si accede ad un elemento con l'operatore .
nome_oggetto.nome_elemento1

dato un puntatore ad oggetto si accede ad un elemento dell'oggetto puntato con l'operatore ->
nome_oggetto->nome_elemento1

La dichiarazione della struttura viene fatta al di fuori di ogni funzione in modo che ogni funzione
possa usarla.

Esercizio 2 (strutture)
#include <iostream>
#include <string>

using namespace std;

struct person { // person e` un nuovo tipo


string name;
string surname;
int age;
double height;
};

void print(person p) {
cout << "Mi chiamo " << p.name << " " << p.surname << " ho " << p.age << "
anni e sono alto " << p.height << " m" << endl;
}

int main(){

person p1,p2;
person *p3;

cout << "Nome?" << endl;


cin >> p1.name;
cout << "Cognome?" << endl;
cin >> p1.surname;
cout << "Eta`?" << endl;
cin >> p1.age;
cout << "Altezza?" << endl;
cin >> p1.height;
print(p1);
p3 = &p1;
cout << (*p3).name << endl;
cout << p3->name << endl; // p3->name e` equivalente a (*p3).name
}

Esercizio 3 (passaggio di vettori)


1. Si crei una funzione che calcoli la somma di un vettore e lo restituisca nel valore di ritorno.
Prototipo:
double vsum(int ndat, double* dati);

2. Si crei una funzione che calcoli la somma, il minimo ed il massimo di un vettore e li


restituisca utilizzando il passaggio per referenza.
3. Si riscriva la funzione del secondo punto utilizzando le strutture (per l'input e/o per l'output).

Due brevi digressioni


Compilazione separata
Passaggio di argomenti al programma principale

Esercizio 4
Provate la compilazione separata per i punti 2 o 3 dell'esercizio 3.

Esercizio 5
Strutturare con funzioni il programma precedentemente preparato (esercitazione 4) per la soluzione
dei minimi quadrati analitici. Potete utilizzare tutto quello che abbiamo visto in questa esercitazione
(funzioni, strutture, compilazione separata)

Compilazione separata

La "traduzione" del file sorgente in file eseguibile (operata dal comando g++) si può dividere in tre
parti

• preprocessore: esegue operazioni preliminari sul file sorgente (inclusioni, definizioni)


• compilazione: analizza sintatticamente, secondo le regole del linguaggio di programmazione
utilizzato, e produce un file oggetto che rappresenta la traduzione del sorgente in linguaggio
macchina, cioè in istruzioni che il processore è in grado di eseguire. Il file oggetto non è
tuttavia ancora eseguibile.
• link: trasforma il file (o i files) oggetto creati dalla compilazione in file eseguibile
includendo le librerie necessarie
Può essere utile separare funzioni che svolgono operazioni diverse in oggetti precompilati che
possano essere direttamente linkate da un programma (senza necessità di essere ri-compilate).
Per fare ciò è necessario separare la dichiarazione della funzione (prototipo) dal suo corpo (insieme
di istruzioni che compongono la funzione).

file vsum.h:
double vsum(int , double *);
file vsum.cpp
double vsum(int ndat, double *dat) {
....
....
}

Per creare il file oggetto si compila con le opzioni


g++ -c vsum.cpp

(esegue solo la compilazione e salva l'oggetto come vsum.o).


A questo punto il programma principale main.cpp diventa
#include <iostream>
#include "vsum.h"

using namespace std;

int main() {
int i,np=10;
double points[10];
for (i=0; i<np; i++) {
cout << "Valore di points[" << i << "]: "; cin >> points[i];
}
cout << "La somma delle componenti vale " << vsum(np, points) << endl;
return 0;
}

ed andrà compilato con il comando


g++ -o main main.cpp vsum.o

È possibile costruire una libreria con file oggetto contenenti funzioni riconducibili allo stessa
problematica (operazioni matematiche, I/O, analisi statistiche, etc...)
ar libmylib.a oggetto1.o oggetto2.o

In compilazione si potrà utilizzare le funzioni presenti nella libreria


g++ -o main main.cpp -l mylib

Si può aggiungere la directory contenente i files oggetti (o gli header files) alla lista delle directory
ove cercare
g++ -o main main.cpp -I DirInc -L DirLib -l mylib

(gli header files andranno in questo caso inclusi come #include<header.h> )

Passaggio di argomenti alla funzione main

È possibile inviare al main() degli argomenti, specificandoli da riga di comando (as esempio dando
da shell il comando ./eseguibile par1). Il sistema operativo chiamerà in questo caso la funzione
main() passandogli due argomenti: in un intero (argc) che indica il numero di argomenti con cui è
stato richiamato l'eseguibile (compreso il nome stesso dell'eseguibile: nell'esempio citato argc varrà
2), ed un char** (argv) che rappresenta un array di char*, di lunghezza argc.
Ogni elemento dell'array contiene un puntatore ad una C-string rappresentante nell'ordine gli
argomenti con cui è stato eseguito il comando da shell (nell'esempio, argv[0] sarà la stringa
"./eseguibile", argv[1] sarà la stringa "par1").
Per poter utilizzare gli argomenti passati in questo modo, il main() dovrà essere definito nel
seguente modo:

main(int argc, char **argv)

All'interno del programma è sempre possibile convertire le stringhe C in stringhe C++


string str_par1(argv[1]);

se poi il parametro contiene un valore numerico occorre leggere tale valore da stringa (per la lettura
da stringa si utilizzano comandi analoghi a quelli necessari per la lettura da file)
#include <sstream> // analogo di fstream
...
istringstream inputstr(str_par1); // analogo di ifstream
double x;
inputstr >> x;
...