#include <vector>

using namespace std;

int main() {
    int x = 10;
    int& ref = x;  // верно что ref == 10
    x = 7;         // верно, что ref == 7
    // то есть ref ссылается на значение переменной x
    // можно менять и x через переменную ref:
    ref = 11;      // верно, что x == 11

    // однако есть так называемые const reference
    const int& const_ref = x;
    // главное отличие, что следующий код не скомпилируется:
    // const_ref = 12;
    // из-за модификатора const мы не можем изменить данные через const_ref
    // однако если мы изменим сам x - то const_ref "увидет" данные изменения

    // основной недостаток reference - они навечно "привязаны" к некоторому объекту

    // когда хочется иметь ссылаться на разные объекты - существуют указатели:
    int* ptr = &x;
    // в данном случае & выступает как унарный оператор взятия адреса переменной
    // синтаксис для работы с указателями чуть сложнее:
    *ptr = 10;
    // так мы записали по адресу ptr число 10 (то есть записали в переменную x, так как сейчас в ptr лежит адрес именно x'а)
    // обратите внимание на * - унарный оператор разыменования - обратен операции взятия адреса
    // в указатели можно записать "ничего":
    ptr = nullptr;
    // nullptr - так называемый нулевой указатель. В старых версиях C++ и C принято писать NULL. В новом стандарте (C++11) был введено специальное слово nullptr;
    // обратите внимание, что сам указатель мы изменяем без использования *
    // вот так можно перенаправить на другой:
    int y = 100;
    ptr = &y;

    // модификатор const можно тоже использовать вместе с указателями
    // но есть два возможных расположения const - до и после *

    const int* const_1 = &x;  // нельзя менять int, сам const_1 менять можно
    int* const const_2 = &x;  // нельзя изменять то, куда направлен const_2
    const int* const const_3 = &x;  // ничего менять нельзя

    // отдельно стоит отметить двойные указатели (а также тройные)
    int** double_pointer = &ptr;
    **double_pointer = 5;
    // штука редкая, но иногда встречается

    // для удобства работы с указателями был придуман оператор ->
    vector<int> data = {1, 2, 3};
    vector<int>& data_ref = data;
    vector<int>* data_ptr = &data;
    // вот так можно обращаться к методам вектора из ref и ptr:
    data_ref.push_back(4);
    (*data_ptr).push_back(5);  // вначале разыменовываем, а затем вызываем push_back
    data_ptr->push_back(6);    // -> объединяет операции * и .
    return 0;
}
