How to fill array of struct containing pointer arrays - c++

I have an small and quite simple issue in C++. I want to fill array of struct containing double arrays. How can I do that?
typedef struct
{
double *inputs[2];
double *target[1];
} Data;
Data data[]
{
new double[2]{10, 20}, new double[1]{30},
new double[2]{40, 50}, new double[1]{60},
new double[2]{70, 80}, new double[1]{90},
new double[2]{100, 110}, new double[1]{120}
};
and in the main()
printf("data[0]: inputs: %f %f, targets: %f\n",
*data[0].inputs[0],
*data[0].inputs[1],
*data[0].target[0]);
This is my idea, but when I run that it will print this:
data[0]: inputs: 10.000000 30.000000, targets: 40.000000
Of course, at the end of the array data (like 3rd or 4th item) it will cause UNAUTHORIZED ACCESS TO MEMORY
Thank you for your ideas and patience ;)

Using modern c++ makes your code both simpler and safer:
#include <iostream>
#include <array>
#include <vector>
struct Data {
std::array<double,2> inputs;
std::array<double,1> target;
};
int main()
{
std::vector<Data> data = {
{ {10, 20}, {30} },
{ {40, 50}, {60} },
{ {70, 80}, {90} },
{ {100, 110}, {120} }
};
std::cout << "data[0]: inputs: " << data[0].inputs[0] << " " << data[0].inputs[1] << ", targets: " << data[0].target[0] << "\n";
}
Your original problem is that double *inputs[2] declares a 2 element array of pointers to double not a pointer to a 2 element array of doubles.

Your Data struct contains 2 fields, array of 2 double pointers, and array of 1 double pointers.
That means that initalizing it takes up to 3 double pointers, which means that in your initalization really looks like this
Data data[]{
{new double[2]{ 10, 20 }, new double[1]{ 30 }, new double[2]{ 40, 50 }}, //1st object
{new double[1]{ 60 }, new double[2]{ 70, 80 }, new double[1]{ 90 }}, //2nd object
{new double[2]{ 100, 110 }, new double[1]{ 120 }} //3rd object but 2 parameters??
};
When trying to print it in a loop, 3rd object will cause a segfault, as target field hasn't been properly initalized (when debugging with Visual Studio it's set to null, not sure about other compilers).

Your problem is here:
typedef struct {
double *inputs[2]; // this
double *target[1]; // this
} Data;
This is an array of pointers and hopefully assumed to behave live a dynamic 1D array.
Simple fix is:
struct Data {
double *inputs = nullptr;
double *target = nullptr;
} ;
However, you have a lot of heap memory allocation using new, which makes a tedious task to delete and thereby the management of your data structure really difficult.
I would strongly suggest you to use std::vector<>, which makes your task much easier and more cleaner.
#include <vector>
#include <iostream>
struct Data
{
std::vector<double> inputs; // use instead of double *inputs[2];
std::vector<double> target; // use instead of double *target[1];
//Data(const std::vector<double>& a, const std::vector<double>& b) :inputs(a), target(b){}
};
int main()
{
std::vector<Data> data = // now in your main structure array
{ { {10, 20}, {30} },
{ {40, 50}, {60} },
{ {70, 80}, {90} },
{ {100, 110},{120} }
};
// access using range based loop now
for(const Data& each_strcut: data)
std::cout << each_strcut.inputs[0] << " " << each_strcut.inputs[1]
<<"\t" << each_strcut.target[0] << std::endl;
return 0;
}

Related

C++ Accessing a data value from an pointer in an array, via pointer to another element and element size

Hope that title made sense!
whilst creating a menu system, I'am trying to access data from a pointer in the nTh element of an array of structs, where I have the address of the pointer in the 1st(0) elements data value, the index of the element I wish to access and the size of the array elements.
the example code returns the correct result for the "display_value(0);", but not for any other elements.
I can see something must be wrong with my logic/math in the "elementToDisplay = sensorData[0].valueToDisplay + (sensorData[0].arrayElementSize * thermistorIndex);" line.. not creating the correct memory address but I can't work it out!
Thanks.
#include <iostream>
using namespace std;
struct thermistors_t{
int itemIDNo;
int valueToDisplay;
int noOfSamples;};
thermistors_t thermistors[]{
{1, 10, 100},
{2, 20, 200},
{3, 30, 300}};
struct sensorData_t{
int itemIDNo;
int *valueToDisplay;
int arrayElementSize;};
const sensorData_t sensorData[]{
{1, &thermistors[0].valueToDisplay, sizeof(thermistors_t)}};
void display_value(int thermistorIndex){
void *elementToDisplay;
int *intToDisplay;
elementToDisplay = sensorData[0].valueToDisplay + (sensorData[0].arrayElementSize * thermistorIndex);
intToDisplay = (int*)elementToDisplay;
cout << *sensorData[0].valueToDisplay << ", ";
cout << *intToDisplay << '\n';
}
int main()
{
display_value(0);
display_value(1);
return 0;
}

