Passing a 2D array into a function in C [duplicate] - c

I have a function which I want to take, as a parameter, a 2D array of variable size.
So far I have this:
void myFunction(double** myArray){
myArray[x][y] = 5;
etc...
}
And I have declared an array elsewhere in my code:
double anArray[10][10];
However, calling myFunction(anArray) gives me an error.
I do not want to copy the array when I pass it in. Any changes made in myFunction should alter the state of anArray. If I understand correctly, I only want to pass in as an argument a pointer to a 2D array. The function needs to accept arrays of different sizes also. So for example, [10][10] and [5][5]. How can I do this?

There are three ways to pass a 2D array to a function:
The parameter is a 2D array
int array[10][10];
void passFunc(int a[][10])
{
// ...
}
passFunc(array);
The parameter is an array containing pointers
int *array[10];
for(int i = 0; i < 10; i++)
array[i] = new int[10];
void passFunc(int *a[10]) //Array containing pointers
{
// ...
}
passFunc(array);
The parameter is a pointer to a pointer
int **array;
array = new int *[10];
for(int i = 0; i <10; i++)
array[i] = new int[10];
void passFunc(int **a)
{
// ...
}
passFunc(array);

Fixed Size
1. Pass by reference
template <size_t rows, size_t cols>
void process_2d_array_template(int (&array)[rows][cols])
{
std::cout << __func__ << std::endl;
for (size_t i = 0; i < rows; ++i)
{
std::cout << i << ": ";
for (size_t j = 0; j < cols; ++j)
std::cout << array[i][j] << '\t';
std::cout << std::endl;
}
}
In C++ passing the array by reference without losing the dimension information is probably the safest, since one needn't worry about the caller passing an incorrect dimension (compiler flags when mismatching). However, this isn't possible with dynamic (freestore) arrays; it works for automatic (usually stack-living) arrays only i.e. the dimensionality should be known at compile time.
2. Pass by pointer
void process_2d_array_pointer(int (*array)[5][10])
{
std::cout << __func__ << std::endl;
for (size_t i = 0; i < 5; ++i)
{
std::cout << i << ": ";
for (size_t j = 0; j < 10; ++j)
std::cout << (*array)[i][j] << '\t';
std::cout << std::endl;
}
}
The C equivalent of the previous method is passing the array by pointer. This should not be confused with passing by the array's decayed pointer type (3), which is the common, popular method, albeit less safe than this one but more flexible. Like (1), use this method when all the dimensions of the array is fixed and known at compile-time. Note that when calling the function the array's address should be passed process_2d_array_pointer(&a) and not the address of the first element by decay process_2d_array_pointer(a).
Variable Size
These are inherited from C but are less safe, the compiler has no way of checking, guaranteeing that the caller is passing the required dimensions. The function only banks on what the caller passes in as the dimension(s). These are more flexible than the above ones since arrays of different lengths can be passed to them invariably.
It is to be remembered that there's no such thing as passing an array directly to a function in C [while in C++ they can be passed as a reference (1)]; (2) is passing a pointer to the array and not the array itself. Always passing an array as-is becomes a pointer-copy operation which is facilitated by array's nature of decaying into a pointer.
3. Pass by (value) a pointer to the decayed type
// int array[][10] is just fancy notation for the same thing
void process_2d_array(int (*array)[10], size_t rows)
{
std::cout << __func__ << std::endl;
for (size_t i = 0; i < rows; ++i)
{
std::cout << i << ": ";
for (size_t j = 0; j < 10; ++j)
std::cout << array[i][j] << '\t';
std::cout << std::endl;
}
}
Although int array[][10] is allowed, I'd not recommend it over the above syntax since the above syntax makes it clear that the identifier array is a single pointer to an array of 10 integers, while this syntax looks like it's a 2D array but is the same pointer to an array of 10 integers. Here we know the number of elements in a single row (i.e. the column size, 10 here) but the number of rows is unknown and hence to be passed as an argument. In this case there's some safety since the compiler can flag when a pointer to an array with second dimension not equal to 10 is passed. The first dimension is the varying part and can be omitted. See here for the rationale on why only the first dimension is allowed to be omitted.
4. Pass by pointer to a pointer
// int *array[10] is just fancy notation for the same thing
void process_pointer_2_pointer(int **array, size_t rows, size_t cols)
{
std::cout << __func__ << std::endl;
for (size_t i = 0; i < rows; ++i)
{
std::cout << i << ": ";
for (size_t j = 0; j < cols; ++j)
std::cout << array[i][j] << '\t';
std::cout << std::endl;
}
}
Again there's an alternative syntax of int *array[10] which is the same as int **array. In this syntax the [10] is ignored as it decays into a pointer thereby becoming int **array. Perhaps it is just a cue to the caller that the passed array should have at least 10 columns, even then row count is required. In any case the compiler doesn't flag for any length/size violations (it only checks if the type passed is a pointer to pointer), hence requiring both row and column counts as parameter makes sense here.
Note: (4) is the least safest option since it hardly has any type check and the most inconvenient. One cannot legitimately pass a 2D array to this function; C-FAQ condemns the usual workaround of doing int x[5][10]; process_pointer_2_pointer((int**)&x[0][0], 5, 10); as it may potentially lead to undefined behaviour due to array flattening. The right way of passing an array in this method brings us to the inconvenient part i.e. we need an additional (surrogate) array of pointers with each of its element pointing to the respective row of the actual, to-be-passed array; this surrogate is then passed to the function (see below); all this for getting the same job done as the above methods which are more safer, cleaner and perhaps faster.
Here's a driver program to test the above functions:
#include <iostream>
// copy above functions here
int main()
{
int a[5][10] = { { } };
process_2d_array_template(a);
process_2d_array_pointer(&a); // <-- notice the unusual usage of addressof (&) operator on an array
process_2d_array(a, 5);
// works since a's first dimension decays into a pointer thereby becoming int (*)[10]
int *b[5]; // surrogate
for (size_t i = 0; i < 5; ++i)
{
b[i] = a[i];
}
// another popular way to define b: here the 2D arrays dims may be non-const, runtime var
// int **b = new int*[5];
// for (size_t i = 0; i < 5; ++i) b[i] = new int[10];
process_pointer_2_pointer(b, 5, 10);
// process_2d_array(b, 5);
// doesn't work since b's first dimension decays into a pointer thereby becoming int**
}

