Unexpected errors regarding structs and arrays - c++

So I'm following a certain tutorial series and trying to use that knowledge to put my own spin on something kindof both similar but also different to the series itself. In one section, to tackle a certain inconvenience which is not important for the scope of my issue, a possible solution was to store certain chunk of data into members of a struct and then call that struct onto a function that later output the data precisely the way we wanted - as an array.
All was well and good, until the function for some reason refused to take in values of the array, claiming there was an overload of information in the array arguments (I will specify the errors later), and that the entity I am returning does not match the function's return type.
Here's my code:
struct TriCoord
{
float Position[3];
int Label[2];
};
std::array<TriCoord, 3> Implement(float x, float y, float z, int j) //2
{
float size = 1.0f;
TriCoord f0;
f0.Position = { x, y, z }; //1
f0.Label = { j, 1 }; //1
TriCoord f1;
f1.Position = { x + 0.5, y + 0.5, z };
f1.Label = { j, 2 };
TriCoord f2;
f2.Position = { x + 0.5, y, z };
f2.Label = { j, 3 };
return { f0, f1, f2 }; //2
};
int main()
{
int X;
float A[3] = Implement(3, 4, 5, 1); //3
std::cout << A[0] << ", " << A[1] << ", " << A[2] << std::endl;
std::cout << "Press Enter key to return" << std::endl;
std::cin >> X;
return 0;
}
I've put comments locating specifically where the errors are.
1) The compiler says that f0 is "not a modifiable lvalue". I see no reason why it shouldn't be. In the array argument at specifically the second element of the array (in this case y), the compiler says that I am adding "too many initializer values". Again, makes no sense. I specified the Position array to have 3 elements and am plugging 3 elements of matching type (float).
These two errors extend to f0.Label, as well as the other TriCoords.
2) The compiler says that the function "returns incomplete type 'std::array'". Furthermore, in the return line, "list-initialization of an object type 'std::array' is not allowed because the type is incomplete".
Technically what I am returning is an std array whose elements are TriCoords and of amount 3, so I don't see the problem once again. I did work around this issue by changing the function's return type to float, but in its stead the return line generates the same error for the second element (in this case f1) as in problem 1.
3) "Initialization with '{...}' expected for aggregate object" I have no idea what this means. I get this error regardless of which return type I specify for my function.
I must emphasise that both me and the series I'm following are using Visual Studios and no such errors popped up in the video I was following. I even copy-pasted the entirety of the video's code line by line and the errors still persisted, leading me to the conclusion that there is something wrong in the way Visual Studios is configured on my end, possibly due to version differences (the video was uploaded this year so it's not running on too old of a version). All my dependencies are correct as well and are present in their respective project-based directories, I have double checked those.
Lastly, the code I used above was a separate testing code I redid on a new project in an attempt to isolate the error. Needless to say, I got the same error in both cases indicating there's nothing inherently wrong with the custom-defined headers and libraries of my original project.

1) You cannot assign into arrays like this once they are initialized.
int arr[3] = {1, 2, 3}; //valid
int arr2[3];
arr2 = {1, 2, 3}; //invalid
In your case, what you could do is instead of: -
TriCoord f0;
f0.Position = { x, y, z };
f0.Label = { j, 1 };
write: -
float tempFloat[3] = { x, y, z };
int tempInt[2] = { j, 1 };
TriCoord f0;
for (int i = 0; i < 3; ++i)
f0.Position[i] = tempFloat[i];
for (int i = 0; i < 2; ++i)
f0.Label[i] = tempInt[i];
2) Solve 1 to solve 2...
3) You are trying to assign std::array<TriCoord, 3> to a float array which is certainly not possible...
At this point, I would strongly advise you to use std::array everywhere.

Related

Incompatible types in assignment of variables in C++

