Esercizio C++ - Problema con le funzioni


#1

Come ho detto in chat l’altra sera ho ripreso a studicchiare c++ e adesso ho iniziato a far esercizi, quindi eccomi qui con il primo inghippo che mi blocca da circa 2 giorni.

Il testo dell’'esercizio “originale” era questo:

Se lasciaste cadere un pallone dalla punta dell’antenna in cima alla torre Eiffel (324 m) con che velocità toccherebbe il suolo? SEMPLIFICAZIONE: non considerare la forza di attrito e la resistenza aereodinamica. Scrivere un programma che in realtà risolva il problema
per una caduta da una altezza qualsiasi indicando anche la velocità in km/sec

Una volta svolto ho deciso di modificarlo inserendo una struttura selettiva che distingua il caso in cui si vuole considerare il corpo privo di massa, risolvendo il problema come nell’esercizio, originale, e il caso in cui il corpo è dotato di massa calcolando anche l’energia potenziale iniziale e l’energia cinetica finale. Fin qui tutto bene, il programma compila e restituisce risultati corretti.

Ho deciso di approfondire e le formule utilizzate per ottenere i risultati le ho scritte come funzioni fuori dal main. Qui sorge il problema. Il programma viene compilato senza errori, ma i risultati sono privi di senso. Immagino che il problema sia nel modo in cui ho definito le funzioni, ma non riesco a capire cosa ho sbagliato.

Questo è il codice (ho lasciato le formule interne al main commentandole, lasciando attive solo le funzioni)

#include <cstdlib>
#include <iostream>
#include <math.h>

using namespace std;

// velocità d'impatto V = sqrt(2gh)
double vel_Imp(double g, double altezza)
{
	double vel_Imp = sqrt(2 * g * altezza);
	return vel_Imp;
}

// Energia Potenziale Ep = mgh
double Ep(double massa, double g, double altezza)
{
	double Ep = massa * g * altezza;
	return Ep;
}

// Energia Cinetica: Ek = 0.5 mv^2
double Ek(double massa, double vel_Imp)
{
	double Ek = 0.5 * massa * vel_Imp * vel_Imp;
	return Ek;
}


int main()
{
	const double g = 9.816; //accelerazione di gravità
	double altezza = 0;
	double massa = 0;
	
	cout << "Calcolo della velocita' d'impatto di un grave in caduta libera" << endl;
	
	cout << "\nIndicare l'altezza di caduta:" << endl;
	cin >> altezza;
	cout << "Altezza h = " << altezza << "m" << endl;

	cout << "\nIndicare la massa del corpo in kg"
		 << "\n(Se si indica 0 il corpo sara' considerato privo di massa)" << endl;
	cin >> massa;

	if (massa == 0)
	{
		cout << "\nCorpo privo di massa" << endl;
		
		// Calcolo velocità
		double vel_Imp(double g, double altezza);
		//double vel_Imp = sqrt(2 * g * altezza);
		cout << "\nVelocita' d'impatto: V = " << vel_Imp << " m/sec" << endl;
	}
	else
		if (massa > 0)
		{
			cout << "\nMassa m = " << massa << " kg" << endl;

			// Calcolo velocità
			double vel_Imp(double g, double altezza);
			//double vel_Imp = sqrt(2 * g * altezza);
			cout << "\nVelocita' d'impatto: V = " << vel_Imp << " m/sec" << endl;
			
			// Calcolo energia potenziale
			double Ep(double massa, double g, double altezza);
			//double Ep = massa * g * altezza;
			cout << "Energia potenziale iniziale: Ep = " << Ep << " J" << endl;

			// Calcolo energia cinetica
			double Ek(double massa, double vel_Imp);
			//double Ek = 0.5 * massa * vel_Imp * vel_Imp;
			cout << "Energia cinetica finale: Ek = " << Ek << " J" << endl;
		}
		else
		{
			cout << "\nERRORE: la massa non puo' essere negativa!" << endl;
		}

	return 0;
}

Allego anche uno screen dei risultati che ottengo usando le funzioni:
Cattura

Help me, please.

Ogni suggerimento per migliorare il codice è ben accetto :slight_smile:

Domanda finale: inizialmente volevo provare a scrivere la struttura selettiva utilizzando una variabile booleana, ma mi sono incartato e il codice funzionava a metà. Ammesso che sia utile l’utilizzo di una variabile booleana in questo caso specifico, quale potrebbe essere un modo per utilizzarla?


#4

Sono millenni che non uso il C e il C++ ma mi sembra che tu ridefinisca troppe volte le funzioni.
Cioè:

double vel_Imp(double g, double altezza)
{
double vel_Imp = sqrt(2 * g * altezza);
return vel_Imp;
}

qui ridefinisci la funzione in

double vel_Imp = sqrt(2 * g * altezza);

mentre dovresti invece definire una variabile x (y, z o pippo o come vuoi)

double x:
x = vel_Imp = sqrt(2 * g * altezza);

e poi concludere con

return x;

In main non devi ridefinire le funzioni e nella chiamata non devi ridefinire il tipo dei dati:

double vel_Imp(double g, double altezza);

Anche qui dovresti dichiarare una variabile a cui assegnare il risultato della funzione:

double risultato;
risultato = vel_Imp(g, altezza);

Esempio:

// Calcolo velocità
double risultato;
risultato = vel_Imp(g, altezza);
cout << “\nVelocita’ d’impatto: V = " << risultato << " m/sec” << endl;


#5

Nel main mi limito a chiamare le funzioni

Questa, nel main, è commentata

Quindi dire alla funzione di ritornare al main il valore appena calcolato, come ho fatto io, è sbagliato?

