9

As far as I know, the derefence operator * returns the value stored in the pointer address. What I'm confused by is the behavior when the operator is used with pointer of an array. For example,

int a[4][2];

Then a is internally converted to pointer of first element of array of 4 elements of 2 ints. Then which value does *a return? I'm really confused!

dbush
  • 205,898
  • 23
  • 218
  • 273
Jin
  • 1,902
  • 3
  • 15
  • 26
  • There is no "pointer to array". An array is not a pointer. "Then `a` is internally converted to pointer of first element of array of 4 elements of 2 ints." is plain wrong! – too honest for this site Aug 06 '16 at 04:18
  • @Olaf What do you mean by there is no pointer to array? Doesn't this ( int(*x)[4][2] ) mean that x is a pointer to an array of 4 elements of 2 ints? – Jin Aug 06 '16 at 04:25
  • @Olaf Sorry but I still don't get it! Then how should '*a' be interpreted if 'a' is not internally converted to pointer to initial element? – Jin Aug 06 '16 at 04:42
  • Really?? Did you consider `a` is called "array" and not "pointer" for a reason? Sorry, but that is a simple logical conclusion (and you gotr the information from tha answers, too). As a programmer, you are **required** to think for yourself in the first place. Please start with it. – too honest for this site Aug 06 '16 at 14:10

2 Answers2

9

The type of a is int[4][2], so the type of *a (or equivalently a[0]) is int[2].

It is not the same as a[0][0]. If you do this:

int a[4][2];
printf("%d\n",*a);

The compiler will tell you this:

warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘int *’

Since an array (in this case one of type int [2]) is being passed to a function, it decays to a pointer to the first element in this context.

If on the other hand you had **a, that is equivalent to a[0][0] and has type int.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • If you're confused by the error message referring to `int *`, its because expresions of array type in any context other than `&` or `sizeof` or related type queries are implicitly converted into pointers. So `int[2]` becomes `int *` – Chris Dodd Aug 06 '16 at 01:14
  • @ChrisDodd: What "related type queries" do you mean? An array expression is converted to a pointer unless it is (a) the operand of unary `&`, (b) the operand of `sizeof`, or (c) a string literal in an initializer used to initialize an array (sub)object. Those are the only exceptions. (The N1570 draft of C11 incorrectly lists a fourth, but the `_Alignof` operator cannot be applied to an expression.) – Keith Thompson Aug 06 '16 at 01:49
  • @KeithThompson: `decltype`, `typeof`, and `alignof` that exist in various extensions, as well as `_Generic`. Also possibly `offsetof`, though in that case conversion to a pointer would have no effect. – Chris Dodd Aug 06 '16 at 18:49
  • Actually the first operand of `_Generic` is converted to a pointer if it's of array type. (gcc agrees; clang doesn't, at least as of version 3.7.1.) `offsetof()` can't take an array expression as an argument, so it doesn't apply. Extensions might be another matter. – Keith Thompson Aug 06 '16 at 20:05
6

This:

int a[4][2];

defined a an array of 4 elements, each of which is an array of 2 int elements. (A 2-dimensional array is nothing more or less than an array of arrays.)

An array expression is, in most contexts, implicitly converted to a pointer to the array object's initial (zeroth) element. (Note the assumption that there is an array object; that has caused some angst, but it's not relevant here.)

The cases where an array expression is not converted to a pointer are:

  • When it's the operand of sizeof;
  • When it's the operand of unary &; and
  • When it's a string literal in an initializer used to initialize an array object.

(Compiler-specific extensions like gcc's typeof might create more exceptions.)

So in the expression *a, the subexpression a (which is of type int[4][2]) is implicitly converted to a pointer of type int(*)[2] (pointer to array of 2 ints). Applying unary * dereferences that pointer, giving us an expression of type int[2].

But we're not quite done yet. *a is also an expression of array type, which means that, depending on how it's used, it will probably be converted again to a pointer, this time of type int*.

If we write sizeof *a, the subexpression a is converted from int[4][2] to int(*)[2], but the subexpression *a is not converted from int[2] to int*, so the expression yields the size of the type int[2].

If we write **a, the conversion does occur. *a is of type int[2], which is converted to int*; dereferencing that yields an expression of type int.

Note that despite the fact that we can legally refer to **a, using two pointer dereference operations, there are no pointer objects. a is an array object, consisting entirely of 8 int objects. The implicit conversions yield pointer values.

The implicit array-to-pointer conversion rules are in N1570 section 6.3.2.1 paragraph 3. (That paragraph incorrectly gives _Alignof as a fourth exception, but _Alignof cannot be applied to an expression. The published C11 standard corrected the error.)

Recommended reading: Section 6 of the comp.lang.c FAQ.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • 1
    In the sentence "If we write sizeof *a, the conversion doesn't occur" does the conversion mean from array of 2 ints to pointer to initial element of array of 2 ints? Also I think the next paragraph should be edited as " *a is type int[2], which is converted to int " – Jin Aug 06 '16 at 04:10
  • 1
    `*a` doesn't have the type `int(*)[2]`; It has the type `int[2]`. – 2501 Aug 06 '16 at 07:19
  • @jwqwerty: Yes, it's the conversion of `*a` from `int[2]` to `int*` that doesn't occur. I've updated my answer accordingly -- and you're right about the type of `*a`. – Keith Thompson Aug 06 '16 at 19:52