0

I know that 2D array is basically pointer to array so in the following code a is pointer to 0th index that is itself an array and than *a should return address of 0th index element how a and *a both return same value

#include <stdio.h>
#include <stdio.h>
      int main () {
          int a[4] [5] = {{1, 2, 3, 4, 5},
                          {6, 7,8, 9, 10},
                          {11, 12, 13, 14, 15},
                          {16, 17,18, 19, 20}};
     
      
         printf("%d\n",a);
         printf("%d\n",*a);
    
    }
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335

4 Answers4

2

For starters to output a value of a pointer you should use the conversion specifier %p instead of %d.

     printf( "%p\n", ( void * )a );
     printf( "%p\n", ( void * )*a) ;

The array designator a used as an argument expression is implicitly converted to a pointer to its first element. As the array declared as a two-dimensional array like

      int a[4] [5] = {{1, 2, 3, 4, 5},
                      {6, 7,8, 9, 10},
                      {11, 12, 13, 14, 15},
                      {16, 17,18, 19, 20}};

then its elements have the type int [5] and the pointer (having the type int ( * )[5]) to which the array is implicitly converted will have the address of the first "row" of the array that is the initial address of the extent of memory occupied by the array.

Dereferencing the pointer you will get the first "row" that is the array a[0] of the type int [5]. Again used as an argument expression it is implicitly converted to a pointer of the type int * to its first element a[0][0]. And the address of the first element of the first "row" that is the initial address of the extent of memory occupied by the array is outputted.

That is the addresses of the array as whole, of its first "row" and of the first element of the first "row" are equal each other. But the corresponding expressions, &a, a, *a (after implicit conversion to pointers) have different types. The expression &a has the type int ( * )[4][5], the expression a (after the implicit conversion) has the type int ( * )[5] and the expression *a (also after the implicit conversion) has the type int *. But their values are equal each other.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
1

I know that 2D array is basically pointer to array

No, it is not. Arrays when used in most expressions "decay" to a pointer to the first element, but that does not make arrays pointers.

so in the following code a is pointer to 0th index

Only in the expression printf("%d\n",a); where a decays into a pointer to its first element. The first element of a is an array of type int [5], so in this printf expression, a decayed to a pointer to such an element, a int (*)[5] type.

Using %d to print pointers is not well-defined behavior so the code is wrong, you should be using %p and cast the parameter to void*: printf("%p\n", (void*)a);

how a and *a both return same value

For any array, the array itself and it's first element naturally reside at the very same address or the concept of arrays wouldn't make any sense. The very definition of an array is a contiguous chunk of items with the same type allocated at contiguous addresses.

When you de-reference *a, you de-reference the decayed array a of type int(*)[5] and get a type int [5]. But since arrays cannot be used in most expressions, this too can be said to decay into a pointer to the first element of int [5], meaning type int*, pointing at item [0] in the first array.

Lundin
  • 195,001
  • 40
  • 254
  • 396
0

There are already two valuable answers above but I think you're still confused about the situation; for I felt the same while I was a rookie (though I'm not a pro yet).

  1. The line below does not return a pointer. Actually, it returns a memory address and the first address holds the first element of the array as data; but as it is on stack, C treats it like a pointer.
int a[4][5] = { ... };
  1. The lines below, again, return memory addresses on stack, but they hold other memory addresses and this time, they are literally pointers; they point to different memory addresses —most probably on the heap.
int** b = malloc(4 * sizeof(int*));
int*  c = malloc(5 * sizeof(int));

Do not keep your hands clean and debug the code below and inspect the output while keeping an eye on the memory dump at the same time:

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

int** copyArray(int row, int col, int pSrc[row][col]) {
    int** pDst = malloc(row * sizeof(int*));

    for (int i = 0; i < row; i++) {
        pDst[i] = malloc(col * sizeof(int));

        for (int j = 0; j < col; j++) {
            pDst[i][j] = pSrc[i][j];
        }
    }

    return pDst;
}

int main() {
    int a[4][5] = { {  1,  2,  3,  4,  5 },
                    {  6,  7,  8,  9, 10 },
                    { 11, 12, 13, 14, 15 },
                    { 16, 17, 18, 19, 20 } };

    int** b = copyArray(4, 5, a);

    printf("%2d %2d %2d %2d %2d\n", a[0][0], a[0][1], a[0][2], a[0][3], a[0][4]);
    printf("%p\n", &a);
    printf("%p\n", a);
    printf("%p\n", *a);
    printf("%p\n", a[0]);
    printf("%p\n", &a[0]);
    printf("\n");
    printf("%2d %2d %2d %2d %2d\n", b[0][0], b[0][1], b[0][2], b[0][3], b[0][4]);
    printf("%p\n", &b);
    printf("%p\n", b);
    printf("%p\n", *b);
    printf("%p\n", b[0]);
    printf("%p\n", &b[0]);

    for (int i = 0; i < 4; i++) {
        free(b[i]);
    }

    free(b);
    return 0;
}
ssd
  • 2,340
  • 5
  • 19
  • 37
0

I know that 2D array is basically pointer to array

No. A 2D array is an array of arrays - no pointers are involved. It would be laid out in memory as

   +––––+
a: |  1 | a[0][0]
   +––––+
   |  2 | a[0][1]
   +––––+
   |  3 | a[0][2]
   +––––+
   |  4 | a[0][3]
   +––––+
   |  5 | a[0][4]
   +—–––+
   |  6 | a[1][0]
   +––––+
   |  7 | a[1][1]
   +—–––+
   |  8 | a[1][2]
   +––—–+
   |  9 | a[1][3]
   +––––+
   | 10 | a[1][4]
   +––––+
   | 11 | a[2][0]
   +––––+
   | 12 | a[2][1]
   +–——–+
     ...

Except when it is the operand of the sizeof or unary & operators, or is a string literal used to initialize the contents of a character array in a declaration, an expression of type "N-element of T" will be converted, or "decay", to an expression of type "pointer to T".

As can be seen from the diagram above, the expressions a, a[0], and a[0][0] all have the same starting address.

The expression a has type "4-element array of 5-element array of int" - unless it is the operand of the sizeof or unary & operators, it "decays" to an expression of type "pointer to 5-element array of int" (int (*)[5]) and its value is the address of a[0].

The expression *a is identical to the expression a[0] and has type "5-element array of int" - again, unless it is the operand of the sizeof or unary & operators, it "decays" to an expression of type "pointer to int" and its value is the address of (*a)[0] (which is identical to the address of a[0][0]).

The expressions a, *a, &a, a[0], and &a[0][0] all yield the same address value (modulo any representational differences between types), but they have different types:

Expression    Type            "Decays" to        Equivalent expression
----------    ----            -----------        ---------------------
         a    int [4][5]      int (*)[5]         &a[0]
        *a    int [5]         int *              &(*a)[0] or &a[0][0]
        &a    int (*)[4][5]   n/a                n/a
      a[i]    int [5]         int *              &a[i][0]
     &a[i]    int (*)[5]      n/a                n/a
   a[i][j]    int             n/a                n/a
  &a[i][j]    int *           n/a                n/a
John Bode
  • 119,563
  • 19
  • 122
  • 198