C
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Functions
-
Section 4: Arrays and Strings
-
Section 5: Pointers
-
Section 6: Memory Management
-
Section 7: Structures and Unions
-
Section 8: The Preprocessor and Build Process
-
Section 9: Standard Library: stdio.h
-
Section 10: Standard Library: stdlib.h
-
Section 11: Standard Library: string.h
-
Section 12: Standard Library: ctype.h and wctype.h
-
Section 13: Standard Library: math.h, complex.h, fenv.h, tgmath.h
-
Section 14: Standard Library: Type and Limit Headers
-
Section 15: Standard Library: Error Handling and Debugging
-
Section 16: Standard Library: Localization and Encoding
-
Section 17: Standard Library: time.h
-
Section 18: Standard Library: Concurrency (C11)
-
Section 19: POSIX and System Programming (unistd.h)
-
Section 20: More Data Structures
-
Section 21: Algorithms in C
-
Section 22: Bitwise Operations
-
Section 23: Command-Line Programs
-
Section 24: Debugging and Best Practices
-
Section 25: Compiler and Language Internals
-
Section 26: Embedded and Cross-Platform Considerations
-
Section 27: Networking Basics
-
Section 28: Practical Projects
-
Section 29: Interview Practice
-
Section 30: C23 Modern Features
-
Section 31: More Practice and Review
45: Pointer Arithmetic
Imagine you're staying at a hotel. You're standing in front of Room 101. If I tell you to "go to the next room," you don't move exactly one inch to the right. You move the entire width of one room to get to Room 102. Whether the rooms are tiny single-occupancy pods or massive luxury suites, "one room over" always puts you at the start of the next valid door.
Pointer arithmetic in C works exactly like that. When you add 1 to a pointer, you aren't adding a single byte to a memory address; you're adding the size of one element of the type that pointer is tracking. I've seen plenty of developers get tripped up by this because they think of memory as a raw string of bytes, but the C compiler is actually doing some invisible math for you behind the scenes.
The Invisible Math of the Compiler
Let's look at a real example. Suppose we have an array of integers representing daily temperature readings. On most modern systems, an int is 4 bytes.
int temps[] = {72, 75, 80, 68, 71};
int *ptr = temps; // ptr points to the first element (72)
If you print the value of ptr, you'll see a memory address—something like 0x7ffeefbff5a0. Now, if you do ptr + 1, you might expect the address to become 0x7ffeefbff5a1. But it won't. It will actually become 0x7ffeefbff5a4.
Why? Because the compiler knows ptr is an int*. It says, "Okay, the user wants the next integer, and since an integer is 4 bytes, I'll jump 4 bytes forward." This is a lifesaver. If it didn't do this, you'd be landing in the middle of a number, reading garbage data.
Navigating the Buffer Manually
While we usually use array indexing like temps[i], pointer arithmetic is what's actually happening under the hood. You can move through a block of memory using the increment (++) and decrement (--) operators.
int temps[] = {72, 75, 80, 68, 71};
int *ptr = temps;
while (ptr < (temps + 5)) {
printf("Current temp: %d\n", *ptr);
ptr++; // Move to the next 'room' (next integer)
}
In the code above, temps + 5 calculates the address just past the end of our array. I prefer this style occasionally when I'm writing high-performance parsers because it can be slightly more efficient than indexing, though modern compilers are so smart they usually optimize both to the same machine code anyway.
Walking Off the Edge of the Map
Here is the danger: C does not have a "fence" around your arrays. If you have 5 elements and you increment your pointer 10 times, C will happily let you do it. You'll just be pointing at some random piece of memory that doesn't belong to your array.
If you try to dereference that pointer (*ptr) after walking off the edge, you're in the danger zone. You might get a "Segmentation Fault" (the OS killing your program for trespassing), or worse, you might read a value that looks correct but is actually a random piece of system data. Always keep a hard boundary in your mind when you're sliding pointers around.
📋 Practical Task
Build a Sensor Data Average Calculator
You are given a buffer of float values representing voltage readings from a sensor. Instead of using array subscripts (like data[i]), you must use pointer arithmetic to navigate the buffer and calculate the average voltage.
Requirements:
- Create an array of 6 floats:
{1.2f, 2.5f, 3.1f, 0.8f, 1.9f, 2.2f}. - Initialize a pointer to the start of the array.
- Use a
whileloop and theptr++operator to traverse the array and sum the values. - Calculate the average and print it to the console.
- Ensure your loop condition correctly stops at the end of the buffer using pointer comparison.
There are no comments for now.