-1

Consider the program,

#include <stdio.h>

int main(){
  int a[][4] = {2,3,4,5,
                43,32,76,3
               };
  int *p;
  int (*q)[4];

  p = (int *)a;
  q = a;
  printf("%u\t%u", (unsigned int)p,(unsigned int)q);
  printf("\n%d\t%d",*(++p),*(++q));
  return 0;
}

In the above program, I have defined two pointers,

1) Integer pointer

2) Pointer to an Array

When compiled using the GCC compiler, I met with two doubts,

Question 1:

Why is that, the statement,

printf("\n%d\t%d",*(++p),*(++q));

returns an address when I try to dereference (++q)?

Question 2:

Is there any way I can use a "Pointer to an array" variable('q' - in this program) to access the consecutive element in a row?

Compiler: GCC; OS: Ubuntu

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
Panther Coder
  • 1,058
  • 1
  • 16
  • 43

3 Answers3

4
  1. *(++q) does not "return an address". It returns a result of type int[4], which is an lvalue of array type. That lvalue refers to a[1] subarray of array a.

    This means that the title of your question is no accurate at all: the dereference operator in this case does return exactly what it is supposed to return. The pointer is declared as a pointer to an array, and the dereference operator evaluates to an lvalue of array type.

    However, immediately after that you use that array lvalue in a context where it decays to pointer type, just like any other array would (see What is array decaying?, Why do arrays in C decay to pointers?). Passing an array as an argument to printf happens to be such a context. So, that original array lvalue decays to a pointer. That pointer value points to the beginning of a[1], which is the same as &a[1][0]. That pointer value is passed to printf and you attempt to print it with %d.

    (Note that using %d in printf to print pointer values triggers undefined behavior.)

  2. Well, you can access them in any way you wish

    q = a;
    q[1][1] = 42; // accesses `a[1][1]`
    ++q;
    (*q)[2] = 5; // accesses `a[1][2]`
    
Community
  • 1
  • 1
AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
1

This declaration

int (*q)[4];

declares a pointer to objects of type int[4]. To simplify the understanding you could introduce a typedef the following way

typedef int T[4];

T *q;
q = a;

So dereferencing the pointer you will get the pointed object of the type T that represents an array of type int[4]. As result using this object in the printf function

printf("\n%d\t%d",*(++p),*(++q));
                         ^^^^^

you will get the second "row" (due to incrementing the pointer ++q) of the array a that is in turn a one-dimensional array of type int[4] that in turn is implicitly converted to pointer to its first element.

Thus the expression *(++q) has the type int * and points to the first element of the second "row" of the array a.

If you want to use this pointer to traverse the elements of the array a you can do it the following way

#include <stdio.h>

int main(void) 
{
    int a[][4] = { { 2, 3, 4, 5 }, { 43, 32, 76, 3 } };

    int ( *q )[4] = a;

    for ( size_t i = 0; i < sizeof( a ) / sizeof( *a ); i++ )
    {
        for ( size_t j = 0; j < sizeof( *q ) / sizeof( **q ); j++ )
        {
            printf( "%2d ", q[i][j] );
        }
        printf( "\n" );
    }

    return 0;
}

The program output is

 2  3  4  5 
43 32 76  3 

That is q[0] is the first "row" of the array a. You can write also just *q. q[1] is the second "row" of the array a. You may can write also like *( q + 1 ). To get access to the elements of each row you can apply the subscript operator like (the first row)

q[0][i] where i is some index value. Or you can write the same like ( *q )[i]

and like (the second row) q[1][i] or ( *( q + 1 ) )[i]

And the special expression like **q yields the first element of the first row of the array a.

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

TL;DR answer, dereferencing a pointer-to-an array produces an array, which, once passed as a function argument, decays to pointer to the first element of the array. So, the final value is of pointer type (the former and the later are of pointer to different type, but they are pointers, nonetheless).


That said, first of all

 printf("%u\t%u", (unsigned int)p,(unsigned int)q);

is implementation dependent behaviour as conversion of a pointer to an integer is implementation defined. If at all, you can cast the pointer to uintptr_t type and print using PRIuPTR format specifier to print the value.

Secondly, pointer arithmetic honors the data type. q is a pointer to an array of 4 ints. Once incremented, it points past the first array. But then, there's a mismatch in the supplied format specifier.

 printf("\n%d\t%d",*(++p),*(++q));
               ^^         ^^^^^^

To elaborate, q is of type pointer-to-array. Dereferencing that produces an array, now once the array is passed as an argument to a function, it decays to the pointer to the first element of the array. So, essentially, you're passing a pointer as the argument to %d format specifier, which is the mismatch, leading to undefined behavior.

Finally, regarding the access to individual elements, you can either use

  • (*(q+m))[n] --> First dereference q to obtain the array, then use indexing
  • q[m][n] --> q[m] produces the array, then n is used as indexing to get individual element.
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261