How do you initialize a 3d array in C++
int min[1][1][1] = {100, { 100, {100}}}; //this is not the way
The array in your question has only one element, so you only need one value to completely initialise it. You need three sets of braces, one for each dimension of the array.
int min[1][1][1] = {{{100}}};
A clearer example might be:
int arr[2][3][4] = { { {1, 2, 3, 4}, {1, 2, 3, 4}, {1, 2, 3, 4} },
{ {1, 2, 3, 4}, {1, 2, 3, 4}, {1, 2, 3, 4} } };
As you can see, there are two groups, each containing three groups of 4 numbers.
Instead of static multidimensional arrays you should probably use one-dimensional array and calculate the index by multiplication. E.g.
class Array3D {
size_t m_width, m_height;
std::vector<int> m_data;
public:
Array3D(size_t x, size_t y, size_t z, int init = 0):
m_width(x), m_height(y), m_data(x*y*z, init)
{}
int& operator()(size_t x, size_t y, size_t z) {
return m_data.at(x + y * m_width + z * m_width * m_height);
}
};
// Usage:
Array3D arr(10, 15, 20, 100); // 10x15x20 array initialized with value 100
arr(8, 12, 17) = 3;
std::vector allocates the storage dynamically, which is a good thing because the stack space is often very limited and 3D arrays easily use a lot of space. Wrapping it in a class like that also makes passing the array (by copy or by reference) to other functions trivial, while doing any passing of multidimensional static arrays is very problematic.
The above code is simply an example and it could be optimized and made more complete. There also certainly are existing implementations of this in various libraries, but I don't know of any.
Here's another way to dynamically allocate a 3D array in C++.
int dimX = 100; int dimY = 100; int dimZ = 100;
int*** array; // 3D array definition;
// begin memory allocation
array = new int**[dimX];
for(int x = 0; x < dimX; ++x) {
array[x] = new int*[dimY];
for(int y = 0; y < dimY; ++y) {
array[x][y] = new int[dimZ];
for(int z = 0; z < dimZ; ++z) { // initialize the values to whatever you want the default to be
array[x][y][z] = 0;
}
}
}
Everyone seems to forget std::valarray. It's the STL template for flat multidimensional arrays, and indexing and slicing them.
http://www.cplusplus.com/reference/std/valarray/
No static initialization, but is that really essential?
Related
I have been studying C++ and low-level graphics and currently have questions on this code from https://www.scratchapixel.com/lessons/3d-basic-rendering/ray-tracing-polygon-mesh.
class PolygonMesh : public Object
{
public:
PolygonMesh(uint32_t nfaces, int *fi, int *vi, Vec3f *p) :
numFaces(nf), faceIndex(NULL), vertexIndex(NULL), P(NULL)
{
// compute vertArraySize and maxVertexIndex
uint32_t vertArraySize = 0;
uint32_t maxVertexIndex = 0, index = 0;
for (uint32_t i = 0; i < numFaces; ++i) {
vertArraySize += nv[i];
for (uint32_t j = 0; j < fi[i]; ++j)
if (vi[index + j] > maxVertexIndex)
maxVertexIndex = vi[index + j];
index += fi[i];
}
maxVertexIndex += 1;
pts = std::unique_ptr<Vec3f []>(new point[maxVertexIndex]);
for (uint32_t i = 0; i < maxVertexIndex; ++i) P[i] = p[i];
vertexIndex = std::unique_ptr<uint32_t []>(new int[maxVertexIndex]);
for (uint32_t i = 0; i < maxVertexIndex; ++i) vertexIndex [i] = vi[i];
faceIndex = std::unique_ptr<uint32_t>(new int[numFaces]);
for (uint32_t i = 0; i < numFaces; ++i) faceIndex[i] = fi[i];
};
~PolygonMesh() { /* release memory */ ... }
bool intersect(...) const { ... }
void getSurfaceData(...) const { ... }
uint32_t numFaces; //number of faces
std::unique_ptr<uint32_t []> faceIndex; //face index
std::unique_ptr<uint32_t []> vertexIndex; //vertex index
std::unique_ptr<Vec3f []> P;
};
int main(...)
{
...
uint32_t numFaces = 2;
uint32_t faceIndex[2] = {4, 4};
uint32_t vertexIndex[8] = {0, 1, 2, 3, 0, 3, 4, 5};
Vec3f P[6] = {
Vec3f (-5, -5, 5), Vec3f ( 5, -5, 5),
Vec3f ( 5, -5, -5), Vec3f (-5, -5, -5),
Vec3f (-5, 5, -5), Vec3f (-5, 5, 5),
};
PolygonMesh *mesh = new PolygonMesh(numFaces, faceIndex, vertexIndex, P);
...
}
The website (the author) says :
The point list, face and vertex index array are passed to the constructor of the MeshPolygon class as well as the number of faces. However we don't know how many points are in the point array. To find out, we look for the vertex with the maximum index value in the vertex index array (lines 13-14). The first element of an array in C++ start at 0, therefore the total number of vertices in the point list is the maximum index value plus 1 (line 17).
So, it is about getting data from polygon mesh! Several questions puzzle me :
Above it says, "...we don't know how many points are in the point array..." In my understanding, why just not read the size of the P array that is being passed from the main() ? That is supposed to be the size of the array, or...?
If my understanding correct, then in the PolygonMesh(..) constructor what happens is deep copying of pointers(and all the values those addresses' possess) ? Is it right? I am asking , because I have just learned( or read) recently about smart pointers, std::move and r-values references. Also, in the code, they don't std::move all the pointers from main to the class object because we want to save those original data (pointers), right?
Is it correct that in order to find Vertex Array Size in the above code for the class object, we could just read the maximum value of uint32_t vertexIndex[8], i.e maximum vertexIndexArray is the total number of vertices?
I assume in line 11 it must be vertIndexArraySize += fi[i]; instead of vertArraySize += nv[i]; because I have no idea where does nv come from what what it means...
Thank you all for your genuine help !
I need to create a lot of small 2-dimension arrays in C++ code.
The problem is that it's a lot of work to create even a simple array:
new int* [2]{
new int[2]{9, 9},
new int[2]{25, 19}
};
Is there any better way how to do that?
I wanted to avoid writing "new int[]..." every time.
If the dimensions are not decided at runtime, and all the inner arrays have the same dimensions, you do not need dynamic allocation here.
Just declare an array:
int myArray[2][2] = {
{9, 9},
{25, 19}
};
That's it!
I recommend allocating as a single dimension array. You can then treat the 1D array as a 2D array:
const unsigned int MAX_ROWS = 2U;
const unsigned int MAX_COLUMNS = 5U;
int example_array[MAX_ROWS * MAX_COLUMNS];
// Get value at [row][column]:
unsigned int one_dim_index = (row * MAX_COLUMNS) + column;
int value = example_array[one_dim_index];
For small array sizes, this would be more efficient since the processor can fit the entire contiguous array in the data cache. With your solution, an array of pointers, you have no idea where the sub-arrays are located and they may not be contiguous (thus requiring a refetch into the cache).
Edit 1: Initializing
You can initialize the array by making the rows and columns pretty:
int example_array[MAX_ROWS * MAX_COLUMNS] =
{
/* row 0 */ 1, 2, 3, 4, 5,
/* row 1 */ 6, 7, 8, 9, 10,
};
Maybe you can use nested for loops to do the task
const int ARRAY_SIZE = 2;
int **create_array() {
int **array = new int*[ARRAY_SIZE];
if (array == nullptr) { return nullptr; }
for (int i=0; i<ARRAY_SIZE; i++) {
array[i] = new int[ARRAY_SIZE];
if (array[i] == nullptr) { return nullptr; }
}
return array;
}
If you want to assing the values you can do it directly in here. But they should come from a function of i. If you want some really specific values it will need to be a manual job
I'm dealing with arbitrary dimension matrix/array, therefore I need to access the multi-dimensional array using pointers.
I have attempted to write a function that extracts a specific column of the multi-dimensional in C:
I have followed several accepted answers: How to use pointer expressions to access elements of a two-dimensional array in C?
Here is my C code:
#include <stdio.h>
//prototype
void get_column_vector_from_matrix (float * info, int rows,
int column_dimension, float * single_dimension);
//main
int main()
{
//test data
float points[][3] = {{3, -2, 1},
{17, 15, 1},
{13, 15, 1},
{6, 12, 12},
{9, 1, 2},
{-1, 7, 2},
{10, 17, 2},
{10, 20, 2}};
int rows = sizeof(points)/sizeof(points[0]);
float single_dimension [rows];
//extract column vector 0, therefore 3,17,13,7,9,-1,10,10 should be returned
get_column_vector_from_matrix(&points,rows,0,single_dimension);
printf("Column 0\n");
for (int i=0; i<rows; i++)
{
printf("data[%i]=%f\n",i,single_dimension[i]);
}
//extract column vector 1, therefore -2,15,15,12,1,7,17,20 should be returned
get_column_vector_from_matrix(&points,rows,1,single_dimension);
printf("Column 1\n");
for (int i=0; i<rows; i++)
{
printf("data[%i]=%f\n",i,single_dimension[i]);
}
//extract column vector 2, therefore 1,1,1,1,2,2,2,2 should be returned
get_column_vector_from_matrix(&points,rows,2,single_dimension);
printf("Column 2\n");
for (int i=0; i<rows; i++)
{
printf("data[%i]=%f\n",i,single_dimension[i]);
}
}
/*=============================================================================
Function: get_column_vector_from_matrix
Description: this function points to an arbitrary multidimensional array of
* dimensions m(rows) by n(columns) and extracts a single dimension
* with all rows. This attempts to extract column vector given a
* m(rows) by n(columns) matrix.The pointer to extracted column is
* set to float * single_dimension parameter.
*
=============================================================================*/
void get_column_vector_from_matrix (float * info, int rows,
int column_dimension, float * single_dimension)
{
int row_i=0;
float value = 0;
if (info!=NULL && single_dimension!=NULL)
{
//return data only at column_dimension
for ( row_i; row_i< rows; row_i++ ) {
//(*(info+row_i)+column_dimension) below is based on https://stackoverflow.com/questions/13554244/how-to-use-pointer-expressions-to-access-elements-of-a-two-dimensional-array-in/13554368#13554368
value = (float)(*(info+row_i)+column_dimension);
*(single_dimension+row_i) = value;
}//end
}
}
Call to get_column_vector_from_matrix(&points,rows,1,single_dimension);
Should return extracting should return 3,17,13,7,9,-1,10,10 however its returning
Column 0
data[0]=3.000000
data[1]=-2.000000
data[2]=1.000000
data[3]=17.000000
data[4]=15.000000
data[5]=1.000000
data[6]=13.000000
data[7]=15.000000
You are not modifying the offset to compensate for the number of columns in your matrix. In memory, the multidimensional array is flat (i.e. 1-dimensional), and it's up to your program to use an appropriate step size to skip over each row.
Since you seem to want your function to operate on arbitrary dimensions, then you must pass the actual number of columns as a parameter (e.g. num_cols), and change your code as follows:
value = info[row_i * num_cols + column_dimension];
single_dimension[row_i] = value;
notice that the parameter info is of type float*, means every step of its increment is always a single float value. You should use pattern like *(info + row_i * NUMBER_OF_COLUMNS + column_dimension) to access the column data.
This has been bugging me for almost 2 days now. I have in my class definition a 2-D dynamic array:
class Raster {
public:
int pixels[][4];
void drawTriangle(Vector2f & V1, Vector2f & V2, Vector2f & V3, PixelColor & colorA, PixelColor & colorB, PixelColor & colorC);
};
In my drawing method I have this loop
for (int Y = maxY; Y >= minY; Y--) {
for (int X = minX; X <= maxX; X++) {
float lambda1;
float lambda2;
float lambda3;
triangle.getBarycentricCoordinate(X, Y, &lambda1, &lambda2, &lambda3);
if ((0.0f <= lambda1 && 0.0f <= lambda2 && 0.0f <= lambda3)) {
PixelColor a = lambda1 * colorA;
PixelColor b = lambda2 * colorB;
PixelColor c = lambda3 * colorC;
PixelColor interpolatedColor = a + b + c;
pixels[Y*width + X][0] = interpolatedColor.R;
pixels[Y*width + X][1] = interpolatedColor.G;
pixels[Y*width + X][2] = interpolatedColor.B;
}
}
}
Can anyone point out why it is wrong? Here is the error message: "Exception thrown: write access violation.
this was 0x111013530C28FA2."
pixels[][2] doesn't define a non-zero length array here. You need to specify a number for the first dimension too.
I don't think that's a dynamic array.
When you declare an array you are required to declare it's size as well. You can tell what kind of array it is by what you create it as and what the data is.
For instance in the following code :
// Here we can see that the array is a 4X3.
int pixels[][3] = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12} };
This would work just fine, because the size of the array is understood.
Further i would like to add that if you really want something not restrained by size and want the size to be dynamic depending on the data you have, then you could use the various containers that Standard Template Library offers such as a std::vector.
Currently I'm learning C++ and I've been trying to create a simple image processing library for learning purposes.
One of my features is eroding an image. As input it has two 2d arrays, and it returns another 2d array. All these arrays are of variable size. Let's give you an example of what I want to achieve.
int image[5][5] =
{
{'0', '0', '0', '0','0'},
{'0', '1', '1', '1','0'},
{'0', '0', '1', '0','0'},
{'0', '1', '1', '1','0'},
{'0', '0', '1', '0','0'},
};
int kernel[3][3] =
{
{'0', '1', '0'},
{'1', '1', '1'},
{'0', '1', '0'},
};
Then I want to pass them to my function (this doesn't compile, but it serves as an example of what I want).
int** erode(int image[][], int kernel[][]);
So far, I've read quite a bit about this. All I've read is that the columns can be of variable length, but the rows can't. So I should be change it to the following:
int** erode(int image[][5], int kernel[][3]);
But that's not really want I want either, because well, the image can be 10*10 and the kernel could be 5*5. So this isn't optimal in this situation either.
Then what I've read is creating a class, that internally stores the image as a 1d array and makes it look like a 2d array. Also I've read about using the Boost.MultiArray class to do this. But well I'm not too happy about that either. Because then I'm forcing the people that use it to also use those classes. And I think it's creating a lot of complexity for something that seems really simple (at least it is in C#)
To be honest, I can't imagine there isn't an easier way to do this. Optimally I'd say only use classes/methods from the standard C++11 library. How would you solve this problem?
Timo
see if you can use templates, eg:
template<int N>
void f(int (&arr)[N][N]);
if arrays have compile time bounds.
but really you should consider boost, armadillo, or tvmet
I would pass the array as a pointer and also pass another parameter which defines the size of the array.
int** erode(int* image, size_t imageSize, int* kernel, size_t kernelSize);
An array is just a list of consecutive variables when in memory and the array variable such as image[5][5] just points to the first element of the array. To pass the arrays you have shown into the function you would use.
int** ret = errode(image, 5, kernel, 3);
Be careful when using this however because it could easily cause a segmentation fault but when used correctly, it will be fine. Also this assumes that the array is square, to overcome this limitation just pass in another parameter which describes the other dimension of the array.
Update
I see Anycorn has posted a very nice solution. His is a safer solution however will require you knowing the size of the array at compile time. If this is the case I would recommend you use what he has said.
Returning a 2D vector is less complicated.
#include <vector>
#include <iostream>
using namespace std;
typedef std::vector<std::vector< int> > vector2D;
int image[5][5] =
{
{0, 0, 0, 0, 0},
{0, 1, 1, 1, 0},
{0, 0, 1, 0, 0},
{0, 1, 1, 1, 0},
{0, 0, 1, 0, 0},
};
int kernel[5][5] =
{
{0, 0, 0, 0, 0},
{0, 1, 1, 1, 0},
{0, 0, 1, 0, 0},
{0, 1, 1, 1, 0},
{0, 0, 1, 0, 0},
};
vector2D erode(int image[5][5], int kernel[5][5])
{
vector2D image_process_data ;
//create 2D vector array
image_process_data.resize(5);
for(int i = 0; i < 5; i++)
{
image_process_data[i].resize(5);
}
//perform calculations
for (int ix = 0; ix < 5; ix++)
{
for (int iy = 0; iy < 5; iy++)
{
image_process_data[ix][iy] = image[ix][iy] + kernel[ix][iy];
}
}
//return the 2D array
return image_process_data;
}
int main( )
{
vector2D new_image;
new_image = erode(image, kernel);
//display new_image
for (int ix = 0; ix < 5; ix++)
{
for (int iy = 0; iy < 5; iy++)
{
cout<<new_image[ix][iy]<<" ";
}
cout<<"\n";
}
return 0;
}
How to set up a 2D vector array:
#include <vector>
#include <iostream>
using std namespace;
#define HEIGHT 5
#define WIDTH 3
int main() {
vector<vector<double> > array2D;
// Set up sizes. (HEIGHT x WIDTH)
array2D.resize(HEIGHT);
for (int i = 0; i < HEIGHT; ++i)
array2D[i].resize(WIDTH);
// Put some values in
array2D[1][2] = 6.0;
array2D[3][1] = 5.5;
return 0;
}
What you wrote about internally storing 1D array is essentially the best solution. Using 2-dimensional array is usually dangerous and can easily lead to errors. If you don't want to create whole class, consider:
const int SizeX = 10, SizeY = 10;
int Array[SizeX*SizeY];
inline int& Get (int x, int y) { return Array[SizeX*y+x]; }
Of course, it is the very simple example, but usually solves a lot of errors.
struct MyOwnArray
{
int SizeX, int SizeY;
int* Data;
inline int& Get (int x, int y) { return Data[SizeX*y+x]; }
}
The code above will allow you to pass references to this struct in a convenient way. And it's only 6 lines of code!
Of course, the code above would need some more code; for example for allocating memory. However, if you carefully program all these parts, you will be pretty safe to use it and it should be well-protected from bugs.