0

I'm new to C++ coming from Java so forgive me for being naive, but I'm trying to pass an array out of a function. I know the way to do this is to pass a pointer, like so:

int *foo(){
   int arr[3] = {1, 2, 3};
   int *arrptr = arr;
   return arrptr;
}

And then to access that array:

int main(){
   int *arrptr = foo();  //create a pointer to array

   //cout all elements
   for(int x = 0; x < 3; x++)
      cout << arrptr[x];

   return 0;
}

And naturally, this works just fine. But for some reason in a different code, this same process only returns the first value of the array and the rest seem to be random.

int main(){
   stringstream allstats;
   allstats << readFile(); //readFile() simply returns a string read from a file

   while(!allstats.eof()){     //check for end of stream
      string temp;             
      getline(allstats, temp); //grab a line from allstats and put it into temp

      double *arr = calculateStats(temp); //create pointer to array of stats calculated for temp

      // print arr
      for(int x = 0; x < 6; x++)
         cout << arr[x] << endl;
      //****This spits out the correct value for arr[0] but for the rest of the array
      //****it is values like 8.58079e-306 which tells me those addresses have been
      //****overwritten.

   }
   return 0;
}

//calculate stats for each player, return as formatted string
double* calculateStats(string player){
   //cut for conciseness, just know it works and the proper values are in the following array

   //create stat array
   double statarr[6] = {(double)BA, (double)OB, (double)H, (double)BB, (double)K, (double)HBP};

   //create pointer to stat array
   double *ptr;
   ptr = statarr;

   return ptr;
}

In Java it would be as simple as just returning an array and the job is done. Is this even possible in C++ or is this just beyond my level of understanding and the solution is much more complicated than I thought?

Insederec
  • 303
  • 1
  • 3
  • 10
  • 2
    instead of array use std::vector - you'll be able to return it from a function – Artemy Vysotsky Sep 13 '17 at 17:00
  • `statarr` needs to be `static` if you want that to use like that. – user0042 Sep 13 '17 at 17:00
  • Why don't you just do `int *arrptr = (int*)arr`? What's the point in putting it into function `foo`? BTW, the difference is that in the function at the bottom of your question, you are returning the address of a local array, which yields undefined behavior (this array "ceases to exist" outside the scope of that function). – goodvibration Sep 13 '17 at 17:00
  • 4
    Your "simple" example and your code are very different. You should be using `std::vector` instead of raw arrays. – crashmstr Sep 13 '17 at 17:06
  • Returning a `std::array` or `std::vector` and just forgetting about C-style arrays will save you a lot of headaches. – Jesper Juhl Sep 13 '17 at 17:13
  • FYI, don't use `while (!eof)`. It's not going to know it's at EOF until it tries reading something and hits the end, which can easily cause problems like going through the loop with a blank input. – chris Sep 13 '17 at 17:13
  • 4
    Helpful hint: the best way to learn C++ is to completely and totally forget everything you know about Java. Start from scratch. C++'s and Java's syntax is deceptively similar, but C++'s classes, objects, and memory model are fundamentally different from Java's, and they have very little in common. The mistake in the shown code is typical for someone coming from a Java background, where one doesn't have to worry about things like object lifetime scopes. Unfortunately, one needs to get this 100% right in C++, and fully understand the fundamental differences between automatic and dynamic scope. – Sam Varshavchik Sep 13 '17 at 17:14
  • I changed the "simple" code to better reflect the way I used it in the example. Its behavior remains the same. As far as vectors, I'm not sure if I should or need to use them, since for this assignment (It's the first few weeks of the course) we have never gone over vectors and we're expected to be using arrays. I don't know any other way to return the type of information I need to return short of finding techniques we haven't gone over in class. – Insederec Sep 13 '17 at 17:25
  • @FrançoisAndrieux: The example at the top of the question (the one I was referring too) converts an `int` array to an `int` pointer. I see no alias rule breaking there, and the OP is doing exactly what I wrote, only inside a function (which as I stated, could just as well be done directly). – goodvibration Sep 13 '17 at 17:42
  • @chris Recommended alternative? I need to check that there is no more input in the stream, but `eof()` was the only thing I could find. – Insederec Sep 13 '17 at 17:45
  • @goodvibration I misread your original comment and have retracted my reply. – François Andrieux Sep 13 '17 at 17:51
  • @Insederec, You can't know whether there's more data without trying to read it. See [this question](http://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong). – chris Sep 13 '17 at 18:44

1 Answers1

0

You cannot have pointer references to local arrays in external functions, since once the local function exits it's stack may be reused and the data in the local variables will contain trash.

You can add word static to your local arrays declaration for it's memory to be persistent across other functions (and repeated calls). Although that is not a recommended solution at all here.

Change:

double statarr[6] = {(double)BA, (double)OB, (double)H, (double)BB, (double)K, (double)HBP};

To:

static double statarr[6] = {(double)BA, (double)OB, (double)H, (double)BB, (double)K, (double)HBP};

Although, a better solution would be to not declare the array local to calculateStats

Something like:

    //calculate stats for each player, return as formatted string
double* calculateStats(string player, double *outArr){
   //cut for conciseness, just know it works and the proper values are in the following array

   //create stat array
   outArr[0] = (double)BA;
   outArr[1] = (double)OB;
   outArr[2] = (double)H;
   outArr[3] = (double)BB;
   outArr[4] = (double)K;
   outArr[5] = (double)HBP;


   return outArr;
}

Then have:

int main(){
   stringstream allstats;
   allstats << readFile(); //readFile() simply returns a string read from a file

   while(!allstats.eof()){     //check for end of stream
      string temp;             
      getline(allstats, temp); //grab a line from allstats and put it into temp

      double arr[6]
      calculateStats(temp, arr) //create pointer to array of stats calculated for temp

      // print arr
      for(int x = 0; x < 6; x++)
         cout << arr[x] << endl;
      //****This spits out the correct value for arr[0] but for the rest of the array
      //****it is values like 8.58079e-306 which tells me those addresses have been
      //****overwritten.

   }
   return 0;
}
Arjun
  • 368
  • 1
  • 3
  • 10
  • Oh! So instead of returning a new array, simply modify the data at the address of an already existing array! Is there any reason not to use this solution? – Insederec Sep 13 '17 at 17:34
  • @Insederec you can also use `std::array`, which allows to be returned from functions. – Guillaume Racicot Sep 13 '17 at 18:36
  • @Insederec "Is there any reason not to use this solution?" - well, just returning a `std::vector` is a lot simpler.. also, `static` variables open up their own whole new can of worms. – Jesper Juhl Sep 13 '17 at 18:39