C++: Advanced Pointer Arithmetic

Last updated: 2026-08-26

In Lesson 23, we learned the basics of pointer arithmetic (p + n, p - q).

But there are many more details to pointer arithmetic — for example, can pointers be compared? What is a void* pointer? What are pointers to pointers?



1. Pointer Comparison

(1) 1.1 Can Pointers Be Compared?

Yes! But only comparisons between pointers pointing to the same array are meaningful.

▶ Example 2: Basic Programming Practice (Difficulty ⭐)

CPP
#include <iostream>

int main() {
 int arr[5] = {10, 20, 30, 40, 50};
 int* p1 = &arr[0];
 int* p2 = &arr[3];
 
 if (p1 < p2) { // ✅ p1 pointed element is before p2
 std::cout << "p1 is before p2" << std::endl;
 }
 
 if (p2 - p1 == 3) { // ✅ two pointers are 3 elements apart
 std::cout << "p1 and p2 are 3 elements apart" << std::endl;
 }
 
 return 0;
}
▶ Try it Yourself

Output:

TEXT 📖 Display only
p1 is before p2
p1 and p2 are 3 elements apart

💡 Key point: Pointer comparisons compare address values (i.e., element positions in the array).


(2) 1.2 Pointer Equality Comparison

CPP
#include <iostream>

int main() {
 int x = 5;
 int* p1 = &x;
 int* p2 = &x;
 
 if (p1 == p2) { // ✅ two pointers point to the same variable
 std::cout << "p1 and p2 point to the same variable" << std::endl;
 }
 
 int y = 10;
 int* p3 = &x;
 int* p4 = &y;
 
 if (p3 != p4) { // ✅ two pointers point to different variables
 std::cout << "p3 and p4 point to different variables" << std::endl;
 }
 
 return 0;
}


2. void* Pointers

(1) 2.1 What is a void* Pointer?

void* is a generic pointer — it can point to any type of data.

CPP
#include <iostream>

int main() {
 int x = 5;
 double y = 3.14;
 char c = 'A';
 
 void* p1 = &x; // ✅ void* can point to int
 void* p2 = &y; // ✅ void* can point to double
 void* p3 = &c; // ✅ void* can point to char
 
 return 0;
}

💡 Characteristics:


(2) 2.2 Uses of void*

