Hello! Welcome to the second module of our course.
In the previous lesson, we concluded our exploration of pointer fundamentals by learning how to trace pointer operations using box-and-arrow diagrams. You even got a small preview of today's topic when you worked with the expression *(bar+1). Today, we will formalize the rules that govern such expressions.
This lesson addresses the first learning outcome of our new module: to perform pointer arithmetic operations, including increment, decrement, addition, and subtraction. Understanding these mechanics is not just about C syntax; it's fundamental to efficiently processing any contiguous block of memory, a common task in your work with AUTOSAR communication buffers and ADAS data streams.
The Core Principle of Pointer Arithmetic
When you add 1 to an integer, the value increases by one. When you add 1 to a pointer, the compiler does something much smarter. Instead of just incrementing the memory address by a single byte, it advances the pointer by the size of the data type it points to.
This ensures that the pointer, after the operation, points to the next element in a sequence, regardless of whether those elements are chars (1 byte), ints (often 4 bytes), or complex structs.

The general rule for adding an integer i to a pointer p is:
This same scaled logic applies to all arithmetic operations on pointers.
To get a formal overview of the valid operations and their corresponding formulas, please read the first few sections of the following document.
Please read the sections titled 'Incrementing Pointer in C', 'Decrementing Pointer in C', 'C Pointer Addition', and 'C Pointer Subtraction'. Focus on the formulas provided and the accompanying code examples. Note how the address changes by a multiple of the data type's size.
Pointer Arithmetic Operations
Based on the reading, let's summarize the four key arithmetic operations. Assume int *p; and int i;.
- Increment (
p++or++p): Moves the pointerpforward to point to the nextintelement. The address increases bysizeof(int). - Decrement (
p--or--p): Moves the pointerpbackward to point to the previousintelement. The address decreases bysizeof(int). - Addition (
p + i): Computes a new address that isielements afterp. The result isp's address plusi * sizeof(int). Note thatp = p + iorp += imodifiesp. - Subtraction (
p - i): Computes a new address that isielements beforep. The result isp's address minusi * sizeof(int).p = p - iorp -= imodifiesp. - Pointer Difference (
p2 - p1): This is a special case. When you subtract two pointers (that point into the same array or memory block), the result is not the difference in bytes. Instead, it's the number of elements between them. The result is a signed integer type calledptrdiff_t(defined in<stddef.h>).
For example, if p1 points to array[2] and p2 points to array[5], then p2 - p1 will be 3.
Test your understanding!
Suppose you have the following declarations on a 64-bit system where sizeof(int) is 4 and sizeof(double) is 8.
int int_array[] = {10, 20, 30, 40, 50};
double dbl_array[] = {1.1, 2.2, 3.3, 4.4, 5.5};
int *ip = &int_array[1]; // ip points to 20, let's say at address 0x1004
double *dp = &dbl_array[1]; // dp points to 2.2, let's say at address 0x2008
- What is the memory address value of
ip + 3? - What is the memory address value of
dp - 1? - If
int *ip2 = &int_array[4];, what is the value ofip2 - ip?
Show answer
ip + 3will point 3intelements pastip. The address will be0x1004 + (3 * sizeof(int)), which is0x1004 + (3 * 4) = 0x1004 + 12 = 0x1010. This is the address ofint_array[4].dp - 1will point 1doubleelement beforedp. The address will be0x2008 - (1 * sizeof(double)), which is0x2008 - 8 = 0x2000. This is the address ofdbl_array[0].ippoints toint_array[1]andip2points toint_array[4]. The differenceip2 - ipis the number of elements between them, which is4 - 1 = 3.
Operator Precedence: *p++, *++p, and ++*p
Things get more interesting when we combine the dereference operator (*) with increment/decrement operators. These compact expressions are extremely common in C code. Understanding them requires knowing about operator precedence and associativity.
Both * (dereference) and ++ (increment) are unary operators with the same precedence. When operators have the same precedence, the compiler uses their associativity to decide the order of evaluation. For these operators, the associativity is right-to-left.
Let's break down the common idioms:
-
*p++(Post-increment pointer)- Associativity is right-to-left, so
++is associated withp. - Because it's a post-increment (
p++), the original value ofpis used in the expression first. - Action: The pointer
pis dereferenced to get the value. After the entire expression is evaluated,pis incremented to point to the next element. - In short: Get the value, then move the pointer.
- Associativity is right-to-left, so
-
*++p(Pre-increment pointer)- Associativity is right-to-left, so
++is associated withp. - Because it's a pre-increment (
++p),pis incremented first. - Action: The pointer
pis incremented to point to the next element. Then, the new address is dereferenced to get the value. - In short: Move the pointer, then get the value.
- Associativity is right-to-left, so
-
++*p(Increment value)- Here,
*pis evaluated first (right-to-left). This gets the value at the addresspis pointing to. - The
++operator then increments this value. - Action: The value that
ppoints to is incremented. The pointerpitself does not move. - In short: Get the value and increment it.
- Here,
The following videos provide excellent, detailed walkthroughs of these concepts.
Pointer Arithmetic - *p++; *++p; ++*p;
First, this video from Abdul Bari provides a clear, conceptual breakdown of how these expressions are evaluated.
Watch the section from 06:23 to 10:20. Focus on the right-to-left evaluation rule and the difference in outcomes for *++p, ++*p, and *p++.
C_77 Pointers in C- part 7 | Pointer Arithmetic (Increment/Decrement) program
Next, watch this video from Jenny's Lectures. It includes a live coding demonstration that shows these operations in a real program, which is invaluable for cementing your understanding.
Please watch the following segments: *p++ (post-increment): 02:59 - 07:27 *++p (pre-increment): 07:27 - 08:53 Live Demo: 12:41 - 20:36 (You can watch this at 1.25x speed). Pay close attention to the printf outputs and how they correspond to the explanations.
A Practical Application: Calculating Memory "Stride"
In your work with communication protocols and data serialization (e.g., parsing SOME/IP packets or CAN frames), you often deal with raw data buffers where different fields are laid out contiguously. Pointer arithmetic is the natural tool for navigating such structures.
A key concept here is the "stride" of an array—the number of bytes between the start of one element and the start of the next. For an array int arr[], the stride is simply sizeof(int).
How would you calculate this stride programmatically using pointers? You might think to do this:int stride = &arr[1] - &arr[0]; // This is WRONG
Because of pointer arithmetic, this subtraction yields the number of elements between the two pointers, which will always be 1.
To get the stride in bytes, you must first cast the pointers to a type with a size of 1, like char*. This effectively bypasses the scaled arithmetic.
int arr[10];
int stride_in_bytes = (char*)&arr[1] - (char*)&arr[0];
// stride_in_bytes will be 4 on a system with 4-byte integers.
This technique is powerful for inspecting the memory layout of data structures and is a practical application of pointer casting combined with arithmetic. You can find more on this in the "Char Star Pointers" and "Stride of an Array" sections of the "Chapter 12. Pointer Arithmetic" resource (LINK).
Conclusion
In this lesson, we formalized the rules of pointer arithmetic, a critical tool for high-performance C programming.
Key Takeaways:
- Pointer arithmetic is always scaled by the size of the data type the pointer points to (
sizeof(*ptr)). - The valid operations are adding/subtracting an integer to a pointer (
p + i,p - i,p++,p--) and subtracting two pointers (p2 - p1). - Subtracting two pointers gives the number of elements between them, not the byte offset.
- Expressions like
*p++and*++pare common idioms whose behavior depends on operator precedence and associativity (right-to-left).*p++: Use value, then increment pointer.*++p: Increment pointer, then use value.++*p: Increment the value pointed to.
Now that we have established how to move pointers through memory in a structured way, we are ready for our next lesson. We will explore the deep and fundamental relationship between pointers and arrays, and you will see why the expression arr[i] is just syntactic sugar for *(arr + i).