1

Code

#include <iostream>
void display(int, int, void* );

int main()
{
    int A[][2]= { 0, 2,
                  4, 2,
                  2, 2};
    int m=3, n=2;
    display(m, n, &A[0][0]);
}

void display(int m, int n, void *p)
{
    int (*q)[m][n]=( int(*)[m][n] )p; // This causing error

    for(int i=0; i<=m-1; i++)
    {
        for(int j=0; j<=n-1; j++)
        {
            std::cout<<q[i][j]<<" ";
        }
        std::cout<<"\n";
    }
}

Output(Error)

Cannot initialize a variable of type 'int (*)[m][n]' with
an rvalue of type 'int (*)[m][n]'

https://stackoverflow.com/a/35657313/11862989 here user mention this but it's not working.

int (*q)[m][n]=( int(*)[m][n] )p; so why this typecasting is not happening.

Abhishek Mane
  • 619
  • 7
  • 20

1 Answers1

2

You don't have to use vectors for statically sized data you can still use "C" style arrays. AND you can do it in a typesafe (and memory access safe way) as shown here :

#include <iostream>

/*
This is an insecure way of doing things anyway since it depends on 
- typeconversion from void* (you could put anything into this function and it would try to display it)
- n and m could differ from actual sizes of the array leading to out of bounds error

void display(int m, int n, void* p)
{
    int(*q)[m][n] = (int(*)[m][n])p; // This causing error <== because it is incorrect syntax

    for (int i = 0; i <= m - 1; i++)
    {
        for (int j = 0; j <= n - 1; j++) // dont compare with <= it just not standard practice
        {
            std::cout << q[i][j] << " ";
        }
        std::cout << "\n";
    }
}
*/

// this would be the fixed size signature 
// note it is typesafe (no void*) and carries the sizes
// within the datatype
void display(int (&values)[3][2])
{
    for(int row=0; row < 3; ++row)
    {
        for(int col=0; col < 2; ++col)
        {
            std::cout << values[row][col] << " ";
        }
        std::cout << "\n";
    }
}


// to make the previous function reusable for other array sizes
// you can make it a function template
// and notice I replaced the index based for loops with range 
// based for loops for added safety 
template<std::size_t N, std::size_t M>
void display_template(int (&values)[N][M])
{
    std::cout << "\nfunction template version of display\n";

    // need a reference to a row
    // and the consts mean that display can only
    // look at the rows and values not change them
    for(const auto& row : values)
    {
        for(const auto value : row)
        {
            std::cout << value << " ";
        }
        std::cout << "\n";
    }
}


int main()
{
    // initialize 2d array in a 2d manner (nested {})
    int values[3][2] {{0,2},{4,2},{2,2}};

    display(values);
    display_template(values);

    return 0;
}
Pepijn Kramer
  • 9,356
  • 2
  • 8
  • 19
  • Upvoted, but be aware that this creates a new function for every array with differing dimensions. – Dúthomhas Jan 12 '22 at 07:21
  • @Dúthomhas I am well aware that for template functions. But its good to mention for those systems that have strict memory limitations and on those systems the non-template version may be used. (anyway my take on it is don't use coding styles that rely on array to pointer decay) – Pepijn Kramer Jan 12 '22 at 07:48
  • @PepijnKramer first of all thanks. I got it. So https://stackoverflow.com/a/35657313/11862989 this answer is wrong in-spite of 7 upvotes right ? – Abhishek Mane Jan 13 '22 at 13:08
  • 1
    I wouldn't say its wrong, it will work.... But it undermines the type system by using a void* (which IMO is really a "C" left over technique). In C++ stay true to your types and the compiler will be your friend. If you think you need a void* to be able to support multiple types, use function templates to make things typesafe. – Pepijn Kramer Jan 13 '22 at 13:53
  • @PepijnKramer I got it. But I am not understanding why we choose `void*` not `int*` & then try to typecast ? – Abhishek Mane Jan 14 '22 at 06:20
  • As long as you have to force the pointer to doubles it doesn't matter if it is an int* or a void* it is still type unsafe so neither is good. So try to minimize type casts in your code and if you do use static_cast, dynamic_cast or last resort reinterpret_cast don't use "c" style casts like (double*) – Pepijn Kramer Jan 14 '22 at 06:28