Returning 2D array pointer from class - c++

I've got a class called Engine which holds and returns a buffer like so:
template <int width, int height, int meshSize>
class Engine {
public:
byte buffers[2][width][height];
byte fBuffer = 0;
byte** getBuffer() {
return buffers[fBuffer];
};
}
and I want to loop through the values in my main, but I can't seem to get it working..
byte* buff;
// main
buff = engine->getBuffer();
for (int x = 0; x < 320; x++) {
for (int y = 0; y < 320; y++) {
if (buff[x][y] != NULL) {
Serial.println(buff[x][y]);
}
// lcd.drawPixel(x, y, RGB(buff[x][y], buff[x][y], buff[x][y]));
}
}
What combination of asterisk and/or parenthesis will work?

You should return a reference to your array, rather than a pointer. I also recommend providing a const overload of getBuffer for read-only operations.
template <int width, int height, int meshSize>
class Engine {
public:
using BufferType = byte[width][height];
BufferType const& getBuffer() const {
return buffers[fBuffer];
};
BufferType& getBuffer() {
return buffers[fBuffer];
};
private:
BufferType buffers[2];
byte fBuffer = 0;
};
You can use auto to deduce this type when calling getBuffer for brevity:
auto& buff = engine->getBuffer(); // reference to the buffer

Related

Passing pointers of vectors with structures C++

I've declared the following function in C++
void setCellInfo (CELL_MESH* target, int Global_ID, int node0,vector<NODE_MESH *>* NodeStore, vector<CELL_MESH *>* CellStore) {
CellStore->push_back(target); //No Errors
target->Global_ID = Global_ID; //No Errors
if (node0 != 0) {
target->node[0] = NodeStore[vector<NODE_MESH *>::size_type(node0)]->ID; //ERROR 1
target->node_pointers[0] = NodeStore[vector<NODE_MESH *>::size_type(node0)]; //ERROR 2
}
}
ERROR1: Gives me a "No member named 'ID' in 'std::vector<NODE_MESH *>'" for the target->node[] attributions although its the entities from the pointers within the vector that have this ID member. Since I'm trying to get a specific entity in the vector using NodeStore[value], I would think it would work.
ERROR2: Gives me "Assigning to 'NODE_MESH *' from incompatible type 'vector<NODE_MESH *>'" for all the target->node_pointers attributions. This seems to be the same problem but with pointers directly (without the ID member).
the NodeStore and CellStore vectors a defined as follows outside the function
vector<NODE_MESH*> NodeStore;
vector<CELL_MESH*> CellStore;
I then try to use the function like this, with 'i' being the int Global_ID and 'nodes_x*y+x' being some integer.
CELL_MESH *newCell = new CELL_MESH;
setCellInfo (&newCell, i, nodes_x*y+x, &NodeStore, &CellStore);
I've tried many different alterations to pointers but can't get it work. Would you know how to ?
Here's a simplified complete version:
#include <vector>
using namespace std;
typedef struct NODE_MESH{
int ID;
}NODE_MESH;
typedef struct CELL_MESH{
int Global_ID;
NODE_MESH* node_pointers[4];
int node[4];
}CELL_MESH;
vector<NODE_MESH*> NodeStore;
vector<CELL_MESH*> CellStore;
double nodes_y = 5;
double nodes_x = 4;
int cells_y = 4;
int cells_x = 3;
void setCellInfo (CELL_MESH* target, int Global_ID, int node0,vector<NODE_MESH *>* NodeStore, vector<CELL_MESH *>* CellStore) {
CellStore->push_back(target); //No Errors
target->Global_ID = Global_ID; //No Errors
if (node0 != 0) {
target->node[0] = NodeStore[vector<NODE_MESH *>::size_type(node0)]->ID; //ERROR 1
target->node_pointers[0] = NodeStore[vector<NODE_MESH *>::size_type(node0)]; //ERROR 2
}
}
int main() {
int i = 0;
for (double y = 0; y < nodes_y; y++) {
for (double x = 0; x < nodes_x; x++) {
NODE_MESH *newNode = new NODE_MESH;
NodeStore.push_back(newNode);
newNode -> ID = i;
i++;
}
}
i = 0;
for (int y = 0; y < cells_y; y++) { //nodes_y since horizontal faces are aligned with nodes horizontaly (same y)
for (int x = 0; x < cells_x; x++) { //x coordinate for horizontal faces is in-between nodes so 0.5 with count for faces
CELL_MESH *newCell = new CELL_MESH;
setCellInfo (newCell, i, nodes_x*y+x, &NodeStore, &CellStore);
i++;
}
}
return 0;
}
Given a variable T* t, the syntax t[x] is equivalent to *(t+x), which is the cause of this confusion. Concretely, NodeStore[vector<NODE_MESH *>::size_type(node0)] is of type vector<NODE_MESH *>& instead of an element of the NodeStore as you expected.
Change your code to take variables by reference instead:
void setCellInfo (CELL_MESH* target, int Global_ID, int node0,vector<NODE_MESH *>& NodeStore, vector<CELL_MESH *>& CellStore) {
CellStore->push_back(target); //No Errors
target->Global_ID = Global_ID; //No Errors
if (node0 != 0) {
target->node[0] = NodeStore[node0]->ID;
target->node_pointers[0] = NodeStore[node0];
}
}
The call is then simply
setCellInfo (&newCell, i, nodes_x*y+x, NodeStore, CellStore);
Alternatively, you will need to dereference the pointer before indexing:
(*NodeStore)[node0]->ID
Final Solution:
void setCellInfo (CELL_MESH* target, int Global_ID, int node0,vector<NODE_MESH *>& NodeStore, vector<CELL_MESH *>& CellStore) {
CellStore.push_back(target);
target->Global_ID = Global_ID;
if (node0 != 0) {
target->node[0] = NodeStore[node0]->ID;
target->node_pointers[0] = NodeStore[node0];
}
}
With this when using it:
CELL_MESH *newCell = new CELL_MESH;
setCellInfo (newCell, i, nodes_x*y+x, NodeStore, CellStore);

