C++ Pointers

0. Introduction

Typically you'd like to store integers, strings, characters, floats, etc in a variable. Just like this:
int a = 5;
string b = "Hello";
char c = 'H';
float d = 3.14;

But what if you want to store the memory address of an integer, string, float, etc? That's where pointers come in the scene.

1. What is a pointer?

A pointer is basically a variable which holds a memory address.

2a. Creating a pointer [Declaration]

From the definition, you know that a pointer just holds a the value of a memory address.

Before you create a pointer, you need to specify the type of data stored in the memory address. It's required for performing various operations on the contents of the memory address.

If the memory address of your pointer holds a float, it'll be called a "float pointer."

In this example, we'll just work with an integer pointer.

Example:
int* a;

Let's break it down:

We created an integer pointer named 'a' since we want to store the value of a memory address holding an integer.

2b. Creating a pointer [Initialization]

In the previous section, we declared a pointer named 'a' but didn't assign any value to it.

As you should know by now, the value will be a memory address. Let's create an integer so we can use its memory address:

int age = 21;

This is how you grab its memory address:

&age;

&age translates to "address of age"

The ampersand (&) acts as the "address of" operator.

Alright, great! Let's set the memory address to the pointer we declared in the previous section named "a."

a = &age;

Congrats! We just created a pointer named "a" whose value is just the memory address of "age."

2c. Creating a pointer [Summary]

Here's what the overall code may look like:
int age = 21;
int* a = &age;

This is all we did so far:

3. Accessing contents of memory address

If we had code like this:
int age = 21;
int* a = &age;

'a' holds the memory address of 'age.' In the address, we have the value '21.'

The code below is how you access memory contents:

cout << *a; // prints 21

The asterisk (*) here is a "dereference" operator.

A dereference operator essentially fetches the contents of a memory address.

In summary, *a translates to "memory contents of 'a'" or "dereference of 'a'."

4a. Practical example [Arrays]

In programming, an array is just like a variable but has multiple values.

In memory, the values are stored one after another. The memory address of the first value is kept and other values are accessed relative to the address of the first.

The code below will create an integer array of 5 elements:

int a[5];

5 integers will be placed side by side in the memory.

If you tried evaluating 'a,'' you'll just get the memory address of the first element in the array.

cout << a; // prints address of first element of 'a'

Here, 'a' is an array and it represents 5 elements.

Somewhere in the memory we have 5 integers side by side but 'a' is just a variable which holds address of the first integer.

What do we call a variable which holds a memory address? POINTER!

Yes, an array is technically a pointer. It's a smart application of the concept of pointers.

Let's create an array of integers called 'a':
int a[] = {50, 2000, 1234}

Let's see what happens when you fiddle with 'a':

cout << a; // prints the address of the first element
cout << *a; // prints the first element, 50
cout << *(a + 1); // prints the second element, 2000
cout << *(a + 2); // prints the third element, 1234

This may help you figure out why the first element of an array always have an index of 0.

Let's look at the most common way of accessing array elements:

cout << a[0]; // prints the first element, 50
cout << a[1]; // prints the second element, 2000
cout << a[2]; // prints the third element, 1234

You may be able to guess how it's all designed now.

4b. Practical example [Accessing variables outside the scope]

Take a look at this code:
void increment() {
	age++; // can't access 'age'
}

int main () {
	int age = 21;

	increment();
	
	cout << age; // still 21

	return 0;
}

You can get the idea:
Integer 'age' only exists within the function 'main' and cannot be accessed from outside.

Variables declared within a function belongs to a function; they live and die with the function.

In other words, 'age' is in the scope of 'main' and cannot be accessed from outside the scope.

But what if you wanted to break the barrier?

Surely, you can pass the variable to 'increment':

void increment(int age) {
	age++;
}

int main () {
	int age = 21;

	increment(age);
	
	cout << age; // but again, it's still 21

	return 0;
}

Nice try but you still failed to break the barrier of scopes.

All you did was pass the value of age to 'increment.'

The code below:

increment(age);
is equivalent to
increment(21);

No wonder why the function, 'increment' can't alter the variable 'age' which belongs to 'main' in any way.

But wait! What if we passed the address of 'age' to 'increment' like this?
increment(&age);

The function 'increment' could be written like this:

void increment(int* age) { // store the memory address in an integer pointer named 'age'
	(*age)++;
}

The overall code would look something like this:

void increment(int* age) { // store the memory address in an integer pointer named 'age'
	(*age)++; // get the contents of the memory and alter it by adding 1 to it
}

int main () {
	int age = 21;

	increment(&age); // pass value of the memory address of 'age'
	
	cout << age; // prints 21, SOLVED!

	return 0;
}

There we have it folks! We broke the barrier of scopes via pointers ;)

4c. Practical example [Swapping variables]

Yeah! Nothing beats the classic example of swapping variables popular in almost every language.

You know it, you got two variables and you want to switch their values.

So if you have 2 integers with values of 5 and 10 respectively, swapping them would mean switching their values and set them 10 and 5 respectively.

void swap (int* a, int* b) {
	int c = *a; // now, c = 5, a = 5, b = 10
	*a = *b; // now, a = 10, b = 10, c = 5
	*b = c; // finally, b = 5, a = 10, c = 5
}

int main () {
	int a = 5, b = 10;
	swap(&a, &b);
	return 0;
}

5. Further reading

Pointers
Pass by reference
Arrays