Learn C++ #14: Understanding Pointers in C++

 


Learn C++ Programming: What are Pointers?

For some beginners... pointers are difficult to understand.

I also experienced this when I was just learning C.

But don't worry...

I will try to explain it in language that is easy to understand.

Okay..

Let's start.

What are Pointers?

Every variable we create in the program will have a memory address.

The memory address functions to determine the location of data storage in memory (RAM).

Sometimes this memory address is called a reference.

Take a look at this picture:

memory address

In this image, we create two variables.. namely scoreand hp.

These two variables have their own memory addresses.

scoreThe memory address variable is 01abc, while hpthe memory address is 02ffd.

As long as an address is still empty... then that address will be selected.

Oh yes, the selection of this memory address is done randomly. This is why this memory is called RAM (Random Access Memory) .

In essence, every time we create a variable it will definitely have a memory address.

If you don't believe it, you can prove it yourself by using the symbol & (ampersand) .

Example:

#include <iostream>
using namespace std;

int main () {

    int  a;
    char b[10];

    cout << "Alamat memori variabel a: " << &a << endl;
    cout << "Alamat memory variabel b: " << &b << endl;
    return 0;
}

In this program, we use symbols &to retrieve the memory address of the variables aand b.

The result:

Program output memory address

So what is the relationship between memory addresses and pointers?

Let's discuss…

A pointer is a special variable that contains a memory address . The pointer will later be able to access data at a memory address. 1

Keywords you need to remember:

"Pointer contains memory address"

How to Create Pointers

Pointers are created by adding a symbol * (asterisk) in front of their name, then filled with the memory address that will be used as a reference.

Example:

int *pointer1 = 00001;

Then *pointer1you will be able to access the data at the memory address 00001. In other words, you *pointer1will use the address 00001as a reference.

We can also create pointers without having to fill them directly with memory addresses.

Example:

int *pointer_ku;

// atau bisa juga

int *pointer_ku = NULL;

So *pointer_kuit will use a memory address 00000, this memory address is specifically for storing data nullor empty data.

Now the problem:

Because we cannot see the memory address list directly, we will have difficulty providing memory address references for pointers.

Not to mention... different computers also have different memory addresses. There are 8 bits, there are also 16, 32, and so on.

The solution:

We have to take the memory address of another variable.

Do you still remember how?

Yes, by using the symbol &.

Take a look at this picture:

pointer

In this image, we create a pointer with a name *ptr_hp*containing the memory address of the variable hp.

In this way..

The pointer *ptr_hpwill be able to access the value at the memory address 02ffd, which is the memory address of the variable hp.

If we want to change the value at the memory address, then we can use a pointer *ptr_hplike this:

*ptr_hp = 95;

So, now the memory address 02ffdwill contain 95as well as the variable hp.

pointer-change-data

To make it clearer, let's try the exercises in the program.

Practice: Accessing data with Pointers

Create a new program with the name contoh_pointer.cpp, then fill it with the following code:

#include <stdio.h>

int main(){
    int score = 50;
    int hp = 100;

    // membuat pointer dengan isi alamat memori dari hp
    int *ptr_hp = &hp;

    // print isi variabel dan alama memori
    printf("Nama Variabel \t Alamat \t Konten\n");
    printf("score \t\t %x \t %d \n", &score, score);
    printf("hp \t\t %x \t %d \n", &hp, hp);
    printf("ptr_hp \t\t %x \t %x \n", &ptr_hp, ptr_hp);
    printf("*ptr_hp \t %x \t %d \n", &ptr_hp, *ptr_hp);

    // mengubah data pada alamat memori dengan pointer
    *ptr_hp = 95;

    printf("hp \t\t %x \t %d \n", &hp, hp);
    printf("*ptr_hp \t %x \t %d \n", &ptr_hp, *ptr_hp);

    return 0;
}

After that, try compiling and running it.

So the result:

pointer example

The pointer *ptr_hpsuccessfully changes the value at the address d57ba6cto 95.

When using pointers, we use a sign *in front of the pointer name to access the value at the memory address. If we don't use this flag, we will get a pointed memory address.

*ptr // ini akan berisi 95 (nilai dari alamat)
ptr // ini akan berisi d57ba6c (alamat memori dari variabel hp)

Oh yes, pointers also have their own memory address.

In the example above, the memory address of the pointer *ptr_hpis d57ba70. Maybe on your computer it will be different, please check it yourself.

If you look at this picture:

Pointer memory address

The memory address used *ptr_hpis 012efthe contents of the memory address 02ffd.

Does anyone here understand?

Now the question:

If we use pointers, won't this waste memory? Because we have to allocate a memory address for the pointer too.

If we can use regular variables, why use pointers?

The use of pointers is actually optional, you can use them... or not.

However..

Under certain conditions, the use of pointers is more optimal.

Later we will discuss this again.

When Should I Use Pointers?

As I said earlier, we don't always have to use pointers in programs.

However, there are certain cases that suggest using pointers instead of the usual way.

Let's be clear..

Let's discuss first, why were pointers created ?

So in the past, computer memory was very limited. Not like now where the capacity is gigabytes.

When we perform iterative operations on data types such as arrays, strings, trees, linked lists, graphs, and so on... it often takes up a lot of memory and makes the program slow.

Using pointers in such operations will improve performance significantly compared to not using pointers. 1

Practice: Pointers for Pass by Reference to Functions

First we will try to use pointers to pass arguments based on their references (pass by reference) .

Example:

#include <stdio.h>

void add_score(int score){
    score = score + 5;
}

int main(){
    int score = 0;

    printf("score sebelum diubah: %d\n", score);
    add_score(score);
    printf("score setelah diubah: %d\n", score);
    return 0;
}

In this program, we create a function with the name add_score()to add the score value by 5.

But when run:

pass by value

The value of the score variable does not change, it remains valuable 0.

Why?

This is because we are doing pass by value , not pass by reference .

Variables scoreare created inside functions main(), then when the function add_score()tries to change their values...

…then changes only occur locally within the function add_score().

Do not believe?

Try to prove it by changing the function add_score()to something like this:

#include <stdio.h>

void add_score(int score){
    score = score + 5;
    printf("Score diubah ke %d\n", score);
}

int main(){
    int score = 0;

    printf("score sebelum diubah: %d\n", score);
    add_score(score);
    printf("score setelah diubah: %d\n", score);
    return 0;
}

The result:

add score

It's true what I said...

The value scorein the function add_score()has changed to 5, but the variable scorein the function main()will still have the value 0.

Now..

This is where we have to use pointers to do pass-by-reference .

Now, try changing the program code to be like this:

#include <stdio.h>

void add_score(int *score){
    *score = *score + 5;
    printf("score diubah ke: %d\n", *score);
}

int main(){
    int score = 0;

    printf("score sebelum diubah: %d\n", score);
    add_score(&score);
    printf("score setelah diubah: %d\n", score);
    return 0;
}

Because we convert function arguments add_score()into pointers, we must provide a memory address when calling it.

So the result is:

pass by reference

Every time a function add_score()is called or executed, the variable value scorewill increase 5.

Let's try changing it to something like this:

#include <stdio.h>

void add_score(int *score){
    *score = *score + 5;
    printf("score diubah ke: %d\n", *score);
}

int main(){
    int score = 0;

    printf("score sebelum diubah: %d\n", score);
    add_score(&score);
    add_score(&score);
    add_score(&score);
    add_score(&score);
    add_score(&score);
    add_score(&score);
    printf("score setelah diubah: %d\n", score);
    return 0;
}

The result:

add score run

Practice: Pointers for Accessing Data in Arrays

Pointers are also often used to access data in arrays.

Example:pointer_array.cpp

#include <stdio.h>

int main(){
    printf("## Program Antrian CS ##\n");

    char no_antrian[5] = {'A', 'B', 'C', 'D', 'E'};

    // menggunakan pointer
    char *ptr_current = no_antrian;

    for(int i = 0; i < 5; i++){
        printf("📢 Pelanggan dengan no antrian %c silakan ke loket!\n", *ptr_current);
        printf("Saat ini CS sedang melayani: %c\n", *ptr_current);
        printf("-------- Tekan Enter untuk Next --------");
        getchar();
        ptr_current++;
    }

    printf("✅ Selesai");
    return 0;
}

In this program, we use it ptr_currentto access array elements. When first created, the pointer ptr_currentwill reference the first element of the array.

Then in the loop an increment is carried out ptr_current++, then this pointer will reference the next array element.

The result:

Practice: Pointers for Accessing Data in Structs

