Pointer Arithmetic
First, the binky video may help. It's a nice video about pointers. For arithmetic, here is an example:
int * pa = NULL;
int * pb = NULL;
pa += 1; // pa++. behind the scenes, add sizeof(int) bytes
assert((pa - pb) == 1);
print_out(pa); // possibly outputs 0x4
print_out(pb); // possibly outputs 0x0 (if NULL is actually bit-wise 0x0)
(Note that incrementing a pointer that contains a null pointer value strictly is undefined behavior. We used NULL because we were only interested in the value of the pointer. Normally, only use increment/decrement when pointing to elements of an array).
The following shows two important concepts
- addition/subtraction of a integer to a pointer means move the pointer forward / backward by N elements. So if an int is 4 bytes big, pa could contain 0x4 on our platform after having incremented by 1.
- subtraction of a pointer by another pointer means getting their distance, measured by elements. So subtracting pb from pa will yield 1, since they have one element distance.
On a practical example. Suppose you write a function and people provide you with an start and end pointer (very common thing in C++):
void mutate_them(int *begin, int *end) {
// get the amount of elements
ptrdiff_t n = end - begin;
// allocate space for n elements to do something...
// then iterate. increment begin until it hits end
while(begin != end) {
// do something
begin++;
}
}
ptrdiff_t
is what is the type of (end - begin). It may be a synonym for "int" for some compiler, but may be another type for another one. One cannot know, so one chooses the generic typedef ptrdiff_t
.
Pointer arithmetic and casting
Pointer arithmetic is expressed in terms of elements of the type that is being pointed at.
ptr+5
increments ptr
by 5 * sizeof(short)
bytes.
The result of ptr2 - ptr
is 5, because the compiler knows that ptr
and ptr2
are pointing at short
elements, and so it divides the difference of the two memory addresses by sizeof(short)
. The number of short
elements between those 2 memory addresses is 5.
Whereas (long) ptr2 - (long)ptr
is not pointer arithmetic, it is just plain ordinary integer arithmetic. It calculates the difference of the 2 memory addresses as-is, without regard to what they are pointing at. Since there are 5 short
elements between the 2 memory addresses , and sizeof(short)
is clearly 2 bytes in your case, the distance between the 2 memory addresses is 10 bytes.
Pointer Arithmetic In C
Like the ++
increment operator, the -
subtraction operator with pointers also takes into account the size of the objects being pointed to. Specifically, the result returned is the number of bytes difference in the pointer values divided by the size of the pointed-to object (12, in your example). So the difference is 12 bytes, divided by size 12, or 1.
C Pointer Arithmetic for Unusual Architectures
Would pointer be equal to 3?
Well, the standard doesn't say how pointers are implemented. The standard tells what is to happen when you use a pointer in a specific way but not what the value of a pointer shall be.
All we know is that adding 1 to a char pointer, will make the pointer point at the next char object - where ever that is. But nothing about pointers value.
So when you say that
pointer = pointer + 1;
will make the pointer equal 1, it's wrong. The standard doesn't say anything about that.
On most systems a char
is 8 bit and pointers are (virtual) memory addresses referencing a 8 bit addressable memory loacation. On such systems incrementing a char pointer will increase the pointer value (aka memory address) by 1. However, on - unusual architectures - there is no way to tell.
But if you have a system where each memory address references 4 bits and a char is 12 bits, it seems a good guess that ++pointer
will increase the pointer by three.
Pointer Arithmetic - Issues with array and pointer to an array
a = (&a+1);
sets a
to point to one “thing” beyond the address of a
.
Earlier, your code sets a
to &arr
, using int *a = &arr;
. (This violates standard C constraints because the type of &arr
is a pointer to an array, not a pointer to an int
. The correct definition would be int *a = arr;
.) I suspect your intent in a = (&a+1);
was to set a
to point to one beyond where it currently points. However, correct code for this would be a = a+1;
. That takes the value of a
, adds one to it, and assigns the result to a
.
In contrast, a = (&a+1);
uses the address of a
instead of its value.
This results in a
pointing to one beyond wherever a
is in memory. In your experiment, it seems that the array arr
happened to be there, and your C implementation behaved accordingly.
(That explains the results you observed, but it is not behavior you should rely on. The C standard does not define what happens when you misuses pointers in this way, and various things, including compiler optimization, can cause programs to behave as if &a+1
did not point to arr
even if arr
is in fact located at the address &a+1
in memory.)
C Pointer Arithmetic, moving around in memory
In C, pointer arithmetic operates in units of the pointed-to type. If a pointer has type char *
, then adding 1 or 2 or 3 to it adjusts it to point to a char
that is 1 or 2 or 3 elements later in a char
array. If a pointer has type Node *
, then adding 1 or 2 or 3 to it adjusts it to point to a Node
that is 1 or 2 or 3 elements later in a Node
array.
If current
points to some Node
X, then current + 1
would point to the Node
that follows X. In contrast, if sizeof (Node)
is, say, 12 bytes, then current + sizeof(Node)
points to Node
that is 12 array elements later than X, so 12•12 = 144 bytes later than X.
In (char *) current + sizeof (Node)
, current
is converted to a char *
. Then pointer arithmetic on this char *
operates in units of char
, so (char *) current + sizeof (Node)
points to 12 bytes after X, which is the distance of one Node
, so it points to the Node
after X.
The fact that sizeof (char *)
and sizeof (Node *)
are the same in your C implementation is irrelevant. These are the sizes of the pointers, not the sizes of the things pointed to. The pointer arithmetic on char *
and Node *
operates in units of sizeof (char)
and sizeof (Node)
.
(Incidentally, I write sizeof (char *)
rather than sizeof(char *)
to convey the fact that sizeof
is not a function, and the parentheses do not mark an argument list. Rather, sizeof is an operator, and here the parentheses are used in the C grammar to distinguish a type.)
Related Topics
Recommended Way to Initialize Srand
How to Convert Vector to Array
Why Is There No Call to the Constructor
Difference Between _Tmain() and Main() in C++
Rand() Returns Same Values When Called Within a Single Function
How to Safely Pass Objects, Especially Stl Objects, to and from a Dll
Separating Class Code into a Header and Cpp File
C++ "Virtual" Keyword For Functions in Derived Classes. Is It Necessary
Algorithm to Convert Rgb to Hsv and Hsv to Rgb in Range 0-255 For Both
Return Type of ':' (Ternary Conditional Operator)
What Happens If I Assign a Negative Value to an Unsigned Variable
Why How to Not Push_Back a Unique_Ptr into a Vector
A Confusing Detail About the Most Vexing Parse
Make_Unique and Perfect Forwarding
Remove Spaces from Std::String in C++
When Should Std::Move Be Used on a Function Return Value
How to Detect Whether There Is a Specific Member Variable in Class
Windows Threading: _Beginthread VS _Beginthreadex VS Createthread C++