Initializing an array of pointers to structs in C++

Initializing an array of pointers to structs in C can be done using compound literals.
typedef struct {
int a;
int b;
} s;
In C:
s *ptrArray[] = {
&(s){
.a = 1,
.b = 2
},
&(s){
.a = 4,
.b = 5
}
};
How can this be done in C++?
I have also seen the difference in initializing structs in C++ not using compound statements:
s s1 = { a: 7, b: 8 };
First - initializing anything to the address of a temporary value seems extremely fishy, in C as well. Are you sure that's valid? Hmmm. Anyway, a C++ compiler will really not let you do that.
As for the your designated (named-field) initialization C++ line - it's actually non-standard, it's a GNU C++ extension, and you can't rely on it.
You could do this:
struct s { int a, b; };
int main() {
s data[] = { { 1, 2 }, { 4, 5 } };
// instead of ptrArray[i], use &(data[i])
}
This compiles just fine. But - a more C++'ish version of this code would be:
#include <array>
struct s { int a, b; };
int main() {
std::array<s, 2> data { s{ 1, 2 }, s{ 4, 5 } };
// instead of ptrArray[i], use &(data[i]),
// or use iterators, or ranged for loops
}
Why would you want to use std::array? Here's one explanation of the benefits. Actually, you could do slightly better and repeat yourself less with:
int main() {
auto data = make_array(s{ 1, 2 }, s{ 4, 5 });
// instead of ptrArray[i], use &(data[i]),
// or use iterators, or ranged for loops
}
The make_array function is taken from here; you also have std::experimental::make_array(), but that's not standardized yet.
If you want to add or remove elements from data at run-time, you might switch to using std::vector:
#include <vector>
struct s { int a, b; };
int main() {
std::vector<s> data { s{ 1, 2 }, s{ 4, 5 } };
// instead of ptrArray[i], use &(data[i]),
// or use iterators, or ranged for loops
}
The reason your initialize was failing is you were attempting to initialize the array of pointers to struct to the address of numeric literal constants. The same as:
#define A 5
int b = &A; /* NOT HAPPENING */
(you can't take the address of 5)
You can solve your problem by simply initializing an array of s instead of an array of pointers to s, e.g.:
s ptrarr[] = { {1, 2}, {4, 5} };
With that change, your array will initialize fine, e.g.
#include <iostream>
typedef struct {
int a;
int b;
} s;
int main (void) {
s ptrarr[] = { {1, 2}, {4, 5} };
int cnt = 0;
for (auto& i : ptrarr)
std::cout << "ptrarr[" << cnt++ << "] : " << i.a << ", " << i.b << "\n";
}
Example Use/Output
$ ./bin/ptrarrystruct
ptrarr[0] : 1, 2
ptrarr[1] : 4, 5

C++ eigen pointer to a Eigen::Map<Eigen::VectorXd> object

Is it possible to define a pointer to a Eigen::Map object? The original code is quite complex but here is what I am trying to achieve (pseudo code)
void testfunction1(... XPtr){
// XPtr is a pointer
// create a vector, map it to a Map object and make XPtr point to the latter
VectorXd Xnew(9);
Xnew << 10, 20, 30, 40, 50, 60, 70, 80, 90;
Map<VectorXd> XnewMap(Xnew.data(), 9);
// make XPtr point to XnewMap so that Xnew data can be
// accessed outside testfunction1()
// ... how? I suspect this to involve some dynamic memory allocation
};
void testfunction2(bool yes){
// main function
VectorXd XR(9);
XR << 1, 2, 3, 4, 5, 6, 7, 8, 9;
const Map<VectorXd> X(XR.data(), 9); // yes the mapped version is needed
// create a pointer to X, say XPtr
// ... how?
if(yes){ // make XPtr point to XnewMap which is defined in testfunction1()
testfunction1(XPtr);
};
//... some computations
// make XPtr point again to X
// ... how?
};
First of all no need to use pointers here because Map is already essentially a pointer, so it would be simpler so update the Map object with placement new. Nonetheless, your current design would require allocation within testfunction1 and deallocation within testfunction2 in case it has been allocated, which is not really safe. So better adopt a functional design by putting "some computations" within a function (or a named lambda), make testfunction1 return by value:
VectorXd testFunction1() { return Xnew; }
void testfunction2(bool yes){
VectorXd XR(9);
XR << 1, 2, 3, 4, 5, 6, 7, 8, 9;
const Map<VectorXd> X(XR.data(), 9);
auto func = [&] (Eigen::Ref<VectorXd> X) {
/* some computation */
}
if(yes) func(testfunction1());
else func(X);
};
If you really want to keep your current logic, then here is a self-contained example using placement new:
#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
using namespace std;
void testfunction1(Map<VectorXd> &XMap){
double * Xnew = new double[9];
::new (&XMap) Map<VectorXd>(Xnew,9);
XMap << 10, 20, 30, 40, 50, 60, 70, 80, 90;
};
int main()
{
bool yes = true;
VectorXd XR(9);
XR << 1, 2, 3, 4, 5, 6, 7, 8, 9;
Map<VectorXd> X(XR.data(), 9);
if(yes) testfunction1(X);
// use X ...
cout << X.transpose() << endl;
// restore X and free memory allocated in testfunction1
if(yes){
delete[] X.data();
::new (&X) Map<VectorXd>(XR.data(),9);
}
cout << X.transpose() << endl;
}
which is pretty bad because it can leak if an exception is raised when using X. You could workaround manual memory management by asking testFunction1 to return a VectorXd (or anything that handle memory allocation/deallocation on its own) and do the placement new in the main function:
#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
using namespace std;
VectorXd testfunction1(){
VectorXd Xnew(9);
Xnew << 10, 20, 30, 40, 50, 60, 70, 80, 90;
return Xnew;
};
int main()
{
bool yes = true;
VectorXd XR(9);
XR << 1, 2, 3, 4, 5, 6, 7, 8, 9;
Map<VectorXd> X(XR.data(), 9);
{
VectorXd X2;
if(yes) {
X2 = testfunction1(); // shallow copy thanks to move semantic
::new (&X) Map<VectorXd>(X2.data(),9);
}
// use X ...
cout << X.transpose() << endl;
// restore X
::new (&X) Map<VectorXd>(XR.data(),9);
}
cout << X.transpose() << endl;
}
Finally, if the content of X should be read-only, then use Map<const VectorXd> and not const Map<VectorXd> as in your initial question.

Initialize private array with unknown number of elements (C++98)

Looks like I missed something fundamental here, but haven't worked it out.
Below is a snippet and its corresponding output.
What I wanted to do is:
- Declare and initialize an array of structs, without knowing the number of elements in advance.
- Ideally the array itself and its number of elements are private members.
What I tried:
Declared m_member_tab[] and m_num_members as private.
Created an Init() function that initializes m_member_tab[] and calculate m_num_members.
Outcome:
m_member_tab[] is initialized ok (see below output).
BUT inside the constructor (after calling Init), m_member_tab is corrupted.
#include <iostream>
using std::cout; using std::endl;
class TArrayTest
{
public:
TArrayTest();
private:
void Init();
typedef struct _TMember
{
int m_key;
int m_val;
}
TMember;
TMember m_member_tab[];
int m_num_members;
};
TArrayTest::TArrayTest()
{
Init();
cout << "Ctor: Number of elements = " << m_num_members << endl;
for( int i = 0; i < m_num_members; i++ )
{
cout << "Ctor: "
<< "key " << m_member_tab[i].m_key
<< " - val " << m_member_tab[i].m_val
<< endl;
}
};
void TArrayTest::Init()
{
TMember m_member_tab[] =
{
{ 1, 100 },
{ 2, 200 },
{ 3, 300 },
{ 4, 400 },
{ 5, 500 },
};
m_num_members = sizeof( m_member_tab ) / sizeof( TMember );
cout << "Init: Number of elements = " << m_num_members << endl;
for( int i = 0; i < m_num_members; i++ )
{
cout << "Init: "
<< "key " << m_member_tab[i].m_key
<< " - val " << m_member_tab[i].m_val
<< endl;
}
}
int main()
{
TArrayTest test;
}
Output:
Init: Number of elements = 5
Init: key 1 - val 100
Init: key 2 - val 200
Init: key 3 - val 300
Init: key 4 - val 400
Init: key 5 - val 500
Ctor: Number of elements = 5
Ctor: key 5 - val 32766
Ctor: key 0 - val 0
Ctor: key 0 - val 0
Ctor: key -1212526907 - val 32623
Ctor: key 0 - val 0
This member declaration:
TMember m_member_tab[];
is not valid C++.
There is an additional problem in the init function, where you declare a local variable of the same name, but it doesn't matter: the above declaration is not just invalid, but since it's not at the end of the struct it doesn't even make sense as a language extension.
Instead, use std::vector, like this:
std::vector<TMember> m_member_tab;
It keeps track of the array size, so you don't need that extra member.
In other news, C++ directly supports initialization of an instance of a class. You should not define ordinary function for that. Instead use the language mechanism for that, namely a constructor.
You can find information about constructors in any tutorial and any introductory C++ textbook.
The language supported mechanism has many advantages compared to an init function.
Oh, and seeing as each item in the array will contain a key and a value, do consider a std::map, or, if you can use C++11 and not just C++98/C03, std::unordered_map (faster but no sorted traversal of keys).
in the first line of void TArrayTest::Init():
TMember m_member_tab[] =
{
{ 1, 100 },
{ 2, 200 },
{ 3, 300 },
{ 4, 400 },
{ 5, 500 },
};
you declare "m_member_tab" a temporary variable, not Member variable. you should write like this:
m_member_tab[] =
{
{ 1, 100 },
{ 2, 200 },
{ 3, 300 },
{ 4, 400 },
{ 5, 500 },
};
The feature you are trying to use does not exist in C++ language. It is illegal to use [] in non-static member array declarations. It is allowed in static member array declarations, but non in non-static ones.
Even if your compiler somehow allows this declaration, it probably interprets it as a zero-sized array. The array size is fixed at that point - there's no way to somehow "intialize" it into a bigger array later.
Member array declaration with [] might be allowed by some compilers as a way to support C-style "struct hack". But that is a completely different technique.

Give me a hint or (Answer) for vector initialization

Im really sad that I have no idea what and how to do .
I have this,
struct TeamS
{
int ID;
string MEMBERS[3];
};
void Initialize (vector <TeamS> & TeamV, const int id[],
const string m[][NUM_MEMBERS], int arraySize);
int main()
{
vector <string> TeamV;
//not sure TeamV is supposed to be int or string
const int ID[NUM_TEAMS] = { 123, 321, 456, 789 };
const string MEMBERS[NUM_TEAMS][NUM_MEMBERS] =
{
{ "Sarah", "Joe", "John" },
{ "Chris", "Kevin", "James" },
{ "Tom", "Kim", "Emily" },
{ "Jill", "Jason", "Jim" }
};
cout << "Starting Initialization" << endl;
cout << "Ending Initialization" << endl;
}
I have to use this prototype
which is :
void Initialize (vector <TeamS> & TeamV, const int id[],
const string m[][NUM_MEMBERS], int arraySize);
to pass in the empty vector and the arrays
For example,
the first element of the vector will have team id: 123 and members: Sarah, Joe, and John.
The second element of the vector will have team id: 321 and members: Chris, Kevin, and James, and so on.
How can I do this??
DO I have to use push_back ??
or is it much easier than I think??
I think you want to make TeamV a vector of type TeamS, so each element in TeamV can contain information about a team (ID and MEMBERS). Using the push_back() method is sounds like a great idea, try it out
vector <string> TeamV; ==> This has to be 'vector<TeamS> TeamV;'
To add elements to vector, first you need to construct individual entries.
Something like:
TeamV.push_back(TeamS());
TeamV[0].ID = id[0];
std::copy(m[0], m[0] + NUM_MEMBERS, TeamV[0].MEMBERS);