Unit 2: Pointers, Reference Variables, Arrays and String Concepts
I. Orientation
C++ provides direct and indirect ways to access data. Arrays and objects store values, pointers store addresses, references provide aliases, and std::string manages variable-length character sequences. Correct use depends on type, object lifetime, ownership, and memory boundaries.
- Addressing: The address-of operator
&obtains an object's address; the dereference operator*accesses the object at a valid stored address. - Lifetime: An address is usable only while the object to which it points remains alive.
- Type safety: A pointer's type determines how dereferencing and pointer arithmetic are interpreted.
- Ownership: A raw pointer does not state whether it owns dynamically allocated memory; modern C++ uses containers and smart pointers to express ownership.
- Indexing: For built-in arrays,
a[i]is defined as*(a + i). - Standard strings:
std::stringowns and manages its character storage, avoiding most manual C-style string operations.
II. Pointer Types and Operations
A. Void pointer
A void pointer, written void*, can hold the address of any object type but cannot be dereferenced directly.
- Conversion to
void*: An object pointer converts implicitly tovoid*. - Conversion back: C++ requires an explicit cast to recover the original pointer type.
- Restriction: Because
voidhas no size or representation, standard C++ does not permit dereferencing or arithmetic onvoid*. - Typical use: Low-level generic interfaces may transport untyped addresses, although templates are usually safer.
int value = 25;
void* raw = &value;
int* typed = static_cast<int*>(raw);
std::cout << *typed; // 25Here, raw stores the address of value, while typed restores the information needed to read an int.
B. Pointer arithmetic
Pointer arithmetic moves through elements of an array according to the pointed-to type's size.
- Increment: If
pis anint*,p + 1points to the nextint, not merely the next byte. - Valid range: Arithmetic is defined only within the same array object or up to its one-past-the-end position.
- One-past pointer: It may be used for comparison or loop termination but must not be dereferenced.
- Subtraction:
q - pgives the number of array elements between two pointers and has typestd::ptrdiff_t. - Equivalence:
p[i],*(p + i), andi[p]have the same built-in meaning.
int data[] = {10, 20, 30};
int* p = data;
std::cout << *(p + 2); // 30Here, p + 2 addresses data[2].
C. Pointer to pointer
A pointer to pointer stores the address of another pointer, adding one level of indirection.
- Declaration: In
int** pp,pppoints to anint*. - Access levels:
ppis the pointer's address,*ppis the storedint*, and**ppis the finalint. - Uses: Common uses include modifying a caller's pointer and representing dynamically allocated pointer tables.
- Type matching: Each
*corresponds to one indirection level.
int value = 7;
int* p = &value;
int** pp = &p;
**pp = 12; // value becomes 12D. Dangling pointer
A dangling pointer holds an address whose object lifetime has ended.
- Deletion case: After
delete p, the storage formerly designated bypis no longer a live object. - Scope case: Returning the address of an automatic local variable produces a dangling pointer when the function returns.
- Consequence: Dereferencing a dangling pointer causes undefined behavior.
- Prevention: Use automatic storage, containers, or smart pointers; after deleting through a raw pointer, assign
nullptrwhen the pointer remains accessible.
int* p = new int(9);
delete p;
p = nullptr;Setting p to nullptr prevents accidental reuse through that variable, though copied pointers would still dangle.
E. Wild pointer
A wild pointer is an uninitialized pointer whose stored bit pattern does not designate a known valid object.
- Cause:
int* p;leaves a local pointer indeterminate when no initializer is supplied. - Risk: Reading, dereferencing, or deleting through such a pointer can produce undefined behavior.
- Difference from dangling: A wild pointer was never given a reliable target; a dangling pointer once referred to a valid object.
- Prevention: Initialize immediately with a valid address or
nullptr.
int* p = nullptr;F. Null pointer assignment
A null pointer assignment explicitly records that a pointer currently designates no object.
- Preferred literal: Since C++11,
nullptris the type-safe null pointer literal. - Testing:
if (p)is true only whenpis non-null;if (p == nullptr)states the test explicitly. - Dereference rule: Dereferencing a null pointer is undefined behavior.
- Advantage over
0orNULL:nullptrcannot be mistaken for an ordinary integer during overload resolution.
int* p = nullptr;
if (p != nullptr)
std::cout << *p;III. Pointers with Classes and Objects
A. Classes containing pointers
A class containing an owning raw pointer must define how copying, moving, assignment, and destruction manage the resource.
- Shallow-copy danger: Compiler-generated copying duplicates the address, potentially causing shared modification and double deletion.
- Deep copy: A copy operation may allocate separate storage and copy the pointed-to value.
- Rule of five: Resource-owning classes may require a destructor, copy constructor, copy assignment operator, move constructor, and move assignment operator.
- Preferred design:
std::vector,std::string, andstd::unique_ptrusually provide safer ownership.
class Number {
std::unique_ptr<int> value;
public:
explicit Number(int n)
: value(std::make_unique<int>(n)) {}
};The unique_ptr automatically releases its int when a Number is destroyed.
B. Pointer to objects
A pointer to an object stores its address and accesses members through the arrow operator.
- Declaration:
Item* p = &obj;makesppoint toobj. - Member access:
p->show()is equivalent to(*p).show(). - Dynamic object:
new Itemreturns anItem*, but direct use ofnewshould normally be replaced bystd::make_unique<Item>(). - Const form: A
const Item*cannot be used to modify the object or call its non-const member functions.
class Item {
public:
int price = 100;
};
Item item;
Item* p = &item;
std::cout << p->price;C. this pointer
Inside a non-static member function, this points to the object for which that function was called.
- Implicit use: Writing
valueinside a member function generally meansthis->value. - Name disambiguation:
this->value = value;distinguishes the data member from a parameter with the same name. - Chaining: Returning
*thisby reference permits calls such asobj.set(2).display(). - Const member: In a
constmember function,thispoints to a const object. - Static exception: Static member functions have no
thispointer because they are not called on a specific object.
class Counter {
int value;
public:
Counter& set(int value) {
this->value = value;
return *this;
}
};D. Array of objects
An array of objects stores multiple class instances contiguously and applies construction and destruction to every element.
- Declaration:
Point points[3];creates threePointobjects. - Initialization: Elements may be list-initialized with constructor arguments.
- Access:
points[i].show()accesses the object at indexi. - Lifetime order: Elements are constructed from first to last and destroyed in reverse order.
- Safer alternative:
std::array<Point, 3>has fixed size, whilestd::vector<Point>supports dynamic size.
class Point {
public:
int x;
explicit Point(int n) : x(n) {}
};
Point points[] = {Point(2), Point(4), Point(6)};IV. Standard C++ Strings
A. Defining and assigning Standard C++ string objects
std::string represents an owned, dynamically sized sequence of characters.
- Header: The class is declared in
<string>. - Definitions:
std::string a;creates an empty string, whilestd::string b = "C++";initializes text. - Assignment:
a = b;copies the characters, so later changes to one string do not alter the other. - Concatenation:
+creates a combined string, and+=appends to an existing string. - Input:
operator>>reads one whitespace-delimited word;std::getline(std::cin, s)reads an entire line.
std::string course = "Object";
course += " Oriented Programming";B. String class member functions
String member functions inspect content, locate characters, compare values, and obtain substrings.
- Size:
s.size()ands.length()return the character count asstd::string::size_type. - Access:
s[i]provides unchecked access;s.at(i)checks bounds and may throwstd::out_of_range. - State:
s.empty()reports whether the size is zero. - Search:
s.find("text")returns the first position orstd::string::npos. - Substring:
s.substr(pos, count)creates a string from at mostcountcharacters starting atpos. - Comparison: Relational operators compare strings lexicographically;
s.compare(t)returns a negative, zero, or positive result. - C interface:
s.c_str()returns a null-terminated character pointer valid subject to later string modifications.
std::string s = "pointer";
std::size_t pos = s.find("int"); // pos is 2
std::string part = s.substr(pos, 3); // "int"C. String class modifiers
String modifiers change the owned character sequence and may alter its size or storage.
- Append:
append(),+=, andpush_back()add characters. - Insert:
insert(pos, text)places text before positionpos. - Erase:
erase(pos, count)removes characters. - Replace:
replace(pos, count, text)substitutes a selected range. - Removal:
pop_back()removes the last character and requires a non-empty string;clear()removes all characters. - Capacity changes:
resize(n)changes logical length, whilereserve(n)requests capacity without adding characters. - Iterator invalidation: Modifications that reallocate storage can invalidate pointers, references, and iterators into the string.
std::string s = "C+";
s.insert(2, "+"); // "C++"
s.replace(0, 1, "Modern C"); // "Modern C++"V. Reference Variables
A. Differences between pointer and reference variables
A reference is an alias for an existing object, whereas a pointer is a separate object that stores an address.
-
Reference variables:
- Initialization:
int& r = x;must bindrwhen it is declared. - Use: Operations on
rdirectly affectx; no dereference syntax is needed. - Rebinding: Assigning
r = ycopiesyintox; it does not makerrefer toy. - Null state: A properly formed reference must bind to an object.
- Initialization:
-
Pointer variables:
- Initialization:
int* p = &x;storesx's address and may later be reassigned. - Use:
*paccesses the pointed-to object, whilep->memberaccesses an object's member. - Null state: A pointer may hold
nullptr. - Arithmetic: A pointer into an array supports constrained arithmetic; a reference does not.
- Initialization:
int x = 5, y = 8;
int& r = x;
int* p = &x;
r = y; // x becomes 8
p = &y; // p now points to yVI. Multidimensional Arrays
A. Declaration and processing of multidimensional arrays inside main and classes
A multidimensional built-in array is an array whose elements are themselves fixed-size arrays.
- Inside
main:int matrix[2][3]declares two rows, each containing threeintelements. - Initialization: Nested braces reflect the row structure:
{{1, 2, 3}, {4, 5, 6}}. - Processing: Nested loops typically traverse rows and then columns.
- Storage: Built-in multidimensional arrays use row-major order, so each complete row occupies contiguous storage.
- Function parameters: For
void f(int a[][3]), the column count3is required to calculatea[i][j]. - Class member:
int data[2][3];can be declared in a class; modern code may use nestedstd::arrayobjects for value semantics and size information.
class Matrix {
int data[2][3]{};
public:
void fill() {
for (std::size_t row = 0; row < 2; ++row)
for (std::size_t col = 0; col < 3; ++col)
data[row][col] = static_cast<int>(row + col);
}
};Here, row selects one of two inner arrays and col selects one of three integers.
VII. Class Member Addressing
A. Pointer to data member
A pointer to data member identifies a non-static member within objects of a particular class rather than storing an ordinary object address.
- Declaration:
int Record::* membermeans thatmembercan identify anintdata member ofRecord. - Initialization:
member = &Record::score;selects the member using its qualified name. - Object access:
object.*memberaccesses that member through an object. - Pointer access:
pointer->*memberaccesses it through a pointer to an object. - Class association: The member pointer must be combined with a suitable object; it does not independently point to one object's storage.
- Static distinction: A static data member has an ordinary address because it belongs to the class rather than each instance.
class Record {
public:
int score = 90;
};
int Record::* member = &Record::score;
Record student;
Record* p = &student;
std::cout << student.*member; // 90
std::cout << p->*member; // 90Did this save you a night before the exam?
LPU Notes is free, and it stays free. Ads cover part of the server bill. The rest comes out of a student's own pocket: the domain, the storage, and keeping the site up through the weeks everyone needs it at once.
The payment button didn't load. An ad blocker or a filtered network is the usual reason. to try again.
Nothing here is ever locked, and nothing unlocks. Chip in only if it was worth it. What it pays for →