【问题标题】:Why do my variables keep resetting themselves?为什么我的变量不断重置自己?
【发布时间】:2020-05-05 20:25:35
【问题描述】:

在我调用 updateStats 后,我的 Stats 结构中包含的所有变量都会不断地自行重置。我没有正确引用或传递我的 Stats 变量吗?不确定要提供哪些其他信息,因为这是我提出的第一个问题,但显然我需要输入更多信息。如果它有帮助,这个程序应该代表了月球着陆器模拟游戏的一个非常基本的版本。

#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);
}'''

【问题讨论】:

  • 您是按值传递,而不是按引用传递。修改你的 updateStats 以获取一个指针,或者让它直接修改全局变量而不是使用传入的参数。
  • updatestats 正在处理您作为 局部变量的副本传递的内容,因此任何更改都不会反映在原始变量中。
  • @MichaelDorgan 说的是原因,尽管我建议不要使用全局变量。另一种方法是使updateStats() 类型为Stats 并返回修改后的a 变量。欢迎来到 SO!
  • (同意,全局变量是一种不好的方法......)
  • OT:关于:printf("Unable to open file.\n"); 错误消息应该输出到stderr,而不是stdout。当错误来自 C 库函数(如 fopen)时,还应输出系统认为发生错误的文本原因。建议调用perror( "Unable to open file.");,因为这将正确执行这两个操作

标签: c


【解决方案1】:

您需要对要更改的变量使用指针:

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;

}

然后像 updateStats(&amp;rocket, thrust, time); 一样调用它。

【讨论】:

    【解决方案2】:

    修复此程序的一种简单方法是返回更新后的统计信息:

    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
    }
    

    然后在调用者中捕获返回值并将其分配回统计信息:

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

    C 程序员经常避开这种方法,因为它所暗示的结构复制并不总是被编译器很好地处理。在对性能不重要的代码中,它可能很好;并为进行函数式编程(完全避免赋值)铺平了道路,将结构视为不可变的,其优势在于,如果该方法与问题很好地融合,它会产生更容易推理的解决方案。

    例如,考虑这个计算斐波那契数的函数:

    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
      }
    }
    

    示例调用;

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

    在任何地方都没有使用指针,也没有赋值语句,只有变量初始化,参数传递和返回。

    我们不会以这种方式在以太网驱动程序和协议栈之间传递数据包,但最好在您的工具箱中使用。

    【讨论】:

    • 你说得对,我的 C 程序员看到这个时就会关门,因为它可以在以后隐藏巨大的 memcpy() 乐趣。不过,您解决了这个问题,您的观点非常有效。
    猜你喜欢
    • 1970-01-01
    • 2013-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-18
    • 1970-01-01
    • 2015-03-08
    相关资源
    最近更新 更多