C++ Initialization query - c++

Can someone please tell me if there is anything incorrect with this initialization:
static unsigned char* var[1]
var[0] = new unsigned char[ 800 * 600 ]
Is this creating a 2D array at var[0] ? Is this even valid ?

It's creating a single array with 480,000 elements (aka 800*600) and storing it in var[0]. It is not creating a 2D array. It's valid as long as var[0] is an unsigned char*.

It is creating a 1-d array of length (800*600) at var[0]. You'll be able to access its elements with:
var[0][0]
var[0][1]
...
var[0][800*600-1]

I think you want something more like (although I may be interrupting the question wrong);
static unsigned char* var = new char*[800]
for (int i =0; i < 800; i++)
var[i] = new char[600]
That will give you a 800x600 2d character array.

Your code is not correct, since var[0] is not a pointer anymore.
You may want to do something like:
static unsigned char* var;
var = new unsigned char[800 * 600];
That does not create a 2D array. It is just a 1D array. Having said that, you can use it as a 2D array if you compute the offset yourself. For instance to access position (row, col) you could do:
var[row * 600 + col]
If you really want a "true" 2D array, you will need to use for instance:
static unsigned char** var;
var = new unsigned char*[600];
for (int i = 0; i < 600; i++)
var[i] = new unsigned char[800];
Of course, if you do not need to dynamically specify the array size at runtime, you can just use a statically allocated array:
static unsigned char var[600][800];
BTW, I assume 600 is the number of rows and 800 the number of cols (like in a matrix). That is why I always use 600 in the first index. Otherwise, just swap the values.

Yes, it's quite incorrect to use new[]. What you're looking for is std::vector<unsigned int> var(800 * 600);.

Related

casting a pointer to an array to a structure in efficient C++11 way

I have a big amount point cloud data that I read from a file into
char * memblock = new char [size];
where size is the size of data. Then I cast my data to float numbers
float * file_content = reinterpret_cast<float *>(memblock);
Now I would like to change the data from a pointer to an array and place it in a certain structure like std::vector<PointXYZ>.
vector.clear();
for (int i = 2; i < file_content_size; i+=3) {
vector.push_back(
PointXYZ(file_content[i-2], file_content[i-1], file_content[i] )
);
}
But I feel there must be a better way than just looping through the whole data, considering that the size of the vector is more than 1e6.
std::vector has a range constructor that you can use to copy the elements to the vector.
std::vector<PointXYZ> vec(memblock, memblock + size);
I believe this will be faster because you are not reallocating memory for every push_back, however you will still be doing a copy of all elements in memblock.
I think you alignment problems when you cast your char* raw data into a float*.
Generally you should arrange things so you cast other types to a char* because that is allowed to alias everything else and ensures you get correct alignment.
// create your array in the target type (float)
std::vector<float> file_content(size/sizeof(float));
// read the data in (cast to char* here)
file.read(reinterpret_cast<char*>(file_content.data()), size);
I honestly don't think you can get away from copying all the data.
std::vector<PointXYZ> points;
points.reserve(file_content.size() / 3);
for(auto i = 0ULL; i < file_content.size(); i += 3)
points.emplace_back(points[i], points[i + 1], points[i + 2])

cpp 3d dynamic creation of 3d arrays consisting of one single memory block

