2

This is an extension to a previous question I previously asked. I can use a template to submit a dynamic 2D array and access the elements. Now, let's say I have a pointer to such an array. I am currently using the method shown here to assign my pointer to the original 2d array. I initially thought I could just change the expected input of the template function to (*A)[M][N] but that's a no-go. Am I missing some concept regarding pointers that someone could kindly explain?

header.h

#pragma once

#include <cstddef>
#include <iostream>
using namespace std;

template<size_t N, size_t M>
       void printPtr( int(*A)[M][N]) {
           for(int i=0; i < M; i++){
               for(int j=0; j<N; j++) {
                   cout << A[i][j] << " ";
               }
               cout << endl;
           }
       }

main.cpp

#include "header.h"
#include <iostream>
using namespace std;

int main() {

    int A[][3] = {
        {1,2,3},
        {4,5,6},
        {7,8,9},
        {10,11,12}
    };

    int (*ptrA)[3] = A;
    printPtr(ptrA);
}
Community
  • 1
  • 1
cdeterman
  • 19,630
  • 7
  • 76
  • 100

3 Answers3

2

If you're not interested in knowing why your code isn't working in the first place just skip to the end of this post

The problem with your code is that you're "simulating" an array decaying by passing your pointer along:

int A[][2] = {
    {1,2,3},
    {4,5,6},
    {7,8,9},
    {10,11,12}
};

int (*ptrA)[3] = A;

This is confirmed by the following code which uses C++11 features:

#include <iostream>
#include <type_traits>
using namespace std;

template <typename T, typename U>
struct decay_equiv : 
    std::is_same<typename std::decay<T>::type, U>::type 
{};

int main() {

    int A[][4] = {
            { 1, 2, 3 },
            { 4, 5, 6 },
            { 7, 8, 9 },
            { 10, 11, 12 }
    };

    std::cout << std::boolalpha
              << decay_equiv<decltype(A), int(*)[3]>::value << '\n'; // Prints "true"
}

Example

You should either pass a non-decayed type (i.e. a type that has all the information regarding the array dimension) to the function via a pointer or a reference:

#include <cstddef>
#include <iostream>
using namespace std;

template<size_t N, size_t M>
void printPtr(int (*A)[M][N] /* Also a reference could work */) {
   for(int i=0; i < M; i++){
      for(int j=0; j<N; j++) {
         cout << (*A)[i][j] << " ";
      }
      cout << endl;
   }
}

int main() {

    int A[][6] = {
            { 1, 2, 3 },
            { 4, 5, 6 },
            { 7, 8, 9 },
            { 10, 11, 12 }
    };

    int(*ptrA)[4][7] = &A; // Not a decayed type
    printPtr(ptrA);
}

Example

Another solution would be to not use a pointer to the array in the first place or dereference it when passing a reference to the array:

template<size_t N, size_t M>
void printPtr( int(&A)[M][N]) {
     for(int i=0; i < M; i++){
         for(int j=0; j<N; j++) {
             cout << A[i][j] << " ";
         }
         cout << endl;
     }
}

...
printPtr(A);
printPtr(*ptrA);

Example

Community
  • 1
  • 1
Marco A.
  • 43,032
  • 26
  • 132
  • 246
1

You defined the function parameter as a pointer to a two-dimensional array

int(*A)[M][N]) 

while are trying to call the function passing as the argument a pointer to a one-dimensional array

int (*ptrA)[3] = A;
printPtr(ptrA);

Moreover the function itself is invalid. It shall look like

template<size_t N, size_t M>
       void printPtr( int(*A)[M][N]) {
           for(int i=0; i < M; i++){
               for(int j=0; j<N; j++) {
                   cout << ( *A )[i][j] << " ";
               }
               cout << endl;
           }
       }

that is you have to use expression ( *A )[i][j] instead of A[i][j]

So you need to change the function the way shown above and to use appropriate pointer as the argument

int (*ptrA)[4][3] = &A;
printPtr(ptrA);

Of course it would be better to define the function parameter as reference to a two-dimensional array. For example

template<size_t N, size_t M>
       void printPtr( int(&A)[M][N]) {
           for(int i=0; i < M; i++){
               for(int j=0; j<N; j++) {
                   cout << A[i][j] << " ";
               }
               cout << endl;
           }
       }

In this case you could call the function like

printPtr( A );
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
0

It should be

template<size_t N, size_t M>
void printPtr(const int(&A)[M][N]) {
   for(int i=0; i < M; i++){
      for(int j=0; j<N; j++) {
         cout << A[i][j] << " ";
      }
      cout << endl;
   }
}

calling with:

printPtr(A);

or

template<size_t N, size_t M>
void printPtr(const int(*A)[M][N]) {
   for(int i=0; i < M; i++){
      for(int j=0; j<N; j++) {
         cout << (*A)[i][j] << " ";
      }
      cout << endl;
   }
}

calling with:

printPtr(&A);

BTW your pointer should be:

int (*ptrA)[4][3] = &A;
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • Thank you, however, I tried both and get the errors `no matching function for call to 'printPtr(int (*&)[4][3])'` and `... 'printPtr(int(**)[4][3])'` respectively. Did I make a strange mistake? – cdeterman Nov 04 '14 at 14:48