recently I have been trying to make a Neural Network with an arduino library and I came across a library, that was quite literally, called Neural Network by George Chousos. I stumbled apon a couple of errors that I managed to fix quite simply, but then I got caught on the error of
sketch_sep22b:24:43: error: incompatible types in assignment of 'float*' to 'float [4]' outputs = NN.FeedForward(inputs[i]);
This is all of my code:
#include <math.h> // Include Math Library
#include <NeuralNetwork.h> // Include Neural Network Framework
const unsigned int layers[] = {4, 9, 4}; // First Value (Inputs), Second Value (Neurons / Hidden Layers), Third Value (Outputs)
float outputs[4] = {}; //Outputs Float
const float* /* Pointer */ inputs[1] = {1};
const float expectedOutputs[1] = {1}; //Training Values
void setup()
{
Serial.begin(9600);
NeuralNetwork NN(layers, NumberOf(layers));
for (int i = 0; i < 3000; i++)
{
for (int j = 0; j < NumberOf(inputs); j++)
{
for (int i = 0; i < NumberOf(inputs) - 1; i++)
{
outputs = NN.FeedForward(inputs[i]);
Serial.println(outputs[0], 7);
}
NN.print();
}
}
}
Edit:
The declaration for FeedForward is:
float *FeedForward(const float *inputs); // Moves Calculated outputs as inputs to next layer.
Okay, I looked at the link and the declaration. The first problem, and the one that's leading to the compiler error is the return type. The declaration is expecting output to be a pointer, not an array. So, changing the declaration of output to:
float* outputs; //Outputs Float
should fix the compiler error. I haven't tried it, but that looks to be the issue the compiler is catching. This will likely return a pointer to an array of 4 floats which you will need to deallocate later (using either free or delete[] depending on how the library allocated the memory) once you're done with it or it will create a memory leak.
As others have noted, your current declaration of input is attempting to access a fixed memory location (1) which leads to undefined behavior, so, you still need to address this as well. Since the library appears to be expecting an input with 4 float values, you should either give it an array with 4 float values declared at compile time, or you could dynamically allocate an array with 4 values at run time.
The first option looks like this:
const float inputs[4] = {1.0, 2.0, 3.0, 4.0};
The second option looks like:
float* input;
...
input = new float[4];
input[0] = 1.0;
input[1] = 2.0;
input[2] = 3.0;
input[3] = 4.0;
...
output = NN.FeedForward(input);
...
delete[] input;

Creating a array of structs #2

