26

What is the following code doing?

int g[] = {9,8};
int (*j) = g;

From my understanding its creating a pointer to an array of 2 ints. But then why does this work:

int x = j[0];

and this not work:

int x = (*j)[0];
Natan Streppel
  • 5,759
  • 6
  • 35
  • 43
Sam Adamsh
  • 3,331
  • 8
  • 32
  • 53
  • 16
    @mjfgates: arrays are not pointers. Stop telling people that. – Benjamin Lindley Apr 20 '12 at 20:16
  • 11
    @mjfgates Indeed there is an array object in C and C++. It just happens that there are weird rules that, for example, cause inplicit conversions from an array to a pointer to the array's first element. – bames53 Apr 20 '12 at 20:29

3 Answers3

51

The parenthesis are superfluous in your example. The pointer doesn't care whether there's an array involved - it only knows that its pointing to an int

  int g[] = {9,8};
  int (*j) = g;

could also be rewritten as

  int g[] = {9,8};
  int *j = g;

which could also be rewritten as

  int g[] = {9,8};
  int *j = &g[0];

a pointer-to-an-array would look like

  int g[] = {9,8};
  int (*j)[2] = &g;

  //Dereference 'j' and access array element zero
  int n = (*j)[0];

There's a good read on pointer declarations (and how to grok them) at this link here: http://www.codeproject.com/Articles/7042/How-to-interpret-complex-C-C-declarations

Ben Cottrell
  • 5,741
  • 1
  • 27
  • 34
  • 2
    this article is very helpful, especially the right to left rule, thanks. – Sam Adamsh Apr 20 '12 at 20:58
  • is the `2` necessary in `int (*j)[2] = &g;` ? Wouldn't it still be a pointer to an array if the `2` was omitted? – johnbakers Jan 12 '16 at 18:58
  • 2
    @johnbakers yes it is absolutely necessary to specify the length of the array, otherwise you will not have a pointer-to-array, and then the code would not compile unless you used a cast. Pointing-to an array implies that you have knowledge of its length at compile time. The compiler message resulting from omitting the array length in MSVC++ reads `error C2440: 'initializing': cannot convert from 'int (*)[2]' to 'int (*)[]'` – Ben Cottrell Jan 14 '16 at 14:03
  • upvoted, thanks for elaborating on this answer despite the time that has passed – johnbakers Jan 14 '16 at 15:12
24
int g[] = {9,8};

This declares an object of type int[2], and initializes its elements to {9,8}

int (*j) = g;

This declares an object of type int *, and initializes it with a pointer to the first element of g.

The fact that the second declaration initializes j with something other than g is pretty strange. C and C++ just have these weird rules about arrays, and this is one of them. Here the expression g is implicitly converted from an lvalue referring to the object g into an rvalue of type int* that points at the first element of g.

This conversion happens in several places. In fact it occurs when you do g[0]. The array index operator doesn't actually work on arrays, only on pointers. So the statement int x = j[0]; works because g[0] happens to do that same implicit conversion that was done when j was initialized.

A pointer to an array is declared like this

int (*k)[2];

and you're exactly right about how this would be used

int x = (*k)[0];

(note how "declaration follows use", i.e. the syntax for declaring a variable of a type mimics the syntax for using a variable of that type.)

However one doesn't typically use a pointer to an array. The whole purpose of the special rules around arrays is so that you can use a pointer to an array element as though it were an array. So idiomatic C generally doesn't care that arrays and pointers aren't the same thing, and the rules prevent you from doing much of anything useful directly with arrays. (for example you can't copy an array like: int g[2] = {1,2}; int h[2]; h = g;)


Examples:

void foo(int c[10]); // looks like we're taking an array by value.
// Wrong, the parameter type is 'adjusted' to be int*

int bar[3] = {1,2};
foo(bar); // compile error due to wrong types (int[3] vs. int[10])?
// No, compiles fine but you'll probably get undefined behavior at runtime

// if you want type checking, you can pass arrays by reference (or just use std::array):
void foo2(int (&c)[10]); // paramater type isn't 'adjusted'
foo2(bar); // compiler error, cannot convert int[3] to int (&)[10]

int baz()[10]; // returning an array by value?
// No, return types are prohibited from being an array.

int g[2] = {1,2};
int h[2] = g; // initializing the array? No, initializing an array requires {} syntax
h = g; // copying an array? No, assigning to arrays is prohibited

Because arrays are so inconsistent with the other types in C and C++ you should just avoid them. C++ has std::array that is much more consistent and you should use it when you need statically sized arrays. If you need dynamically sized arrays your first option is std::vector.

Community
  • 1
  • 1
bames53
  • 86,085
  • 15
  • 179
  • 244
10

j[0]; dereferences a pointer to int, so its type is int.

(*j)[0] has no type. *j dereferences a pointer to an int, so it returns an int, and (*j)[0] attempts to dereference an int. It's like attempting int x = 8; x[0];.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • 3
    In addition, remember that `j[0]` is equivalent to `*(j + 0)`. `(*j)[0]` is therefore equivalent to `j[0][0]`, which is equivalent to `*(*(j + 0) + 0)`, which works out to be `**j`. Any way you look at it, it won't work. – chris Apr 20 '12 at 20:10
  • so then how would you create a pointer to a group of array elements? – Sam Adamsh Apr 20 '12 at 20:11
  • You set the pointer to the first element, and use it like an array, since `j[1] == *(j + 1) == the next element in the array`. – chris Apr 20 '12 at 20:12
  • 1
    @SamAdams asks, "How would you create a pointer to a group of array elements?" Like this: `int (*j)[2]` [cdecl is your friend](http://cdecl.ridiculousfish.com/?q=declare+j+as+pointer+to+array+2+of+int) – Robᵩ Apr 20 '12 at 20:30
  • 1
    @Robᵩ while that is a pointer to an array, typically you don't actually want a pointer to an array. Idiomatic C uses a pointer to one of the elements instead, and I'd say to avoid raw arrays entirely. – bames53 Apr 20 '12 at 20:34