50

Program:

#include<stdio.h>

int main(void) {
    int x[4];
    printf("%p\n", x);
    printf("%p\n", x + 1);
    printf("%p\n", &x);
    printf("%p\n", &x + 1);
}

Output:

$ ./a.out
0xbff93510
0xbff93514
0xbff93510
0xbff93520
$

I expect that the following is the output of the above program. For example:

x        // 0x100
x+1      // 0x104  Because x is an integer array
&x       // 0x100  Address of array
&x+1     // 0x104

But the output of the last statement is different from whast I expected. &x is also the address of the array. So incrementing 1 on this will print the address incremented by 4. But &x+1 gives the address incremented by 10. Why?

Jordan Melo
  • 1,193
  • 7
  • 26
mohangraj
  • 9,842
  • 19
  • 59
  • 94
  • 3
    It seems that &x+1 gives you the address after the array memory (4*4=16 or 0x100)... – alnet Nov 18 '15 at 09:09
  • 30
    This is one of those cases where you clearly see the difference between a pointer and an array. – Klas Lindbäck Nov 18 '15 at 09:15
  • 15
    Important clarification: those addresses are in hex. "*Incremented by 4*" means a 0x4 increment as well, but **"*incremented by 0x10*" means "*incremented by 16*," not by 10.** – kdbanman Nov 18 '15 at 17:36
  • 2
    @LukePark It should actually be of type int (*)[4] – rationalcoder Nov 18 '15 at 21:54
  • 1
    Just a note (unrelated to the question you are asking): Your program has undefined behaviour (at least under C99), because you need to cast the pointers to `void *` before passing them to `printf` (because it is a variadic function). See [Printing pointers in C](http://stackoverflow.com/questions/197757/printing-pointers-in-c). – sleske Nov 19 '15 at 10:09
  • Possible duplicate of [Why is arr and &arr the same?](http://stackoverflow.com/questions/8916656/why-is-arr-and-arr-the-same) – Mark Hurd Nov 25 '15 at 02:37

5 Answers5

64
x -> Points to the first element of the array.
&x ->Points to the entire array.

Stumbled upon a descriptive explanation here: http://arjunsreedharan.org/post/69303442896/the-difference-between-arr-and-arr-how-to-find

SO link: Why is arr and &arr the same?

Community
  • 1
  • 1
thepace
  • 2,221
  • 1
  • 13
  • 21
26

In case 4 you get 0x100 + sizeof x and sizeof x is 4 * sizeof int = 4 * 4 = 16 = 0x10.

(On your system, sizeof int is 4).

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
i486
  • 6,491
  • 4
  • 24
  • 41
9

An easy thumbrule to evaluate this is:

Any pointer on increment points to the next memory location of its base type.

The base type of &x here is int (*p)[4] which is a pointer to array of 4 integers.

So the next pointer of this type will point to 16 bytes away (assuming int to be 4 bytes) from the original array.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Kowshika
  • 101
  • 2
3

Even though x and &x evaluate to the same pointer value, they are different types. Type of x after it decays to a pointer is int* whereas type of &x is int (*)[4].

sizeof(x) is sizeof(int)*4.

Hence the numerical difference between &x and &x + 1 is sizeof(int)*4.

It can be better visualized using a 2D array. Let's say you have:

int array[2][4];

The memory layout for array is:

array
|
+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+

array[0]        array[1]
|               |
+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+

If you use a pointer to such an array,

int (*ptr)[4] = array;

and look at the memory through the pointer, it looks like:

ptr             ptr+1
|               |
+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+

As you can see, the difference between ptr and ptr+1 is sizeof(int)*4. That analogy applies to the difference between &x and &x + 1 in your code.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
-6

Believe it or not, the behaviour of your program is undefined!

&x + 1 is actually pointing to just beyond the array, as @i486's answer cleverly points out. You don't own that memory. Even attempting to assign a pointer to it is undefined behaviour, let alone attempting to dereference it.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • 9
    I always thought that this was defined since taking a pointer to one-past the end of an array was defined. I guess it may be different since this isn't an array of `int[4]`s, it's only one. – chbaker0 Nov 18 '15 at 11:03
  • 3
    @chbaker0: For address arithmetic, non-array types are treated as if they are arrays of length 1. It's less clear when array types are involved, but I am under the impression that `&arr + 1` is well-defined, because it would point to the same address as `arr + 4`, which is well-defined. –  Nov 18 '15 at 11:54
  • 9
    @Bathsheba: Can you cite the standard here? Usually, past the end pointers are well-defined things; why should it not be in this particular case? –  Nov 18 '15 at 11:57
  • I'll try to dig it out. Note that we don't have an array of arrays here. So there's no "past the end". I'll add the "language lawyer" tag to the question to attract more attention. – Bathsheba Nov 18 '15 at 11:58
  • 5
    @Bathsheba: As Hurkyl mentions, there should be a blurb in the Standard about how "scalar" objects are treated as arrays of size of 1 for the purpose of "past-the-end" pointers. I would expect this to hold in this case (since an array can contain arrays), but the Standard regularly defies my expectations. – Matthieu M. Nov 18 '15 at 12:36
  • That *sounds* wholly implausible. For a scalar, how can it be that you are allowed to look beyond it? I'll make a trivial edit to my answer so upvoters can reverse: perhaps then we can all thrash this one out. – Bathsheba Nov 18 '15 at 12:38
  • 6
    @Bathsheba You are not allowed to "look" beyond the array, but IIRC you are explicitly allowed to store that address in a pointer. I think [this answer](http://stackoverflow.com/a/988220/2096401) (and others to that question) cover this. – TripeHound Nov 18 '15 at 13:59
  • But this is only for the array case. x[4] is a *scalar* type: it is *not* in an array of x[4] elements. &x + 1 is therefore UB. I'm obviously not being clear enough. – Bathsheba Nov 18 '15 at 14:01
  • 1
    @Bathsheba His point is that it is (notionally) an array of 1 element where "element" is itself an array of 4 int elements. – Random832 Nov 18 '15 at 15:20
  • ...which *itself* is a scalar. And &x + 1 is pointer arithmetic on a scalar. – Bathsheba Nov 18 '15 at 15:27
  • 12
    @Bathsheba C11 6.5.6 p7: "a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one". Not even a note - this is main text. (immediately precedes the stuff about one-past-the-end) **No UB here.** Scalars are exactly the same as arrays for pointer arithmetic purposes. – Alex Celeste Nov 18 '15 at 16:19
  • @Leushenko: Although I agree about the intent, _technically_ that sentence is not applicable because we are not discussing a pointer to an object. We are talking about the one-past-the-end pointer. And that sentence doesn't. :) – Lightness Races in Orbit Nov 18 '15 at 16:50
  • 3
    @LightnessRacesinOrbit the sentence is specifically about arithmetic, and clarifies that the next paragraph (where the one-past rule is explained) applies to arrays and scalars equally. – Alex Celeste Nov 18 '15 at 16:55
  • @Leushenko: I'm not convinced you understood my comment. You seem to have circular logic. You're arguing that Sentence A proves that Sentence B applies here, but Sentence A can only be applied _if_ Sentence B applies here. Sentence A on its own says nothing about the hypothetical one-past-a-scalar pointer. It only compares the pointing-to-a-scalar pointer and the pointer-to-array-element-one pointer; at best, you could use that to construct an argument about what happens when you increment such a pointer, which _may_ be sufficient but I've yet to see convincing evidence of that. – Lightness Races in Orbit Nov 18 '15 at 16:58
  • 4
    @LightnessRacesinOrbit ...Sentence A lays the groundwork for Sentence B by denying that there is a distinction between the two cases, establishing that there is no "one past a scalar" case; scalars are arrays for arithmetic purposes. (If you haven't checked the text yet, the opening words of the sentence are "For the purposes of these operators, ..." - I really don't see how A can be taken as standalone.) – Alex Celeste Nov 18 '15 at 17:03
  • @Leushenko: No, it does not deny that there is a distinction between one-past-a-scalar and one-past-an-array. It only denies that there is a distinction between to-a-scalar and to-array-element-one. As I said, your logic is circular. But I _still_ agree that your conclusion is almost certainly the intent of the language. I think the standard wording is vague here and needs improvement. – Lightness Races in Orbit Nov 18 '15 at 17:04
  • 1
    @LightnessRacesinOrbit It denies there even is such thing as one-past-scalar, since there are no scalars at all in pointer arithmetic. – Agent_L Nov 18 '15 at 17:05
  • One of the problems I have here is that the *type* of the pointer yielded by x + 4 (which is valid) is different to &x + 1 (which I don't think is). I can't see anything concrete in the standard that states that just because you can assign a pointer to x + 4 implies that you can do the same with &x + 1. Why could you? The types are unrelated. And my argument that you can't fundamentally do the latter since it's a scalar still holds. We all know that int x = 9; int* p = &x + 1; is undefined. Or is it? – Bathsheba Nov 18 '15 at 17:13
  • 4
    @Bathsheba That code at the end of your comment is defined. That is what 6.5.6, p7 is all about. – this Nov 18 '15 at 17:14
  • 3
    Code is undefined but for a different reason. `"%p"` matches `void*`, not `int *`, etc. Code should be `printf("%p\n", (void*) x);` etc. – chux - Reinstate Monica Nov 18 '15 at 20:31