Why do my variables keep resetting themselves?

Viewed 89

All the variables included in my Stats struct continuously reset themselves after I've called updateStats. Am I not referencing or passing my Stats variable correctly? Not sure what other info to give as this is the first question I've asked, but apparently I need to type more. If it helps this program is supposed to represent a very basic version of the Lunar Lander simulation game.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

struct _stats
{
    double altitude, velocity, mass, fuel, acceleration;
};
typedef struct _stats Stats;

void printStats(Stats a, double thrust)
{
    printf("Thrust: %f  Altitude: %f  Velocity: %f  Mass: %f  Fuel: %f\n", thrust, a.altitude, a.velocity, a.mass, a.fuel);
}
void updateStats(Stats a, double thrust, int time)
{
    a.acceleration += (thrust / a.mass -1.6) * time;
    a.mass -= thrust / 3000.0;
    printf("aaaaa%f", a.mass);
    a.fuel -= thrust / 3000.0;
    a.velocity += a.acceleration * time;
    a.altitude += a.velocity * time;
}
double thrustAllowed(Stats a, double thrust)
{
    if (thrust/1000 <= 45 && thrust <= (3000 * a.fuel))
    {
        return thrust;
    }
    else
        return (3000*a.fuel)/1000;
}

int main(void)
{
    FILE* inputFile = fopen("simulation.csv", "wt");
    if (!inputFile)
    {
        printf("Unable to open file.\n");
        return 1;
    }

    int time = 0;
    double thrust = 0;
    Stats rocket;
    rocket.altitude = 150000;
    rocket.velocity = -325;
    rocket.mass = 9000;
    rocket.fuel = 1800;
    rocket.acceleration = 0;
    while (time < 150)
    {
        time++;
        fprintf(inputFile, "Enter a Thrust in kN: ");
        scanf("%lf", &thrust);
        fprintf(inputFile, "%f", thrust);
        thrust = thrust * 1000;
        if (thrustAllowed(rocket, thrust) == thrust)
        {
            updateStats(rocket, thrust, time);
            fprintf(inputFile, "\nThrust: %.1f  Altitude : %.1f  Velocity : %.1f  Mass : %.1f  Fuel : %.1f\n", thrust, rocket.altitude, rocket.velocity, rocket.mass, rocket.fuel);
            if (rocket.altitude <= 0)
            {
                if (rocket.velocity <= 0 && rocket.velocity >= -1)
                {
                    fprintf(inputFile, "Soft Landing!!!");
                    break;
                }
                else
                {
                    fprintf(inputFile, "You broked it");
                    break;
                }
            }
        }
        else
            fprintf(inputFile, "Thrust must be <= %.1f\n", thrustAllowed(rocket, thrust));
    }
    fclose(inputFile);
}'''
2 Answers

You need to use pointers for variables you want to change:

void updateStats(Stats* a, double thrust, int time) {
    a->acceleration += (thrust / a->mass -1.6) * time;
    a->mass -= thrust / 3000.0;
    printf("aaaaa%f", a->mass);
    a->fuel -= thrust / 3000.0;
    a->velocity += a->acceleration * time;
    a->altitude += a->velocity * time;

}

and then call it like updateStats(&rocket, thrust, time);.

An easy way to fix this program is to return the updated stats:

Stats updateStats(Stats a, double thrust, int time)
//^^^ void return type changed to Stats
{
    a.acceleration += (thrust / a.mass -1.6) * time;
    // [.. abridged ...]
    return stats; // new return statement
}

Then capture the return value in the caller and assign that back to the stats:

    if (thrustAllowed(rocket, thrust) == thrust)
    {
        rocket = updateStats(rocket, thrust, time);
        // ^^^^^ capture returned stats back to rocket

C programmers often eschew this approach because the copying of structures that it implies is not always treated well by compilers. In code that isn't performance critical it can be nice; and paves the way to doing functional programming (avoiding assignments entirely), treating structures as immutable, the advantage there being that if that approach blends well with the problem, it results in a solution that is easier to reason about.

For instance, consider this function for calculating Fibonacci numbers:

struct fib { int a, int b };

struct fib fib(struct fib in, int n)
{
   if (n == 0) {
     return old;
  } else {
     struct fib new = { old.a + old.b, old.a };
     return fib(new, n - 1); // tail call: susceptible to optimization
  }
}

Example call;

{
  struct fib init = { 1, 1 };
  struct fib calc = fib(init, 5);
  // ...
}

No pointers are used anywhere, and there are no assignment statements, only variable initializations, and parameter passing and returning.

We wouldn't pass packets between an ethernet driver and protocol stack this way, but it's good to have in your toolbox.

Related