0

I have a Fortran code in which I need to sort two arrays that are related to each other. I would like to do this in a C++ function in order to leverage the built-in sort algorithm in the STL. Because Fortran is pass-by-reference, all arguments to the C++ function must be pointers. The following function esort sorts the arrays correctly, but does not return the correct values. I believe this is because the pointers are passed by value, so the update at the end of the function has no effect. How should I change my code to achieve the desired effect?

#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;

void esort(double* lambda, double* vecs, int* n) {

  double* res_lam = new double[*n];
  double* res_vec = new double[*n * *n];
  vector<pair<double, int> > order(*n);

  for (int i=0; i<*n; i++) {
    order[i] = make_pair(lambda[i], i);
  }

  sort(order.rbegin(), order.rend());

  for (int i=0; i<*n; i++) {
    pair<double, int> p = order.at(i);
    res_lam[i] = p.first;
    for (int j=0; j<*n; j++) {
      res_vec[*n*i + j] = vecs[*n*p.second + j];
    }
  }

  lambda = res_lam;
  vecs = res_vec;

  delete [] res_lam;
  delete [] res_vec;

  return;
}

int main() {

  double lambda[] = {0.5, 2.0, 1.0};
  double vecs[] = {0.5, 0.5, 0.5, 2.0, 2.0, 2.0, 1.0, 1.0, 1.0};
  int n = 3;

  esort(lambda, vecs, &n);

  cout << "lambda" << endl;
  for (int i=0; i<n; i++) {
    cout << lambda[i] << " ";
  }
  cout << endl;
  cout << "vecs" << endl;
  for (int i=0; i<n; i++) {
    for (int j=0; j<n; j++) {
      cout << vecs[j*n + i] << " ";
    }
    cout << endl;
  }

  return 0;
}

Output:

lambda
0.5 2 1 
vecs
0.5 2 1 
0.5 2 1 
0.5 2 1

Desired Output:

lambda
0.5 1 2 
vecs
0.5 1 2 
0.5 1 2 
0.5 1 2

EDIT: The ith element of lambda corresponds to the ith column of vecs (in Fortran's column-major order). In order to avoid hassling with multi-dimensional arrays in C++, I am simply representing vecs as a 1D array within esort. The point of esort is to sort lambda and then reorder vecs such that the ith element of lambda still corresponds to the ith column of vecs.

EDIT 2: By placing cout statements inside esort, I have confirmed that res_lam and res_vec have the values that I want them to have at the end of the routine. My issue is getting those values returned to the calling program.

8
  • "Because Fortran is pass-by-reference, all arguments to the C++ function must be pointers" Wait what Commented Jun 24, 2015 at 3:31
  • Um you seem to be confused about pointers. If you really want to make use of C++'s features, this is really about the worst way to go about it.. Commented Jun 24, 2015 at 3:32
  • @LightnessRacesinOrbit, I'm fairly new to C++, so I'm definitely open to suggestions on better ways of doing things. Commented Jun 24, 2015 at 3:36
  • 1
    You say the arrays are related to each other but, other than through code that (by your own admission) does not accurately represent that relationship, you don't tell us how that is. Please specify your requirements/goals in words. Commented Jun 24, 2015 at 3:43
  • 1
    Are you trying to pass an array by reference, or a pointer by reference? Because the title asks the former, while the code suggests the latter. Commented Jun 24, 2015 at 5:31

3 Answers 3

1

It is true that C++ passes all of its arguments by value, including pointers, meaning that assigning to lambda and vecs has no effect on the caller: those variables only point to the data. You need to copy your results into that pointed-to memory, as shown below by using copy from <algorithm>. Also rbegin and rend are reverse iterators, which causes sort to sort backward from what you wanted; I changed it to begin and end. I would further suggest using vector for your temporary res_lam and res_vec arrays.

#include<iostream>
#include<vector>
#include<algorithm>
#include<functional>

using namespace std;

void esort(double* lambda, double* vecs, int* n) {

  vector<double> res_lam(*n);
  vector<double> res_vec(*n * *n);
  vector<pair<double, int> > order(*n);

  for (int i=0; i<*n; i++) {
    order[i] = make_pair(lambda[i], i);
  }

  sort(order.begin(), order.end());

  for (int i=0; i<*n; i++) {
    pair<double, int> p = order.at(i);
    res_lam[i] = p.first;
    for (int j=0; j<*n; j++) {
      res_vec[*n*i + j] = vecs[*n*p.second + j];
    }
  }

  copy(res_lam.begin(), res_lam.end(), lambda);
  copy(res_vec.begin(), res_vec.end(), vecs);
}
Sign up to request clarification or add additional context in comments.

Comments

0

void esort(double* lambda, double* vecs, int* n)

When calling this function, it creates local pointer variables that reference the same memory address. In the code when the following is done:

lambda = res_lam;
vecs = res_vec;

It doesn't mean that you are changing the value of the memory address you passed as argument to the function, but rather the local pointer variable of the function lambda and vecs are now pointing to a different memory address.

6 Comments

Technically correct. Yet, re-allocating memory is a really stupid thing to do here. So this is not a good solution.
@Ediac, so how could I fix my code? I tried void esort(double* &lambda, double* &vecs, int* n) but then I get segfault whenever I try to access elements of lambda or vecs.
Yeah i know, just highlighting the OP's faults :)
@LightnessRacesinOrbit, could you elaborate on how I might still achieve my goals without reallocating memory?
@astay13 Went away for a moment, but it seems like there are new answers now
|
0

Alternatively you can use Pointer to Pointer Concept.

void esort(double** lambda, double** vecs, int* n)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.