How to use vector<MyObject> with ImGui::ListBox?

I'm trying to display a vector of objects in a listbox that will be rendered dynamically in every frame.
This is my class and I want to display every attribute later in the listbox:
class Waypoint {
public:
int x, y, z;
char action;
};
What I'm trying now as I don't really know is this:
Waypoint wp1;
wp1.action = 'R';
wp1.x = 100;
wp1.y = 100;
wp1.z = 7;
Waypoint wp2;
wp2.action = 'S';
wp2.x = 100;
wp2.y = 100;
wp2.z = 6;
std::vector<Waypoint> listbox_items { wp1, wp2 };
static int listbox_item_current = 1;
ImGui::ListBox("listbox::Cavebot", &listbox_item_current, listbox_items);
Of course this is not working, and I'm getting this error:
E0304 no instance of overloaded function "ImGui::ListBox" matches the argument list
How can I display dynamically all my objects attributes in the listbox?
ImGui::ListBox takes a char* as a displayed text, so you could not use a single char. You should re-design your class like this:
class Waypoint {
public:
int x, y, z;
std::string action;
};
Then use this function:
bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(void*, int, const char**), void* data, int items_count, int height_in_items)
Example:
bool waypoint_getter(void* data, int index, const char** output)
{
Waypoint* waypoints = (Waypoint*)data;
Waypoint& current_waypoint = waypoints[index];
*output = current_waypoint.action.c_str(); // not very safe
return true;
}
ImGui::ListBox(
"listbox::Cavebot",
&listbox_item_current,
waypoint_getter,
listbox_items.data(),
listbox_items.size()
);

how to solve invalid types for array subscript error?

I'm trying to pass a 3D array to function and change it's values. The problem is that I get an error: invalid types 'unsigned char[int]' for array subscript.
Code in main:
unsigned char image[height][width][BYTES_PER_PIXEL];
setBlankImage((unsigned char*)image, width, height);
Function code:
void setBlankImage(unsigned char *image, int width, int height){
for(int i = 0; i < height; ++i){
for(int j = 0; j < width; ++j){
image[i][j][2] = 0;
image[i][j][1] = 0;
image[i][j][0] = 0;
}
}
}
Any suggestions?
There are at least 3 methods of passing an array:
Using array notation.
Using std::vector<std::vector<std::vector<int>>>
Pointer to the first location.
Your code is using method 3 above. Since it's a pointer to a single location, you'll have to adjust the pointer to the appropriate cell using linear algebra (see my comments).
The simplest method is to use std::vector.
The first option would work with your code:
void setBlankImage(int image[][256][256]);
If you can freely change the type of image and its dimensions are known at compile-time, I'd suggest doing something like this:
#include <array>
#include <iostream>
template <typename T, size_t Width, size_t Height, size_t Depth>
using My3DArray = std::array<std::array<std::array<T, Depth>, Height>, Width>;
template <typename T, size_t Width, size_t Height, size_t Depth>
void setBlankImage(My3DArray<T, Width, Height, Depth>& arr, T value = 0){
for(auto& slice0: arr) {
for(auto& slice1: slice0) {
for(auto& elem: slice1) {
elem = value;
}
}
}
}
int main()
{
My3DArray<int, 4, 3, 2> arr;
arr[0][0][0] = 42;
std::cout << arr[0][0][0] << std::endl;
try {
arr.at(3).at(2).at(1) = 43; // OK
arr.at(3).at(2).at(2) = 44; // Exception
arr[3][2][2] = 45; // Good old SEGFAULT
}
catch(const std::out_of_range& e) {
std::cout << "There's even OOB check, sweet!" << std::endl << e.what() << std::endl;
return -1;
}
return 0;
}
Here, image is declared with type unsigned char***:
unsigned char image[height][width][BYTES_PER_PIXEL];
Here, you cast it to a unsigned char* before invoking your function:
setBlankImage((unsigned char*)image, width, height);
You should change the parameter to be of type unsigned char***.

