2

The following code works, but is it OK?

#include <iostream>

using namespace std;

void display(int (*A)[3], int m, int n)
{
        for(int i=0;i<m;i++)
                for(int j=0;j<n;j++)
                        cout << A[i][j] << endl;
}

int main()
{
        int arr[][3] = {{1,2,3},{4,5,6}};
        display(arr,2,3);
}

Since A is a pointer to integer array of size 3, effectively aren't we just referring to the first row? It works because the 6 elements are in contiguous locations, hence we are traversing 6 times from the address of the first item. Is my understanding correct?

1
  • The two elements are in contiguous locations. arr is an array of size two. where each element is itself an array of size three. All arrays are stored contiguously, whatever the element type. Commented Jun 11, 2019 at 15:47

4 Answers 4

1

Yes, it is fine. Like with any pointer arithmetic, you are using a pointer to the first object. The first object of an int[2][3] array is of type int[3] and a pointer to that object is of type int(*)[3], an array pointer.

Your code is completely equivalent to void display(int A[2][3], int m, int n). In this case the compiler silently adjusts the parameter to a pointer to the first object "between the lines", so you end up with exactly the same code. Though my version here is preferred since it is more readable.

As for why you can use A[i][j], think of A[i] as pointer arithmetic on objects of sizeof(int[3]).


C would also allow you to do void display(int m, int n, int A[m][n]), but that isn't possible in C++.

Sign up to request clarification or add additional context in comments.

4 Comments

"Though my version here is preferred since it is more readable." display(int A[2][3]) is confusing as 2 is ignored. I really prefer int(*)[3] or even better int(&a)[2][3] (possibly with template) (so both n and m are unneeded). and to avoid C-array syntax, std::vector or std::array may be used.
@Jarod42 How can self-documenting code be confusing? int A[2][3] clearly expects an array of 2x3. Not 4x3 or 10x3. It will still work if you pass such an array, but that's the callers problem then.
if really 2 3 are expected, take it by reference, so compiler can check argument. Else, it is mostly like a comment which might not be in correlation with code.
@Jarod42 That's another option in C++, but this question was originally tagged both C and C++.
0

The way you're passing this array is correct.

Anytime you pass an array to a function, you're actually passing a pointer to the first element. In this case, each element of the array is a int[3].

For the same reason, if you defined arr as int arr[2] then you can pass it to a function expecting a int *.

Comments

0

The code is fine. Arrays decay to a pointer to their first element. That means a 2d array will decay into a pointer to an array.

That said, you can also pass the array by reference, which allows you to not have to specify the array size since it can be deduced for you. Changing you function to

template <size_t rows, size_t cols>
void display(const int (&A)[rows][cols])
{
    for(int i=0;i<rows;i++)
            for(int j=0;j<cols;j++)
                    cout << A[i][j] << endl;
}

allows you to call it like display(arr); instead of display(arr,2,3);.

1 Comment

That also allows for-range: for (const auto& row : A) {for (auto e : row) { std::cout << e << std::endl;}}.
0

Since A is a pointer to integer array of size 3, effectively aren't we just referring to the first row?

Yes, A points to the first (at index zero) element of the 2D array. There are a total of two elements in the 2D array. Each of them is a 1D array i.e. a row of the 2D array. A[i] is the ith (zero based) row. A[i][j] is the jth element of the ith row.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.