How to pass 3D arrays using triple pointers? - c++

Is it really possible?
I know how to pass 2-D arrays using double pointer. And as per my understanding, it should for 3-D arrays as well. But I would love to be proven wrong. This question will surely reveal how the arrays are interpreted.
The fact here is that the 3-D array is a contiguous block, not some array of pointers of smaller chunks.
This program gives me error :
#include <iostream>
using namespace std;
void display(int ***arr, int l, int m, int n)
{
for(int i=0; i<l; i++)
for(int j=0; j<m; j++)
for(int k=0; k<n; k++)
cout << *(*(*(arr+i)+j)+k) << endl;
}
int main()
{
int arr[][2][2] = {{{1,2},{3,4}},{{10,20},{30,40}}};
display((int***)arr,2,2,2);
}
OUTPUT
test.cpp:17:19: error: cannot convert 'int (*)[2][2]' to 'int***' for argument '1' to 'void display(int***, int, int, int)'
display(arr,2,2,2);
^
2D Arrays passed to double pointer
I believe I can do something similar to 3D arrays as well, but this is way too bad to read.
#include <iostream>
using namespace std;
void display(int **arr, int m, int n)
{
for(int i=0; i<m; i++)
for(int j=0; j<n; j++)
cout << *(*(arr+i)+j) << " " << arr[i][j] << endl;
}
int main()
{
int arr[][3] = {{1,2,3},{4,5,6}};
int *temp[2];
for(int i=0; i<2; i++)
temp[i] = *(arr+i);
display(temp,2,3);
}
OUTPUT
1 1
2 2
3 3
4 4
5 5
6 6

What you do for 2D arrays is correct because you have built an auxiliary array of pointers and you pass that array of pointer as a int **. Even for 2D arrays, this
void display(int **arr, int m, int n);
...
int arr[][3] = {{1,2,3},{4,5,6}};
display(arr,2,3); // WRONG! use a 2D array as an array of pointers
would be wrong.
And anyway, the C++ standard is unfriendly with multi-dimensional arrays: there is no way to write a strictly conformant program passing a multi-dimensional arrays of unknown dimension. Many compilers accept it as extensions, but it may be non portable on other compilers.
The idiomatic way is to only use 1D arrays as the underlying data structure, and provide methods to process it as a multi-dimensional container by internally doing index computations.
BTW I have tried to build a multi-dimensional contiguous container with arbitrary run-time dimensions, respecting all the constraints of the standard containers, and given up after realizing that the standard did not allow it: it is impossible to build a nice iterator over object that do not hold their own data. Here is my best attempt. The answers and comments explain why it is hopeless.

Although you can pass a 1-D array like this
void pass1Darray(int a[])
{
statements;
}
int main()
{
int a[10];
pass1Darray(a);
}
In fact, compiler would see int a[] as int* a and this is the reason why people wonder is it possible to pass a 2-D array by pointer_to_pointer.
But it doesn't make sense!
If you want to pass a 2-D arraybob[5][10], you can see bob as a array and its element is a array, and pass it like this
void pass2Darray( int (*array) [10] ) // it means you pass a pointer which points to a int[10]
{
statements;
}
int main()
{
int bob[5][10];
pass2Darray(bob);
}
This is about passing a 2-D array.
btw, English is not my native langueue, and I'm a beginner of c++ , too.
If there's something wrong, please let me know, thank you.

When you declare an array locally int arr[][2][2] the compiler instantiate a one dimensional vector and "remember" what the offset is to get the right index.
Also local arrays are stored in the stack which is not good if you need large matrices. Another property of int arr[][2][2] is that why when you try to pass it as argument to a function, int arr[][2][2] is the type. You have to specify all the dimensions.
Pointers work differently. If you instantiate a 2D array you need to allocate an array of pointers to rows, and allocate each row array to hold data individually. In C++ I think it's best to use the standard library, which has a standard implementation of dynamic pointers that take care of all allocations. std::vector
In conclusion:
I would use local arrays when the memory required is small and I don't need to use pointers. Local arrays are good if you want to avoid using the heap.
Using pointersm new/delete or malloc/free is allowed but I think it's better to use the standard library in C++, so I would use std::vector in all other scenarios.

