c++ array of uint8 buffers - c++

In C++, I have an uint8 buffer of the length [len]. When allocating a single buffer I do this:
uint8 *buffer= new uint8[len];
What's the syntax for allocating an array of such buffers? This gives me a syntax error:
uint8** buffers = new uint8[len]*[bufferCount];

The way you initialize a 2d array is as follows:
uint8** buffers = new uint8*[bufferCount];
for (int i = 0; i < bufferCount; i++)
buffers[i] = new uint8[len];

#include <vector>
using byte_vector = std::vector<uint8_t>;
using byte_vector_vector = std::vector<byte_vector>;
// example of a 1-dimension vector
auto v1 = byte_vector(len, inital_value);
// example of a [2, len] vector
auto v_of_v = byte_vector_vector {
byte_vector(len, initial_value),
byte_vector(len, initial_value)
};
// print the uint8 at (0,1)
std::cout << v_ov_v[0][1] << std::endl;

You asked
What's the syntax for allocating an array of such buffers?
You can use:
uint8** buffers = new uint8*[bufferCount];
However, use this only if std::vector is absolutely not an option for some reason.

Related

memcpy copies more than expected when using modern C++ syntax

int vertexCount = 5;
std::vector<DirectX::XMVECTOR> vertices(vertexCount);
for (int i = 0; i < vertexCount; ++i) {
vertices[i] = DirectX::XMVectorSet(i, i, i,0);
}
/*1-*/ std::shared_ptr<void> vertexData = std::make_shared<DirectX::XMVECTOR*>(new DirectX::XMVECTOR[vertexCount]);; //this works
/* 2-*/ std::shared_ptr<void> vertexData = std::make_shared<std::vector<DirectX::XMVECTOR>>(vertexCount); // this doesnt work why??
memcpy(vertexData.get(), pxVertices.data(), vertexCount * sizeof(DirectX::XMVECTOR));
when I use C-style array syntax memcpy works fine, but when I create the shared pointer using modern C++ style I get an overflow, I mean in this example the new capacity is [capacity] = 66584576, before the memcpy it had size of 5 !
so what went wrong?

ROS C++ MultiArray initialize and fill with values

I want to publish a 3D array as a std_msgs::Float32MultiArray in ROS. It should have the dimensions [1920,1080,10], which corresponds to [image_width, image_height, depth].
However, I didn't find a clear documentation on how to initialize and fill this multi-array. Here is what I did so far:
std_msgs::Float32MultiArray my_array;
my_array.layout.dim.push_back(std_msgs::MultiArrayDimension());
my_array.layout.dim[0].label = "width";
my_array.layout.dim[0].size = 1920;
my_array.layout.dim.push_back(std_msgs::MultiArrayDimension());
my_array.layout.dim[1].label = "height";
my_array.layout.dim[1].size = 1080;
my_array.layout.dim.push_back(std_msgs::MultiArrayDimension());
my_array.layout.dim[2].label = "depth";
my_array.layout.dim[2].size = 10;
my_array.layout.data_offset = 0;
my_array.data.clear();
// Initialize the data with 0
// ???
// Fill in values from a list to this array
// PSEUDOCODE
for (point &p : 3d_points_buffer)
{
// Fill the array like this:
//my_array[p.x, p.y, p.z] = p.value;
//???
}
Unfortunately, this is as far as I get. Could anyone show me how I could initialize the whole data array with zeros and how to set a specific entry my_array[x,y,z] to a certain value?
Thank you very much!

A heap has been corrupted after populating another 2d array

I am writing a program where I need to take 2 text files and see where the smaller image is inside the bigger one. For this I need to use 2 dimensional arrays. This has all been going fine when I was just using one however now that I have populated the second array with the data from the smaller image I am getting an error saying:
Unhandled exception at 0x77338519 (ntdll.dll) in Wheres Wally.exe:
0xC0000374: A heap has been corrupted (parameters: 0x773758A0).
I have managed to narrow it down to one line in particular which is when the second array is actual given values
//Array Containing Initial Values Of The Base Image
double* baseImage = new double(largeImageRowSize * largeImageCollumnSize);
//Array Containing Values Of The Small Image
double* wallyImage = new double(smallImageRowSize * smallImageCollumnSize);
//Fill BaseImage with all values from the text file
baseImage = read_text("Cluttered_scene.txt", 1024, 768);
//Allocate 36 arrays for each row (so 49x36 arrays)
for (int i = 0; i < getLargeRowSize(); i++)
a2dArray[i] = new double[getLargeCollumnSize()];
//Put data of image into 2d array
int largeImageCounter = 0;
for (int y = 0; y < getLargeCollumnSize(); y++) {
for (int x = 0; x < getLargeRowSize(); x++) {
a2dArray[y][x] = baseImage[largeImageCounter];
largeImageCounter++;
//cout << a2dArray[x][y];
}
}
//Fill wallyImage array with all values of the small wally text file
wallyImage = read_text("Wally_grey.txt", 49, 36);
//Allocate 36 arrays for each row (so 49x36 arrays)
for (int i = 0; i < getSmallRowSize(); i++)
a2dArrayForWally[i] = new double[getSmallCollumnSize()];
//Put data of image into 2d array
int smallImageCounter = 0;
for (int y = 0; y < getSmallCollumnSize(); y++) {
for (int x = 0; x < getSmallRowSize(); x++) {
a2dArrayForWally[y][x] = wallyImage[smallImageCounter];
smallImageCounter++;
//cout << a2dArray[x][y];
}
}
The line giving the error is within the final for loop
a2dArrayForWally[y][x] = wallyImage[smallImageCounter];
So obviously this is something to do with where the memory is being stored, but I'm new to C++ and after googling I cant seem to find whats wrong with my code.
Any help would be greatly appreciated!
Edit:
Through trying to solve the error myself I have discovered that the issue arises when the smallImageCounter reaches 430. Before that data is stored with no issues
You confused new double() with new double[]. The first one allocates a single double and initializes it to the value from the parenthesis, where the second one allocates a dynamic array of doubles of a size from the square brackets.
Change:
double* baseImage = new double(largeImageRowSize * largeImageCollumnSize);
double* wallyImage = new double(smallImageRowSize * smallImageCollumnSize);
to:
double* baseImage = new double[largeImageRowSize * largeImageCollumnSize];
double* wallyImage = new double[smallImageRowSize * smallImageCollumnSize];

