Re: [C] gcc non compila

Messaggioda UeCiccio » 26/10/2019, 23:50

vict85 ha scritto:Il punto è che quel codice sembra vecchio e ritengo che sia colpa del libro. Le variabili possono ormai essere definite in qualsiasi punto del codice e ci sono reali vantaggi a definirle solo quanto servono. Inoltre è utile sempre inizializzare le variabili a qualche valore quando le definisci. Questi due piccoli accorgimenti rendono il codice più leggibile, più facile da mantenere ed eliminano il rischio di alcuni errori insidiosi.

Inoltre, a mio avviso, la funzione pow non andrebbe insegnata. Infatti, non ha alcun senso usare pow per calcolare potenze basse, calcolabili con uno o due prodotti. E spesso viene usata all'interno di cicli, anche se sarebbe possibile calcolare la nuova potenza a partire dalla vecchia con una singola moltiplicazione.


Se ho capito bene dovrei scrivere il programma in questa maniera:
Codice:
#include <stdio.h>
#include <math.h>

#define G 9.81
// Questo programma calcola i valori dell'energia cinetica K = 1/2mv^2 e dell'energia potenziale U = mhg in funzione del tempo di un punto materiale di massa m soggetto a una gravità. Le grandezze sono quelle del sistema metrico internazionale. */
int main(){
   
    double m = 0;                       // massa del punto materiale
    double v0 = 0;                      // velocità iniziale del punto materiale
    double h0 = 0;                      // quota iniziale
    double t = 0;                       // tempo
    printf (" Inserisci la massa del punto materiale espressa in kg: ");
    scanf ("%lf", &m);
    printf ("\n Inserisci la velocità iniziale espressa in m/s (verso positivo verso l'alto) : ");
    scanf ("%lf", &v0);
    printf ("\n Inserisci la quota iniziale in m: ");
    scanf ("%lf", &h0);
    printf ("\n Inserisci l'istante di tempo in s nel quale vuoi conoscere i valori dell'energia cinetica e dell'energia potenziale: ");
    scanf ("%lf", &t);
   
    //calcola v e h
    double v = 0;                       // velocità in funzione del tempo
    double h = 0;                       // quota in funzione del tempo
    v = v0 - G*t;
    h = h0 + v0*t - G/2. * t*t;
   
    /* calcola i valori di K e U */
    double U = 0, K = 0;                    // energia potenziale e cinetica
    K = m/2. * v*v;
    U = m*G*h;
    printf ("\n L'energia cinetica all'istante t = %f s è %f J", t, K);
    printf ("\n L'energia potenziale all'istante t = %f s è %f J \n", t, U);
UeCiccio
Starting Member
Starting Member
 
Messaggio: 4 di 12
Iscritto il: 23/10/2019, 17:47

Re: [C] gcc non compila

Messaggioda claudio86 » 27/10/2019, 08:58

UeCiccio ha scritto:Se ho capito bene dovrei scrivere il programma in questa maniera:

Non proprio. Stai inizializzando le variabili a zero, per poi sovrascriverle immediatamente con il valore che vuoi assegnare loro.

Codice:
//calcola v e h
double v = 0;                       // velocità in funzione del tempo
double h = 0;                       // quota in funzione del tempo
v = v0 - G*t;
h = h0 + v0*t - G/2. * t*t;


Invece dovresti direttamente inizializzarle con quel valore.

Codice:
//calcola v e h
double v = v0 - G*t;                      // velocità in funzione del tempo
double h = h0 + v0*t - G/2. * t*t;        // quota in funzione del tempo


Fanno eccezione le varibili che chiedi all'utente. Quelle potresti forse lasciarle non inizializzate.
"This theorem, as many others, is proven by writing zero in a creative way…"
claudio86
Senior Member
Senior Member
 
Messaggio: 533 di 1130
Iscritto il: 09/01/2011, 15:12

Re: [C] gcc non compila

Messaggioda vict85 » 27/10/2019, 13:13

UeCiccio ha scritto:Se ho capito bene dovrei scrivere il programma in questa maniera:


Più o meno. Intendevo come dice Claudio. Risulta comunque importante anche controllare ciò che ricevi come input, anche se non è essenziale con i programmi giocattolo che fai ora. Ho messo la lettura delle variabili in funzioni a parte e controllato che la massa sia non negativa:
Codice:
#include <stdio.h>
#include <math.h>

#define G ( 9.81 )

double leggi_massa( );
double leggi_velocita_iniziale( );
double leggi_quota_iniziale( );
double leggi_tempo( );

void clear_stdin( );

/*
 * Questo programma calcola i valori dell'energia cinetica K = 1/2mv^2 e dell'energia potenziale
 * U = mhg in funzione del tempo di un punto materiale di massa m soggetto a una gravita'. Le
 * grandezze sono quelle del sistema metrico internazionale.
 */
int
main( )
{
    // massa del punto materiale
    double const m = leggi_massa( );

    printf( "\n" );

    // velocita' iniziale del punto materiale
    double const v0 = leggi_velocita_iniziale( );

    printf( "\n" );

    // quota iniziale
    double const h0 = leggi_quota_iniziale( );

    printf( "\n" );

    // tempo
    double const t = leggi_tempo( );

    printf( "\n" );

    // calcola v e h
    // velocità in funzione del tempo
    double const v = v0 - G * t;
    // quota in funzione del tempo
    double const h = h0 + t * ( v0 - 0.5 * G * t );

    // calcola i valori di K e U
    // energia cinetica
    double const K = 0.5 * m * v * v;
    // energia potenziale
    double const U = m * G * h;
    printf( "L'energia cinetica all'istante t = %g s e' %g J\n", t, K );
    printf( "L'energia potenziale all'istante t = %g s e' %g J \n", t, U );
}

double
leggi_massa( )
{
    double m;
    printf( "Inserisci la massa del punto materiale espressa in kg: " );
    if ( scanf( "%lf", &m ) == 0 || m < 0 )
    {
        clear_stdin( );
        printf( "Errore nella lettura della massa. Riprovare.\n" );
        return leggi_massa( );
    }
    return m;
}

double
leggi_velocita_iniziale( )
{
    double v;
    printf( "Inserisci la velocita' iniziale espressa in m/s (verso positivo verso l'alto) : " );
    if ( scanf( "%lf", &v ) == 0 )
    {
        clear_stdin( );
        printf( "Errore nella lettura della velocita' iniziale. Riprovare.\n" );
        return leggi_velocita_iniziale( );
    }
    return v;
}

double
leggi_quota_iniziale( )
{
    double h;
    printf( "Inserisci la quota iniziale in m: " );
    if ( scanf( "%lf", &h ) == 0 )
    {
        clear_stdin( );
        printf( "Errore nella lettura della quota iniziale. Riprovare.\n" );
        return leggi_quota_iniziale( );
    }
    return h;
}

double
leggi_tempo( )
{
    double t;
    printf(
        "Inserisci l'istante di tempo in s nel quale vuoi conoscere i valori dell'energia "
        "cinetica e dell'energia potenziale: " );
    if ( scanf( "%lf", &t ) == 0 )
    {
        clear_stdin( );
        printf( "Errore nella lettura del tempo. Riprovare.\n" );
        return leggi_tempo( );
    }
    return t;
}

void
clear_stdin( )
{
    int c;
    while ( ( c = getchar( ) ) != '\n' && c != EOF )
    {
    }
}


La funzione clear_stdin serve a gestire il caso in cui inserisci qualcosa che scanf non sa tradurre in double e rimane bloccato. Alcuni libri ti consigliano fflush(stdin) per farlo ma non è un modo portabile per farlo. Lo standard dice infatti che è un undefined behaviour (ovvero il compilatore può generare il codice che preferisce, dall'eliminare la chiamata alla funzione a farti la stessa cosa che ho scritto in clear_stdin). Quindi non usare mai fflush con stdin.

Un piccolo commento a parte: i caratteri accentati non sono visualizzati bene nella console. Quindi non scriverli nei printf.
vict85
Moderatore
Moderatore
 
Messaggio: 9922 di 19253
Iscritto il: 16/01/2008, 00:13
Località: Berlin

Re: [C] gcc non compila

Messaggioda UeCiccio » 27/10/2019, 17:59

Essenzialmente qual è la differenza tra lo scrivere #define G (9.81) e double G = 9.81?
UeCiccio
Starting Member
Starting Member
 
Messaggio: 5 di 12
Iscritto il: 23/10/2019, 17:47

Re: [C] gcc non compila

Messaggioda vict85 » 27/10/2019, 19:14

UeCiccio ha scritto:Essenzialmente qual è la differenza tra lo scrivere #define G (9.81) e double G = 9.81?


Il secondo definisce una variabile di nome G e gli assegna il valore 9.81 . Se la variabile è costante e il compilatore capisce che può eliminarla, lo fa. Ovvero, non è detto che nell'esecuzione del codice a G sia assegnata una qualche posizione in memoria.
Per quanto riguarda #define è un po' più difficile da spiegare perché dovresti comprendere come viene compilato il codice. In pratica, prima che il compilatore inizi a interpretare il codice, fa alcune operazioni preliminari. Durante queste operazioni, esegue le istruzioni del preprocessore (oltre a eliminari spazi inutili e commenti).
Vediamo cosa fanno le istruzioni principali:
  • #include "filename" copia l'intero contenuto di filename all'interno del file che contiene l'istruzione.
  • #define nome valore definisce una regola di sostituzione, ovvero dice al compilatore di sostituire ogni ripetizione di nome con valore
  • #if cond1 codice1 #elseif cond2 codice2 #else codice3 #endif serve a selezionare il codice giusto a seconda di alcune condizioni. Le altre opzioni sono eliminate.
  • #pragma serve a dare istruzioni al compilatore. Le istruzioni possibili dipendono dal compilatore anche se alcune come once sono disponibili su quasi tutti i sistemi.
  • #error blocca la compilazione con un errore.

https://en.wikipedia.org/wiki/C_preprocessor
vict85
Moderatore
Moderatore
 
Messaggio: 9923 di 19253
Iscritto il: 16/01/2008, 00:13
Località: Berlin

Re: [C] gcc non compila

Messaggioda Raptorista » 28/10/2019, 09:46

In aggiunta a quanto detto da vict, nel caso specifico che hai riportato, la differenza principale è che una variabile definita come double G = 9.81 [senza const] può cambiare valore nel corso del programma, mentre ciò che è definito via #define è immutabile.

Sebbene l'uso di #define sia una pratica molto diffusa, soprattutto in C, in generale mi sento di consigliarti di dichiarare variabili vere e di dichiararle costanti, cioè come const double G = 9.81, anziché usare #define. La differenza non sarà apprezzabile nel caso di piccoli programmi come questo, ma è una pratica migliore e quindi tanto vale farci l'abitudine.
Una spiegazione dettagliata si trova, ad esempio, nel libro di Meyers Effective C++, capitolo 1, sezione 2.
Un matematico ha scritto:... come mia nonna che vuole da anni il sistema per vincere al lotto e crede che io, in quanto matematico, sia fallito perché non glielo trovo


Immagine
Avatar utente
Raptorista
Moderatore
Moderatore
 
Messaggio: 5351 di 9616
Iscritto il: 28/09/2008, 19:58

Re: [C] gcc non compila

Messaggioda vict85 » 28/10/2019, 10:58

Raptorista ha scritto:In aggiunta a quanto detto da vict, nel caso specifico che hai riportato, la differenza principale è che una variabile definita come double G = 9.81 [senza const] può cambiare valore nel corso del programma, mentre ciò che è definito via #define è immutabile.

Sebbene l'uso di #define sia una pratica molto diffusa, soprattutto in C, in generale mi sento di consigliarti di dichiarare variabili vere e di dichiararle costanti, cioè come const double G = 9.81, anziché usare #define. La differenza non sarà apprezzabile nel caso di piccoli programmi come questo, ma è una pratica migliore e quindi tanto vale farci l'abitudine.
Una spiegazione dettagliata si trova, ad esempio, nel libro di Meyers Effective C++, capitolo 1, sezione 2.


Non sono sicuro, ma penso che esista una qualche differenza nel modo in cui il C++ e il C gestiscono le variabili const. Insomma, sicuramente il C++ ha voluto eliminare sin dall'inizio la necessità dei define1, ma forse alcune cose non sono valide in C. È possibile però che questo non sia più vero nel 2019: ho imparato il C++ e il C nel 2003; molte cose sono cambiate da allora.

Che io sappia, C e C++ interpreteranno il seguente codice in modo diverso:
Codice:
int const A = 3;
int b[A];

e in C potrebbe non compilare.

Note

  1. Per esempio ora ci sono constexpr e template.
vict85
Moderatore
Moderatore
 
Messaggio: 9924 di 19253
Iscritto il: 16/01/2008, 00:13
Località: Berlin

Re: [C] gcc non compila

Messaggioda apatriarca » 28/10/2019, 16:12

Da questa pagina: https://en.cppreference.com/w/c/language/const
Notes

C adopted the const qualifier from C++, but unlike in C++, expressions of const-qualified type in C are not constant expressions; they may not be used as case labels or to initialize static and thread storage duration objects, enumerators, or bit field sizes. When they are used as array sizes, the resulting arrays are VLAs.


In altre parole, in C ci sono maggiori limitazioni nei posti in cui una variabile dichiarata costante possa essere utilizzata. In queste circostanze l'uso del preprocessore può essere l'unica alternativa.
apatriarca
Moderatore
Moderatore
 
Messaggio: 5304 di 10436
Iscritto il: 08/12/2008, 20:37
Località: Madrid

Precedente

Torna a Informatica

Chi c’è in linea

Visitano il forum: Nessuno e 1 ospite