-1

So, I was messing around with pointers in C

int o = 10;
int x = 20;
int *pA = NULL;
pA = &o;

and after adding an integer to the pointer
pA += x;
the address stored in the pointer changed from
000000000061FE18
to
000000000061FE68

After checking the value the address was pointing to using *pA the value was 0 and I could add an integer to this address using

*pA += x;

and *pA became equal to 20, but the value stored in variable o was still 10.

Could anyone explain what happened here?

Raysh
  • 13
  • 3
  • Does this answer your question? [Pointer Arithmetic](https://stackoverflow.com/questions/394767/pointer-arithmetic) – Jorengarenar Jul 18 '20 at 09:04
  • 1
    Adding to a pointer advances the pointer by that many times the size of that to which it points. After all, `p[5]` is identical to `*(p + 5)`. So if `p[5]` gets the 6th `int` (for example), then `p + 5` must necessarily advance the pointer by the size of five `int` objects. – ikegami Jul 18 '20 at 09:06
  • You never touch value of `o` It should still be `10` afterwards. Where do vou get `30``from? – Gerhardh Jul 18 '20 at 10:29
  • my bad I forgot to mention that I added x to o too before adding to x to pointer on my code – Raysh Jul 18 '20 at 10:45
  • Copy/paste only code that you tested, else you waste time/effort:( – Martin James Jul 18 '20 at 11:11

3 Answers3

1

pA += x; - The pointer pA itself is incremented by the value of x multiplied by the size of type pA is pointing to and is equal to the size of x, which is int.

So, assume sizeof(int) or sizeof(x) is 4 and x has the value of 20, you end up multiplying the pointer value of pA by 80 because 4 * 20 = 80, which is matching to your test results.

0x61FE68 - 0x61FE18 = 0x50 = 80d.

After adding an integer to the pointer pA += x; .... (and) checking the value the address was pointing to using *pA the value was 0...

Since you incremented the pointer pA itself by 20 * sizeof(int) with pA += x;, pA points no longer to any valid object and beyond the bounds of the object it should point to.

To increment the pointer in this way invokes undefined behavior as well as dereferencing this pointer.

That it displayed 0 is just happen arbitrary to the situation. You can't rely on anything. The value can change already at the next execution.

... and I could add an integer to this address using *pA += x; and *pA became equal to 20.

The behavior is undefined as said above. pA does not point to any legally referenced object.

...but the value stored in variable o was still 30.

o isn't changed at all. With the first statement pA += x; you incremented the pointer itself, not the object o pA pointed to at the first place.

Could anyone explain what happened here?

You incremented the pointer pA by sizeof(int) * 20 with the first pA += x;. Everything else can't be really explained, because the behavior is just undefined.

0

The new address pointed by a pointer, after a constant value is added to it, depends on the type it points to:

NewAddress = OldAddress + ConstantValue * sizeof ( Type )

So, in plain math, with pA += x, you have

new_address_pointed_by_pA = old_address_pointed_by_pA + x * sizeof( int )

And since x=20 and an integer in your machine is 4 bytes big, this becomes

new_address_pointed_by_pA = old_address_pointed_by_pA + 20*4 = 
                          = old_address_pointed_by_pA + 80

That's exactly what you experience, as 0x61FE68 - 0x61FE58 = 0x50. Your addresses, in fact, are represented in hexadecimal format. So the new address is 0x50=80 beyond the old one, and that fits with the simple calculation I showed above.


What does that new address contain? Well, we don't know. It depends on the history of that specific memory location.

If it was never used, it's not surprising it contained 0. And it was also expected that after *pA = x it contained 20. And, again, it is not surprising at all that the location it was originally pointing remains unchanged.

But... with that assignment you could have raised a segmentation fault exception. An OS usually raises this signal when a memory location not assigned to your task is accessed.
So, pay attention when you play with pointers, making sure that any arithmetics performed on them leads to legal new values.

Roberto Caboni
  • 7,252
  • 10
  • 25
  • 39
  • @P__J__ you misunderstood my goal. It was not C but plain arithmetics. My goal was showing to the OP the different steps to come to the result they experience. I usually listen to advices, but I don't want to switch to that expression. I could change my expression so that it is clear that it is a "plain didactic calculation"? – Roberto Caboni Jul 18 '20 at 10:31
  • 1
    @RobertoCaboni I did but you cant use this syntax for it. It is simple misleading. Put more effort in the explanation and the equations – 0___________ Jul 18 '20 at 10:33
  • @P__J__ I admit it was misleading. Could you review if now it is more clear, please? – Roberto Caboni Jul 18 '20 at 10:35
  • @Gerhardh see my comment above. It was an admittedly misleading attempt to show the steps in plain math, not C code. Now that I've changed the symbols it should be more clear. – Roberto Caboni Jul 18 '20 at 10:58
0

Here you have a small program which should explain pointer arithmetic a bit.

#include <stdio.h>

#define PRINTDIFF(type, p1, p2) printf("sizeof(%s) = %zu p1=%p p2 = %p diff(bytes) = %zi \ndiff(objects) = %zi diff(bytes)/sizeof(%s) = %zi\n\n", \
                                #type, sizeof(type), \
                                (void *)(p1), \
                                (void*)(p2), \
                                ((char *)(p2) - (char *)(p1)), \
                                (p2) - (p1),\
                                #type, \
                                ((char *)(p2) - (char *)(p1)) / sizeof(type))


int main(void)
{
    short s;
    char c;
    int i;
    long long ll;
    long double ld;

    short *sp = &s;
    char *cp = &c;
    int *ip = &i;
    long long *llp = &ll;
    long double *ldp = &ld;

    PRINTDIFF(short, sp, sp + 10);
    PRINTDIFF(char, cp, cp + 500);
    PRINTDIFF(int, ip, ip + 5);
    PRINTDIFF(long long, llp, llp + 5);
    PRINTDIFF(long double, ldp, ldp + 5);
}

https://godbolt.org/z/4eP3rc

And the result:

sizeof(short) = 2 p1=0x7ffe0660eb76 p2 = 0x7ffe0660eb8a diff(bytes) = 20 
diff(objects) = 10 diff(bytes)/sizeof(short) = 10

sizeof(char) = 1 p1=0x7ffe0660eb75 p2 = 0x7ffe0660ed69 diff(bytes) = 500 
diff(objects) = 500 diff(bytes)/sizeof(char) = 500

sizeof(int) = 4 p1=0x7ffe0660eb70 p2 = 0x7ffe0660eb84 diff(bytes) = 20 
diff(objects) = 5 diff(bytes)/sizeof(int) = 5

sizeof(long long) = 8 p1=0x7ffe0660eb68 p2 = 0x7ffe0660eb90 diff(bytes) = 40 
diff(objects) = 5 diff(bytes)/sizeof(long long) = 5

sizeof(long double) = 16 p1=0x7ffe0660eb50 p2 = 0x7ffe0660eba0 diff(bytes) = 80 
diff(objects) = 5 diff(bytes)/sizeof(long double) = 5

BTW when you learn you should experiment yourself writing the short programs which will help you understand the C language. There is no easy, effortless way of learning C

0___________
  • 60,014
  • 4
  • 34
  • 74