In C++ in ROOT (the CERN language), I have declared a 2D array of histograms:
TH1F *hist[xlen][ylen];
where xlen and ylen are not variable-length; I assign them values in my code.
I would like to pass this 2D array into a function. I'm having trouble specifying the input parameter, however. Can someone help me out?
For an example, I can pass a 1D histogram (TH1F *hist[length];) with a function like,
void func(TH1F** Hist) {
cout<<Hist[0]<<endl;
}
Please note that although my 2D histogram has a definite size (i.e. xlen, ylen), as defined in my code, I do not want the function to be limited to arrays of a single size.
If you want to use the same function for different dimensions within the same program, the only way I see is to pass a pointer to the first element of the array together with the dimensions and then calculate each index on your own, i.e. by current_row_index * column_size + current_column_index:
void func(int rows, int columns, int **hist) {
static int arr[10] = {0,1,2,3,4,5,6,7,8,9};
for(int r=0; r<rows; r++) {
for(int c=0; c<columns; c++) {
int* aPtr = &arr[(r*columns+c)%10];
hist[r*columns + c] = aPtr;
cout << *hist[r*columns + c] << " ";
}
cout << endl;
}
}
int main() {
int *a20x10[20][10] = {};
int *a5x3[5][3] = {};
func(20,10,&a20x10[0][0]);
func(5,3,&a5x3[0][0]);
return 0;
}
/*But first of all you want to pass by reference, so a
* more correct function call might be:
*/
void Call(TH1F **Hist, size_t size_x, size_t size_y);
/* allows changing hist or setting to NULL
* in function
*/
void Call2(TH1F ***Hist, size_t size_x, size_t size_y);
/* with a call like */
int main(void)
{
TH1F *hist[xlen][ylen] = NULL;
/* malloc here/memset hist */
Call(*hist, xlen, ylen);
Call2(hist, xlen, ylen);
return (0);
}
You can do this with a template function. The template will automatically pick up the dimensions of the array.
template<int C, int R>
void func(TH1F* (&hist)[C][R])
{
cout << hist[0][0] << endl;
}
I managed to get it to work trivially by circumventing the issue: Using a vector of vectors instead of a 2D array.
The answer by Stephan seems the closest to solving it as intended, but did not work. It is also a bit too complicated for me to know how to adjust the code to make it work.
Related
Im kind of begginer in C++, just to programming in PHP and JAVA, I have problem to make a pointer to 2d array, then use this pointer in different function and cout values of [0] and [1].
There is part of my script.
int size_dd = 5;
int dd[size_dd][2];
for (int i = 0; i < size_dd; i ++)
{
dd[i][0] = 2 * i + 10;
dd[i][1] = 4 * i + 20;
}
I can read the dd[i][0] in main function but I cannot call them in function read(int* twodarray), as it returns int[int] and the 2nd parameter from array is lost.
Thing is that I need to make pointer to this array and call it in other function.
But the problem is when I handle *dd in to the function, it return that dd is int[int] value instead of int[int][int], how can I resolve it?
Your function should have following signature:
void fooByPtr(int(*arr)[5][6]) {
(*arr)[4][4] = 156;
}
// Call ex:
int dd[5][6];
fooByPtr(&dd);
You can also do it with reference and template:
void fooByRef(int (&arr)[5][6]) {
arr[4][4] = 156;
}
template<int N, int M>
void fooByRefTempl(int(&arr)[N][M]) {
arr[4][4] = 156;
}
Some other comments to your code (also the one from comment):
You can create arrays using constant values as sizes, so this is wrong:
int size_dd = 5;
and should be:
const int size_dd = 5;
in your fun_call you should dereference your array: (*dwu_wymiar) before indexing it.
finally, change funCall(int(*dwu_wymiar)[][2], to int(*dwu_wymiar)[5][2], as in my example above.
I originally asked using nested std::array to create an multidimensional array without knowing dimensions or extents until runtime but this had The XY Problem of trying to accomplish it with std::array.
The questions One-line initialiser for Boost.MultiArray and How do I make a multidimensional array of undetermined size a member of a class in c++? and their answers give some helpful information how to use Boost::MultiArray to avoid needing to know the extents of the dimensions at runtime, but fail to demonstrate how to have a class member that can store an array (created at runtime) whose dimensions and extents are not known until runtime.
Just avoid multidimensional arrays:
template<typename T>
class Matrix
{
public:
Matrix(unsigned m, unsigned n)
: n(n), data(m * n)
{}
T& operator ()(unsigned i, unsigned j) {
return data[ i * n + j ];
}
private:
unsigned n;
std::vector<T> data;
};
int main()
{
Matrix<int> m(3, 5);
m(0, 0) = 0;
// ...
return 0;
}
A 3D access (in a proper 3D matrix) would be:
T& operator ()(unsigned i, unsigned j, unsigned k) {
// Please optimize this (See #Alexandre C)
return data[ i*m*n + j*n + k ];
}
Getting arbitrary dimensions and extent would follow the scheme and add overloads (and dimensional/extent information) and/or take advantage of variadic templates.
Having a lot of dimensions you may avoid above (even in C++11) and replace the arguments by a std::vector. Eg: T& operator(std::vector indices).
Each dimension (besides the last) would have an extend stored in a vector n (as the first dimension in the 2D example above).
Yes. with a single pointer member.
A n multidimensional array is actually a pointer. so you can alocate a dynamic n array and with casting, and put this array in the member pointer.
In your class should be something like this
int * holder;
void setHolder(int* anyArray){
holder = anyArray;
}
use:
int *** multy = new int[2][1][56];
yourClass.setHolder((int*)multy);
You can solve the problem in at least two ways, depending on your preferences. First of all - you don't need the Boost library, and you can do it yourself.
class array{
unsigned int dimNumber;
vector<unsigned int> dimSizes;
float *array;
array(const unsigned int dimNumber, ...){
va_list arguments;
va_start(arguments,dimNumber);
this->dimNumber = dimNumber;
unsigned int totalSize = 1;
for(unsigned int i=0;i<dimNumber;i++)
{
dimSizes.push_back(va_arg(arguments,double));
totalSize *= dimSizes[dimSizes.size()-1];
}
va_end(arguments);
array = new float[totalSize];
};
float getElement(unsigned int dimNumber, ...){
va_list arguments;
va_start(arguments,dimNumber);
unsgned int elementPos = 0, dimAdd = 1;
for(unsigned int i=0;i<dimNumber;i++)
{
unsigned int val = va_arg(arguments,double);
elementPos += dimAdd * val;
dimAdd *= dimsizes[i];
}
return array[elementPos]
};
};
Setting an element value would be the same, you will just have to specify the new value. Of course you can use any type you want, not just float... and of course remember to delete[] the array in the destructor.
I haven't tested the code (just wrote it straight down here from memory), so there can be some problems with calculating the position, but I'm sure you'll fix them if you encounter them. This code should give you the general idea.
The second way would be to create a dimension class, which would store a vector<dimension*> which would store sub-dimensions. But that's a bit complicated and too long to write down here.
Instead of a multidimensional array you could use a 1D-array with an equal amount of indices. I could not test this code, but I hope it will work or give you an idea of how to solve your problem. You should remember that arrays, which do not have a constant length from the time of being compiled, should be allocated via malloc() or your code might not run on other computers.
(Maybe you should create a class array for the code below)
#include <malloc.h>
int* IndexOffset; //Array which contains how many indices need to be skipped per dimension
int DimAmount; //Amount of dimensions
int SizeOfArray = 1; //Amount of indices of the array
void AllocateArray(int* output, //pointer to the array which will be allocated
int* dimLengths, //Amount of indices for each dimension: {1D, 2D, 3D,..., nD}
int dimCount){ //Length of the array above
DimAmount = dimCount;
int* IndexOffset = (int*) malloc(sizeof(int) * dimCount);
int temp = 1;
for(int i = 0; i < dimCount; i++){
temp = temp * dimLengths[i];
IndexOffset[i] = temp;
}
for(int i = 0; i < dimCount; i++){
SizeOfArray = SizeOfArray * dimLengths[i];
}
output = (int*)malloc(sizeof(int) * SizeOfArray);
}
To get an index use this:
int getArrayIndex(int* coordinates //Coordinates of the wished index as an array (like dimLengths)
){
int index;
int temp = coordinates[0];
for(int i = 1; i < DimAmount; i++){
temp = temp + IndexOffset[i-1] * coordinates[i];
}
index = temp;
return index;
}
Remember to free() your array as soon as you do not need it anymore:
for(int i = 0; i < SizeOfArray; i++){
free(output[i]);
}
free(output);
I'm sorry if I didn't pick a descriptive or concise name. A lot of questions sound similar, but I haven't been able to find what I'm looking for. What I want to do is store a 2D array of pointers somewhere and assign a variable in some object to that array to be able to access it.
Here's some example code that has the same compile error I'm getting with a bigger project.
#include <iostream>
using namespace std;
struct X{
float n, * b[8][8];
X(){
n = 1;
b[1][5] = &n;
cout << *(b[1][5]) << endl;
}
void Set(float * c[8][8]){
b = c;
cout << *(b[1][5]) << endl;
}
};
main(){
float m, * a[8][8];
m = 2;
a[1][5] = &m;
X obj;
obj.Set(a);
}
What I want to happen in this code is that an X object starts with its own 2D array, whose value pointed to by b[1][5] should be printed as "1". Then the main method's 2D array, a, is passed to the object's Set() method and assigned to its array variable. The value pointed to by b[1][5] should then be printed as "2".
However, I can't figure out what type the Set() parameter, c, should be. I get
error: incompatible types in assignment of ‘float* (*)[8]’ to ‘float* [8][8]’
when I try to compile. As for why I want to do this, I'm trying to use an array of pointers to objects, not floats, but it's the same error.
Try this:
#include <iostream>
using namespace std;
struct X{
float n;
float* (*b)[8];
X(){
n = 1;
b = new float*[8][8];
b[1][5] = &n;
cout << *(b[1][5]) << endl;
}
void Set(float * c[8][8]){
delete[] b;
b = c;
cout << *(b[1][5]) << endl;
}
};
main(){
float m, * a[8][8];
m = 2;
a[1][5] = &m;
X obj;
obj.Set(a);
}
Here, X stores a pointer to a 1D array, which we are treating as a pointer to the first element of a 2D array - i.e. as just a 2D array.
In X's constructor, X allocates its own array with new and sets its pointer to point to that. When calling Set(), X deletes its own array, and sets its pointer to point to the array provided by the caller.
The only thing to watch out for is, if you call Set() again, that array will in turn be deleted (which will blow up if that array is a stack array, like in this case). So, it might be advisable to separate the line that does delete[] b into its own member function, and call it only when necessary.
Your problem with set is that you need to copy the array contents - just doing b=c can't do what you want.
void Set(float * c[8][8]){
for(unsigned int i=0; i<8; ++i) {
for(unsigned int j=0; j<8; ++j) {
b[i][j] = c[i][j];
}
}
cout << *(b[1][5]) << endl;
}
There are several bugs I think..
Firstly, in Set() function you have assigned an array name. But array name should not be used as a variable. You can solve this by making 2D array of pointer b as a pointer to 1D array of pointer like float * (*b)[8]...
Secondly, when you send the 2D array of pointer as argument of Set() function it is decaying into a pointer to 1D array of pointer i.e something like this float *(*a)[8]. so you have to make the formal argument of Set() function a pointer to 1D array of pointers like void Set(float * (*c)[8])...
And finally there is a thing your float variable m inside main is a local to main , so when control pass to Set() function I think the compiler cant find the value(may be deallocated) in the m...so it outputs undefined or give run time error..you can solve this by making m a static version. i.e by declaring static float m...
In total make your code like following :
#include <iostream>
using namespace std;
struct X{
float n, *(*b)[8];
X(){
n = 1;
b[1][5] = &n;
cout << *(b[1][5]) << endl;
}
void Set(float * (*c)[8]){
b = c;
cout << *(b[1][5]) << endl;
}
};
main(){
float * a[8][8];
static float m;
m = 2;
a[1][5] = &m;
X obj;
obj.Set(a);
}
This will output correctly :)
I want to make class library, a function which its parameter is a matrix of unknown size, and the user will create his own matrix with his own size and pass it to this function to do some operations on his matrix like this, will be the function
calculateDeterminantOfTheMatrix( int matrix[][])
{
some Operations to do on matrix
}
Multi-dimensional arrays are not very well supported by the built-in components of C and C++. You can pass an N-dimension array only when you know N-1 dimensions at compile time:
calculateDeterminantOfTheMatrix( int matrix[][123])
However, the standard library supplies std::vector container, that works very well for multi-dimension arrays: in your case, passing vector<vector<int> > &matrix would be the proper way of dealing with the task in C++.
int calculateDeterminantOfTheMatrix(vector<vector<int> > &matrix) {
int res = 0;
for (int i = 0 ; i != matrix.size() ; i++)
for(int j = 0 ; j != matrix[i].size() ; j++)
res += matrix[i][j];
return res;
}
As an added bonus, you wouldn't need to pass dimensions of the matrix to the function: matrix.size() represents the first dimension, and matrix[0].size() represents the second dimension.
C solution:
In C you can't omit array size (except leftmost) when passing as function parameter.
You can write:
int a[]
but can't:
int a[][]
just for example:
int a[][20]
This constraint is here, because compiler needs to determine proper offsets for accessing array elements. However, you can make it this way:
void print_arbitrary_2D_array(void *arr, int y, int x)
{
/* cast to 2D array type */
double (*p_arr)[y][x] = (double (*)[y][x]) arr;
int i, j;
for (i = 0; i < y; ++i) {
for (j = 0; j < x; ++j)
printf(" %lf", (*p_arr)[i][j]);
putchar('\n');
}
}
double arr_1[4][3] = {
{ 3.3, 5.8, 2.3 },
{ 9.1, 3.2, 6.1 },
{ 1.2, 7.9, 9.4 },
{ 0.2, 9.5, 2.4 }
};
double arr_2[2][5] = {
{ 3.6, 1.4, 6.7, 0.1, 4.2 },
{ 8.4, 2.3, 5.9, 1.4, 8.3 }
};
print_arbitrary_2D_array(arr_1, 4, 3);
putchar('\n');
print_arbitrary_2D_array(arr_2, 2, 5);
There are multiple approaches you could take.
C way of doing things -> Pass in a int** but be extremely cautious here. This is not quite a 2D array. You will have to correctly allocate memory to this pointer, or, alternatively, you need to know the size at compile time. (For instance staticly allocating an array of size M * N and then disallowing anything bigger). In order to dynamically allocate the memory, you need to know the number of rows and columns.
C++ way -> #include <vector> after which you can simply use vector<vector<int> > &matrix (Careful about the space after the <int> unless you're using c++11 compiler.), which will allocate a vector of int vectors which is basically a 2d array. The memory management will be taken care of for you in this case.
I would write a simple class wrapper for the matrix with column and row defined.
template <typename T>
class Mat {
std::size_t _row;
std::size_t _col;
T *_mat_elem;
public:
Mat(std::size_t r, std::size_t c)
: _row(r), _col(c), _mat_elem(new T[r*c] {}
~Mat() {/* remember to do delete [] here */}
// element access, for example
T& at(std::size_t r, std::size_t c)
{
return *(_mat_elem+r*_col+c);
}
};
But actually you are re-inventing the wheels. There are good libraries for matrix handling out there.
use this method
declare an array of pointers
ex: int *a[n];
Then allocate memory for them using a for loop
ex:
for( int i=0 ; i<n ; i++ )
a[i] = new int[n];
Now pass the argument like normal array.
ex: print_array(a,n);
And print_array function looks like
print_array(int **a,int n)//the prototype for the print_array
{
//access the array using index such as
std:: cout<<a[1][1]<<endl;
}
The above case is for the array of nxn incase mxn is required then
allocate the memory like
for( int i=0 ; i<m ; i++ )
a[i] = new int[n];
then pass the both m,n and to the function and access the array in the for loop.
The Best way to use 2D array in the function that I have found so far is to use Mapping Function. As in the example below , I have use the mapping function to print 2D array
void Print2D(int x[],int ROWS,int COLS)
{
for(int i=0;i<ROWS;i++)
{
for(int j=0;j<COLS;j++)
cout << x[i*COLS+j] << ' ';
cout << endl;
}
}
Here it is how to use it in main
int main(){
int x[3][3];
Print2D(&x[0],3,3);
}
Here &x[0] is the starting address of the First Row of 2D array or more precisely Starting address of 2D array
I'm new to C/C++ and I've been cracking my head but still got no idea how to make an "structure" like this
It's supposed to be a 3D dynamic array using pointers.
I started like this, but got stuck there
int x=5,y=4,z=3;
int ***sec=new int **[x];
It would be enough to know how to make it for a static size of y and z;
Please, I'd appreciate that you help me.
Thanks in advance.
To create dynamically 3D array of integers, it's better you understand 1D and 2D array first.
1D array: You can do this very easily by
const int MAX_SIZE=128;
int *arr1D = new int[MAX_SIZE];
Here, we are creating an int-pointer which will point to a chunk of memory where integers can be stored.
2D array: You may use the solution of above 1D array to create a 2D array. First, create a pointer which should point to a memory block where only other integer pointers are held which ultimately point to actual data. Since our first pointer points to an array of pointers so this will be called as pointer-to-pointer (double pointer).
const int HEIGHT=20;
const int WIDTH=20;
int **arr2D = new int*[WIDTH]; //create an array of int pointers (int*), that will point to
//data as described in 1D array.
for(int i = 0;i < WIDTH; i++){
arr2D[i] = new int[HEIGHT];
}
3D Array: This is what you want to do. Here you may try both the scheme used in above two cases. Apply the same logic as 2D array. Diagram in question explains all. The first array will be pointer-to-pointer-to-pointer (int*** - since it points to double pointers). The solution is as below:
const int X=20;
const int Y=20;
const int z=20;
int ***arr3D = new int**[X];
for(int i =0; i<X; i++){
arr3D[i] = new int*[Y];
for(int j =0; j<Y; j++){
arr3D[i][j] = new int[Z];
for(int k = 0; k<Z;k++){
arr3D[i][j][k] = 0;
}
}
}
// one-liner
typedef std::vector<std::vector<std::vector<int> > > ThreeDimensions;
// expanded
typedef std::vector<int> OneDimension;
typedef std::vector<OneDimension> TwoDimensions;
typedef std::vector<TwoDimension> ThreeDimensions;
(this is tagged c++, after all)
EDIT in response to Joe's question
hello again Joe =) sure. here's the example:
#include <vector>
#include <iostream>
int main(int argc, char* const argv[]) {
/* one-liner */
typedef std::vector<std::vector<std::vector<int> > >ThreeDimensions;
/* expanded */
typedef std::vector<int>OneDimension;
typedef std::vector<OneDimension>TwoDimensions;
typedef std::vector<TwoDimensions>ThreeDimensions;
/*
create 3 * 10 * 25 array filled with '12'
*/
const size_t NElements1(25);
const size_t NElements2(10);
const size_t NElements3(3);
const int InitialValueForAllEntries(12);
ThreeDimensions three_dim(NElements3, TwoDimensions(NElements2, OneDimension(NElements1, InitialValueForAllEntries)));
/* the easiest way to assign a value is to use the subscript operator */
three_dim[0][0][0] = 11;
/* now read the value: */
std::cout << "It should be 11: " << three_dim[0][0][0] << "\n";
/* every other value should be 12: */
std::cout << "It should be 12: " << three_dim[0][1][0] << "\n";
/* get a reference to a 2d vector: */
TwoDimensions& two_dim(three_dim[1]);
/* assignment */
two_dim[2][4] = -1;
/* read it: */
std::cout << "It should be -1: " << two_dim[2][4] << "\n";
/* get a reference to a 1d vector: */
OneDimension& one_dim(two_dim[2]);
/* read it (this is two_dim[2][4], aka three_dim[1][2][4]): */
std::cout << "It should be -1: " << one_dim[4] << "\n";
/* you can also use at(size_t): */
std::cout << "It should be 12: " << one_dim.at(5) << "\n";
return 0;
}
You can try:
for(int i=0;i<x;i++) {
sec[i] = new int *[y];
for(int j=0;j<y;j++) {
sec[i][j] = new int [z];
}
}
And once you are done using this memory you can deallocate it as:
for(int i=0;i<x;i++) {
for(int j=0;j<y;j++) {
delete [] sec[i][j];
}
delete [] sec[i];
}
delete [] sec;
Comprehensive answers.
If you are really writing this in C++ (not rough C) I think you should take another look at this complicated data structure. IMO redesign while keeping in mind what you are trying to do would be better.
What you're trying to do is not idiomatic in C++. Of course, you can use a int***pointer for this, but this is strongly discouraged. In C++ we have better ways to get there.
vector<vector<vector<int> > > foo (5,vector<vector<int> >(4, vector<int>(3)));
This will result in something with the memory layout similar to what you asked for. It supports dynamic resizing and inner vectors to have different sizes just like in your picture. In addition, you don't have to worry about manual allocation / deletion of any of it. Also, the vectors know their size so you don't have to remember it somewhere.
But if you just want a "rectangular" 3D array where all the elements are consecutivly stored in the same memory block, you could use a boost::multiarray.
OK let us take your beginnings
int ***sec = new int**[x];
sec is now an array of int**s of length x, so now I am just going to focus on making the zeroeth element be what you want
sec[0] = new int*[y];
Now sec[0] points to array of int*s of length y, now just need to get the last bit of the tree done, so
sec[0][0] = new int[z];
And finally to get it to the form in your diagram
sec[0][0][z-1] = 0;
This does seem a little like a homework question, make sure you actually understand the answer and why it works.
If it's the actual arrays you'r having problems with look here: Declaring a pointer to multidimensional array and allocating the array
Not sure exactly what you want but you might want to read up on about linked lists.