How to use memset or fill_n to initialize a dynamic two dimensional array in C++

I have a 2D array created dynamically.
int **abc = new int*[rows];
for (uint32_t i = 0; i < rows; i++)
{
abc[i] = new int[cols];
}
I want to fill the array with some value (say 1). I can loop over each item and do it.
But is there a simpler way. I am trying to use memset and std::fill_n as mentioned in this post.
std::fill_n(abc, rows * cols, 1);
memset(abc, 1, rows * cols * sizeof(int));
Using memset crashes my program. Using fill_n gives a compile error.
invalid conversion from 'int' to 'int*' [-fpermissive]
What am I doing wrong here ?
You could just use vector:
std::vector<std::vector<int>> abc(rows, std::vector<int>(cols, 1));
You cannot use std::fill_n or memset on abc directly, it simply will not work. You can only use either on the sub-arrays:
int **abc = new int*[rows];
for (uint32_t i = 0; i < rows; i++)
{
abc[i] = new int[cols];
std::fill_n(abc[i], cols, 1);
}
Or make the whole thing single-dimensional:
int *abc = new int[rows * cols];
std::fill_n(abc, rows*cols, 1);
Or I guess you could use std::generate_n in combination with std::fill_n, but this just seems confusing:
int **abc = new int*[rows];
std::generate_n(abc, rows, [cols]{
int* row = new int[cols];
std::fill_n(row, cols, 1);
return row;
});
I think that your main problem here is that you don't have an array of int values. You have an array of pointers to ints.
You probably should start with int* abc = new int[rows * cols]; and work from there, if I understand what you are trying to achieve here.
Just use with * inside the loop you already have:
for (uint32_t i = 0; i < rows; i++)
{
abc[i] = new int[cols];
std::fill_n(*(abc+i), cols, sizeof(int));
}
fill_n don't know where the memory maps the new int array, so you must be carefully coding that way.
I recommend to read:
A proper way to create a matrix in c++
Since you've already got good, workable answers to solve your problem, I want to add just two pointers left and right from the standard path ;-)
a) is just a link to the documentation of Boost.MultiArray
and b) is something I don't recommend you use, but it might help you to understand what you've initially tried. And since your profile shows visual studio tags, you might come in contact with something like this in the win32 api. If that is the case the documentation usually tells you not to use free()/LocalFree()/... on the elements and the "outer" pointer-pointer but to use a specialized function.
(note: I'm not trying to make this code look pretty or clever; it's a mishmash of c and a little c++-ish junk ;-))
const std::size_t rows = 3, cols =4;
int main()
{
std::size_t x,y;
// allocate memory for 0...rows-1 int* pointers _and_ cols*rows ints
int **abc = (int**)malloc( (rows*sizeof(int*)) + cols*rows*sizeof(int) );
// the memory behind abc is large enough to hold the pointers for abc[0...rows-1]
// + the actual data when accessing abc[0...rows-1][0....cols-1]
int* data = (int*)((abc+rows));
// data now points to the memory right after the int*-pointer array
// i.e. &(abc[0][0]) and data should point to the same location when we're done:
// make abc[0] point to the first row (<-> data+(cols*0)), abc[1] point the second row (<-> data+(cols*1)....
for(y=0;y<rows; y++) {
abc[y] = &(data[y*cols]);
}
// now you can use abc almost like a stack 2d array
for(y=0; y<rows; y++) {
for (x=0; x<cols; x++) {
abc[y][x] = 127;
}
}
// and -since the memory block is continuos- you can also (with care) use memset
memset(&abc[0][0], 1, sizeof(int)*rows*cols);
// and with equal care ....
std::fill_n( &(abc[0][0]), rows*cols, 127);
// and get rid of the whole thing with just one call to free
free(abc);
return 0;
}

