5

I am trying to write a function which can take array of any dimension and print values in the array successfully. But I am not able to move forward because we have to declare all the dimensions except left most one when declaring function. Is there any possibility that we can write a generalised function which can take array as input for any dimensions?

for example, the function should be able to take 2 dimensional array or 3 dimensional array or n dimensional array where n is any number.

kadina
  • 5,042
  • 4
  • 42
  • 83
  • 1
    It might be possible with [variadic templates](http://en.cppreference.com/w/cpp/language/parameter_pack). – Some programmer dude Sep 19 '14 at 19:43
  • You may be able to use a template in some way, but that would open the program to error, especially because it sounds like you are working with a team. – Cartier Sep 19 '14 at 19:43
  • @JoachimPileborg It depends if the generation is random, or predefined; a variadic template would work for pre-defined not random. – Cartier Sep 19 '14 at 19:46
  • The answer would also seem to depend on whether this is a C or a C++ question, since I don't think templates exist in C. – user3386109 Sep 19 '14 at 19:50

6 Answers6

10

Using recursion for each dimension and template (so in C++), following may help:

template <typename T>
void print(const T&e)
{
    std::cout << e << " ";
}

template <typename T, std::size_t N>
void print(const T (&a)[N])
{
    std::cout << "{";
    for (const auto& e : a) {
        print(e);
    }
    std::cout << "}" << std::endl;
}

Example usage:

int a[2][3][4];
print(a);

Live example

Jarod42
  • 203,559
  • 14
  • 181
  • 302
3

If you code you array as one-dimensional and then calculate the single index yourself, you can certainly have a program act as though the array was made for a variable number of dimensions.

My initial though on how to do that would be to start with a vector containing the extent of each dimension you intend to use.

The number of elements in that vector would be the number of dimensions you have.

Logicrat
  • 4,438
  • 16
  • 22
3

An array is passed to a function as a pointer to the type of the array elements, regardless of the dimensionality of the array. You could have further arguments to specify the number of dimensions, n, and an array (another one) of length n specifying the number of elements in each dimension. Note that the [] notation is simply a tidy way of performing pointer addition.

Tom
  • 93
  • 1
  • 6
3

If you want to access particular element or operate on the array but if you want to create the matrix dynamically, you can use use pointers to access each element by passing the dimensions in the print function.

Since if you have a multidimensional array defined as int [][], then x = y[a][b] is equivalent to x = *((int *)y + a * NUMBER_OF_COLUMNS + b);

Check this post for more details: How to use pointer expressions to access elements of a two-dimensional array in C?

So, if you want to print whole matrix or access any particular element, you can do like:

#include <iostream>
using namespace std;

//the function print_2D_matrix receives 4 arguments: pointer to first element
//                                                   dimension of array arr, i.e. n x m
//                                                   index of the element to be printed, i.e. a and b
void print_2D_matrix(int *arr, int n, int m, int a, int b){
    for(int i = 0; i < n; i++){
        for(int j = 0; j < m; j++)
            printf("%d ", *(arr + (i * m) + j));
        printf("\n");
    }
    //go to the address just before a row, i.e. (a - 1) * NO_OF_COLUMNS 
    //then go to the address on b column, i.e. (a - 1) * NO_OF_COLUMNS + b
    //since we started from the base address, i.e. first element( arr[0][0] ), subtract 1 
    printf("arr[3][3] = %d\n", *(arr + ((a - 1) * m) + b - 1));    //print arr[a][b]
} 

int main() {
    int n, m;
    cin>>n>>m;
    int arr[n][m];

    for(int i = 0; i < n; i++)    //initialize the matrix
        for(int j = 0; j < m; j++)
            arr[i][j] = i * j;

    print_2D_matrix((int *) arr, n, m, 3, 3);

    return 0;
}

Output for above program (for n x m = 4 x 5) is:

0 0 0 0 0
0 1 2 3 4
0 2 4 6 8
0 3 6 9 12
arr[3][3] = 4
Community
  • 1
  • 1
crazy_Fish
  • 78
  • 4
0

I'm sure this violates at least one rule of the C standard but it should work in practice. Note that it uses 0 as a sentinel value for the terminating element of any level of the array.

void print(void* p, int dim)
{
    if (dim == 1)
    {
        int* a = (int*) p;
        while (*a)
        {
            printf("%d ", *a++);
        }
        printf("\n");
    }
    else
    {
        void** a = (void**)p;
        while (*a)
        {
            print(*a++, dim - 1);
        }
    }
}

void test()
{
    int x0 [] = { 11, 12, 13, 14, 15, 0 };
    int x1 [] = { 21, 22, 23, 0 };
    int x2 [] = { 0 };
    int x3 [] = { 41, 42, 0 };
    int x4 [] = { 51, 52, 53, 0 };
    int* y0 [] = { x0, x3, 0 };
    int* y1 [] = { 0 };
    int* y2 [] = { x1, x2, x4, 0 };
    int** z [] = { y0, y1, y2, 0 };

    print(z, 3);
}

Prints:

11 12 13 14 15
41 42
21 22 23

51 52 53
MooseBoys
  • 6,641
  • 1
  • 19
  • 43
0

I have made a function that can print any n-dimensional iterable container:

template<typename Object, typename Iterable>
void Print(
    const Iterable& iterable,
    const string& separatorDimensions = "\n",
    const function<void(const Object&)>& funcPrintElem = [] (const Object& obj) {
        static_assert(
            is_arithmetic_v<Object> || is_same_v<remove_const_t<remove_pointer_t<Object>>, char>,
            R"(The object from the innermost range is not a built-in/c-string type, please provide a valid print element function.)"
            );
        cout << obj << ' ';
    }
) {
    if constexpr (ranges::range<Iterable>) {
        ranges::for_each(iterable, [&] (const auto& it) { Print(it, separatorDimensions, funcPrintElem); });
        cout << separatorDimensions;
    } else {
        funcPrintElem(iterable);
    }
}

The function has a default std::function that can print any built-in type like int, unsigned char, long long etc... and the c-string like char* or const char*, if you have another object like a pair or tuple or an object of your class you can pass a function that prints your object.

You can use the function like this: (you must explicitly tell the function your inner most object like below)

int main() {
    cout << "v: " << endl;
    vector<uint16_t> v { 1, 2, 3 };
    Print<uint16_t>(v);

    cout << endl << "ll: " << endl;
    list<list<const char*>> ll { { "a", "b" }, { "c", "d" } };
    Print<const char*>(ll);

    struct smth {
        int a;
        char b;
    };

    cout << endl << "smths: " << endl;
    vector<smth> smths { { 14, '0' }, { 18, '1' } };
    Print<smth>(smths, "\n", [] (const smth& obj) { cout << "a = " << obj.a << ", b = " << obj.b << endl; });

    return 0;
}

The function can be found here, maybe I will update in the future to support more things.

You need to have at least c++20 for this function to work.

Claudiu HBann
  • 56
  • 1
  • 9