tags:

views:

100

answers:

5

Hi everyone,

I have found that a struct (with an array of doubles and one integer) defined in a separate Cpp-file, but called from main sends unreasonable values to cout for the array. Below what I hope to be a minimum example, along with the console output.

My apologies should my code be scrambled -- I have been struggling a bit with formatting it properly.

I'd be grateful if someone could help me understand and rectify this.

Best, Jo

(1) main.cpp:

#include "iostream"
#include "defs.h"

using namespace std;

int main()
{
    MyStruct myModel=ConstructModel();

    cout << endl << "myModel goes first:" << endl;
    for(int i=0; i<myModel.n; i++)
        cout << "myModel.Y[" << i << "]=" << myModel.Y[i] << endl;
    cout << "myModel.n=" << myModel.n << endl;

    MyStruct myOtherModel;
    myOtherModel.n=2; double Y[2]={0.1,0.1};
    myOtherModel.Y=Y;

    cout << endl << "now myOtherModel:" << endl;
    for(int i=0; i<myModel.n; i++)
        cout << "myOtherModel.Y[" << i << "]=" << myOtherModel.Y[i] << endl;

    return 0;
}

(2) defs.cpp:

#include "defs.h"

MyStruct ConstructModel()
{
 MyStruct Model;

 double Y[2]={0.1,0.1}; Model.Y=Y;
    int n=2; Model.n=n;

    return Model;
}

(3) defs.h:

#ifndef DEFS_H  
#define DEFS_H

struct MyStruct
{
    double *Y;//length (n+1)
    int n;
};

MyStruct ConstructModel();

#endif

Console output

On my machine (WinXP 32bit, MSVC2008), this gives:

myModel goes first:

myModel.Y[0]=1.12947e-307

myModel.Y[1]=1.80243e-307

myModel.n=2

now myOtherModel:

myOtherModel.Y[0]=0.1

myOtherModel.Y[1]=0.1

+10  A: 

Your struct contains a naked pointer to doubles. In defs.cpp, you're initializing that to a local variable. Outside the scope of ConstructModel(), that memory is no longer valid.

If you want an array in a struct, you have to declare it (including its size, which then has to be the same for all MyStructs). But rather than using arrays, why don't you use e.g. std::list<double> or std::vector<double>?

Pontus Gagge
Thanks to everyone and in particular to Pontus Gagge -- this was a case of "going out of scope" a bit too subtle for me.Using vectors will prove very helpful indeed; my unawareness of the ST libraries was the only reason for not using them.@Pontus Gagge: To clarify, by "declaring an array in a struct", you mean a declaration with a constant size that is the same for all MyStruct objects? That is, there are no two instances a,b, of such structs with differing size of a.Y, b.Y?Thanks, Jo
Johannes
+1  A: 

When the function ConstructModel finishes the array gets out of scope. Try creating array on the heap.

Dialecticus
+2  A: 

The problem is that the array Y contained in ConstructModel is only valid for as long as ConstructModel is being executed. You're (indirectly) passing back a pointer to this local variable, which is no longer valid by the time it's being accessed.

Martin B
+2  A: 
MyStruct ConstructModel()
{
  MyStruct Model;

  double Y[2]={0.1,0.1}; 

here you assign the address of the local Y[0] to Model.Y:

  Model.Y=Y;
  int n=2; 
  Model.n=n;

  return Model;

here the local Y goes out of scope and is destroyed, leaving Model.Y with a pointer to a non-existing object:

}
sbi
A: 

It's not an answer, but yet another question on back of the above.

If I change the code to the below, the pointer does not seem to go out of scope when the struct only consists of this one pointer. If the struct is defined to contain another value (say, an integer), the address is lost. Doesn't this seem to suggest that the explanations to my first question are not the full picture?

I'm not sure if this is of any interest to anyone. I suspect the internals for declaring and defining/allocating a struct cause this phenomenon -- maybe someone can confirm/explain.

#include "iostream"
using namespace std;

struct MyStruct
{
    //int n; // <-- if commented, result is as expected. Else, address is lost.
    double *Y;//length (n+1)
};

MyStruct ConstructModel()
{
    MyStruct Model;
    //int n=2; Model.n=n;
    double Y[2]={0.1,0.1}; Model.Y=Y;
    return Model;
}


int main()
{
    MyStruct myModel=ConstructModel();

    for(int i=0; i<2; i++)
        cout << "myModel.Y[" << i << "]=" << myModel.Y[i] << endl;

    return 0;
}

UPDATE: Compilation with g++ instead of MSVC does not show a difference in output. Seems hence to be compiler-specific...

Johannes
`#include <iostream>`
graham.reeds