🚀 C# ile Programlamaya Giriş: Kodlamaya İlk Adımını At, Kendi Projelerini Geliştirmeye Başla!
00HOME 01POSTS 02COURSES 03ELECTRİCAL_ENERGY 04AUTOMOTİVE_ENGİNEERİNG 05TOOLS 06LAB 07GLOSSARY 08TAGS ♡MY LIST ⌕SEARCH
TRENG

Pointers and references

Learn addresses, pointers and references through examples; swap, const references and nullptr.

Pointers are the "scary" topic of C++, but they actually rest on a simple idea: every variable has an address in memory, and we can create variables that hold that address. This lesson lays the groundwork for both pointers and their safer siblings, references.

Address and pointer

  • &x: gives the address of the variable x.
  • int* p: declares a "pointer to int".
  • *p: reaches the value at the place p points to (dereference).
  • nullptr: a safe empty value meaning "I point nowhere".

Reference

A reference is an alias for an existing variable. After you write int& r = x;, r and x are the same box. A reference must be bound to a variable when it is declared and cannot be rebound to another variable later; it cannot be nullptr. That is why it is safer than a pointer.

#include <iostream>
#include <vector>

void swapValues(int& a, int& b) {        // by reference: the originals change
    int temp = a;
    a = b;
    b = temp;
}

double average(const std::vector<double>& v) {   // read without copying or changing
    double t = 0.0;
    for (double x : v) t += x;
    return t / v.size();
}

void reset(double* p) {                  // by pointer: a nullptr check is a must
    if (p != nullptr) *p = 0.0;
}

int main() {
    int x = 10;
    int* p = &x;
    *p = 20;          // write to where p points -> x = 20
    int& r = x;
    r++;              // r is an alias for x -> x = 21
    std::cout << "x = " << x << '\n';

    int a = 3, b = 7;
    swapValues(a, b);
    std::cout << "a=" << a << " b=" << b << '\n';

    std::vector<double> v = {2.0, 4.0, 6.0};
    std::cout << "average = " << average(v) << '\n';

    double load = 5.5;
    reset(&load);
    std::cout << "load = " << load << '\n';

    int arr[3] = {10, 20, 30};
    int* q = arr;                        // points to the first element of the array
    std::cout << *(q + 1) << ' ' << q[2] << '\n';
    return 0;
}
x = 21
a=7 b=3
average = 4
load = 0
20 30

What happened in the code?

Passing by reference

In the previous lesson we said that parameters are copied. In the swapValues(int& a, int& b) function, however, the & means the original variables are changed; that is why a and b really did swap places. If you are passing a large object that you won't change, use a const reference: there is no copying cost, and the function cannot change it. average(const std::vector<double>& v) is an example of this.

Passing by pointer

In the call reset(&load) we pass the address. Since a pointer can be empty, the function first does a nullptr check. In new code, prefer a reference where possible, and a pointer for cases where "there may be no value".

The relationship between arrays and pointers

An array's name can decay into the address of its first element. q + 1 moves to the next int (4 bytes ahead); *(q + 1) gives its value and is the same as q[1]. This is called pointer arithmetic.

In embedded systems, hardware registers are accessed through pointers. For example, a port register sits at a fixed address in memory and is pointed to like this: volatile std::uint32_t* const port = reinterpret_cast<volatile std::uint32_t*>(0x40020014);. volatile tells the compiler "this value can be changed by the hardware, don't optimize it away". This is the foundation of writing to hardware with C++.

Dangerous situations: (1) using a pointer that was never given an initial value, (2) dereferencing nullptr, (3) keeping the address of a local variable that no longer exists (a dangling pointer), (4) going past the end of an array. All of these are undefined behavior: the program sometimes works, sometimes crashes, and sometimes silently produces a wrong result.

Pointer or reference?

PropertyReferencePointer
Can it be empty?NoYes (nullptr)
Can it be rebound to something else later?NoYes
Usager (directly)with *p

Try it yourself

  1. Write a swap function that swaps two double values.
  2. Write a function that multiplies every element of a vector by 2: its parameter should be std::vector<double>&.
  3. Print an int array using pointer arithmetic (*(q + i)).
  4. Declare int* p = nullptr; and write an if that checks it before dereferencing.

// Mini quiz

Click an option; you will see right away, with the reason, whether it is correct or not.

1. In the line int* p = &x;, what does &x mean?
2. Which of these is a way a reference differs from a pointer?
3. What is the best way to pass a large vector to a function that only reads it?

Mark it when you finish: your progress is saved and you earn +20 XP.

Tip: ← → keys let you move between lessons.