0

Long time Reader, First time Asker.

So I'm working on a coding project of which the long term goal is to make a solar system simulator. The idea is that that it whips up a randomized solar system with a few rules like 'at formation the first planet after the frostline has to be the largest gas giant' etc, and calculates the orbits to check for stability.

Obviously it's not done yet, I'm having some trouble with using the arrays in the subroutines. I know that you can't directly take arrays in and out of functions, but you can take pointers to said arrays in and out of functions if you do it right.

I apparently have not done it right below. I've tried to comment and make the code as readable as possible, here it is.

#include <cstdlib>
#include <fstream>
#include <iostream>
#include <tuple>
#include <vector>
#include <stdio.h>
#include <math.h>
#include <complex>
#include <stdint.h>
#include <time.h>
#include <string.h>
#include <algorithm>

//#include "mpi.h"

using namespace std;

double MyRandom(){

//////////////////////////
//Random Number Generator
//Returns number between 0-99
//////////////////////////

    double y = 0;
    unsigned seed = time(0);
    srand(seed);
    uint64_t x = rand();

    x ^= x << 13;
    x ^= x >> 7;
    x ^= x << 17;

    x = (1070739 * x) % 2199023255530;
    y = x / 21990232555.31 ;
    return y;
}
////////////////////////

///////////////////////
tuple< char& , float& , float& , float& , int& > Star(){

////////////////////////////
//Star will generate a Star
//Randomly or User Selected
//Class, Luminosity, Probability, Radius, Mass, Temperature
//Stars always take up 99% of the mass of the system.
///////////////////////////

char Class;
string Choice;
float L, R, M;
int T;
tuple< char& , float& , float& , float& , int& > star( Class = 'i', L = 1 , R = 1 , M = 1 , T = 3000) ;
cout << "Select Star Class (OBAFGKM) or Select R for Random: ";
cin >> Choice;
if ( Choice == "R" ) {
    double y;
    y = MyRandom();
    if (y <= 0.003) Class = 'O';
    if ((y > 0.003) && (y <= 0.133)) Class = 'B';
    if ((y > 0.133) && (y <= 0.733)) Class = 'A';
    if ((y > 0.733) && (y <= 3.733)) Class = 'F';
    if ((y > 3.733) && (y <= 11.333)) Class = 'G';
    if ((y > 11.333) && (y <= 23.433)) Class = 'K';
    else Class = 'M';
    }
    if (Class == 'O') {
        L = 30000;
        R = 0.0307;
        M = 16;
        T = 30000;
    }
    if (Class == 'B') {
        L = 15000;
        R = 0.0195;
        M = 9;
        T = 20000;
    }
    if (Class == 'A') {
        L = 15;
        R = 0.00744;
        M = 1.7;
        T = 8700;
    }
    if (Class == 'F') {
        L = 3.25;
        R = 0.00488;
        M = 1.2;
        T = 6750;
    }
    if (Class == 'G') {
        L = 1;
        R = 0.00465;
        M = 1;
        T = 5700;
    }
    if (Class == 'K') {
        L = 0.34;
        R = 0.00356;
        M = 0.62;
        T = 4450;
    }
    if (Class == 'M') {
        L = 0.08;
        R = 0.00326;
        M = 0.26;
        T = 3000;
    }

    return star;
}
////////////

////////////
float* Planet( float &L, float &R, float &M, int &T, int &n){

///////////////////////////
//Planet generates the Planets
//Random 1 - 10, Random distribution 0.06 - 6 JAU unless specified by User
//Frost line Calculated, First Planet after Frost line is the Jupiter
//The Jupiter will have the most mass of all Jovian worlds
//Otherwise divided into Jovian and Terrestrial Worlds, Random Masses within groups
//Also calculates if a planet is in the Habitable Zone
////////////////////////////

    float frostline, innerCHZ, outerCHZ;
    float a = 0.06; // a - albedo
    float m = M / 100; //Mass of the Jupiter always 1/100th mass of the Star.
    float sys[n];
    float* system[n][5] = {{0}};

    for (int i = 0 ; i < n ; i++){
        sys[i] = MyRandom()/10 * 3; //Distances in terms of Sol AU
    }
    sort(sys, sys + n );
    for (int i = 0 ; i < n ; i++){
        system[i][0] = &sys[i];
        system[i][1] = 0; //system[i][0] is x, system[i][1] is y
    }

    frostline = (0.6 * T / 150) * (0.6 * T/150) * R / sqrt(1 - a);
    innerCHZ = sqrt(L / 1.1);
    outerCHZ = sqrt(L / 0.53);

    for (int i = 0 ; i < n ; i++){
        if (system[i][0] <= &frostline) {
            float tmass = m * 0.0003 * MyRandom();
            system[i][2] = &tmass ; //system[i][2] is mass, [3] is marker for the Jupter
            system[i][3] = 0 ;
        }

        if ((system[i][0] >= &frostline) && (system[i-1][0] < &frostline)){
            system[i][2] = &m ;
            float J = 1;
            system[i][3] = &J ;
        }

        if ((system[i][0] >= &frostline) && (system[i-1][0] >= &frostline)) {
            float jmass = m * 0.01 * MyRandom();
            system[i][2] = &jmass ;
            system[i][3] = 0 ;
        }

        if ((system[i][0] >= &innerCHZ) && (system[i][0] <= &outerCHZ)){
            float H = 1;
            system[i][4] = &H;
        }
        else system[i][4] = 0; //[4] is habitable marker

    }

    return system[n][5];
}
////////////