I believe I can do something similar to 3D arrays as well, but this is way too bad to read.
Yes, as n.m. explained in their comment
In your 2D code you have created a brand new array of pointers, populated it, and passed it to your function instead of your original 2D array. In your 3D code you have not attempted anything of the sort.
Since the question is tagged as C++, we can use a different toolbox than C coders have to.
In C++, a parameter can be passed to a function by reference, not only by value, and we can write a template that can be used by the compiler to generate the right function for used type.
#include <iostream>
#include <iomanip>
template <class T, size_t L, size_t M, size_t N>
void display( T const (&arr)[L][M][N], int width )
// ^^^^^^
{
for (size_t i = 0; i < L; ++i) {
for (size_t j = 0; j < M; ++j) {
for (size_t k = 0; k < N; ++k) {
std::cout << std::setw(width) << arr[i][j][k];
}
std::cout << '\n';
}
std::cout << '\n';
}
}
int main()
{
int arr[3][2][4] = {
{ {1,2,3,4},
{5,6,7,8}
},
{ {10,20,30,40},
{50,60,70,80}
},
{ {100,200,300,400},
{500,600,700,800}
}
};
display(arr, 5);
}
Live, HERE.
The next step would be, of course, to write a class which encapsulates the concept of a multidimensional array.

Related

2-D array and pointer in C++ -- how to go through every every element using pointer of a 2-D matrix

For practice, I want to define a Matrix addition of two 2-D Matrces by pulling the pointers of them. Here is the initiation
const double A[2][2]={{1,2},{3,4}};
double B[2][2]={{4,3},{2,1}};
const double* a=*A;
double* b=*B;
However, since the pointer merely points to the first element of the first array within each matrix, a=*(A+0), how can i go through every element of each Matrix? And I only wnat to use pointer as parameter here.
void D2Add(const double*, double*){
...for loop here...
}
I only wnat to use pointer as parameter here
That way you will have undefined behavior. The different sub arrays may be placed in different pages/segments in memory and Accessing an array out of bounds is not guaranteed to work. I removed the sentence trying to explain a possible pitfall when accessing a sub array out of bounds because I can't find a good description of it right now.
One way to avoid undefined behavior is to take the arrays by reference instead:
#include <cstddef>
#include <iostream>
template<std::size_t Y, std::size_t X>
void D2Add(const double(&A)[Y][X], double(&B)[Y][X]) {
for(std::size_t y = 0; y < Y; ++y) {
for(std::size_t x = 0; x < X; ++x) {
B[y][x] += A[y][x];
}
}
}
int main() {
const double A[2][2]={{1,2},{3,4}};
double B[2][2]={{4,3},{2,1}};
D2Add(A, B);
for(auto& inner : B) {
for(auto value : inner) std::cout << value << ' ';
std::cout << '\n';
}
}
Output:
5 5
5 5
This is a very interesting question actually.
Formally, you're indeed only allowed to access the elements of the first sub-array, and trying to access the other one would cause undefined behavior.
But practically, there's a good chance that you might be able to loop from 0 to 4, treating the arrays as 1D arrays of size 4. But I would advise against doing this if possible.
I Hope you have good understanding of how Multi-Dimensional array is laid in memory.
problem- It is not possible by just pointers until your function has a way to know dimensions of array.
As specified, we need to pass dimensions to functions as well.
Since you only want to go through every element, I'll be print each element for demonstration.
void D2Add(const double* ptr, int nRow, int nCol) {
for (int i=0; i<nRow; i++) {
for (int j=0; j<nCol; j++) {
std::cout << *(ptr+(i*nCol)+j) << std::endl;
}
}
}

C++ - passing static 2d array to functions