Use 1: Writing generic functions (later you'll learn that std::memcpy uses void*)

CPP
#include <iostream>
#include <cstring>

int main() {
 int arr1[5] = {1, 2, 3, 4, 5};
 int arr2[5];
 
 // std::memcpy Use void* to accept any type'spointer
 std::memcpy(arr2, arr1, 5 * sizeof(int));
 
 for (int i = 0; i < 5; i++) {
 std::cout << arr2[i] << " ";
 }
 std::cout << std::endl;
 
 return 0;
}

Use 2: Dynamic memory allocation (later you'll learn that malloc returns void*)


(3) 2.3 Converting void*

To use the value pointed to by void*, you must convert it to a pointer of a concrete type.

CPP
#include <iostream>

int main() {
 int x = 5;
 void* p = &x; // void* pointing to int
 
 // ❌ Error: Cannot directly dereference void*
 // std::cout << *p << std::endl;
 
 // ✅ Correct: First convert to int*
 int* intPtr = static_cast<int*>(p);
 std::cout << *intPtr << std::endl; // Output 5
 
 return 0;
}

💡 Tip: static_cast is C++'s type conversion operator (covered later), which is safer than C-style (int*)p.



3. Multi-Level Pointers (Pointers to Pointers)

(1) 3.1 What is a Pointer to a Pointer?

A pointer to a pointer is a pointer that stores the address of another pointer (nesting dolls).

CPP
#include <iostream>

int main() {
 int x = 5;
 int* p = &x; // p points to x
 int** pp = &p; // pp points to p (pointer to pointer)
 
 std::cout << "x = " << x << std::endl;
 std::cout << "*p = " << *p << std::endl; // Dereference once: get x value
 std::cout << "**pp = " << **pp << std::endl; // Dereference twice: get x value
 
 return 0;
}

(2) 3.2 Declaring Multi-Level Pointers

Declaration Meaning
int x; x is an int
int* p; p is an int* (pointer to int)
int** pp; pp is an int** (pointer to int*)
int*** ppp; ppp is an int*** (pointer to int**)

💡 How to read: Read from right to left.


(3) 3.3 Uses of Multi-Level Pointers

Use 1: Dynamic 2D arrays (covered later)

CPP
// Dynamically allocate a 3x4 2D array
int** matrix = new int*[3]; // matrix is a pointer to pointer
for (int i = 0; i < 3; i++) {
 matrix[i] = new int[4];
}

Use 2: Functions that need to modify a pointer (rare, just be aware)

CPP
#include <iostream>

void allocateInt(int** ptr) {
 *ptr = new int(5); // Modify *ptr (i.e., modify the original pointer)
}

int main() {
 int* p = nullptr;
 allocateInt(&p); // Pass the pointer address
 std::cout << *p << std::endl; // Output 5
 delete p; // Free memory
 return 0;
}


4. Pointers and const Combinations

(1) 4.1 Four Combinations

Declaration Meaning Can change pointer? Can change pointed-to value?
int* p; Ordinary pointer ✅ Yes ✅ Yes
const int* p; Pointer to const int ✅ Yes ❌ No
int* const p = &x; Const pointer (must initialize) ❌ No ✅ Yes
const int* const p = &x; Const pointer to const ❌ No ❌ No

💡 Memory trick: Read from right to left.


(2) 4.2 Example: const int* (Commonly Used)

CPP
#include <iostream>

void printArray(const int* arr, int size) {
 for (int i = 0; i < size; i++) {
 std::cout << arr[i] << " ";
 }
 std::cout << std::endl;
 
 // ❌ Cannot modify:arr[i] = 0; // Compile error
}

int main() {
 int arr[5] = {1, 2, 3, 4, 5};
 printArray(arr, 5);
 return 0;
}

Output:

TEXT 📖 Display only
1 2 3 4 5

💡 Key point: const int* arr is the most commonly used function parameter type — it means "I only read, I don't modify."



5. Practice: Implementing String Copy with Pointers

▶ Example 1: Hand-written strcpy (Difficulty ⭐⭐)

CPP
#include <iostream>

void myStrcpy(char* dest, const char* src) {
 while (*src != '\0') {
 *dest = *src; // Copy character
 dest++; // Move pointer
 src++;
 }
 *dest = '\0'; // Add null terminator
}

int main() {
 char src[] = "Hello";
 char dest[20];
 
 myStrcpy(dest, src);
 std::cout << "src = " << src << std::endl;
 std::cout << "dest = " << dest << std::endl;
 
 return 0;
}
▶ Try it Yourself

Output:

TEXT 📖 Display only
src = Hello
dest = Hello

💡 Tip: This program uses pointer arithmetic and dereferencing — it's excellent practice for understanding pointers.


▶ Example 3: Traversing an Array with Pointers (Difficulty ⭐)

CPP
#include <iostream>

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    int* p = arr; // p points to first array element

    std::cout << "Traversing array with pointers: " << std::endl;
    for (int i = 0; i < 5; i++) {
        std::cout << "*p = " << *p << std::endl;
        p++; // Move pointer to next element
    }

    // pointer subtraction calculates number of elements
    int* end = arr + 5;
    std::cout << "Number of elements:" << end - arr << std::endl;

    return 0;
}
▶ Try it Yourself

Output:

TEXT 📖 Display only
Traversing array with pointers: 
*p = 10
*p = 20
*p = 30
*p = 40
*p = 50
Number of elements:5

❓ FAQ

Q: Why can't void be dereferenced?* A: Because void is a type with no size — the compiler doesn't know whether to read 1 byte, 4 bytes, or 8 bytes.

It must be converted to a pointer of a concrete type (like int*, double*) before the compiler knows the step size.

Q: What are multi-level pointers used for? A: In real projects, int** is most commonly seen in: > 1. Dynamic 2D arrays (e.g., new int*[3]) > 2. Functions that need to modify the pointer itself (e.g., void foo(int** p) can modify where p points)

Pointers beyond two levels (int*** etc.) are not recommended — too hard to understand.

Q: Are const int and int const the same? A: Yes! The following two forms are equivalent: > > const int p; // Recommended > int const p; // equivalent, but less common > > > But int* const p is different — this is a const pointer (cannot change what it points to).


📖 Summary


📝 Exercises

  1. Basic (Difficulty ⭐): Declare an int variable x = 5, then declare an int* pointer p pointing to x, then declare an int** pointer pp pointing to p. Output x, *p, **pp and verify they are equal.

  2. Intermediate (Difficulty ⭐⭐): Write a function void swap(int** a, int** b) that swaps what two pointers point to.

TEXT 📖 Display only
Input: p1 points to x, p2 points to y
Call swap(&p1, &p2)
Output: p1 points to y, p2 points to x
  1. Challenge (Difficulty ⭐⭐⭐): Use void* and pointer arithmetic to hand-write a myMemcpy function:
  2. Function prototype: void myMemcpy(void* dest, const void* src, size_t n)
  3. Functionality: copy n bytes from src to dest
  4. Hint: copy byte by byte (use char* for pointer arithmetic)

10. 🚀 Next Step

Now that you've learned advanced pointer concepts, let's move on to References (Lesson 25) — the "safer version" of pointers, an important C++ feature!

Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