Hi,
I'm pretty new to C++ but have a lot of experience in Python. In python its pretty straight forward to make functions that both take arrays/vectors as input and return arrays/vectors.

My thought here is to make a function to calculate the gravitational force between to bodies with mass m1 and m2, at position r1 and r2 respectively. r1 and r2 should be arrays (mathematical vectors) and the resulting force should also be an array (mathematical vector).

using namespace std;
#include <iostream>

double *grav_force (double m1, double m2, double *r1, double *r2){
    // Calculate distance between bodies:
    double r12; // scalar distance
    double r_12 [2]; // distance vector
    for (int i=0; i<2 ; i++){
        r12 += (r2[i] - r1[i])*(r2[i] - r1[i]);
        r_12[i] = r2[i] - r1[i];
    }
    r12 = sqrt(r12);
    // Gravitational factor:
    double G = m1*m2/(r12*r12*r12); // Grav.const. = 1
    double f_x = G*r_12[0]; // r_12[0] is the x-coordinate of the distance vector
    double f_y = G*r_12[1];
    double f_g [2];
    f_g[0] = f_x;
    f_g[1] = f_y;
    return f_g;
}


int main(int argc, char* argv[])
{
    double r1 [2] = {1.0, 2.0};
    double r2 [2] = {2.0, 4.0};
    double m1 = 1.0;
    double m2 = 1.0;
    double *asd = grav_force(m1, m2, r1, r2);
    cout << "*asd: " << *asd << endl;

    return 0;
}

Output:

*asd: 0.0894427

As you can see only the first component of the force vector is returned. How to solve this?

Edited 5 Years Ago by brynjar: typo

Thanks! (I'm confused by the '*', but hopefully I'll get it sometime.)

*asd dereferences asd. Gives you the content of the address asd points to.
*asd == asd[0]
*(asd + 1) == asd[1]
...

Hi,

You can not return a local array. returning a local array will create invalid memory access. Your double f_g [2]; is a local array and as soon as you are getting out of the function, your address is invalid.

So

cout << "asd: " << asd[0] << ", " << asd[1] << endl; //This will access the invalid memory and potential crash will happened

* is the notation of pointer.
A pointer variable is a variable which holds a address of a variable.

int x = 10; //x is a integer vairable which holds 10
int *i = &x; // i is a pointer type varirable which holds the address of x.

cout << i; //will print the address of x
cout << *i // will print 10. we are access x indirectly through i.

*i = 5; //This will set x value as 5.
cout << x; //this will print 5 as we have changed its value.

Now about Array:
You can think of an array as a pointer which points to a consecutive set of bytes.

int array[10];// this allocates 10 integers and array name binds to the first integer address.

Now, you dont want to return an array. actually you dont need to.

void function(int result[2]){
   result[0] = 5; // this will change the original array as result is bind to the address of that array.
   result[1] = 6;
}

void main(void)
{
    int arr[2];

    function(arr); //passes the address of arr

    cout << arr[0]; //this will print 5
}

Before you do any C++ programming: I would suggest to read about pointer and reference.

Vector is different than array and it is value semantics. if you want to pass reference of vector (you should always pass by reference), then you should use &

passing a vector by value will create a separate copy of the vector.

Read about:
1) Scope of variable
2) Pointer/Reference

Edited 5 Years Ago by alwaysLearning0: n/a

Ahhh.. right.. still i sometime write my turbo C days coding style which I did 10 years ago!! sometime childhood habits doesn't go away. :)

If you would like to return a newly generated "array" from a function, you can create a pointer to that type and dynamically allocate space for the array, within the grav_force function, set its values, then return its address.

Ex:

double* foo(double, double, int&);

int main(int argc, char* argv[])
{
double* arrPtr(nullptr);
double numOne = 3.14, numTwo = 6.28;
int size = 0;                         // array size variable 

arrPtr = foo(numOne, numTwo, size);   // returns pointer to allocated space on the heap

// Use arrPtr like you would an array but don't forget to free the memory afterwards
delete [] arrPtr;
arrPtr = nullptr;
return 0;
}

// Function accepts two double values to assign to allocated array
// and sets the array size with a reference variable.
double* foo(double firNum, double secNum, int& size)
{
   size = 2;
   double* myNewArrPtr = new double[size];      // allocate space for 2 double values
   myNewArrPtr[0] = firNum;
   myNewArrPtr[1] = secNum;
   // Use myNewArrPtr like you would an array, with size telling you how much 
   // elements you have within.
   // Return pointer to allocated space
   return myNewArrPtr;
}