A modification to shengy's first suggestion, you can use templates to make the function accept a multi-dimensional array variable (instead of storing an array of pointers that have to be managed and deleted):
template <size_t size_x, size_t size_y>
void func(double (&arr)[size_x][size_y])
{
printf("%p\n", &arr);
}
int main()
{
double a1[10][10];
double a2[5][5];
printf("%p\n%p\n\n", &a1, &a2);
func(a1);
func(a2);
return 0;
}
The print statements are there to show that the arrays are getting passed by reference (by displaying the variables' addresses)

Surprised that no one mentioned this yet, but you can simply template on anything 2D supporting [][] semantics.
template <typename TwoD>
void myFunction(TwoD& myArray){
myArray[x][y] = 5;
etc...
}
// call with
double anArray[10][10];
myFunction(anArray);
It works with any 2D "array-like" datastructure, such as std::vector<std::vector<T>>, or a user defined type to maximize code reuse.

You can create a function template like this:
template<int R, int C>
void myFunction(double (&myArray)[R][C])
{
myArray[x][y] = 5;
etc...
}
Then you have both dimension sizes via R and C. A different function will be created for each array size, so if your function is large and you call it with a variety of different array sizes, this may be costly. You could use it as a wrapper over a function like this though:
void myFunction(double * arr, int R, int C)
{
arr[x * C + y] = 5;
etc...
}
It treats the array as one dimensional, and uses arithmetic to figure out the offsets of the indexes. In this case, you would define the template like this:
template<int C, int R>
void myFunction(double (&myArray)[R][C])
{
myFunction(*myArray, R, C);
}

anArray[10][10] is not a pointer to a pointer, it is a contiguous chunk of memory suitable for storing 100 values of type double, which compiler knows how to address because you specified the dimensions. You need to pass it to a function as an array. You can omit the size of the initial dimension, as follows:
void f(double p[][10]) {
}
However, this will not let you pass arrays with the last dimension other than ten.
The best solution in C++ is to use std::vector<std::vector<double> >: it is nearly as efficient, and significantly more convenient.

Here is a vector of vectors matrix example
#include <iostream>
#include <vector>
using namespace std;
typedef vector< vector<int> > Matrix;
void print(Matrix& m)
{
int M=m.size();
int N=m[0].size();
for(int i=0; i<M; i++) {
for(int j=0; j<N; j++)
cout << m[i][j] << " ";
cout << endl;
}
cout << endl;
}
int main()
{
Matrix m = { {1,2,3,4},
{5,6,7,8},
{9,1,2,3} };
print(m);
//To initialize a 3 x 4 matrix with 0:
Matrix n( 3,vector<int>(4,0));
print(n);
return 0;
}
output:
1 2 3 4
5 6 7 8
9 1 2 3
0 0 0 0
0 0 0 0
0 0 0 0

Single dimensional array decays to a pointer pointer pointing to the first element in the array. While a 2D array decays to a pointer pointing to first row. So, the function prototype should be -
void myFunction(double (*myArray) [10]);
I would prefer std::vector over raw arrays.

We can use several ways to pass a 2D array to a function:
Using single pointer we have to typecast the 2D array.
#include<bits/stdc++.h>
using namespace std;
void func(int *arr, int m, int n)
{
for (int i=0; i<m; i++)
{
for (int j=0; j<n; j++)
{
cout<<*((arr+i*n) + j)<<" ";
}
cout<<endl;
}
}
int main()
{
int m = 3, n = 3;
int arr[m][n] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
func((int *)arr, m, n);
return 0;
}
Using double pointer In this way, we also typecast the 2d array
#include<bits/stdc++.h>
using namespace std;
void func(int **arr, int row, int col)
{
for (int i=0; i<row; i++)
{
for(int j=0 ; j<col; j++)
{
cout<<arr[i][j]<<" ";
}
printf("\n");
}
}
int main()
{
int row, colum;
cin>>row>>colum;
int** arr = new int*[row];
for(int i=0; i<row; i++)
{
arr[i] = new int[colum];
}
for(int i=0; i<row; i++)
{
for(int j=0; j<colum; j++)
{
cin>>arr[i][j];
}
}
func(arr, row, colum);
return 0;
}

You can do something like this...
#include<iostream>
using namespace std;
//for changing values in 2D array
void myFunc(double *a,int rows,int cols){
for(int i=0;i<rows;i++){
for(int j=0;j<cols;j++){
*(a+ i*rows + j)+=10.0;
}
}
}
//for printing 2D array,similar to myFunc
void printArray(double *a,int rows,int cols){
cout<<"Printing your array...\n";
for(int i=0;i<rows;i++){
for(int j=0;j<cols;j++){
cout<<*(a+ i*rows + j)<<" ";
}
cout<<"\n";
}
}
int main(){
//declare and initialize your array
double a[2][2]={{1.5 , 2.5},{3.5 , 4.5}};
//the 1st argument is the address of the first row i.e
//the first 1D array
//the 2nd argument is the no of rows of your array
//the 3rd argument is the no of columns of your array
myFunc(a[0],2,2);
//same way as myFunc
printArray(a[0],2,2);
return 0;
}
Your output will be as follows...
11.5 12.5
13.5 14.5

One important thing for passing multidimensional arrays is:
First array dimension need not be specified.
Second(any any further)dimension must be specified.
1.When only second dimension is available globally (either as a macro or as a global constant)
const int N = 3;
void print(int arr[][N], int m)
{
int i, j;
for (i = 0; i < m; i++)
for (j = 0; j < N; j++)
printf("%d ", arr[i][j]);
}
int main()
{
int arr[][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
print(arr, 3);
return 0;
}
2.Using a single pointer:
In this method,we must typecast the 2D array when passing to function.
void print(int *arr, int m, int n)
{
int i, j;
for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
printf("%d ", *((arr+i*n) + j));
}
int main()
{
int arr[][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
int m = 3, n = 3;
// We can also use "print(&arr[0][0], m, n);"
print((int *)arr, m, n);
return 0;
}

#include <iostream>
/**
* Prints out the elements of a 2D array row by row.
*
* #param arr The 2D array whose elements will be printed.
*/
template <typename T, size_t rows, size_t cols>
void Print2DArray(T (&arr)[rows][cols]) {
std::cout << '\n';
for (size_t row = 0; row < rows; row++) {
for (size_t col = 0; col < cols; col++) {
std::cout << arr[row][col] << ' ';
}
std::cout << '\n';
}
}
int main()
{
int i[2][5] = { {0, 1, 2, 3, 4},
{5, 6, 7, 8, 9} };
char c[3][9] = { {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'},
{'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R'},
{'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '&'} };
std::string s[4][4] = { {"Amelia", "Edward", "Israel", "Maddox"},
{"Brandi", "Fabian", "Jordan", "Norman"},
{"Carmen", "George", "Kelvin", "Oliver"},
{"Deanna", "Harvey", "Ludwig", "Philip"} };
Print2DArray(i);
Print2DArray(c);
Print2DArray(s);
std::cout <<'\n';
}

In the case you want to pass a dynamic sized 2-d array to a function, using some pointers could work for you.
void func1(int *arr, int n, int m){
...
int i_j_the_element = arr[i * m + j]; // use the idiom of i * m + j for arr[i][j]
...
}
void func2(){
...
int arr[n][m];
...
func1(&(arr[0][0]), n, m);
}

You can use template facility in C++ to do this. I did something like this :
template<typename T, size_t col>
T process(T a[][col], size_t row) {
...
}
the problem with this approach is that for every value of col which you provide, the a new function definition is instantiated using the template.
so,
int some_mat[3][3], another_mat[4,5];
process(some_mat, 3);
process(another_mat, 4);
instantiates the template twice to produce 2 function definitions (one where col = 3 and one where col = 5).

If you want to pass int a[2][3] to void func(int** pp) you need auxiliary steps as follows.
int a[2][3];
int* p[2] = {a[0],a[1]};
int** pp = p;
func(pp);
As the first [2] can be implicitly specified, it can be simplified further as.
int a[][3];
int* p[] = {a[0],a[1]};
int** pp = p;
func(pp);

You are allowed to omit the leftmost dimension and so you end up with two options:
void f1(double a[][2][3]) { ... }
void f2(double (*a)[2][3]) { ... }
double a[1][2][3];
f1(a); // ok
f2(a); // ok
This is the same with pointers:
// compilation error: cannot convert ‘double (*)[2][3]’ to ‘double***’
// double ***p1 = a;
// compilation error: cannot convert ‘double (*)[2][3]’ to ‘double (**)[3]’
// double (**p2)[3] = a;
double (*p3)[2][3] = a; // ok
// compilation error: array of pointers != pointer to array
// double *p4[2][3] = a;
double (*p5)[3] = a[0]; // ok
double *p6 = a[0][1]; // ok
The decay of an N dimensional array to a pointer to N-1 dimensional array is allowed by C++ standard, since you can lose the leftmost dimension and still being able to correctly access array elements with N-1 dimension information.
Details in here
Though, arrays and pointers are not the same: an array can decay into a pointer, but a pointer doesn't carry state about the size/configuration of the data to which it points.
A char ** is a pointer to a memory block containing character pointers, which themselves point to memory blocks of characters. A char [][] is a single memory block which contains characters. This has an impact on how the compiler translate the code and how the final performance will be.
Source

Despite appearances, the data structure implied by double** is fundamentally incompatible with that of a fixed c-array (double[][]).
The problem is that both are popular (although) misguided ways to deal with arrays in C (or C++).
See https://www.fftw.org/fftw3_doc/Dynamic-Arrays-in-C_002dThe-Wrong-Way.html
If you can't control either part of the code you need a translation layer (called adapt here), as explained here: https://c-faq.com/aryptr/dynmuldimary.html
You need to generate an auxiliary array of pointers, pointing to each row of the c-array.
#include<algorithm>
#include<cassert>
#include<vector>
void myFunction(double** myArray) {
myArray[2][3] = 5;
}
template<std::size_t N, std::size_t M>
auto adapt(double(&Carr2D)[N][M]) {
std::array<double*, N> ret;
std::transform(
std::begin(Carr2D), std::end(Carr2D),
ret.begin(),
[](auto&& row) { return &row[0];}
);
return ret;
}
int main() {
double anArray[10][10];
myFunction( adapt(anArray).data() );
assert(anArray[2][3] == 5);
}
(see working code here: https://godbolt.org/z/7M7KPzbWY)
If it looks like a recipe for disaster is because it is, as I said the two data structures are fundamentally incompatible.
If you can control both ends of the code, these days, you are better off using a modern (or semimodern) array library, like Boost.MultiArray, Boost.uBLAS, Eigen or Multi.
If the arrays are going to be small, you have "tiny" arrays libraries, for example inside Eigen or if you can't afford any dependency you might try simply with std::array<std::array<double, N>, M>.
With Multi, you can simply do this:
#include<multi/array.hpp>
#include<cassert>
namespace multi = boost::multi;
template<class Array2D>
void myFunction(Array2D&& myArray) {
myArray[2][3] = 5;
}
int main() {
multi::array<double, 2> anArray({10, 10});
myFunction(anArray);
assert(anArray[2][3] == 5);
}
(working code: https://godbolt.org/z/7M7KPzbWY)

You could take arrays of an arbitrary number of dimensions by reference and peel off one layer at a time recursively.
Here's an example of a print function for demonstrational purposes:
#include <cstddef>
#include <iostream>
#include <iterator>
#include <string>
#include <type_traits>
template <class T, std::size_t N>
void print(const T (&arr)[N], unsigned indent = 0) {
if constexpr (std::rank_v<T> == 0) {
// inner layer - print the values:
std::cout << std::string(indent, ' ') << '{';
auto it = std::begin(arr);
std::cout << *it;
for (++it; it != std::end(arr); ++it) {
std::cout << ", " << *it;
}
std::cout << '}';
} else {
// still more layers to peel off:
std::cout << std::string(indent, ' ') << "{\n";
auto it = std::begin(arr);
print(*it, indent + 1);
for (++it; it != std::end(arr); ++it) {
std::cout << ",\n";
print(*it, indent + 1);
}
std::cout << '\n' << std::string(indent, ' ') << '}';
}
}
Here's a usage example with a 3 dimensional array:
int main() {
int array[2][3][5]
{
{
{1, 2, 9, -5, 3},
{6, 7, 8, -45, -7},
{11, 12, 13, 14, 25}
},
{
{4, 5, 0, 33, 34},
{8, 9, 99, 54, 44},
{14, 15, 16, 19, 20}
}
};
print(array);
}
... which will produce this output:
{
{
{1, 2, 9, -5, 3},
{6, 7, 8, -45, -7},
{11, 12, 13, 14, 25}
},
{
{4, 5, 0, 33, 34},
{8, 9, 99, 54, 44},
{14, 15, 16, 19, 20}
}
}

Related

How can I use int** to pass a 2D array in C

Trying to work on leetcode #497 in C on my vscode. When writing main(), I am not sure how to deal with int** that leetcode provides. Is it possible to pass a 2D array using int**?
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int rectsSize;
int * rectsColSize;
int** rects;
} Solution;
int points[100];
Solution* solutionCreate(int** rects, int rectsSize, int* rectsColSize) {
Solution* sol = malloc(sizeof(Solution));
sol->rects = rects;
sol->rectsSize = rectsSize;
sol->rectsColSize = rectsColSize;
//some codes
}
return sol;
}
int* solutionPick(Solution* obj, int* retSize) {
//some codes
return ret;
}
void solutionFree(Solution* obj) {
free(obj);
}
int main(void)
{
int rects[2][4] = {{1, 1, 5, 5}, {6, 6, 9, 9}};
int rectsSize = 2;
int rectsColSize = 4;
int retSize;
Solution* obj = solutionCreate(rects, rectsSize, &rectsColSize);
int* param_1 = malloc(sizeof(int));
param_1 = solutionPick(obj, &retSize);
solutionFree(obj);
return 0;
}
While in general there are many different ways to handle 2D array, the simple answer is no. There is a lot of info about 2d arrays in C: 1, 2, 3, etc. In principle, when dealing with 2d arrays, every dimension except first to the left needs to be specified exactly. In your case, every rectangle is defined by 4 integers, so instead int** rects consider int*[4] rects. This makes rectsColSize useless, because now each column has constant size of 4 ints.
Just for completness: what you are trying to do is second approach to arrays, where each column has independent size, and (usually) additional malloc call. While this approach is also valid and requires int** type, it is not needed for your task. Nice description of the difference here.
Edit
Here is how to loop through 2d arrays:
#define col 4
void print_2d(int (*a)[col], int aSize){
for(size_t i = 0; i < aSize; i++){
for(size_t j = 0; j < col; j++){
printf("%d ", a[i][j]);
}
printf("\n");
}
}
and here for int**:
void print_pp(int** a, int aSize, int* aiSize){
for(size_t i = 0; i < aSize; i++){
for(size_t j = 0; j < aiSize[i]; j++){
printf("%d ", a[i][j]);
}
printf("\n");
}
}
It seems that you want to convert int*[4] to int**, or more precisely, int*[4] arr2d with it's size int arr2dSize to structure Solution. In that case, here is wrapper to solutionCreate.
Solution* solutionCreateWrap(int (*arr2d)[4], int arr2dSize) {
int* rectsColSize = malloc(arr2dSize * sizeof(int));
int** rects = malloc(arr2dSize * sizeof(int*));
size_t arr2dMem = arr2dSize * 4 * sizeof(int);
rects[0] = malloc(arr2dMem);
memcpy(rects[0], arr2d, arr2dMem);
rectsColSize[0] = 4;
for(size_t i = 1; i < arr2dSize; i++){
rects[i] = rects[0] + i*4;
rectsColSize[i] = 4;
}
sol->rects = rects;
sol->rectsSize = rectsSize;
sol->rectsColSize = rectsColSize;
//some codes
}
return solutionCreate(rects, arr2dSize, rectsColSize);
}
Now for int rects[2][4] = {{1, 1, 5, 5}, {6, 6, 9, 9}}; call solutionCreateWrap(rects, 2) will return initialised structure Solution. It looks gruesome, and it's details are even worse, so if it just works, you may skip the explanation. Understanding low level C details isn't neccesarily to write in it, and this (or any other) explanation cannot possibly cover this matter, so don't be discouraged, if you won't get it all.
arr2d is contiguous block of memory of arr2dSize*4 integers. When multiplied by sizeof(int) we get size in bytes - arr2dMem in my code. Declaration int (*arr2d)[4] means, that arr2d is of type int*[4]. Knowing this we can cast it to int* like so: int* arr = (int*)arr2d and expression arr2d[i][j] is translated as arr[i*4+j].
The translation to rects is as follows; int** is array of pointers, so every rect[i] has to be pointer to i-th row of arr2d. Knowing this, everything else is pointer arithmetic. rects[0] = malloc(arr2dMem); and memcpy(rects[0], arr2d, arr2dMem); copies whole arr2d to rect[0], then every next rects[i] = rects[0] + i*4; is shifted 4 integers forward. Because rect is of type int**, the expression rects[i][j] translates to *(rects[i]+j), and replacing rects[i] by rects[0] + i*4, we get *((rects[0] + 4*i)+j), that is rects[0][4*i+j]. Note striking similarity between last expression, and arr[i*4+j]. rectsColSize is somewhat superfluous in this case, but it is essential in general int** array, when every subarray could have different sizes. After wrap function is done, rects is exact copy of arr2d, but with type appropriate for your Solution structure, so we can call solutionCreate().

Pass a constant two-dimensional array to function as a structure in C

I'm a novice in C and I need a structure to pass constant two-dimensional arrays to function as one parameter. I want to make this
const int a_size_x = 20;
const int a_size_y = 30;
const int a_output_array[size_x][size_y] = {{..., ...}, ..., {..., ...}};
const int b_size_x = 20;
const int b_size_y = 30;
const int b_output_array[size_x][size_y] = {{..., ...}, ..., {..., ...}};
void function(const int array[], int arr_size_x, int arr_size_y){
for (int i = 0; i < arr_size_x; i++)
{
for (int j = 0; j < arr_size_y; j++)
{
printf("%i ", array[i][j];
}
printf("\n");
}
function(a_output_array, a_size_x, a_size_y);
function(b_output_array, b_size_x, b_size_y);
easier to be able to call function(a) like this:
const struct OUTPUT
{
const int size_x;
const int size_y;
const int array[size_x][size_y];
};
struct OUTPUT a = {.size_x = 20, .size_y = 30, .array = {{...}, ..., {...}};
....
struct OUTPUT z = {.size_x = 30, .size_y = 20, .array = {{...}, ..., {...}};
function(const struct OUTPUT out){
for (int i = 0; i < out.size_x; i++)
{
for (int j = 0; j < out.size_y; j++)
{
printf("%i ", out.array[i][j];
}
printf("\n");
}
function(a);
function(b);
but of course compiler says that size_x and size_y is undeclared in struct declaration.
I've read about flexible array members, but there's dynamic memory allocation needed, and in AVR Harvard architecture malloc can't work in program memory, where i put all this data.
Is there some way to do it in C? May be, in C++?
UPDATE Answer that worked for me - create a one-dimensional array of lenght 2 + width*height where first two members are true width and height and use a pointer to work with this. Here's an example function to print out this array:
char arr [11] =
{
3 // width
3 // height
1, 2, 3,
4, 5, 6,
7, 8, 9
}
void print_array(char *ptr)
{
char width = *ptr++;
char height= *ptr++;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
print("%c\t", *ptr++);
}
print("\n");
}
}
print_array(arr);
For most compilers, 2D arrays can be refered to as 1D as such:
matrix[3][3]=[1,2,3
4,5,6
7,8,9]
Index in 1D is calculated by row size*row number. For example: matrix[5]=6.
This means you can pass only 1 parameter, the row length, and by calculating the length of the whole vector you can deduce the 2nd parameter (number of rows).
You can add the row length parameter to the end of your array, and by so passing the array only, if that helps.
When declaring an array with an initializer, the bounds of the array must be constants. A variable with a const qualifier does not qualify as a constant. You can however use a macro which does a text substitution:
#define A_SIZE_X 2
#define A_SIZE_Y 3
const int a_output_array[A_SIZE_X][A_SIZE_Y] = {{3,4,5},{6,7,8}};
#define B_SIZE_X 2
#define B_SIZE_Y 3
const int b_output_array[B_SIZE_X][B_SIZE_Y] = {{1,2,3},{4,5,6}};
When passing a 2D array to a function, the definition must say that it expects a 2D array. Your is expecting const int array[] which is a 1D array.
You can have a function accept arrays with different bounds if the bounds are specified first in the definition:
void function(int arr_size_x, int arr_size_y, const int array[arr_size_x][arr_size_y]) {
You can then call it like this:
function(A_SIZE_X, A_SIZE_Y, a_output_array);
function(B_SIZE_X, B_SIZE_Y, b_output_array);
Side note first, the first snippet has a wrong signature and your compiler should warn you:
void function(const int array[], int arr_size_x, int arr_size_y){
here, array is a pointer to int (in a function signature, an array automatically gets adjusted to a pointer), but for passing a 2d array, you would need a pointer to array of int. Did you test that snippet? I assume it doesn't do what you want.
With C99 and above (assuming the compiler supports VLA, variable length arrays), something like this would be correct:
void function( int arr_size_x, int arr_size_y, const int (*array)[arr_size_y]){
As for your idea with a struct, you could only do it when you keep the second dimension fixed. A C array is contiguous in memory, so to do the indexing correctly, the compiler must know all dimensions except for the first one at compile time. VLAs are an exception to that rule, but you can't declare a VLA statically.
What you can do however is using a flat array and do the 2d indexing yourself, like in this tiny example:
struct outputdata
{
size_t rows;
size_t cols;
int *data;
};
const int a_data[] = {1, 2, 3, 4, 5, 6};
const struct outputdata a = {
.rows = 2,
.cols = 3,
.data = a_data
};
// [...]
void function(const struct outputdata x)
{
for (size_t r = 0; r < x.rows; ++r)
{
for (size_t c = 0; c < x.cols; ++c)
{
printf("%d ", x.data[r*x.cols + c]);
}
}
}

Passing three dimensional arrays to a function in C

I use to program with FORTRAN, but I decided to learn C and C++. I started with C language, and the one thing that I never used are pointers, because FORTRAN pass values by reference. I built the sample code below to understand how pointers work with multidimensional arrays:
#include <stdio.h>
#include <stdlib.h>
#define DIM1 3
#define DIM2 2
#define DIM3 4
void display3DArray1(int, int , int n, int (*arr)[][n]);
void display3DArray2(int rows, int cols1, int cols2,int arr[][cols1][cols2]);
int main(void)
{
int matrix3D[DIM1][DIM2][DIM3] = {
{{1, 2, 3, 4}, {5, 6, 7, 8}},
{{9, 10, 11, 12}, {13, 14, 15, 16}},
{{17, 18, 19, 20}, {21, 22, 23, 24}}
};
int (*pmatrix3D)[DIM2][DIM3] = matrix3D;
display3DArray1(DIM1, DIM2, DIM3,pmatrix3D);
display3DArray2(DIM1, DIM2, DIM3,pmatrix3D);
return 0;
}
void display3DArray1(int rows, int cols1, int cols2,int (*arr)[][cols2]) {
printf("\n");
for(int i=0; i<rows; i++) {
for(int j=0; j<cols1; j++) {
for(int k=0; k<cols2; k++) {
printf("*arr : %d adress: %p\n",*(*((*arr+i*cols1))+j*cols2+k),*((*arr+i*cols1))+j*cols2+k);
}
}
}
}
void display3DArray2(int rows, int cols1, int cols2,int arr[][cols1][cols2]) {
printf("\n");
for(int i=0; i<rows; i++) {
for(int j=0; j<cols1; j++) {
for(int k=0; k<cols2; k++) {
printf("*arr : %d adress: %p\n", *(*(*(arr+i)+j) + k), *(*(arr+i)+j) + k) ;
}
}
}
}
The code works, but there is something that I wasn't able to understand. When I try to use the second printf of the second function in the first one I get a compilation error:
"invalid use of array with unspecified bounds" -- under gcc.
Why *(arr + i) doesn't work in the first function?
You can use the following two ways to pass/print the matrix:
void display3DArray1(int rows, int cols1, int cols2, int *A) {
int *a, i, j, k;
printf("\n");
for(i=0; i<rows; i++) {
for(j=0; j<cols1; j++) {
for(k=0; k<cols2; k++) {
a= A+(i*cols1*cols2)+(j*cols2)+k;
printf("%d, %p\n", *a, a);
}
}
}
}
void display3DArray2(int A[DIM1][DIM2][DIM3]) {
int i, j, k;
printf("\n");
for(i=0; i<DIM1; i++) {
for(j=0; j<DIM2; j++) {
for(k=0; k<DIM3; k++) {
printf("%d, %p\n", A[i][j][k], &A[i][j][k]);
}
}
}
}
The first method does not rely on the dimensions of the matrix; the second one does. As a result, the first one needs explicit address calculations (row i, col j, cell k).
Use calls respectively:
display3DArray1(DIM1, DIM2, DIM3, (int *)matrix3D);
display3DArray2(matrix3D);
Note the cast of the matrix to an int pointer.
In your code, you used parameter names to specify the dimensions of the matrix. In my C version, that is not legal; they must be constants.
Just a complement to Paul Ogilvie's answer.
The correct usage of Variable Length Arrays would be:
void display3DArray3(int rows, int cols1, int cols2,int arr[][cols1][cols2]) {
printf("\n");
for(int i=0; i<rows; i++) {
for(int j=0; j<cols1; j++) {
for(int k=0; k<cols2; k++) {
printf("*arr : %d adress: %p\n", arr[i][j][k], &arr[i][j][k]);
}
}
}
}
I was a bit puzzled, to be honest. The core issue is that the declaration of a function parameter like in f(T arr[]) declares an incomplete type whose size is not known (neither at compile time nor at run time). Originally I thought empty square brackets in function parameter declarations simply declare a pointer — notation notwithstanding —, but that is not the case. The parameter still has array type, albeit incomplete.1
When you write
void display3DArray1(int rows, int cols1, int cols2,int (*arr)[][cols2])
you declare a pointer to such an incomplete type of unknown size. This pointer cannot be manipulated in all the usual ways; in particular, adding to it in order to jump to the next element is impossible because we don't know where the current element ends (and hence the next element starts). But you try that in
printf("*arr : %d adress: %p\n", *(*(*(arr+i)+j) + k), *(*(arr+i)+j) + k) ;
with the innermost arr+1. Just dereferencing it works, because the variable holds the address of the first element all right. This is what the print in the first function does:
printf("*arr : %d adress: %p\n",*(*((*arr+i*cols1))+j*cols2+k),*((*arr+i*cols1))+j*cols2+k);
with *arr. The element size of the incomplete array to which arr points is known (these elements are arrays of cols2 ints), so that we can add to *arr, even if we can't add to arr proper.
For completeness: Why can you access arr that way in the second function? Well:
void display3DArray2(int rows, int cols1, int cols2,int arr[][cols1][cols2])
declares arr as an incomplete array type, true; but the size of its elements is well known: Those are cols1 x cols2 int matrices. The declaration just doesn't specify how many are there, but we can surely iterate them if we somehow know when to stop.
1 Of course this array, like any other, "decays" to a pointer in most contexts, so that the missing type information doesn't matter. But it matters if we have pointers to them.
I had trouble finding the correct syntax for dereferencing matrices of rank2 and rank3. The intent is to remove a level of indexing for faster execution. Here's some pseudo code that will get you started. This is more about getting the syntax right (MSVC 2019) than an example of working code.
int recurse(int n, unsigned char rank2[13][4], unsigned char rank3[13][4][13])
{
if (n < 13)
{
unsigned char (*deRefRank1)[4] = &rank2[n]; // deref matrix rank 2 to rank 1
unsigned char(*deRefRank2)[4][13] = &rank3[n]; // deref matrix rank 3 to 2
// insert pre-recurse code here ... use (*deRefRank1)[] and (*deRefRank2)[][]
if (recurse(n + 1, rank2[n], rank3[n])
return -1;
// insert post-recurse code here ...
}
return 0;
}
Your array indexing in the 'print' routines is invalid. The declaration of 'matrix3D' implies that the type of that name is 'pointer to int'. NOTE: Only one level of indirection there. The indexing expressions have a bunch of ''-s in front of terms; in C that means 'the item to the right of the '' is a pointer which must be dereferenced to get to the value'. That means you are in effect treating 'matrix3D' as 'pointer to (pointer to (pointer to int))' which is too many indirections.

how to access the 3-d array using pointer to an array

i have declared a pointer to a group of 3-d array which I have shared below.I have a problem in accessing elements of the 3-d array using pointers to the 3-d array.
#include <stdio.h>
void main()
{
int m,row,col;
int *ptr,*j;
int array[2][5][2]={10,20,30,40,50,60,70,80,90,100,18,21,3,4,5,6,7,81,9,11};
int (*p)[5][2]; // pointer to an group of 3-d array
p=array;
for(m=0;m<2;m++)
{
ptr=p+m;
for(row=0;row<5;row++)
{
ptr=ptr+row;
for(col=0;col<2;col++)
{
printf("\n the vale is %d",*(ptr+col));
}
}
}
}
output:
the value is 10
the value is 20
the value is 20
the value is 30
the value is 40
the value is 50
the value is 70
the value is 80
the value is 18
the value is 21
the value is 18
the value is 21
the value is 21
the value is 3
the value is 4
the value is 5
the value is 7
the value is 81
the value is -1074542408
the value is 134513849
my question is how to access the elements of 3-d array using pointer to an array and in my case the output shows my code not accessing the elements 90,100,9,11 and how do i can access this in the above code.Thanks in advance.
Although flattening the arrays and accessing them as 1-d arrays is possible, since your original question was to do so with pointers to the inner dimensions, here's an answer which gives you pointers at every level, using the array decay behaviour.
#include <stdio.h>
/* 1 */
#define TABLES 2
#define ROWS 5
#define COLS 2
/* 2 */
int main()
{
/* 3 */
int array[TABLES][ROWS][COLS] = {
{ {10, 20}, {30, 40}, {50, 60}, {70, 80}, {90, 100} },
{ {18, 21}, {3, 4}, {5, 6}, {7, 81}, {9, 11} }
};
/* pointer to the first "table" level - array is 3-d but decays into 2-d giving out int (*)[5][2] */
/* name your variables meaningully */
int (*table_ptr)[ROWS][COLS] = array; /* try to club up declaration with initialization when you can */
/* 4 */
size_t i = 0, j = 0, k = 0;
for (i = 0; i < TABLES; ++i)
{
/* pointer to the second row level - *table_ptr is a 2-d array which decays into a 1-d array */
int (*row_ptr)[COLS] = *table_ptr++;
for (j = 0; j < ROWS; ++j)
{
/* pointer to the third col level - *row_ptr is a 1-d array which decays into a simple pointer */
int *col_ptr = *row_ptr++;
for (k = 0; k < COLS; ++k)
{
printf("(%lu, %lu, %lu): %u\n", (unsigned long) i, (unsigned long) j, (unsigned long) k, *col_ptr++); /* dereference, get the value and move the pointer by one unit (int) */
}
}
}
return 0; /* report successful exit status to the platform */
}
Inline code comments elaborated with reference
It's good practise to have the dimensions defined commonly somewhere and use it elsewhere; changing at one place changes it at all places and avoids nasty bugs
main's retrun type is int and not void
It's recommended not to avoid the inner braces
Use size_t to hold size types
Problems in your code
For the line ptr=p+m;, GCC throws assignment from incompatible pointer type; reason is p is of type int (*)[5][2] i.e. pointer to an array (size 5) of array (size 2) of integers, which is assigned to ptr which is just an integer pointer. Intead if you change it to int (*ptr) [5]; and then do ptr = *(p + m);. This is what my code does (I've named p as table_ptr), only that it doesn't use m but it increments p directly.
After this at the third level (inner most loop), you need a integer pointer say int *x (in my code this is col_ptr) which you'd do int *x = *(ptr + m1). Bascially you need to have three different pointers, each for one level: int (*) [5][2], int (*) [2] and int *. I've named them table_ptr, row_ptr and col_ptr.
Rewritten your code below and just used the pointer p to print everything.
#include <stdio.h>
void main()
{
int m,row,col;
int array[2][5][2]={10,20,30,40,50,60,70,80,90,100,18,21,3,4,5,6,7,81,9,11};
int (*p)[5][2]; // pointer to an group of 3-d array
p=array;
for(m=0;m<2;m++)
{
for(row=0;row<5;row++)
{
for(col=0;col<2;col++)
{
printf("\n the vale is %d", *((int*)(p+m) + (row*2) + col));
}
}
}
}
You can easily access all the elements simply by a looping through 2*5*2 = 20 and using a pointer to the first element of array, i.e, array[0][0][0] assuming 3D array as 1D array of arrays of arrays of int's.
#include <stdio.h>
void main()
{
int m; //row,col;
int *ptr; //,*j;
int array[2][5][2]={10,20,30,40,50,60,70,80,90,100,18,21,3,4,5,6,7,81,9,11};
//int (*p)[5][2]; // pointer to an group of 3-d array
//p=array;
ptr = &array[0][0][0];
for(m=0;m <2;m++)
{
for (m = 0; m < 20; m++)
/* ptr=ptr+m;
for(row = 0;row < 5;row ++)
{
ptr=ptr+row;
for(col=0;col<2;col++)
{
printf("\n the vale is %d",*(ptr+col));
}
}*/
printf("\n the vale is %d", *(ptr++));
}
}
I commented some parts of your code and left it in the modified code to let you clear what I have done.
#include<stdio.h>
int main()
{
int array[2][2][2]={1,2,3,4,5,6,7,8};
int *p;
p=&array[0][0][0];
int i=0,j,k;
/*Accessing data using pointers*/
for(i=0;i<2;i++)
{
for(j=0;j<2;j++)
{
for(k=0;k<2;k++)
{
printf("%d\n",*p);
p++;
}
}
}
return 0;
}
This is a sample code where elements in a 2X2X2 array is been accessed using pointers.
Hope it helps !!!!

Define a matrix and pass it to a function in C

I want to create a program in which I can pass a matrix to a function using pointers.
I initialized and scanned 2 matrices in the void main() and then I tried to pass them to a void add function. I think I am going wrong in the syntax of declaration and calling of the function. I assigned a pointer to the base address of my matrix. (for eg: int *x=a[0][0], *y=b[0][0]). What is the right declaration? How can I specify the dimensions?
Given a 2D array of
T a[N][M];
a pointer to that array would look like
T (*ap)[M];
so your add function prototype should look like
void add(int (*a)[COLS], int (*b)[COLS]) {...}
and be called as
int main(void)
{
int a[ROWS][COLS];
int b[ROWS][COLS];
...
add(a, b);
However, this code highlights several problems. First is that your add function is relying on information not passed via the parameter list, but via a global variable or symbolic constant; namely, the number of rows (the number of columns is explicitly provided in the type of the parameters). This tightly couples the add function to this specific program, and makes it hard to reuse elsewhere. For your purposes this may not be a problem, but in general you only want your functions to communicate with their callers through the parameter list and return values.
The second problem is that as written, your function will only work for matrices of ROWS rows and COLS columns; if you want to add matrices of different sizes within the same program, this approach will not work. Ideally you want an add function that can deal with matrices of different sizes, meaning you need to pass the sizes in as separate parameters. It also means we must change the type of the pointer that we pass in.
One possible solution is to treat your matrices as simple pointers to int and manually compute the offsets instead of using subscripts:
void add (int *a, int *b, size_t rows, size_t cols)
{
size_t i;
for (i = 0; i < rows; i++)
{
size_t j;
for (j = 0; j < cols; j++)
{
*(a + cols * i + j) += *(b + cols * i + j);
}
}
}
and call it like so:
int main(void)
{
int a[ROWS][COLS] = {...};
int b[ROWS][COLS] = {...};
int c[ROWS2][COLS2] = {...};
int d[ROWS2][COLS2] = {...};
...
add(a[0], b[0], ROWS, COLS);
add(c[0], d[0], ROWS2, COLS2);
...
}
The types of a[0] and b[0] are "COLS-element arrays of int"; in this context, they'll both be implicitly converted to "pointer to int". Similarly, c[0] and d[0] are also implicitly converted to int *. The offsets in the add() function work because 2D arrays are contiguous.
EDIT I just realized I was responding to caf's example, not the OP, and caf edited his response to show something very similar to my example. C'est la guerre. I'll leave my example as is just to show a slightly different approach. I also think the verbiage about passing information between functions and callers is valuable.
Something like this should do the trick.
#define COLS 3
#define ROWS 2
/* Store sum of matrix a and b in a */
void add(int a[][COLS], int b[][COLS])
{
int i, j;
for (i = 0; i < ROWS; i++)
for (j = 0; j < COLS; j++)
a[i][j] += b[i][j];
}
int main()
{
int a[ROWS][COLS] = { { 5, 10, 5} , { 6, 4, 2 } };
int b[ROWS][COLS] = { { 2, 3, 4} , { 10, 11, 12 } };
add(a, b);
return 0;
}
EDIT: Unless you want to specify the dimensions at runtime, in which case you have to use a flat array and do the 2D array arithmetic yourself:
/* Store sum of matrix a and b in a */
void add(int rows, int cols, int a[], int b[])
{
int i, j;
for (i = 0; i < rows; i++)
for (j = 0; j < cols; j++)
a[i * cols + j] += b[i * cols + j];
}
#caf has shown a good code example.
I'd like to point out that:
I assigned a pointer to the base
address of my matrix. (for eg: int
*x=a[0][0],*y=b[0][0]).
You are not assining a pointer to the base of the matrix. What this does is assign to the value pointed by x and y, the base value in a and b respectively.
The right way would be
int (*x)[] = a;
int (*y)[] = b;
or alternatively
int *x = &a[0][0];
int *y = &b[0][0];

Resources