Initializing an array of pointers to structs in C++ - 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

Related

Embedded C++ static initialization of struct arrays

While migrating to C++ I require a certain function that seems to have been deprecated.
sorry, unimplemented: non-trivial designated initializers not supported
What is the correct way to implement the following data storage system in C++ for memory constraint systems?
typedef union union_t {
float f;
int i;
} arg;
typedef struct type_t {
int a;
arg b;
int d;
} element;
const element list[] = {
{
.a = 1,
.b = { .f = 3.141519f },
.d = 6
},
{
.a = 3,
.b = { .i = 1 },
}
};
Often the use of std:map or std:vector is suggested. Which is suitable, however list is immutable and must be able to compile and link to a specific block of flash. Both seem unfit for that purpose.
The highest I can go is ARM Compiler 6, which is C++14.
The way you shown is almost correct compliant with the incoming C++20 standard. Only that .d also have to be initialized. Is it what I suggest to use.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0329r4.pdf
To handle this in C++14 you have to initilize it explicilty:
typedef union union_t {
float f;
int i;
} arg;
typedef struct type_t {
int a;
arg b;
int d;
} element;
const element list[] = {
{
/*.a = */ 1,
/*.b = */ { /*.f = */ 3.141519f },
/*.d = */ 6
},
{
/* .a = */ 3,
/* .b = */ { /* .i = */ 1 },
0
}
};

How to fill array of struct containing pointer arrays

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;
}

c++ int array with values of 2 dimension int array (3d array)

I'm trying to make an array which contain int[][] items
i.e
int version0Indexes[][4] = { {1,2,3,4}, {5,6,7,8} };
int version1Indexes[][4] = { ...... };
int version15Indexes[][4] = { ... };
(total of 16)
int indexes[][][] = { version0Indexes,version1Indexes, .. };
anyone can suggest how to do so ?
Thanks
You can use an array of pointers to array:
int (*indexes[])[4] = { version0Indexes, version1Indexes, .. };
Either you inline your arrays inside indexes:
int indexes[][2][4] = {
{ { 1, 2, 3, 4}, {5, 6, 7, 8} },
{ {....}, {....} }
....
}
Or you make indexes an array of pointers:
int (*indexes[])[4] = { version0Indexes, version1Indexes, .... };
What you wrote in your question is not directly possible because, when used, an array variable is actually a pointer (that's why indices has to be an array of pointers).

How to initialize pointer to pointer with premade data?

I have a pointer to a pointer, since I can't pass dynamic arrays to functions. However, if I want to initialize that pointer-to-pointer with premade data, how can I set it since {a,b,c} notation for arrays won't work for pointers?
You can do this:
static int row1[] = {1, 2, 3};
static int row2[] = {4, 5, 6, 7};
static int row3[] = {8, 9, 10, 11, 12, 13};
static int *pptr[] = {row1, row2, row3};
At this point, pptr can be assigned to an int**:
int **p = pptr;
[This answer is only relevant if you need a double*. Your question was edited to say pointer to pointer - if that's what you need, this answer is not relevant.]
You can do this instead:
double fValues[3] = { 1, 2, 3 };
The variable fValues is already a pointer - array variables without the [] are pointers to the first element of the array. This is not a dynamic array, so you don't need to allocate/free its memory.
Assuming your function that takes a double pointer looks something like this:
void Func(double* pDbl) {...}
you'd call it like this:
Func(fValues);
You can create small dynamic arrays recursively something like this:
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
typedef struct
{
int* pValues;
size_t Count;
} List;
const List ListEnd = { NULL, 0 };
List NewList(int Value, List SubList)
{
List l;
l.Count = SubList.Count + 1;
if (SubList.Count == 0)
{
l.pValues = malloc(sizeof(int));
}
else
{
l.pValues = realloc(SubList.pValues, l.Count * sizeof(int));
}
if (l.pValues == NULL)
{
// do proper error handling here
abort();
}
// moving data isn't necessary if the list elements are
// in the reverse order
memmove(&l.pValues[1], &l.pValues[0], SubList.Count * sizeof(int));
l.pValues[0] = Value;
return l;
}
void PrintDynArr(int* pValues, size_t Count)
{
while (Count--)
{
printf("%d\n", *pValues++);
}
}
int main(void)
{
int* p;
PrintDynArr(p = NewList(1,
NewList(2,
NewList(3,
NewList(4, ListEnd)))).pValues,
4);
free(p);
return 0;
}
Output:
1
2
3
4

How do I do something like this some_function({1,1,1,1})?

Lets say I have a function with prototype like this: int func(int * a), and it accepts an array as an argument.
How do I do this without the compiler showing errors everywhere: func({1,1,1,1})
Like this:
int func(int * a);
void somewhere_else()
{
int arr[4] = { 1, 1, 1, 1 };
func(arr);
}
Don't use raw arrays, and certainly don't pass pointers to them into functions. Ew! We're not in 1975 any more.
#include <cstddef>
#include <iostream>
#include <vector>
void func(std::vector<int> const& v) {
for (std::size_t i = 0; i < v.size(); i++)
std::cout << v[i] << " ";
}
int main() {
func({ 1, 2, 3, 4 });
}
// Output: "1 2 3 4 "
This requires a compiler that is compliant with certain features of C++11. Namely initializer lists.
You can use std::initializer_list:
int func(std::initializer_list<int> a) {
// do something with a here
}
Or you can write a wrapper that uses std::initializer_list (if for some reason you cannot change the original function):
int func_wrapper(std::initializer_list<int> a) {
std::vector<int> b = a;
func(b.data());
}
one way to do that would be
#include <iostream>
#include <stdio.h>
void abc (int *a,int z)
{
int m= z/sizeof(*a);
for(int i=0;i<m;i++)
{
std::cout<<"values " <<*a<<"\n";
a++;
}
}
int main()
{
int ar[]={11,12,13,14,15,1166,17};
std::cout << sizeof(ar)<<"size\n";
abc(ar,sizeof(ar));
getchar();
}
here in this case you dont need to worry about size and all. In case of
int ar[3]={1,2,3} that will give junk values if you try and search for NULL as
the third place is occupied by element 3
All you need is an (int[]) cast:
#include <iostream>
static void f (int* a) {
while (*a) std::cout << *a++ << "\n" ;
}
int main() {
f ((int[]){1,2,3,4,0}) ;
}
This code outputs
1
2
3
4
It works in C too -- see this ideone link.
Updated to add: I posted a new question about the legality of this construct, and Mat's answer is worth reading if you're interested in that kind of thing. Briefly, it seems that it is valid only in C99, but that some compilers allow it as an extension in all C/C++ variants.