double vel_Imp(double g, double altezza)
{
	double vel_Imp = sqrt(2 * g * altezza);
	return vel_Imp;
}

Oh, questo mi era sfuggito. In effetti è vero, il tipo dei parameri della funzione è già stato dichiarato.


#6

Si, ho copiato la riga sbagliata, ma sopra fai proprio quello.

come ho scritto prima, dovrebbe essere così:

devi creare una variabile a cui assegnare il risultato, non riutilizzare il nome della funzione.
Oppure direttamente:

return sqrt(2 * g * altezza);


#7

#8

Ok, funziona. :smile:
Adesso ho capito meglio come gestire il passaggio delle variabili delle funzioni alle variabili del main, grazie @FastFede :beer:

Ho pulito il codice dalle formule “vecchie”, è ancora migliorabile?

#include <cstdlib>
#include <iostream>
#include <math.h>

using namespace std;

// velocità d'impatto V = sqrt(2gh)
double vel_Imp(double g, double altezza)
{
	double vel = sqrt(2 * g * altezza);
	return vel;
}

// Energia Potenziale Ep = mgh
double Ep(double massa, double g, double altezza)
{
	double Ep = massa * g * altezza;
	return Ep;
}

// Energia Cinetica: Ek = 0.5 mv^2
double Ek(double massa, double vel_Imp)
{
	double Ek = 0.5 * massa * vel_Imp * vel_Imp;
	return Ek;
}


int main()
{
	const double g = 9.816; //accelerazione di gravità
	double altezza = 0;
	double massa = 0;
	double vel = 0;
	
	cout << "Calcolo della velocita' d'impatto di un grave in caduta libera" << endl;
	
	cout << "\nIndicare l'altezza di caduta:" << endl;
	cin >> altezza;
	cout << "Altezza h = " << altezza << "m" << endl;

	cout << "\nIndicare la massa del corpo in kg"
		 << "\n(Se si indica 0 il corpo sara' considerato privo di massa)" << endl;
	cin >> massa;

	if (massa == 0)
	{
		cout << "\nCorpo privo di massa" << endl;
		
		// Calcolo velocità
		vel = vel_Imp(g, altezza);
		cout << "\nVelocita' d'impatto: V = " << vel << " m/sec" << endl;
	}
	else
		if (massa > 0)
		{
			cout << "\nMassa m = " << massa << " kg" << endl;

			// Calcolo velocità
			vel = vel_Imp(g, altezza);
			cout << "\nVelocita' d'impatto: V = " << vel << " m/sec" << endl;
			
			// Calcolo energia potenziale
			double en_pot = 0;
			en_pot = Ep(massa, g, altezza);
			cout << "Energia potenziale iniziale: Ep = " << en_pot << " J" << endl;

			// Calcolo energia cinetica
                        // Non uso la funzione vel_Imp perche' la funzione ha già passato il risultato
			// per il calcolo della velocita' alla variabile vel
			double en_cin = 0;
			en_cin = Ek(massa, vel);
			cout << "Energia cinetica finale: Ek = " << en_cin << " J" << endl;
		}
		else
		{
			cout << "\nERRORE: la massa non puo' essere negativa!" << endl;
		}

	return 0;
}

Ad esempio, è utile portare le variabili “en_pot” e “en_cin” fuori dall’if visto che vengono usate solo se il corpo è dotato di massa? Mi spiego meglio, ha senso tenerle come variabili valide in tutto il main se, come in questo caso, le stesse vengono usate solo se è vero che m > 0?


#9

Potresti evitare quelle variabili così:

cout << “Energia potenziale iniziale: Ep = " << Ep(massa, g, altezza) << " J” << endl;

idem nelle funzioni:

double vel_Imp(double g, double altezza)
{
double vel = sqrt(2 * g * altezza);
return vel;
}

double vel_Imp(double g, double altezza)
{
return sqrt(2 * g * altezza);
}

Ma non credo tu stia esercitandoti per scrivere codice miniaturizzato, l’uso di tre variabili double non pesa nella grandezza dell’eseguibile compilato, né nella velocità di esecuzione :slight_smile:

E infine favorisce la chiarezza del codice


#10

No no, proprio no :old_lol:


#11

Bravo @JDM, continua così!

Dal momento che stai cominciando dalle basi, ti propongo l’applicazione di una “good practice” in una delle tue funzioni (in realtà molto poco utile in questo caso specifico):

// Energia Cinetica: Ek = 0.5 mv^2
double Ek(double massa, double vel_Imp)
{
	double Ek = 0;
	// verifico solo la massa, la vel_Imp potrebbe essere zero
	if (massa > 0) {
		Ek = 0.5 * massa * vel_Imp * vel_Imp;
	}
	return Ek;
}

La dichiarazione di cui parli ha senso farla solo nella IF, ma come dice @FastFede finché si tratta di variabili semplici, non hanno impatto.
E’ comunque meglio se le variabili le dichiari sempre nell’ambito in cui agiscono (quindi se vengono usate solo nella IF, dichiarale nella IF).

Keep on code!
:1st_place_medal:


#12

Quindi, in genere, è preferibile inserire un controllo all’interno della funzione piuttosto che, magari, eseguirlo prima di chiamare la funzione stessa nel main?


#13

Ma certo! Lo scopo primo delle funzioni esterne è quello di permettere l’esecuzione di codice “ripetitivo” che altrimenti dovresti includere ogni volta che decidi di usarla: e se due funzioni sono simili, ma in una il controllo c’è e nell’altra no?
Delega alle funzioni queste responsabilità e poniti sempre nelle condizioni di scrivere del codice più autosufficiente possibile come se dovesse essere usato da qualcun altro.

biük
:weight_lifting_man: