Pointers and references are the two ways to refer indirectly to objects. A reference is an alias for another object: an lvalue reference T& binds to a named object, cannot be null, and cannot be reseated, while a const reference const T& can bind to temporaries as well as named objects and is the standard way to pass large objects to functions without copying. A pointer is a variable that stores a memory address and can be null, reseated, and used with pointer arithmetic; reading or writing through a null or dangling pointer is undefined behavior. nullptr, introduced in C++11, is the preferred null pointer constant because it avoids the integer-versus-pointer ambiguity of the traditional NULL macro and improves overload resolution. Const interacts with pointers in three useful ways: int* const p is a const pointer that cannot be reseated but whose pointee can change, const int* p is a pointer to const that cannot modify the pointee but can be reseated, and const int* const p locks down both. A void* holds the address of an object of unknown type but cannot be dereferenced directly and must be cast to a typed pointer before use, which is why it appears mainly in C-style APIs. A function pointer stores the address of a function and can be invoked through that pointer, useful for callbacks; in modern C++, std::function or a lambda is usually preferable. A dangling reference points to memory whose lifetime has ended, and returning a reference to a local variable is one of the classic ways to create one.
Memory in C++ comes from two principal sources. Stack allocation is fast and automatic: a local variable lives in the current stack frame and is freed when the scope exits. Heap allocation uses new and delete, and persists until explicitly freed. The new and delete operators are type-safe and call constructors and destructors, unlike the C library functions malloc and free, which only allocate raw bytes; mixing them across the two systems is undefined behavior. delete releases a single object and calls one destructor, while delete[] releases a C-style array allocated with new T[n] and calls the destructor for every element, and mismatching the two is also undefined behavior. Placement new constructs an object at a preallocated memory address, such as in a custom allocator or memory pool, and the corresponding cleanup requires an explicit destructor call followed by operator delete. A memory leak occurs when dynamically allocated memory is never freed and gradually exhausts the process; the recommended remedy is RAII through smart pointers and standard containers rather than raw new and delete.
C++ offers four named casts that make the intent of each conversion explicit, in contrast to the C-style cast (int)x whose meaning is hidden. static_cast performs compile-time type conversions with type checking and is used for numeric conversions, upcasting in an inheritance hierarchy, and void*-to-typed-pointer conversions. const_cast is the only cast that can add or remove const or volatile qualifiers, but modifying an originally const object through the result is undefined behavior. reinterpret_cast performs low-level, implementation-defined bitwise conversions between pointer and integer types and should be used only when the platform's memory layout is fully understood. dynamic_cast safely converts pointers and references within an inheritance hierarchy with runtime type checking enabled by RTTI, returning nullptr for a pointer or throwing std::bad_cast for a reference when the cast is invalid. The volatile keyword tells the compiler that a variable's value may change outside its control, such as a memory-mapped hardware register, and disables certain optimizations; const volatile means the program cannot modify the variable but something else might. Unlike std::atomic, however, volatile provides no thread-safety guarantees.