Unit 2 - Notes
CSE202
Unit 2: Pointers, Reference Variables, Arrays and String Concepts
1. Fundamentals of Pointers
Void Pointer (void*)
A void pointer is a special type of pointer that can hold the address of any data type (int, float, char, user-defined classes). It is often referred to as a generic pointer.
- Characteristics:
- It has no associated data type.
- Dereferencing: You cannot directly dereference a void pointer because the compiler does not know how many bytes to read. It must be explicitly typecast to another pointer type first.
- Pointer Arithmetic: Standard C++ does not allow arithmetic on void pointers (because the size of the underlying type is unknown), though some compilers (like GCC) allow it as an extension (treating it as
char*).
Example:
int n = 10;
void* ptr = &n; // Valid: holding int address
// cout << *ptr; // ERROR: Cannot dereference 'void*'
cout << *(static_cast<int*>(ptr)); // Valid: Output 10
Pointer Arithmetic
Pointer arithmetic operations allow moving the pointer to point to different memory locations. Pointers do not increment by "1" literally; they increment by the sizeof(type).
Formula:
- Valid Operations:
- Increment (
++): Moves to the next element. - Decrement (
--): Moves to the previous element. - Addition (
+ integer): Moves forward by elements. - Subtraction (
- integer): Moves backward by elements. - Subtraction of two pointers: Returns the number of elements between two addresses.
- Increment (
Pointer to Pointer (Double Pointer)
A pointer to a pointer is a form of multiple indirection (or a chain of pointers). It is a variable that keeps the address of another pointer.
- Declaration:
int **pptr; - Logic:
pptrstores the address ofptr.ptrstores the address of variablevar.varstores the value.
Example:
int var = 3000;
int *ptr = &var;
int **pptr = &ptr;
// Accessing value:
// *ptr == 3000
// **pptr == 3000
2. Common Pointer Problems
Improper use of pointers is a common source of bugs in C++.
Dangling Pointer
A pointer points to a memory location that has been deleted (freed) or is no longer valid.
- Causes:
- Deallocating memory using
deletewithout setting the pointer tonullptr. - Returning the address of a local variable from a function (the local variable is destroyed when the function exits).
- Deallocating memory using
- Fix: Always set pointers to
nullptrimmediately after deletion.
Wild Pointer
A pointer that has been declared but not initialized. It points to an arbitrary (random) memory location.
- Risk: Dereferencing a wild pointer causes undefined behavior or program crashes.
- Fix: Initialize pointers to
nullptror a valid address upon declaration.
Null Pointer Assignment
Trying to dereference a pointer that holds a NULL or nullptr value.
- Consequence: Results in a runtime error (Segmentation Fault).
- Best Practice: Always check if a pointer is not null before dereferencing.
if (ptr != nullptr) { ... }
3. Pointers and References
Differences Between Pointer and Reference Variables
| Feature | Pointer | Reference |
|---|---|---|
| Definition | A variable that holds the memory address of another variable. | An alias (another name) for an existing variable. |
| Syntax | int* ptr = &a; |
int& ref = a; |
| Reassignment | Can be reassigned to point to different variables. | Cannot be reassigned to refer to another variable after initialization. |
| Memory | Has its own memory address and occupies storage. | Does not strictly occupy memory (conceptually); shares the address of the referent. |
| Nullability | Can be assigned nullptr. |
Must reference a valid object; cannot be null. |
| Indirection | Requires * to access the value. |
Accessed directly like a normal variable. |
| Arithmetic | Supports arithmetic operations. | No arithmetic operations performable on the reference address itself. |
4. Arrays and Multidimensional Arrays
Declaration and Processing of Multidimensional Arrays
1. Inside main (Procedural approach)
Multidimensional arrays are arrays of arrays. In memory, they are stored in row-major order.
int main() {
// Declaration and Initialization
int matrix[2][3] = {
{1, 2, 3},
{4, 5, 6}
};
// Processing (Nested Loops)
for(int i = 0; i < 2; i++) {
for(int j = 0; j < 3; j++) {
cout << matrix[i][j] << " ";
}
cout << endl;
}
return 0;
}
2. Inside a Class (OOP approach)
Arrays can be data members of a class.
class Matrix {
int data[3][3];
public:
void input() {
// Logic to accept input into data[i][j]
}
void display() {
// Logic to print data[i][j]
}
};
5. The Standard C++ String Class (std::string)
The <string> library provides a safe and convenient way to handle text compared to C-style character arrays (char*).
Defining and Assigning
#include <string>
// ...
std::string s1; // Default constructor (empty string)
std::string s2 = "Hello"; // Assignment
std::string s3("World"); // Constructor
std::string s4 = s2; // Copy constructor
Member Functions
length()orsize(): Returns the number of characters.at(index): Returns the character at a specific index (with bounds checking).substr(start, length): Returns a substring.find(substring): Returns the index of the first occurrence of the substring.compare(str): Compares two strings lexicographically.
Modifiers of String Class
append(str)or+=: Adds text to the end of the string.push_back(char): Adds a single character to the end.pop_back(): Removes the last character.insert(pos, str): Inserts a string at a specified position.erase(pos, len): Removes characters from a specific position.replace(pos, len, str): Replaces a portion of the string.
6. Pointers and Objects (OOP Integration)
Pointer to Objects
Just as we have pointers to primitive types, we can have pointers to class objects.
- Syntax:
ClassName *ptr; - Accessing Members: When using a pointer to an object, members are accessed using the arrow operator (
->) instead of the dot operator (.).
class Box {
public:
int length;
void show() { cout << length; }
};
int main() {
Box b;
b.length = 10;
Box *ptr = &b; // Pointer to object
ptr->length = 20; // Using arrow operator
ptr->show(); // Output: 20
}
Array of Objects
An array where each element is an object of a class.
- Memory: Allocated contiguously.
- Requirement: If the class has a constructor, it must have a default (no-argument) constructor to initialize the array elements.
Box boxes[3]; // Creates 3 Box objects
boxes[0].show(); // Access via dot operator
Classes Containing Pointers
When a class contains a pointer as a data member, memory management becomes critical.
- Deep Copy vs. Shallow Copy: The default copy constructor performs a shallow copy (copies the address only). If one object deletes the memory, the other object has a dangling pointer.
- Rule of Three: If a class needs to manage dynamic memory (via pointers), you almost always need to implement:
- Destructor (to
deletememory). - Copy Constructor (to perform Deep Copy).
- Copy Assignment Operator (to perform Deep Copy).
- Destructor (to
Pointer to Data Member
C++ allows pointers to point specifically to members within a class definition, rather than a specific instance's data.
- Concept: It stores the "offset" of the member within the class layout. It can only be used in conjunction with a specific object.
- Declaration:
DataType ClassName::*PointerName; - Assignment:
PointerName = &ClassName::MemberName; - Access:
- With object:
object.*pointer - With object pointer:
objPointer->*pointer
- With object:
Example:
class Data {
public:
int val;
};
int main() {
int Data::*ptrToVal = &Data::val; // Pointer to data member
Data d;
d.val = 10;
cout << d.*ptrToVal; // Accessing via pointer to member. Output: 10
}
The this Pointer
The this pointer is a special implicit pointer available inside all non-static member functions of a class.
- Definition: It points to the object that invoked the member function.
- Type:
ClassName * const this(A constant pointer to the class type).
Key Uses:
- Distinguish parameters from member variables:
CPPvoid setValues(int x) { this->x = x; // 'this->x' is member, 'x' is parameter } - Method Chaining: Returning the current object reference allows cascading calls.
CPPClass& add(int a) { this->val += a; return *this; // Returns reference to current object } // Usage: obj.add(5).add(10);