7

We have

 int a[5]={10, 20, 30, 40, 50};

I would like to know how does the following two code segment do?

 int *ptr = (int *)(&a+1);
 int *t = (int *)(&a -1);

If we have

 printf("%d  %d  %d \n", *(a+1), *(ptr-1), *(t+1));

What should be the result?

4
  • 4
    What did your program say when you tried it? Commented Aug 9, 2010 at 4:32
  • This was a test question and was not assumed to answer by running on a computer. Commented Aug 9, 2010 at 4:34
  • 1
    @user297850, sure, but why not run it on a computer now so that you can understand it? Commented Aug 9, 2010 at 4:36
  • @user Nobody answered the question straight, but the result will be 10 50 ??, where ?? is some value at &a - 4*(sizeof(int)). Read caf's answer, it's got the best explanation. Commented Aug 9, 2010 at 5:11

4 Answers 4

6

Since the type of a is array-of-5-ints, that means that the type of &a is pointer-to-array-of-5-ints.

When you add or subtract 1 from a pointer, you ask it to point to the next or previous object of that type in memory. So &a+1 is creating a pointer to the array-of-5-int immediately after a in memory (which doesn't exist), and &a-1 is creating a pointer to the array-of-5-int immediately before a in memory (which also doesn't exist). In memory, it looks like this (where each cell represents one int):

Address:    &a-1                      &a                      &a+1
Contents:  | ?  | ?  | ?  | ?  | ?  | 10 | 20 | 30 | 40 | 50 | ?  | ?  | ?  | ?  | ?  |

When a is used in the expression *(a+1), it is converted to a pointer to its first element - so a pointer-to-int pointing at the 10 value. Adding one to it then makes a pointer pointing at the next int - a+1 points at the 20 value. *(a+1) then fetches that value, so the first number printed is 20.

As ptr is also a pointer-to-int, that means that ptr - 1 creates a pointer to the int immediately before ptr - in this case, it'll be pointing at the 50. So the second number printed is 50.

Similarly, t + 1 creates a pointer to the int immediately after t - in this case, it's the second ? in the above diagram. This is an uninitialised value - it could print anything at all, or even crash the program.

Address:    &a-1                      &a                       &a+1
            t    t+1                  a   a+1            ptr-1 ptr
Contents:  | ?  | ?  | ?  | ?  | ?  | 10 | 20 | 30 | 40 | 50  | ?  | ?  | ?  | ?  | ?  |
Sign up to request clarification or add additional context in comments.

3 Comments

+1 I just want to add that the crisis could've been averted if those parentheses were removed (ie: int *ptr = (int *) &a + 1, which is the same as int *ptr = ((int *) &a) +1). Then it would print 20 10 10
@Null, yes, but, more simply, int* ptr = a + 1; would be just fine -- a, being an array of ints, "decays" to "pointer to int" when used in an expression. No casts, nor complications, needed;-).
@NullUserException: A very nice observation, and one that shows clearly how the effect of the +1 changes depending on the type of the pointer it's applied to.
4

