C extract specific column from multi-dimensional array using pointers only - c++

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.

Related

C++. Low level graphics. Polygon mesh data reading via classes. Need elaboration on the code of the constructor

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 !

How to calculate the sum of individual elements from two 2D arrays?

I want to write a function addArrays which will, as parameters, take two 2D arrays of type int and of dimensions 3x4, and it's job is to add individual elements of each index from the given arrays and display it in the console.
In main(), I created two 2D arrays arrA and arrB of appropriate sizes with intitialized members and check the functionality of the created function.
My code so far:
#include <iostream>
using namespace std;
void addArrays(int x[3][4], int y[3][4]);
int main()
{
int arrA[3][4] = { {7, 8, 13, 22}, {56, 4, 78, 3}, {22, 13, 46, 5} };
int arrB[3][4] = { {32, 47, 56, 14}, {33, 100, 19, 64}, {4, 18, 157, 84} };
}
void addArrays(int x[3][4], int y[3][4])
{
}
Honestly, I know how to work with 1D arrays, but not displaying the sum of all individual elements. I know I have to use a for loop, but again, I'm confused as to how to pass in a 2D array and use it.
You mention you know how to work with 1D arrays, it's the same for 2D arrays, only with one more dimension.
In a 1D array you use arrA[0] to access the first element of the array, in a 2D array you use arrA[0][0] to access the first element in the first line of the array, arrA[0][1] to access the second element in the first line of the array. To access the first element in the second line you would use arrA[1][0] and so on, you get the idea.
So to loop through all the elements in the array you can use nested loops like so:
void addArrays(int x[3][4], int y[3][4])
{
for( int i = 0; i < 3; i++){ // make sure to use the correct dimensions
for(int j = 0; j < 4; j++){ // 3 lines and 4 columns
// x[i][j] accesses elements in array x
// y[i][j] accesses elements in array y
}
}
}
I think you'll manage to do the math yourself. After that you just need to send data to the standard output, i.e. to print data in the console. For that, as you may know, you use std::cout.
Side notes:
In the function void addArrays(int x[3][4], int y[3][4]){...} you may omit the first dimension of the array i.e. int x[][4] or int (*x)[4] instead of int x[3][4], since the argument will decay to a pointer to array.
Since it seems that you are not to change the values of the passed arrays, using const is recommend. You would have void addArrays(const int (*x)[4], const int (*y)[4]);
As you are using C++, you can take advantage of the possibility of using references, something like void addArrays(const int (&x)[3][4], const int (&y)[3][4]){/*same code*/}, the benefit being you must pass a correct object to the function otherwise the program will fail to compile whereas in the previous versions if you pass, for example, NULL, i.e. addArrays(arrA, NULL); the program will compile fine but will result in undefined behavior when you run it. References are safer and you should use them when possible.
It's more or less consensual among more experienced C++ programmers that the usage of using namespace std; is not a good practice, you can read more about it, and find alternatives following the link.
I will start this for you and try to give you an idea of the general structure, but since you have not shown your attempt at the problem I won't fill things in for you.
The basic idea here when looping through 2D arrays (of size MxN) is that you can really just think about it in terms of looping through M arrays of length N.
void loopThroughArray(int arr[M][N])
{
// Loop over M arrays
for (int m = 0; m < M; ++m) {
// For each m'th array, loop over its N contents
for (int n = 0; n < N; ++n) {
// Doing work
arr[m][n] = 1234;
}
}
}

Easy way to create multiple-dimension arrays in C++ with new operator

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

C++ Eigen: How to concatenate matrices dynamically (pointer issue?)

I have the following problem:
I have several partial (eigen) MatrixXds I want to concatenate to another, larger, MatrixXd variable I only have as a pointer. However, both the size of the smaller matrices and their number are dynamic, so I cannot use the << operator easily.
So I'm trying the following (the smaller matrices are stored in list_subdiagrams, obviously, and basis->cols() defines the number of matrices), using Eigen's MatrixXd block funtionality:
// sd[] contains the smaller matrices to be concatenated; all are of the same size
// col defines the total number of smaller matrices
MatrixXd* ret = new MatrixXd(sd[0]->rows(), col*sd[0]->cols());
for (int i=0; i<col; ++i){
ret->block(0, i*sd[0]->cols(), sd[0]->rows(), sd[0]->cols()) = *(sd[i]);
}
This, unfortunately, appears to somehow overwrite some part of the *ret variable - for before the assignment via the block, the size is (in my test-case) correctly shown as being 2x1. After the assignment it becomes 140736006011136x140736006011376 ...
Thank you for your help!
What do you mean you don't know the size? You can use the member functions cols()/rows() to get the size. Also, I assume by concatenation you mean direct sum? In that case, you can do something like
#include <iostream>
#include <Eigen/Dense>
int main()
{
Eigen::MatrixXd *A = new Eigen::MatrixXd(2, 2);
Eigen::MatrixXd *B = new Eigen::MatrixXd(3, 3);
*A << 1, 2, 3, 4;
*B << 5, 6, 7, 8, 9, 10, 11, 12, 13;
Eigen::MatrixXd *result = new Eigen::MatrixXd(A->rows() + B->rows(), A->cols() + B->cols());
result->Zero(A->rows() + B->rows(), A->cols() + B->cols());
result->block(0, 0, A->rows(), A->cols()) = *A;
result->block(A->rows(), A->cols(), B->rows(), B->cols()) = *B;
std::cout << *result << std::endl;
delete A;
delete B;
delete result;
}
So first make sure it works for 2 matrices, test it, then extend it to N.

How to initialize 3D array in C++

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?