In C, you can always add two numbers. You can always add an integer to a pointer, or subtract two pointers. You will always get an "answer": the compiler will generate code and the code will execute. That's no assurance that answer is valid, useful, or even defined.
The C standard defines the language. Within the scope of what the syntax admits, it defines what's valid -- what definitely means something -- and what's not. When you color outside those lines, the compiler may produce weird code or no code. In C, it's not the job of the compiler to anticipate every weird circumstance and arrive at a reasonable answer. The compiler writer assumes the programmer knows the rules, and is not required to verify he followed them.
There are lots of examples of valid syntax that's meaningless or undefined. In math, you cannot take the log of a negative, and you cannot divide by zero. Dividing by zero doesn't yield zero or not zero; the operation is undefined.
In your case, ptr3
has a value, duly computed, 8 larger than buffer
. That's the result of some pointer arithmetic. So far, so good.
But just because you have a pointer, doesn't mean it points to anything. (void*) 0
is explicitly guaranteed not point to anything. Likewise, your ptr3
doesn't point to anything. It needn't even be a value 8 larger than buffer
. Section 6.5.6 of the C standard defines the result of adding an integer to a pointer, and puts it this way:
If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.
When you say, I am getting consecutive memory locations (for ex.1000.....1007), what you're seeing is behavior. You had to see some behavior. And that behavior is undefined. According to the standard, you could see some other behavior, such as wrapping back to 1000 or 0.
What the compiler accepts and what the standard defines are two different things.