'returning an array in C++ with templates

I have the following code, where the kronecker product of 2 arrays is computed. In this code I want to return the array C which is the kronecker product of the two arrays back to the main function. I have tried pointers instead of void but I am not able to do it. Also I want tje function to compute the kroecker product of the arrays of any sizes so I have used templates here. How can I return the array C (Kronecker product) back to the main.

#include <iostream>
using namespace std;
#include <any>
#include <vector>


template <size_t size_x1, size_t size_y1, size_t size_x2, size_t size_y2>

void Kroneckerproduct(int (&A)[size_x1][size_y1],int (&B)[size_x2][size_y2])
{

 int rowa=size_x1;
 int cola=size_y1; 
 int rowb=size_x2;
 int colb=size_y2;

    int C[rowa * rowb][cola * colb];

    // i loops till rowa
    for (int i = 0; i < rowa; i++) {
        //for (int i = 0; i < size_x1; i++) {

        // k loops till rowb
        for (int k = 0; k < rowb; k++) {
           // for (int k = 0; k < size_x2; k++) {

            // j loops till cola
            for (int j = 0; j < cola; j++) {
                //for (int j = 0; j < size_y1; j++) {

                // l loops till colb
                for (int l = 0; l < colb; l++) {
                   // for (int l = 0; l < size_y2; l++) {

                    // Each element of matrix A is
                    // multiplied by whole Matrix B
                    // resp and stored as Matrix C
                    C[i + l + 1][j + k + 1] = A[i][j] * B[k][l];
                    cout << C[i + l + 1][j + k + 1] << " ";
                }
            }
            cout << endl;
        }
    }




}


int main()
{
    int A[3][2] = { { 1, 2 }, { 3, 4 }, { 1, 0 } },
        B[2][3] = { { 0, 5, 2 }, { 6, 7, 3 } };

    Kroneckerproduct(A, B);
    return 0;
}


Solution 1:[1]

To return an array from a function, you must dynamically allocate it first. This is necessary as the array declared in the function statically is cleared after the function finishes its execution.

To create an array of dimension m x n you can do something like this:

int** c = new int*[m];

for (int i = 0; i < m; i++)
{
    c[i] = new int[n];
}

Now, you can simply return it using return c;

Also, you need to delete this array manually as it was dynamically created. You can do so by using:

for(int i = 0; i < m; i++)    // To delete the inner arrays
    delete [] c[i];   
delete [] c;

Solution 2:[2]

One heritage from old C is that raw arrays cannot be directly transferred by value. The traditional workaround is to wrap the array in a struct if the size is not so large that might overflow the stack.

You are using a none standard extension of C++ in your program:

int rowa=size_x1;
int cola=size_y1; 
int rowb=size_x2;
int colb=size_y2;
int C[rowa * rowb][cola * colb];

These definitions lead to runtime stack allocated array, which is not standard. A minor modification on modern compilers however makes for a standard solution:

constexpr int rowa=size_x1;
constexpr int cola=size_y1; 
constexpr int rowb=size_x2;
constexpr int colb=size_y2;

Or on older compilers:

enum{
    rowa=size_x1,
    cola=size_y1,
    rowb=size_x2,
    colb=size_y2
};

Next tip: using namespace std; this is bad practice at global scope. Prefixing standard identifiers with std:: makes code more understandable, while avoiding possible name collisions.

Instead of using raw arrays, you'd better use std::array for static sized arrays and std::vector for dynamic sized or large arrays:

#include <array>
template<std::size_t cols, std::size_t rows>
using array2d = std::array<std::array<int, rows>, cols>;

constexpr std::size_t size_x = 3;
constexpr std::size_t size_y = 4;

array2d<size_x,size_y> a;

Moreover, since it looks you are creating a tensor/matrix library, you may consider a redesign to define a template class instead of simple use of arrays.

Solution 3:[3]

C style arrays aren't regular, which makes them a big pain to deal with. That's why std::array exists.

template <size_t size_x1, size_t size_y1, size_t size_x2, size_t size_y2>
std::array<std::array<int, size_y1 * size_y2>, size_x1 * size_x2> Kroneckerproduct(const std::array<std::array<int, size_y1>, size_x1> & A, const std::array<std::array<int, size_y2>, size_x2> & B)
{
    std::array<std::array<int, size_y1 * size_y2>, size_x1 * size_x2> C;

    for (int i = 0; i < size_x1; i++) {
        for (int k = 0; k < size_x2; k++) {
            for (int j = 0; j < size_y1; j++) {
                for (int l = 0; l < size_y2; l++) {
                    C[(i * size_x2) + l][(j * size_y2) + k] = A[i][j] * B[k][l];
                }
            }
        }
    }

    return C;
}

I've also fixed the indexing of C. When you were printing what you'd just written to an element of C, it wasn't obvious that you were overwriting values. You can see the difference if you print the indexes

std::cout << "C[" << (i + l + 1) << "][" << (j + k + 1) << "] ";

vs

std::cout << "C[" << ((i * size_x2) + l) << "][" << ((j * size_y2) + k) << "] ";

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 SudhanshuSuman
Solution 2 Red.Wave
Solution 3 Caleth