The example may be a bit silly, but you can return a pointer to a block of memory if you allocate it within the function itself.

In C++, we don't tend to use C style arrays, it is more common and easier to use standard classes that can hold arrays. In this case, you can use either std::vector<double> or, if you have a reasonably recent compiler, std::array<double,2>, as so:

#include <iostream>
#include <array>

using namespace std;

array<double,2> grav_force (double m1, double m2, const array<double,2>& r1, const array<double,2>& r2){
    // Calculate distance between bodies:
    double r12; // scalar distance
    array<double,2> r_12; // distance vector
    for (int i=0; i<2 ; i++){
        r12 += (r2[i] - r1[i])*(r2[i] - r1[i]);
        r_12[i] = r2[i] - r1[i];
    }
    r12 = sqrt(r12);
    // Gravitational factor:
    double G = m1*m2/(r12*r12*r12); // Grav.const. = 1
    return array<double,2>{ G*r_12[0], G*r_12[1] };
}

int main(int argc, char* argv[])
{
    array<double,2> r1 = {1.0, 2.0};
    array<double,2> r2 = {2.0, 4.0};
    double m1 = 1.0;
    double m2 = 1.0;
    array<double,2> asd = grav_force(m1, m2, r1, r2);
    cout << "asd: " << asd[0] << ", " << asd[1] << endl;

    return 0;
}

Or, better yet, you can use std::valarray which has most vector operations you would like:

#include <iostream>
#include <valarray>

using namespace std;

valarray<double> grav_force (double m1, double m2, const valarray<double>& r1, const valarray<double>& r2){
    // Calculate distance between bodies:
    valarray<double> r_12 = r2 - r1; // distance vector
    double r12 = sqrt((r_12 * r_12).sum()); // scalar distance
    // Gravitational factor:
    double G = m1*m2/(r12*r12*r12); // Grav.const. = 1
    return G * r_12;
}

int main(int argc, char* argv[])
{
    valarray<double> r1(2); r1[0] = 1.0; r1[1] = 2.0;
    valarray<double> r2(2); r2[0] = 2.0; r2[1] = 4.0;
    double m1 = 1.0;
    double m2 = 1.0;
    valarray<double> asd = grav_force(m1, m2, r1, r2);
    cout << "asd: " << asd[0] << ", " << asd[1] << endl;

    return 0;
}

Edited 5 Years Ago by mike_2000_17: n/a

If you would like to return a newly generated "array" from a function, you can create a pointer to that type and dynamically allocate space for the array, within the grav_force function, set its values, then return its address. ...

In general, it is bad programming practice to allocate memory within a function which will be returned to the caller because it then becomes the callers responsibility to free that memory. This is appropriate at times when you are creating some sort of resource or handle to it but not so much when simply performing a calculation.

Alternatively, I would say that passing in the memory where the results are to be stored by the function called is safer. For example, with slight modifications to your original function:

void grav_force (double m1, double m2, double *r1, double *r2, double *rOut){
  // Calculate distance between bodies:
  double r12; // scalar distance
  double r_12 [2]; // distance vector
  for (int i=0; i<2 ; i++){
    r12 += (r2[i] - r1[i])*(r2[i] - r1[i]);
    r_12[i] = r2[i] - r1[i];
  }
  r12 = sqrt(r12);
  // Gravitational factor:
  double G = m1*m2/(r12*r12*r12); // Grav.const. = 1
  double f_x = G*r_12[0]; // r_12[0] is the x-coordinate of the distance vector
  double f_y = G*r_12[1];
  rOut[0] = f_x;
  rOut[1] = f_y;
  return f_g;
}

You now store the result in the rOut array provided by the caller of the function. Your calling semantics change slightly:

int main(int argc, char* argv[])
{
  double r1 [2] = {1.0, 2.0};
  double r2 [2] = {2.0, 4.0};
  double m1 = 1.0;
  double m2 = 1.0;
  double asd[2];
  grav_force(m1, m2, r1, r2, asd);
  cout << "asd[0]: " << asd[0] << ", asd[1]: " << asd[1]<< endl;
 
  return 0;
}

All that being said, using the array standard class as suggested by others in this thread is a better solution.
-lou

This article has been dead for over six months. Start a new discussion instead.