C++ - Need to pass a 2D array, but must be dynamically sized

I am using a C++ library that requires that I pass it a 2D array. Their code example gives a statically sized array like this:
double data[][2] = {
{ 10, 20, },
{ 13, 16, },
{ 7, 30, },
{ 15, 34, },
{ 25, 4, },
};
But I need to pass run-time sized data. So I was attempting to do this:
// unsigned numBins is passed in to this function and set at run time
double** binData = new double*[numBins];
for(unsigned i=0; i < numBins; ++i) {
binData[i] = new double[2];
}
//Set the data with something like
// binData[7][0] = 10;
// binData[7][1] = 100;
//Later, diligently delete my data...
However, this fails in the library I am using. It ends of graphing some garbage numbers.
I understand that arrays are not pointers. And the library may be getting confused doing a "sizeof" somewhere.
If I am unable to change this library (it's 3rd party), how do I go about passing it dynamically sized data?
Thanks,
Maddie.
Probably the API expects a pointer to the first element of what it assumes is a flattened representation of a 2D array.
So the easy approach is as follows:
template<typename T>
struct FlatVectorAs2D {
private:
size_t width;
size_t height;
std::vector<T> flat_vec;
public:
std::vector<T>& base() { return flat_vec; }
std::vector<T> const& base() const { return flat_vec; }
size_t w() const { return width; }
size_t h() const { return height; }
T* operator[]( size_t index1 ) {
return &flat_vec[index1*height];
}
T const* operator[]( size_t index1 ) const {
return &flat_vec[index1*height];
}
FlatVectorAs2D( size_t w = 1, size_t h = 1 ):width(w), height(h) {
flat_vec.resize(w*h);
}
void resize( size_t w, size_t h ) {
width = w;
height = h;
flat_vec.resize(w*h);
}
T* raw() { return flat_vec.data(); }
T const* raw() const { return flat_vec.data(); }
};
Use:
void api_function(double* d);
int main() {
size_t width = 50;
size_t height = 100;
FlatVectorAs2D<double> buffer( width, height );
buffer[0][1] = 1.0;
api_function( buffer.raw() );
}
naturally this will depend on how exactly the API works.
But if my guess is right, this will help.
Try this:
typedef double two_doubles[2];
int main()
{
two_doubles * p = new two_doubles[300];
// ...
delete[] p;
}
Now p points to the first subarray of an array of 200 units of two doubles. That is, p[i] is a double[2], and p[i][0], p[i][1] are its member elements.
(Even better to use std::unique_ptr<two_doubles[]> p(new two_doubles[300]); and forget about the memory management.)

Weird error in Turbo C++ IDE - Class template related question

Basically I'm trying to compile a template class which is meant to represent a table for adding up polynomials. As a result of this the table needs to be nullable.
This is the sort of thing I am trying to represent http://www.mathsisfun.com/algebra/polynomials-adding-subtracting.html.
And this is the template which is meant to do it:
template <class T> class TableWithBlanks : public Table<T> {
public:
TableWithBlanks( const int width, const int height ) : w(width), h(height), table_contents( new t_node[width][height]
{
table_contents = new t_node[width][height];
// Go through all the values and blank them.
for( int i = 0; i < w; i++)
{
for( int a = 0; a < h; a++)
{
table_contents[i][a].value_ptr = NULL;
}
}
}
void set_value( const int width, const int height, const T* table_value_ptr)
{
if( width <= w && height <= h )
{
table_contents[w][h] = table_value_ptr;
}
}
T* get_value( const int width, const int height)
{
if( width <= w && height <= h )
{
return table_contents[width][height];
}
}
private:
typedef struct node {
T* value_ptr;
} t_node;
t_node** table_contents;
int w;
int h;
};
And this is the error I am getting:
[C++ Error] TableWithBlanks.h(16):
E2034 Cannot convert
'TableWithBlanks::node
( *)[1]' to
'TableWithBlanks::node
* *'
The PolynomialNode class is a class which is a linked list, where each node in the list represent the terms in a simple polynomial - I don't need to go into details.
In this line, you're trying to dynamically construct a two-dimensional array:
table_contents = new t_node[width][height];
but C++ doesn't work this way. For an example of how to allocate two-dimensional arrays, see this question, for example.