I am writing this post in reference to my recent one - Create a array of structs
So, where I've got now is this code:
struct MacroMas
{
int x;
int y;
int Delay;
int SemiAutoDelay;
int ammo;
void Cords(int x, int y, int Delay)
{
this->x = x;
this->y = y;
this->Delay = Delay;
}
};
MacroMas* temp()
{
MacroMas _ret;
MacroMas* macroMasArray = new MacroMas[107];
for (int index = 0; index <107 ; ++index)
macroMasArray[index] = MacroMas();
macroMasArray[0].Cords(-3, 4, 16);
macroMasArray[1].Cords(-3, 4, 17);
// Some more code
return macroMasArray;
Thanks to John, who got me on the right way, but unfortunately, I can't accept this answer, because this eliminates only "randomization" bug. Now here's a stable problem - In array, only the first (macroMasArray[0]) is properly stored, other array's elements get the same value, as the first one. For example. mascroMasArray[10] should be 1,5,17, but is -3,4,16. Same as 0th element
You're simply misunderstanding the debugger. You are always looking at element zero. The other elements have the correct values, but you are not looking at them.
Because you've declared macroMasArray as a pointer to MacroMas the debugger presumes it's intended only to point to a single object.
You need to specifically type in the watch window which element you want, e.g.
macroMasArray[1]
or make sure you highlight the entire element, including the index.

unexpected value return by array variable

I am trying to pass array to function (*getcreditcurve). I am expecting function (*getcreditcurve) to return an array. Main function is expected to send several such array to function (*getcreditcurve), pointer function is expected to return a array to main function for different array using the logic given in pointer function (*getcreditcurve). I am not getting error but I don’t get correct value. I expect I+1 to be 3 * 0.0039 = 0.0117 and I+2 to be 4 *0.0060 = 0.0024 however I get following in excel output
'00D4F844 00D4F84C'
Even if I change the print statement to
'print << *(I1+1) << '\t' << *(I2+2) << endl;'
I get following excel out put
-9.26E+61 -9.26E+61
Can somebody help in trouble shooting please? Sorry I went through other post/question in this site but not able to get simplest way to solve this issue. I am going to use this logic to build other projects so simplified the question just to resolve main issue.
#include<iostream>
#include<cmath>
#include<fstream>
typedef double S1[5];
using namespace std;
double *getcreditcurve(double *);
int main()
{
S1 C1 = { 0.0029, 0.0039, 0.0046, 0.0052, 0.0057 };
S1 C2 = { 0.0020, 0.0050, 0.0060, 0.0070, 0.0080 };
typedef double *issuer;
issuer I1 = getcreditcurve(C1);
issuer I2 = getcreditcurve(C2);
ofstream print;
print.open("result1.xls");
print << (I1+1) << '\t' << (I2+2) << endl;
print.close();
return 0;
}
double *getcreditcurve(S1 ptr)
{
const int cp = 5;
typedef double curve[cp];
curve h;
h[0] = 2 * ptr[0];
h[1] = 3 * ptr[1];
h[2] = 4 * ptr[2];
h[3] = 5 * ptr[3];
h[4] = 6 * ptr[4];
return h;
}
If you want getcreditcurve to return an array, then try this:
const int cp = 5;
typedef double curve[cp];
curve getcreditcurve(S1 ptr) {
But that gives an error error: ‘foo’ declared as function returning an array. Functions can't return C arrays. But the good news is that if you fully embrace C++ you can return std::array instead.
#include<array>
const int cp = 5;
typedef curve std::array<double,cp>;
curve getcreditcurve(S1 ptr) {
But really, std::vector is probably much better as you have more flexibility about the size.
#include<vector>
std::vector<double> getcreditcurve(std::vector<double> ptr)
{
std::vector<double> h;
h.push_back(2 * ptr.at(0));
h.push_back(3 * ptr.at(1));
h.push_back(4 * ptr.at(2));
h.push_back(5 * ptr.at(3));
h.push_back(6 * ptr.at(4));
return h;
}
In fact, pretty much all problems with C arrays can be solved by std::vector. Then, in special situations, you can use std::array. But focus on std::vector for now.
It's not possible to return a C array from a function. There are other things you can return, such as std::vector or std::array. You should consider redesigning your application around those two instead.
But if you really need to use C arrays in C++, I suggest that instead of trying to return an array from getcreditcurve, you pass an extra array into getcreditcurve which will be used to store the result. This is called an output parameter.
void getcreditcurve(double*, double *);
This would solve the "scope" problem. The caller (main) would then create the array before calling getcreditcurve and would then pass that to getcreditcurve. As a result, getcreditcurve does not have to take responsibility for creating (or destroying) any object.
double I1[5];
getcreditcurve(I1, C1); // will store its result on `I1`.
This might be the easiest option if you really really need to get this working as soon as possible.
If you are willing to make some further changes, you can make a much safer program. The short term goal is to abolish all uses of * (except to use it for multiplication).
C arrays cannot be passed by value, in particular they cannot be returned. There are other funky things you can do (passing special pointers), but the best thing to do with C arrays is to pass them by reference. In C++, reference-passing behaviour is quite consistent and works well.
// http://stackoverflow.com/questions/31362360/unexpected-value-return-by-array-variable
#include<iostream>
#include<cmath>
#include<fstream>
typedef double S1[5];
using namespace std;
/* In the following declaration, the two parameters
* are taken by reference (note the '&').
* This is almost always the best way to pass arrays.
*
* Also, this is a template where N is automatically
* set to the correct number of parameters. This nice
* automatic behaviour is possible only because the
* array is taken by reference.
*
* Finally, note that the second reference, for 'input',
* has 'const'. This is to emphasize that 'input' is for input,
* that getcreditcurve will not be allowed to modify the input argument.
*/
template<size_t N>
void getcreditcurve(double (&output)[N],const double (&input)[N]);
int main()
{
/* S1 is the type - array of five doubles */
/* Here declare and initialize C1 and C2 as two variables
* of this type */
S1 C1 = { 0.0029, 0.0039, 0.0046, 0.0052, 0.0057 };
S1 C2 = { 0.0020, 0.0050, 0.0060, 0.0070, 0.0080 };
// create the two output arrays first, within main
S1 I1;
S1 I2;
// call getcreditcurve, passing in the output and input arrays
getcreditcurve(I1,C1);
getcreditcurve(I2,C2);
ofstream print;
/* you can't create Excel(.xls) files in C++ easily
* Better to just create a .csv file instead
* csv = comma-separated values
*/
print.open("result1.csv");
print << I1[0] << ',' << I2[3] << endl;
print.close();
return 0;
}
template<size_t N>
void getcreditcurve(double (&output)[N],const double (&input)[N])
{
output[0] = 2 * input[0];
output[1] = 3 * input[1];
output[2] = 4 * input[2];
output[3] = 5 * input[3];
output[4] = 6 * input[4];
}
But seriously, you really should just ditch C arrays entirely. This is C++, not C. Use std::vector<double> instead.

Initializing typedef struct from C library properly in C++

I want to include a library in my C++ project (controls RGB LED strips on the Raspberry Pi).
Importing the library is working fine but I have quite the issue with properly initializing some structs. I'm pretty lost where to even find the proper syntax, I did a lot of googling but didn't get very far.
What I want to at first is getting the sample application going that comes with the library. See: https://github.com/richardghirst/rpi_ws281x/blob/master/main.c
My main issue is this. How do I do what is done below the C++ way?
ws2811_t ledstring =
{
.freq = TARGET_FREQ,
.dmanum = DMA,
.channel =
{
[0] =
{
.gpionum = GPIO_PIN,
.count = LED_COUNT,
.invert = 0,
.brightness = 255,
},
[1] =
{
.gpionum = 0,
.count = 0,
.invert = 0,
.brightness = 0,
},
},
};
The way this is initialized is C specific and doesn't compile in any current C++ standard. See: Why does C++11 not support designated initializer list as C99?
So far I only ever used my own structs and also never used typedef, so I'm just confused the way structs are defined here.
The struct(s) that gets initialized above is defined in this way. See: https://github.com/richardghirst/rpi_ws281x/blob/master/ws2811.h
typedef struct
{
int gpionum; //< GPIO Pin with PWM alternate function
int invert; //< Invert output signal
int count; //< Number of LEDs, 0 if channel is unused
int brightness; //< Brightness value between 0 and 255
ws2811_led_t *leds; //< LED buffers, allocated by driver based on count
} ws2811_channel_t;
typedef struct
{
struct ws2811_device *device; //< Private data for driver use
uint32_t freq; //< Required output frequency
int dmanum; //< DMA number _not_ already in use
ws2811_channel_t channel[RPI_PWM_CHANNELS];
} ws2811_t;
What I tried was this:
ws2811_led_t matrix[WIDTH][HEIGHT];
ws2811_channel_t channel0 = {GPIO_PIN,LED_COUNT,0,255,*matrix};
ws2811_t ledstring = {nullptr,TARGET_FREQ,DMA,channel0};
That compiles but results in a malloc error when I come to actually "render" to the LED strip:
int x, y;
for (x = 0; x < WIDTH; x++)
{
for (y = 0; y < HEIGHT; y++)
{
cout << "LEDs size: " << (y * WIDTH) + x << endl;
ledstring.channel[0].leds[(y * WIDTH) + x] = matrix[x][y];
}
}
Results in this error message after the loop construct finishes:
malloc(): memory corruption (fast): 0x021acaa8
You should be able to use use following initializer:
ws2811_t ledstring =
{
nullptr,
TARGET_FREQ,
DMA,
{
{ GPIO_PIN, 0, LED_COUNT, 255 },
{ 0 }
}
};
This line
ledstring.channel[0].leds[(y * WIDTH) + x] = matrix[x][y];
is almost certainly the cause of the memory corruption, as that can only happen by either a buffer overrun or dereferencing an invalid (but non-NULL) pointer.
I see some problems in this code
ws2811_channel_t channel0 = {GPIO_PIN,LED_COUNT,0,255,*matrix};
ws2811_t ledstring = {nullptr,TARGET_FREQ,DMA,channel0};
First, in the initializer for channel0 you are setting the leds field to the contents of matrix[0][0] rather than its address. You need to change the final initializer to be simply matrix.
Next, you are initializing channel0.leds to point to the two dimensional array matrix, but treating it as a single dimensional array in ledstring.channel[0].leds[(y * WIDTH) + x]. This should probably be ledstring.channel[0].leds[x][y].
Finally, the last initializer for ledstring should probably be {channel0} for clarity. That's not a big issue, but it allows you to initialize more than one entry in the array.

How to get VC++ to access a pointer as a 2D array

I'm doing a little graphics programming and I have a two dimentional array (that varies in size during program execution) that I store using openGL.
So when I go to access it, all I get is a void pointer back.
To make the logic easier, I want the compiler to pretend that it is, and use it as, a 2D array (because arr[i][j] is more concise and less error prone than ptr[i * y + j]).
This clever method of casting I found works fine in GCC (on the linux machines at uni):
Vertex (&vertices)[tess][tess] = *reinterpret_cast<Vertex (*)[tess][tess]>(
glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY)
);
Which basically casts the block of memory pointer openGL gave me to a tess X tess 2D array, and creates a reference of that type to point at it.
This allows me to access the memory like vertices[i][j].
Vertex is just a typedefed struct containing floats
However, at home on my Windows machine, VS'12 has a hissy fit, complaining that it requires the integers where tess is written to be constant (specifically; error C2057: expected constant expression).
I have no idea why.
Now, I understand that VS doesn't support VLA's, but I am not creating an array here, I'm creating a reference to something that I don't know the size of 'till runtime.
So it shouldn't care if the size changes between function calls, right? Why is this not allowed?
Not to be deterred I tried using std::array
std::array<std::array<Vertex, tess>, tess>& vertices;
And apart from the obvious references must be initialized this test didn't help me because it still complained about expression must have a constant value (specifically; error C2975: '_Size' : invalid template argument for 'std::array', expected compile-time constant expression)
I am at a loss at what to try here, I was so proud of the reinterpret_cast and how simple it made things and was sure I wasn't using a method that was contravening the standard.
I don't want to create a std::vector from the pointer then copy the data from that dynamic array back into the pointer location when I'm finished; that just seems so inefficient when the memory block is already just sitting there!
There's no way to create a vector around a pre-existing block of memory, is there? ..no that sounds silly.
I want to see if this can be done without giving up and just using it as Vertex*; Ideas?
Can someone enlighten me as to why it isn't working in VS?
Is there something I can do to get it working (extensions/updates to VS)?
Does VS'13 add support for this?
I am also getting the error C2087: 'vertices' : missing subscript that I can't explain.
As well as these other errors that seem to show VS desperately wants tess to be constant:
error C2466: cannot allocate an array of constant size 0
error C2540: non-constant expression as array bound
error C2440: 'initializing' : cannot convert from 'Vertex [1][1]' to 'Vertex (&)[][1]'
Well that was fun; I implemented a class to handle exactly what I wanted.
It's not as typesafe as I'd like, but I learned a lot doing it
Much like how I felt implementing should-be-a-part-of-the-specification, syntactic-sugar-esque functionality for javascript before I discovered jQuery.
Basically, instead of being able to do this.
int (&array)[x][y] = *reinterpret_cast<int (*)[x][y]>(pointer);
You will have to do this
MDAI<int, 2> array = MDAI<int, 2>(pointer, x, y);
But other than that it works flawlessly! :D
I initially wrote just a specialised TwoDArray class but found I actually had some 3D arrays too.
So instead of implementing a 3D version (that returned TwoDArray when you drilled down) I made something more generic and can help with arrays of as many dimensions as you'd like.
#include <Windows.h>
#include <iostream>
/*MultiDimensional Array Interpretation
has the compiler use a flat pointer reference as if it were a faceted array
C++11/GCC VLA-supporting equivalent:
int (&array)[x][y] = *reinterpret_cast<int (*)[x][y]>(pointer);
using MDAI, <C++11 and MSVS compatible:
MDAI<int, 2> array = MDAI<int, 2>(pointer, x, y);
*/
template<class Type, unsigned int dimension>
class MDAI {
private:
Type* array;
//+1 to guard against zero-length-array
unsigned int bounds[dimension + 1];
public:
//unfortunately I can't use `unsigned int &(dimensions)[dimension]` to make it safe
//because of how operator[]() tries to construct its return value
/*constructor*/
MDAI(Type* array, unsigned int* bounds)
: array(array)
{
std::copy(bounds, bounds + dimension, this->bounds);
}
/*programmer usable constructor for typing of the dimensions, instead of having to declare an array*/
MDAI(Type* array, ...)
: array(array)
{
va_list arguments;
va_start(arguments, array);
for (int index = 0; index < dimension; ++index)
bounds[index] = va_arg(arguments, unsigned int);
va_end(arguments);
}
/*drills down one level into the multi dimensional array*/
MDAI<Type, dimension - 1> operator[](unsigned index) {
if (dimension < 1) {
std::cerr << "MDAI is not an array.\n";
throw 1;
}
if (index < 0 || index >= bounds[0]) {
std::cerr << "Index out of bounds.\n";
throw 1;
}
//figure out how many addresses to jump
for (unsigned int index2 = 1; index2 < dimension; ++index2)
index *= bounds[index2];
return MDAI<Type, dimension - 1>(array + index, bounds + 1);
}
/*'dereferences' the array to get a reference to the stored value*/
Type& operator*() {
if (dimension > 0) {
std::cerr << "MDAI is an array.\n";
throw 1;
}
return *array;
}
/*allows the compiler to automagically 'convert' the MDAI into whatever the user thinks it is*/
operator Type&() {
return **this;
}
/*makes assignment work automagically too!*/
MDAI<Type, dimension>& MDAI<Type, dimension>::operator=(Type value) {
**this = value;
return *this;
}
};
Testing a three-dimensional array of bounds 2-4-3:
void main(unsigned int argC, char** argV) {
using namespace std;
int array[2][4][3] = {
{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
{10, 11, 12}
},
{
{13, 14, 15},
{16, 17, 18},
{19, 20, 21},
{22, 23, 24}
}
};
//cast array to pointer, then interpret
MDAI<int, 3> mdai((int*)array, 2, 4, 3);
//testing correct memory access
cout << 15 << ' ' << mdai[1][0][2] << endl;
//testing modifcations using mdai are in array
mdai[0][2][1] = -1;
cout << array[0][2][1] << ' ' << mdai[0][2][1] << endl;
//testing modifications in array show up in mdai
array[1][3][2] = -23;
cout << -23 << ' ' << mdai[1][3][2] << endl;
//testing automatic type casting
cout << -15.0 << ' ' << mdai[0][0][1] * -7.5 << endl;
}
It's as seamless as it would have been had I left it as an array reference.
For compile-time safety I wanted to have redeclare operator*() as, specifically;
Type& MDAI<Type, 0>::operator*()
so you could only call it on a <X, 0>
But I couldn't figure it out.
Similarly get operator[]() to only appear for dimensions greater than 0
Oh well, runtime checking will have to be good enough