How am I supposed to pass static 2d array to function in cpp as an argument? I tried something like that:
void foo(int (&tab)[N][N]) {
// function body
}
int main() {
int n;
cin >> n;
int tab[n][n];
foo(tab); // doesn't work
return 0;
}
I get "no matching function error" when I try to call foo.
I need static arrays, because vectors are too slow for my needs. I would like to avoid declaring array with 10000 rows and columns, too. Moreover, I would want to use functions, because it will make my code readable. Is there any solution for this problem which will meet my expectations?
With cin >> n;int tab[n][n];, you declare a variable length array (i.e. an array which's dimensions are not compile-time-constants).
You have two problems here: First, they are not supported by standard C++, and second they are not compatible with fixed size array parameters you introduced.
If you declare your array with compile time known size, however, it will work:
#define N 10
void foo(int (&tab)[N][N]) {
cout << tab[1][1] << endl;
}
int main() {
int tab[N][N] = {};
tab[1][1]=15;
foo(tab);
return 0;
}
The classical C++ solution would involve using vectors of vectors. If it's not suitable (because you want more speed or more control over memory), you can define your own class for a square 2-D array.
One idea I used in my code is, implement it using an underlying 1-D vector, with accessor method returning a pointer.
struct My_2D_Array
{
explicit My_2D_Array(size_t n):
m_size(n),
m_data(n * n)
{
}
int* operator[](size_t i)
{
return m_data.data() + i * m_size;
}
size_t m_size;
std::vector<int> m_data;
};
This not only lacks all sanity checks, and also makes bound-checked access impossible (because the accessor returns a bare pointer), but will work as a quick-and-dirty solution.
Usage in your code:
int foo(My_2D_Array& matrix)
{
// example
return matrix[2][3] + matrix[3][2];
}
int main()
{
int n;
cin >> n;
My_2D_Array tab(n);
foo(tab);
return 0;
}
This idea is highly customizable - you can make the code for My_2D_Array as simple or as clever as you want. For example, if you still don't like usage of vector, even though it's 1-D, you can manage (allocate/deallocate) your memory separately, and store int*, instead of vector<int>, in My_2D_Array.
Just use a vector<> of vector<int>. No need for mucking around with non-standard arrays.

Passing and modifying array of vectors through functions in c++

(I'm from C background and new in C++ and its STLs)
I'm writing a C++ array of vectors that will be passed (as a reference of an array of vectors) through a function and will be processed in it.
In this case [in C] I would have passed a pointer to my custom data type (call by value under the hood.)
My code that's giving errors in compile time while trying to do so:
#include <cstdio>
#include <vector>
using namespace std;
/*
the problem is I can't get the syntax. vector<type> &var is
a reference to a single dimension array of vectors.
*/
void pass_arrayOf_vect(vector<int> &array, int lmt);
int main() {
int lmt = 10;
vector<int> lst[lmt];
pass_arrayOf_vect(lst, lmt);
return 0;
}
/*
and the traditional ambiguity of whether using "." or "->" for
accessing or modifying indexes and their members.
*/
void pass_arrayOf_vect(vector<int> &lst, int lmt) {
for (int i = 0; i < lmt; i++) {
lst[i].push_back(i*i);
}
for (int i = 0; i < lmt; i++) {
printf("array[%d]: ", i);
for (int j = 0; j < lst[i].size(); j++) {
printf("%d ",lst[i][j]);
}
printf("\n");
}
printf("\n");
return;
}
In the main function the lst variable is an array of vectors. When you pass this to the pass_arrayOf_vect function you pass a pointer to the first element.
I.e. when you do
pass_arrayOf_vect(lst, lmt);
it's actually the same as doing
pass_arrayOf_vect(&lst[0], lmt);
So the function you call needs to accept a pointer to a vector as its first argument (not a reference):
void pass_arrayOf_vect(vector<int> *array, int lmt);
// ^
// Note use of asterisk instead of ampersand
An even better solution would be to use an std::array of vectors instead. Or if you're on an older compiler without support for std::array, or need the amount to be run-time configurable (in which case you can't use plain C-style arrays anyway), use a vector of vectors.

How to solve the issue passing an unknown-sized 2D array to a function?

I have a program in which the object array's size is determined during the runtime, so it's dynamically allocated (2D array, read from file). I also have a function which takes these objects as parameters. The problem is if the function parameters are 2D arrays that are passed to the function the 2nd dimension should be determined. However, in my case it is not. My program won't compile since the prototype does not have the 2nd dimension mentioned.
Here is what I tried:
//global variables
int residentCount=0;
int hospitalCount=0;
Resident** residents;
Hospital** hospitals;
bool readFromFiles(const string, const string, const int); //sizes are determined in here
void print(Hospital*[hospitalCount], Resident*[residentCount]); //declaration issue
How can I solve this?
You are programming in C++, so you should:
avoid dynamic allocation and handling memory management on your own always when it's possible
take advantage of objects with automatic storage duration instead, follow RAII idiom
avoid using C-style arrays and actually avoid writing C code that is just compilable as C++ in general
use great features that C++ provides, especially those bundled within STL
avoid using global variables when local equivalents suffice
This is how it could look like:
typedef std::vector<Resident> Residents;
typedef std::vector<Hospital> Hospitals;
// passing by const reference:
void print(const std::vector<Hospitals>&, const std::vector<Residents>&);
int main()
{
std::vector<Hospitals> hospitals;
std::vector<Residents> residents;
...
} // <-- lifetime of automatics declared within main ends here
Note that hospitals and residents will be objects with automatic storage duration, usable in similar manner than your C-style 2D arrays. When the execution goes out of the scope of main, these vectors are destructed and memory, where their elements (including elements of their elements) resided before is automatically cleaned up.
Also note that I suggest you to pass by const reference, i.e. const std::vector<Hospitals>&, which prevents the copy of passed object being created and const keyword explicitely tells to the caller: "Although you pass this object by reference, I will not change it."
Just pass a pointer to the first element of the array and the dimensions, that's enough, example:
void PrintHospitals(Hospital* Hospitals, size_t HospitalRows, size_t HospitalColumns)
{
size_t i, j;
Hospital* hospital;
for (i = 0; i < HospitalRows; i++)
for (j = 0; j < HospitalColumns; j++)
{
hospital = Hospitals + HospitalColumns * i + j;
PrintHospital(hospital);
}
}
int main()
{
Hospital hospitals[10][20];
// ...
PrintHospitals(&hospitals[0][0], 10, 20);
return 0;
}
Here is a solution using templates to create two-dimensional array wrappers for existing data:
template<typename T>
class Array2d {
public:
int Rows;
int Cols;
T** Data;
Array2d(int rows, int cols, T** data) :
Rows(rows),
Cols(cols),
Data(data) { }
};
void print(Array2d<Hospital> h, Array2d<Resident> r) {
for (int i = 0; i < h.Rows; i++) {
for (int j = 0; j < h.Cols; j++) {
//Print Data[i][j] element here
}
}
// Other print code
}
int main()
{
Resident** residents;
Hospital** hospitals;
//Init data arrays
Array2d<Hospital> h(10, 10, hospitals);
Array2d<Resident> r(10, 10, residents);
print(h, r);
}

c++ dynamic size of the array

I have got a small problem with 1D array in c++. I have got a function line this:
void func(int (&array)[???])
{
// some math here;
"for" loop {
array[i] = something;
}
}
I call the functions somewhere in the code, and before I made math I'm not able to know dimension of the array. The array goes to the function as a reference!, because I need it in the main() function. How I can allocate array like this?, so array with ?? dimension goes to the function as reference then I have to put the dimension and write to it some values.
Since you're using C++, why not use a std::vector<> instead?
Other have mentioned that you should use std::vector in C++ and they are right.
But you can make your code work by making func a function template.
template <typename T, size_t N>
void func(T (&array)[N])
{
// some math here;
"for" loop {
array[i] = something;
}
}
Use a pointer, not a reference:
void func(int *a, int N);
Or, easier, use a vector:
void func(std::vector<int> &a);
Vectors can be allocated by simply saying
std::vector<int> a(10);
The number of elements can be retrieved using a.size().
If the array you pass to func is a stack array, and not a pointer, you can retain its size by using a function template:
template <class T, size_t N>
void func(T(&array)[N])
{
size_t array_length = N; // or just use N directly
}
int main()
{
int array[4];
func(array);
}
That said, as others have already pointed out, std::vector is probably the best solution here.
As well as vector which has been suggested you could possibly use valarray which is also part of STL and is intended specificially to handle mathematical collections.
What you have to realize, is that arrays are pointers. A definition like int array[5] will allocate space for 5 integers on the stack and array will be the address of the first value. Thus, to access the first value in the array, you can write
array[0] or *array (which is the same as *(array + 0))
In the same way to retrieve the address of the third element, you can write
&array[2] or array + 2
Since arrays are pointers, you don't have to worry about the runtime size of your array if you would like to pass it to a function, simply pass it as a pointer:
void func(int *array)
{
int size;
//compute size of the array
for (int i = 0; i < size; ++i)
{
//do whatever you want with array[i]
}
}