Dynamically allocating 2D int array

Can someone please point out what I am doing wrong in the following code?
int* a = NULL;
int* b = NULL;
a = new int[map->mapSize.width];
b = new int[map->mapSize.height];
layer->tileGids = new int[a][b];
Here's what the code uses:
typedef struct _size {
int width, height;
} size;
class Map {
size mapSize;
}
class Layer {
int * tileGids;
}
EDIT: Compiler-Errors (in line 6 of the first bit of code):
error: expression in new-declarator must have integral or enumeration type|
error: 'b' cannot appear in a constant-expression|
Solution:
I have decided to accept lightalchemist's answer. In essence, what works for me is use a vector instead of the array. Vector manages the memory for you and hence is a lot easier to deal with.
You can't pass a pointer for initializing the size of an array. Others have now mentioned this.
This post (it's not mine) seems like it might help you: http://eli.thegreenplace.net/2003/07/23/allocating-multi-dimensional-arrays-in-c/
You should also consider doing the allocation in the class Layer's constructor and then deleting the memory in it's destructor (i.e. RAII - resource acquisition is initialization). This is considered good style.
Finally, you might consider using continuous memory and a custom indexing scheme, which you could easily use Layer to encapsulate. This of course depends upon how big things will get. The bigger they get the better the case for continuous memory becomes.
This should give you a flavor.
#include <iostream>
#include <cstdlib>
int main()
{
const size_t ROWS = 5;
const size_t COLS = 2;
const size_t size = ROWS*COLS;
int* arr = new int[size];
int i = 0;
for ( size_t r = 0 ; r < ROWS; ++r )
{
for (size_t c = 0; c < COLS; ++c )
{
arr[r*COLS+c] = i++;
}
}
for ( int j = 0; j < i; ++j)
{
std::cout << arr[j] << std::endl;
}
delete [] arr;
}
Firstly, your variables "a" and "b" are pointers. Your code:
layer->tileGids = new int[a][b]
is the root cause of the problem.
I'm trying to guess your intention here and I think what you are trying to do is make layer.tileGids a 2 dimension array to reference a "grid" of size (mapSize.Width, mapSize.height) so that you can refer to each "cell" in the grid using layer.tileGids[x][y].
If you are indeed trying to create a 2 dimension array, there are 2 methods to do it.
Method 1:
class Layer {
int ** tileGids; // NOTE the "**" to indicate tileGids is a pointer to pointer i.e. 2D array.
}
To initialize it:
int width = map->mapSize.width;
int height = map->mapSize.height;
layer.tileGids = new int*[width]; // NOTE the "int*" to indicate tileGids is a new array of pointers to int.
for (int i = 0; i < width; i++) // Initialize each element in layer.tileGids[] to be a pointer to int.
{
layer.tileGids[i] = new int[height];
}
Now you can access the items in layer.tileGids using:
int value = layer.tileGids[x][y] // where 0 <= x < width and 0 <= y < height
To deallocate this data structure, similar to how you allocate it, you need to deallocate each dynamically allocated array in each "row":
for (int i = 0; i < width; i++)
{
delete [] layer.tileGids[i]; // Deallocate each row.
}
delete [] layer.tileGids; // Deallocate "array" to the pointers itself.
Method 2:
Now another easier, less messy method (avoid pointers) is to use the C++ vector class. You need to make the following changes:
#include <vector>
class Layer {
vector<vector<int> > tileGids; // Note the space at "<int> >".
}
To initialize:
int width = map->mapSize.width;
int height = map->mapSize.height;
layer.tileGids = vector<vector<int> >(width, vector<int>(height, 0)); // Initialize all entries to 0.
To access the elements:
int value = layer.tileGids[x][y]; // Where 0 <= x < width and 0 <= y < height
Note that for the second method using vectors, you do not have to do any memory cleanup as is required in the first method because the vector will automatically take care of it. However, because a vector can grow dynamically i.e. you can add items to it, you lose the safety of having a fixed size array i.e. someone could accidentally increase the size of your grid if you use the vector method but if he tries to do that when you intialized it using the first method above an error will occur and you will immediately know that something is wrong.
Can someone please point out what I am doing wrong in the following code?
A lot. You're allocating two single arrays (a "row array" and a "column array", not what you need), and then you try to do something strange.
Generally you can't (strictly speaking) dynamically allocate a 2D array in C++ (because the type system would still need the type, along with the dimensions, to be known at compile time). You can emulate it with an array of arrays or so, but the best way is to allocate an 1D array:
int width=5;
std::vector<int> tab(width*height);
and then access the element by calculating the coordinates manually:
// access the element (1,2)
tab[1 + 2*width] = 10;
This way you're essentially interpreting a 1D array as a 2D array (with performance equal to static 2D arrays).
Then it's best to wrap the indexing with a class for convenience; boost::multi_array also has this done for you already.
a and b are int* here:
layer->tileGids = new int[a][b];
Perhaps you meant to say this?
layer->tileGids = new int[*a][*b];