All the problems come from the use of &a, which is a pointer to "an array of five integers", so that pointer arithmetic (when you think in terms of addresses) gets "scaled" by sizeof(a) (which might e.g. be 20 if int are 4 bytes and the compiler needs no padding for alignment purposes -- reasonable hypotheses, though far from certain of course.

So, after

int *ptr = (int *)(&a+1);
int *t = (int *)(&a -1);

ptr is a pointer to int at the memory address "sizeof(a) more than the address a", and t similarly for "sizeof(a) less than the address of a". Therefore...:

 printf("%d  %d  %d \n", *(a+1), *(ptr-1), *(t+1));

What should be the result?

Quite possibly a segmentation violation, otherwise 20 followed by two completely arbitrary integer values. Since ptr and t are pointers to int, the address arithmetic scaling for their -1 and +1 does not compensate that done on &a (the scaling in terms of memory addresses is by sizeof(int), not sizeof(a)!), so ptr-1 and t+1 are pointing to (alleged;-) ints that are respectively "a few ints after the end of a" and "a few ints before the start of a".

There's no way to know whether at those arbitrary addresses there is any memory which the process is allowed to address (whence the possibility for segmentation violatons), and, if any accessible memory is there, what its contents "seen as an int" might possibly be.

Edit: @caf points out that ptr - 1 is not invalid -- it correctly points to the last element of a; so the output (unless there's a segmentation fault, which @NullUserException thinks is very unlikely but on this point we disagree;-) would start with 20 50 before the third, "arbitrary" junk. Point is, per the C standard, it is valid to compute (though not to use) the pointer "just one past the end" of an array, and the sizeof an array must be exactly that array's length time the sizeof its elements (padding is allowed for an element's type, if needed, and if so it shows in the element's own sizeof, but not for the array as a whole). Subtle, but important;-).

16 Comments

You're not quite right here. a, the pointer to an array of integers, is not necessarily stored next to *a, the integers themselves. The issue is not the scaling, but rather the level of referencing at which the arithmetic is done. Take a closer look...
@user297850, Alex: The segfault/random memory dereference was exactly what I got, which you can see in the output mentioned in my answer.
By the way, *(ptr - 1) is OK - it points at the last int in a. *(t + 1) is garbage, though.
@Alex: a[1] = 20, so shouldn't it be "20 followed by two completely arbitrary integer values" ?
@Alex Just a couple of minor corrections: (1) *(a+1) is 20, not 10 (2) *(ptr-1) is guaranteed to point at a[4], (3) *(t+1) points at a[-4], which is garbage, but very unlikely to segfault the program.
|
0

"What should be the result"?

Next time you want to know what a tiny code snippet like this should do, check this out: http://ideone.com/4fCud

The result I got out of that was:

20 50 134520820

Edit:

When you run a program, see output like this, and find yourself asking, "where did that value come from?" you may have run into undefined behavior.

In this case the third value doesn't point to where you might think it would point. It is reading uninitialized memory (most likely), memory owned by code that is in your process space, but outside your program (a library you loaded, or the C runtime), or memory that simply has nothing to do with this program (less likely, because of protected memory).

5 Comments

Uhh... you do realize the third number is garbage based on whatever happened to be in memory at the time, right?
@darron: Yep, I know that. The point of the post was to demonstrate that there were compilers online for simple questions like this, so the author need not ask it to begin with. The better question for him to ask would have been "why isn't it outputting the values I expect?"
The problem is just that your answer doesn't mention the fact that the last number is garbage... which is important here. If someone wrote "20 50 134520820" as the answer to this on a test it'd be wrong.
@darron: I don't think that the test analogy applies here. Discussions are provided in a QA format, but that simply lowers the barrier to entry. I don't think Stack Overflow's purpose is just to provide answers, but to increase understanding. I provided the answer the way I did because I didn't want to duplicate other people's efforts and information, and felt there was some value to the information I added.
@darron: However, at your persistence, I can add a note explaining the program's output :)
-1

Let's look at it piece by piece.

&a means the address of a. So, it gets the address of the address of the integer 10.
&a+1 is the next pointer over from that. So it's the thing stored after the variable a in memory. Bad idea.
&a-1 is the thing stored before a in memory. Again, bad idea.

*(a+1) is the thing at the location pointed to by a, plus one integer. That would be a[1], or 20.
*(ptr-1) is a, because ptr is &a+1, so ptr-1 is &a. It's the pointer value of a. Printing it as %d is a mistake. If you were to say **(ptr-1), you'd get a more-meaningful 10 from the printf.
*(t+1) is also a, as per the above but with the pluses and minuses switched.

8 Comments

@Borealid, key defect in your answer: ptr is &a+1, so ptr-1 is &a. -- NO!!! You're ignoring the completely different scaling of those +1 and -1 (since ptr is a pointer to int, memory addresses in arithmetic on ptr are scaled by sizeof(int), while memory addresses in arithmetic on &a are clearly scaled by sizeof(a) which must be several times more than sizeof(int)).
@Alex Martelli: Actually, if ptr==&a+1, then ptr-1==&a, on any standards-compliant C implementation on a 32-bit machine. This is because all types being arithmetically manipulated are pointers, and on x86_32, sizeof(void*)==sizeof(int) and the size of all pointer types are the same. So, no matter how many bold exclamation points you put, what I said was true. Come back with test code if you're really sure of yourself.
@Borealid, you're simply, desperately wrong all the way -- have you tried some printf("%p\n", (void*)(eachofthese)) for each of the pointer values eachofthese that you're mentioning, for goodness' sake?!
The key difference here is that ptr and &a+1 have different types (ptr has type int *, and &a+1 has type int (*)[5]) - so ptr - 1 and (&a+1)-1 do not calculate the same address.
@caf: Given sizeof(int)==sizeof(int*), they do. See my previous comment.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.