Using pointers in structs will help us make code easier and easier to read than without pointers.

As an example..

For example, we have a struct like this:

struct Player {
  char *name;
  int score;
  int hp;
	struct Weapon *weapon;
};

struct Weapon {
	char *name;
  int attack;
  int guard;
};

The struct Playerinside there is another struct, namely struct Weapon. Well here we use pointers for structs Weapon.

struct Weapon *weapon;

The question:

How do I access data in struct weapon?

There are two ways, we can use the .(dot) operator and ->the (pointer operator).

First, let's try using dots.

Please create a new program with the name pointer_struct.cpp, then fill it with the following code:

#include <iostream>

using namespace std;

int main(){
    struct Weapon {
        string name;
        int attack;
        int guard;
    };

    struct Player {
        string name;
        int score;
        int hp;
        Weapon *weapon;
    };

    Player player1;
    player1.name    = "Petani Kode";
    player1.score   = 0;
    player1.hp      = 100;
    player1.weapon = new Weapon;

    (*player1.weapon).name = "Katana";
    (*player1.weapon).attack = 16;
    (*player1.weapon).guard = 10;

    // cetak status player
    cout << "PLAYER STATUS" << endl;
    cout << "Name: " << player1.name << endl;
    cout << "Score: " << player1.score << endl;
    cout << "HP: " << player1.hp << endl;
    cout << "Weapon" << endl;
    cout << "  name: " << (*player1.weapon).name << endl;
    cout << "  attack: " << (*player1.weapon).attack << endl;
    cout << "  guard: " << (*player1.weapon).guard << endl;

    return 0;
}

After that, compile and run.

So the result is:

Example of Struct pointers

Pay attention to the code!

When we access member data in a struct that is in the form of a pointer with the dot operator, we have to use parentheses *to state that it is a pointer.

(*player1.weapon).name = "Katana";
(*player1.weapon).attack = 16;
(*player1.weapon).guard = 10;

If only one member is a struct pointer, this is fine.

But..

If, for example, there is a struct pointer member and inside it there is a struct pointer and inside it there is a struct pointer, we will definitely be confused.

The code could be like this:

(*(*(*player.weapon).katana).type).name = "Wakizashi";

Duh! I'm just confused reading it.

So, so it's not like this... we can use the arrow operator ( ->) to access members of a struct that uses pointers.

Example:

player->weapon->katana->type->name = "Wakizashi";

This is easier to read than the previous one.

So, if there are member pointers in the Struct, then you should use operators ->to access the members.

Let's change the previous code ( pointer_struct.cpp) to be like this:

#include <iostream>

using namespace std;

int main(){
    struct Weapon {
        string name;
        int attack;
        int guard;
    };

    struct Player {
        string name;
        int score;
        int hp;
        Weapon *weapon;
    };

    Player player1;

    // membuat pointer untuk player1
    Player *p1 = &player1;

    p1->name    = "Petani Kode";
    p1->score   = 0;
    p1->hp      = 100;
    p1->weapon = new Weapon;

    p1->weapon->name = "Katana";
    p1->weapon->attack = 16;
    p1->weapon->guard = 10;

    // cetak status player
    cout << "PLAYER STATUS" << endl;
    cout << "Name: " << p1->name << endl;
    cout << "Score: " << p1->score << endl;
    cout << "HP: " << p1->hp << endl;
    cout << "Weapon" << endl;
    cout << "  name: " << p1->weapon->name << endl;
    cout << "  attack: " << p1->weapon->attack << endl;
    cout << "  guard: " << p1->weapon->guard << endl;

    return 0;
}

The result:

Example of Struct pointers

In this program we create two variables for the Player struct, namely player1and p1. The variable p1will be a pointer to access data on player1.

// membuat struct player
Player player1;
// membuat pointer untuk player
Player *p1 = &player1;

Because p1it is a pointer that references a struct player1, we can access the members player1with the arrow operator ( ->).

What is next?

We have discussed the basic concept of pointers in C++. You have to understand this concept, so that later when you meet pointers you won't be confused.

We don't always have to use pointers, but there are certain cases such as data access in Structs... using pointers is highly recommended so that the code is easier to read.

If you are still confused, please ask in the comments.

Next, please learn about memory allocation with the functions malloc()calloc()realloc(), and free().

Happy learning. 🙌

Post a Comment

Previous Post Next Post