I have to implement a simulation on a 3D Ising lattice represented by ones and minus ones on a 3D it would be very useful if the size could be determined at runtime (for more flexibility).
As there are many accesses to the entries the memory allocation should be as local as possible.
If found something for a 2D array:
Copy 2D array using memcpy? :
GridUnit** newGrid;
newGrid = new GridUnit*[width];
newGrid[0] = new GridUnit[width * height];
for (int i = 1; i < width; i++)
newGrid[i] = newGrid[i-1] + height;
Deallocation becomes simpler:
delete[] newGrid[0];
delete[] newGrid;
and my rating is too low to comment or reply to the post.
I have basically two questions about the code:
1.why is the grid defined as pointers to arrays of
length = width
and the the iteration takes place over an index going up to width shifting the address by height? isn't that messing up the row and column index?
2.Should I then declare an array of length=width with pointers to arrays of length=height*depthwhich would result in the following code:
int*** new3dGrid(int width, int height, int depth){
int*** newGrid;
newGrid = new int**[height*depth];
newGrid[0][0] = new int[width * height * depth];
for (int i = 1; i < width; i++){
newGrid[i] = newGrid[i-1] + height*depth;
for (int j=1;j<height;j++){
newGrid[i][j]=newGrid[i][j-1]+depth;
}
}
return newGrid;
}
First of all: I STRONGLY suggest you to use, when possible, standard C++ containers; in 2D case (caution: not tested)
std::vector<std::vector<GridUnit> > gu2d (width, std::vector<GridUnit>(height));
I strongly suggest this especially if isn't absolutely clear the example that you mention.
Consider if you access at position i, j
gu2d[i][j] = GridUnit();
where, by mistake, j value is height; without realizing it, you modify gu2d[i+1][0]. If gu2d is a vector of vectors, with gu2d.at(i).at(j) you obtain bound checking and a nice exception.
why is the grid defined as pointers to arrays of length = width and the iteration takes place over an index going up to width shifting the address by height?
You can see a 2D matrix as an array of width rows of cells where each row is of height cells.
So the first pointer (newGrid) has lenght width because it references width rows.
Every row has length height, so the width values referenced by newGrid are separated (shifted) by a space of height (in pointer metric).
I think you can be clearer if you read the first answer to this question
How do I declare a 2d array in C++ using new?
Should I then declare an array of length=width with pointers to arrays of length=height*depth which would result in the following code
I'm not an English native speaker but it seems to me that you have chosen an unhappy order of names. I suppose you should use depth before width.
But, using your actual names (width is the dimension of the first index, height of the second, depth of the third)...
Exactly.
Your code should change
newGrid = new int**[height*depth];
width
newGrid = new int**[width];
In the 3D case, you can see newGrid as (with your choose one names) an array of width 2D matrix where the 2D matrix are array of height rows of depth cells. So every 2D matrix is of size heigth * depth.
Caution: remember to delete with
delete newGrid[0][0];
delete newGrid;
p.s.: sorry for my bad English
--- EDIT ---
Sorry: I haven't seen a point that is important about your hypotesis of new3dGrid: you should allocate three pointers, not two: newGrid, as int***, for size width; newGrid[0], as int** for size width * height; newGrid[0][0], as int*, for size width * height * depth. The three types of pointers need different allocated area.
I propose the different template version (caution: not tested) [corrected by Ben Voigt; thanks!]
template <typename T>
T*** new3dGrid (unsigned height, unsigned width, unsigned depth)
{
T*** newGrid;
newGrid = new T**[width];
newGrid[0] = new T*[width * height];
newGrid[0][0] = new T[width * height * depth];
for ( unsigned i = 0U ; i < width ; ++i )
{
if ( i > 0U )
{
newGrid[i] = newGrid[i-1U] + height;
newGrid[i][0] = newGrid[i-1U][0] + height * depth;
}
for ( unsigned j = 1U ; i < height ; ++j )
newGrid[i][j] = newGrid[i][j-1U] + depth;
}
return newGrid;
}
and you should delete three pointers
delete newGrid[0][0];
delete newGrid[0];
delete newGrid;
Sorry.

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

Converting linear array to a bidimensional array of structs using pointers

EDIT: I will improve this question. I will clarify it right in a little days.
first, I am writing a litlle bmp image analyzer. I have the following problem: The image is stored on plain bytes, without format as an array.
The image is 24 bits, and requires 3 bytes per pixel. I have tried with a solution that I have found on this stackoverflow page, but I can not adapt it for structures.
I have tried but it references invalid areas and bytes. Here's my complete code if you want to see it in TinyPaste (just for a better highlighting): The code in TinyPaste
EDIT 1: This code is in C++, I want to translate it to pure C for portability reasons. This is just the example from I taken the idea of convert a linear array to bidimensional. I have tried to adapt it to pure C for structs but I fail.
This snippet was taken from a stackoverflow question that made me think about this
//The resulting array
unsigned int** array2d;
// Linear memory allocation
unsigned int* temp = new unsigned int[sizeX * sizeY];
// These are the important steps:
// Allocate the pointers inside the array,
// which will be used to index the linear memory
array2d = new unsigned int*[sizeY];
// Let the pointers inside the array point to the correct memory addresses
for (int i = 0; i < sizeY; ++i)
{
array2d[i] = (temp + i * sizeX);
}
// Fill the array with ascending numbers
for (int y = 0; y < sizeY; ++y)
{
for (int x = 0; x < sizeX; ++x)
{
array2d[y][x] = x + y * sizeX;
}
}
I adapt it to reference structs, but it fails. I have tried multiplying by three in this line:
array2d[i] = (temp + i * sizeX /* multiply by 3*/);
But it still without work. I have also done the related castings from char to the struct bmp_pixel(char r, char g, char b).
Can somebody tell me how to adapt it to pure C for structs?? Thanks.

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