#097 – 2 ways to manipulate pointers

A pointer points to a memory address.

These gives you two different levers to manipulate pointers:

  1. The pointer itself
  2. The object the pointer is pointing to.

Three things to take away:

  • ptr refers to the pointer variable itself.
  • ptr refers to the object at the address stored in the pointer.
  • Assigning to ptr changes where the pointer points; assigning to ptr changes the object being pointed at.

Operation 1: Change the address of the pointer

Assigning a new address to a pointer changes what object it points to.

#include <iostream>

int main(){
    int indoorTemperature { 22 };
    int outdoorTemperature { 31 };

    int* activeReading { &indoorTemperature };

    std::cout << "Current reading: " << *activeReading << '\\n';

    activeReading = &outdoorTemperature;

    std::cout << "Current reading: " << *activeReading << '\\n';
}

// Output:
Current reading: 22
Current reading: 31

This line changes the pointer:

activeReading = &outdoorTemperature;

It does not modify indoorTemperature.

It simply makes activeReading store a different address. After that assignment, dereferencing the pointer gives access to outdoorTemperature.

Operation 2: change the value being pointed at

Assigning through a dereferenced pointer modifies the object at the stored address.

#include <iostream>

int main(){
    int motorSpeedRpm { 1800 };

    int* selectedMotorSpeed { &motorSpeedRpm };

    std::cout << "Before update: " << motorSpeedRpm << " rpm\\n";

    *selectedMotorSpeed = 2200;

    std::cout << "After update:  " << motorSpeedRpm << " rpm\\n";
}

// Output:
Before update: 1800 rpm
After update:  2200 rpm

This line does not change the pointer:

*selectedMotorSpeed = 2200;

The pointer still points to motorSpeedRpm.

What changes is the object being pointed at. Since selectedMotorSpeed points to motorSpeedRpm, assigning through *selectedMotorSpeed changes motorSpeedRpm.

The same pointer can do both

A pointer can be reseated and then used to modify the new target.

#include <iostream>

int main(){
    int channelAOffset { 3 };
    int channelBOffset { -2 };

    int* activeOffset { &channelAOffset };

    *activeOffset = 5;

    activeOffset = &channelBOffset;

    *activeOffset = 0;

    std::cout << "Channel A offset: " << channelAOffset << '\\n';
    std::cout << "Channel B offset: " << channelBOffset << '\\n';

    return 0;
}

// Output:
// Channel A offset: 5
// Channel B offset: 0

This line modifies the first object:

*activeOffset = 5;

At that point, activeOffset points to channelAOffset.

This line changes where the pointer points:

activeOffset = &channelBOffset;

After that, this line modifies the second object:

*activeOffset = 0;

A const caveat

This Nibble assumes an ordinary pointer:

int* ptr;

Const changes what can be modified.

For example:

const int* ptr;

means the object cannot be modified through the pointer.

int* const ptr { &value };

means the pointer cannot be reseated.

Those forms are important, but the base model stays the same: ptr is the pointer, and *ptr is the object being pointed at.

Takeaway

Pointers can be manipulated in two different ways.

  1. By changing the address the pointer is pointing to
  2. Dereference the pointer and changing the value at the address