intex0075
intex0075

Reputation: 115

pointer to array and 2D array representation

I have doubt in syntax of pointer to array and 2D array

#include<stdio.h>
#include<stdlib.h>

void show ( int q[][4], int row )
{
  int i, j ;
  for ( i = 0 ; i < row ; i++ )
  {
     for ( j = 0 ; j < 4 ; j++ )
      printf ( "%d ", q[i][j] ) ;
    printf ( "\n" ) ;
  }
  printf ( "\n" ) ;
}

int main( )
{
 int a[][4] = {
                {1, 2, 3, 4},
                {5, 6, 7, 8},
                {9, 0, 1, 6}
              } ;
 show ( a, 3, 4 ) ;
 return 0;
}

The above code works with all the below notations

void show ( int q[][4], int row )
void show ( int q[3][4], int row )
void show ( int ( *q )[4], int row, int col )

 int q[][4]  == int q[3][4]==int ( *q )[4] // represents pointer to 1D array with size 4

I have read this

int q[ ][4]; This is same as int ( *q )[4], where q is a pointer to an array of 4 integers. The only advantage is that we can now use the more familiar expression q[i][j] to access array elements.

Question:

The show() function works with both of these, int q[][4] and int q[3][4] to receive 2D array's address.

But these are representation for 2D array right?

we can't allocate 2D like the following

  int (*a)[4] = {                 
                {1, 2, 3, 4},
                {5, 6, 7, 8},
                {9, 0, 1, 6}
              } ; 

But 2D can be allocated via this statement

     int a[][4]={                 
                {1, 2, 3, 4},
                {5, 6, 7, 8},
                {9, 0, 1, 6}
              } ; 

int (*a)[4] is not the same as int a[][4], then how come both 'pointer to array' and '2D array notation' can be used in show function?

Upvotes: 2

Views: 868

Answers (3)

John Bode
John Bode

Reputation: 123468

First, some language from the C standard:

6.3.2.1 Lvalues, arrays, and function designators
...
3 Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.

In the call to the show function, the expression a has type "3-element array of 4-element array of int". By the rule above, this expression is replaced with an expression of type "pointer to 4-element array of int" before the call is made; thus, show receives a pointer value of type int (*)[4], not an array.

More standard language:

6.7.5.3 Function declarators (including prototypes)
...
7 A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to type’’, where the type qualifiers (if any) are those specified within the [ and ] of the array type derivation. If the keyword static also appears within the [ and ] of the array type derivation, then for each call to the function, the value of the corresponding actual argument shall provide access to the first element of an array with at least as many elements as specified by the size expression.

Thus, in the context of a function parameter declaration, T a[n], T a[], and T *a are all equivalent. If T is an array type, such as "4-element array of int", then int a[3][4], int a[][4], and int (*a)[4] are all equivalent.

Note that this is only true for function parameter declarations. When you're declaring an array object, the following language comes into play:

6.7.8 Initialization
...
22 If an array of unknown size is initialized, its size is determined by the largest indexed element with an explicit initializer. At the end of its initializer list, the array no longer has incomplete type.

So when you write

int a[][4] = {
            {1, 2, 3, 4},
            {5, 6, 7, 8},
            {9, 0, 1, 6}
          } ;

you are declaring an Nx4 array of int, not a pointer to an array of int -- the inner dimension 3 is inferred from the number of 4-element arrays in the initializer.

Upvotes: 0

Dave
Dave

Reputation: 11162

Functions have special rules regarding array parameters, the basic rule is if you speak the function's prototype, and your first word is array, you change it to "pointer to", so that

(int foo[5]) ==> array[5] of int ==> pointer to int
(int foo[][4]) ==> array[] of array[4] of int  ==>  pointer to array[4] of int
(int (*foo)[4]) ==> pointer to array[4] of int ==>  pointer to array[4] of int
(int *argv[]) ==> array of pointer to int ==> pointer to pointer to int

Within a function, that conversion doesn't happen, and there is a big difference between array and pointer types.

int a[] = {5, 3, 2};

Is legal, but

int *a = {5, 3, 2};

is not. As a rule, you can't assign a pointer from an array initializer. Instead, c99 provides compound literals:

int *a = (int[]){5, 3, 2};

int (*a)[4] = (int [][4]){
     {2, 2, 3, 1},
     {2, 3, 5, 3},
};

Upvotes: 2

Daniel Fischer
Daniel Fischer

Reputation: 183888

Arrays are not pointers, but in many situations, arrays decay into pointers, for example when passed as function arguments. So when you pass an int q[][4] to a function, the function receives an int (*q)[4], a pointer to arrays of four int. That's why both forms work as arguments to show(). But for the declaration and initialization, the real type matters, so you can't initialize a pointer with an array-initializer.

Upvotes: 2

Related Questions