////////////
float* Time( float *system , int n){

///////////////////////////
//Time advances the solar system.
//Plots the Orbits
//Uses MPI to spread it's calculations.
///////////////////////////

    return system;
}
////////////

////////////
void FinalCheck( float system){

///////////////////////////
//Final Checks
//Reports if a Planet spent the whole Time in the Habitable Zone
///////////////////////////

/*for (int i = 0 ; i < row ; i++){
    if (system[i][4] == 1.0) {
        cout << "Planet " << i << " in this system is Habitable." ;
        }
    // The Habitable stat only means liquid water can exist on the surface
    // Add pi if planet enters habitable zone, minus 1 if it leaves.
    // If planet was habitable but left, assuming all life was destroyed
    }
*/
}
////////////

int main(){

char Class;
int T;
float L, R, M;

tuple< char , float , float , float , int > star( Class , L , R , M , T );
star = Star();

int n = MyRandom()/10 + 1;

float * system[n][5] = {{0}};
float system1[n][5] = {{0}};
system[n][5] = Planet( L , R , M, T, n);

for (int i = 0 ; i < 100 ; i++) {
 system1[n][5] = Time( *system, n );
 system[n][5] = &system1[n][5];
}
FinalCheck( *system[n][5]);

///////////////////////////
//Report cleans everything up and gives the results
//Shows the plot, lists the Planets
//Reports the Positions and Masses of all Planets
//Reports which was the Jupiter and which if any were Habitable
//////////////////////////
return 0;
}

The problem is when I run a compiler over this line 227 gets flagged -

  system1[n][5] = Time( *system, n );

With the following error:

  error: cannot convert 'float**' to 'float*' for argument '1' to 'float* Time(float*, int)

I get that this means that the compiler things I'm trying to equate a pointer-to-a-pointer with a pointer, but I'm not sure how it arrived at that conclusion or how to fix it. I'd appreciate help with this, especially the second part. I also would love to hear anything about passing arrays through subroutines as apparently I'm not doing it right, or at least not well.

Update 1 : - Got the short-term fix in and the compiler makes it through but gives a segmentation fault (core dumped) error when I try to run it. Looks like I have some reading and updates to do though with the namespace, the pointers, and possibly changing the arrays into vectors instead. Feels like if I concentrate on those first it might fix the segmentation error.

Jason
  • 11
  • 3
  • Not your compiler error but http://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope – chris Apr 10 '20 at 17:54
  • 1
    `float sys[n];` -- This is not valid C++. Arrays in C++ must have their sizes denoted by a compile-time constant, not a runtime value such as `n`. You should use `std::vector sys(n);` instead. Same issue here: `float* system[n][5] = {{0}};` – PaulMcKenzie Apr 10 '20 at 17:56
  • `system` should be a 1-D array of structs. – stark Apr 10 '20 at 18:00

2 Answers2

1

Your variable system is declared as

float * system[n][5] = {{0}};

which is a pointer to a 2D array (which will decay to float*** when passed to a function).

Your Time function is declared as

float* Time( float *system , int n);

where the 1st argument needs to be a float*.

That means this call

system1[n][5] = Time( *system, n );

should actually be something like

system1[n][5] = Time( **system, n );

That being said, there are a number of issues in your code.

To start off, don't do using namespace std;.

Also, this line float sys[n]; is not allowed. You can't have variable length arrays in c++.

cigien
  • 57,834
  • 11
  • 73
  • 112
  • Didn't know about the decay thing, so it might explain that actually. I tried the suggestion you had with line 227 and it changed the error to ```error: cannot convert 'float*' to 'float' in assignment``` Otherwise no change. Don't know what you mean by not using namespace std either. And dynamically sized arrays in c++ not allowed? I must not understand what you actually mean by that. – Jason Apr 10 '20 at 18:14
  • If you're not sure how pointers work, you shouldn't be using so many of them. Try std::vector instead, it's much easier to use. Also, see [this](https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice), and [this](https://stackoverflow.com/questions/15013077/arrayn-vs-array10-initializing-array-with-variable-vs-real-number) – cigien Apr 10 '20 at 18:19
0
float* system[n][5]

system here is a 2D array of float*s, not floats.

So, in other words, system decays to float***, *system decays to float**, **system decays to float*, and ***system decays to float.

So, the compiler is correct. You're passing what decays to a float** to Time() which expects a float*.

You're going to have to reconfigure your code to pass the right thing, whatever that is.


Side note: please be advised that the way you're creating arrays isn't valid C++ and may cause issues later.