Pointers Interview Question on C and C++ : Pointers are one of the most powerful and essential features of C and C++. They allow efficient memory manipulation and direct interaction with hardware. In this blog post, we will explore various types of pointers, their descriptions, and usage examples.
Here are some important pointer-related interview questions, covering NULL pointers, dangling pointers, wild pointers, function pointers, and more. You can use these to write your blog post.
Basic Pointer Questions
1. What is a pointer in C/C++?
A pointer is a variable that stores the memory address of another variable. It allows direct access and manipulation of memory, making it a powerful feature in C and C++.
2. How do you declare and initialize a pointer?
A pointer is declared using the *
symbol. Initialization can be done in multiple ways:
int a = 10; // Normal variable
int* ptr = &a; // Pointer storing the address of 'a'
Alternatively, you can initialize a pointer to nullptr
:
int* ptr = nullptr; // Pointer initialized to null (C++11 onwards)
3. What happens if you try to dereference an uninitialized pointer?
Dereferencing an uninitialized pointer (wild pointer) leads to undefined behavior, which may cause a segmentation fault or crash. Example:
int* ptr; // Uninitialized pointer
std::cout << *ptr; // Undefined behavior (may crash)
4. What is the difference between a pointer and a reference in C++?
Feature | Pointer | Reference |
---|---|---|
Syntax | int* ptr = &x; | int& ref = x; |
Nullability | Can be nullptr | Cannot be null |
Reassignment | Can change what it points to | Cannot be changed after initialization |
Memory Address | Stores an address explicitly | Acts as an alias for the variable |
5. How can you print the address stored in a pointer?
You can print the address using cout
in C++ or printf
in C:
int a = 10;
int* ptr = &a;
std::cout << "Address stored in ptr: " << ptr << std::endl;
Or in C:
printf("Address stored in ptr: %p\n", (void*)ptr);
NULL Pointers
1. What is a NULL pointer?
A NULL pointer is a pointer that does not point to any valid memory location. It is used to indicate that the pointer is not assigned a valid address. In C/C++, it is typically defined as:
#define NULL 0 // In C
#define NULL nullptr // In C++ (C++11 onwards uses 'nullptr')
Example:
int* ptr = NULL; // Pointer initialized to NULL
2. Why should you initialize a pointer to NULL?
Initializing a pointer to NULL helps prevent it from becoming a dangling or wild pointer. It makes it easier to check whether a pointer is valid before using it.
Example:
int* ptr = NULL; // Safe initialization
if (ptr == NULL) {
std::cout << "Pointer is NULL, safe to check before use." << std::endl;
}
3. What happens if you dereference a NULL pointer?
Dereferencing a NULL pointer leads to undefined behavior, which typically results in a segmentation fault (crash).
Example:
int* ptr = NULL;
std::cout << *ptr; // Crash! Undefined behavior
4. How do you check if a pointer is NULL before using it?
Before dereferencing, always check if a pointer is NULL:
if (ptr != NULL) {
std::cout << *ptr; // Safe to use
} else {
std::cout << "Pointer is NULL, cannot dereference!" << std::endl;
}
In modern C++ (C++11 and later), it’s better to use nullptr
:
if (ptr != nullptr) {
std::cout << *ptr;
}
5. Is NULL the same as 0 in C++?
- In C,
NULL
is typically defined as0
. - In C++,
NULL
is still0
, butnullptr
(introduced in C++11) is a better alternative because it is strongly typed and prevents accidental type conversions.
Example:
int* p1 = NULL; // Works, but NULL is just 0
int* p2 = 0; // Also works, but less readable
int* p3 = nullptr; // Preferred in C++ (strongly typed)
Thus, while NULL
and 0
are technically the same in older C++, nullptr
is the preferred way in modern C++.
Dangling Pointers
1. What is a dangling pointer?
A dangling pointer is a pointer that refers to a memory location that has been freed, deleted, or gone out of scope. Accessing such a pointer leads to undefined behavior and potential program crashes.
2. How does a dangling pointer occur?
A dangling pointer can occur in several situations:
- Deallocation of memory
- When dynamically allocated memory is freed but the pointer still holds the address.
int* ptr = new int(10); delete ptr; // Memory is freed std::cout << *ptr; // Dangling pointer access! Undefined behavior
- Returning address of a local variable
- A local variable goes out of scope when a function returns, making the pointer invalid.
int* getPointer() { int x = 10; return &x; // Returning address of local variable (invalid) } int* ptr = getPointer(); std::cout << *ptr; // Dangling pointer access!
- Pointer to an object that goes out of scope
- When a pointer points to an object that has gone out of scope.
int* ptr; { int x = 10; ptr = &x; // x goes out of scope after this block } std::cout << *ptr; // Dangling pointer access!
3. How can you prevent dangling pointers?
To avoid dangling pointers, follow these practices:
✔ Set pointers to NULL after freeing memory
int* ptr = new int(10);
delete ptr;
ptr = nullptr; // Prevents dangling
✔ Avoid returning addresses of local variables
int* getPointer() {
static int x = 10; // Static variables persist after function returns
return &x;
}
✔ Use smart pointers (C++11 and later)
- Smart pointers (
std::unique_ptr
andstd::shared_ptr
) manage memory automatically and prevent dangling pointers.
#include <memory>
std::unique_ptr<int> ptr = std::make_unique<int>(10);
4. What happens if you use a dangling pointer?
Using a dangling pointer leads to undefined behavior, which may cause:
- Segmentation faults (crashes)
- Corrupt program data
- Hard-to-debug memory issues
5. Example of a dangling pointer scenario
#include <iostream>
void dangerousFunction() {
int* ptr = new int(20);
delete ptr; // Memory is freed
std::cout << *ptr; // Accessing freed memory (undefined behavior!)
}
int main() {
dangerousFunction();
return 0;
}
✅ Solution: Set ptr = nullptr;
after delete ptr;
to prevent accidental access.
Wild Pointers
1. What is a wild pointer?
A wild pointer is an uninitialized pointer that holds a garbage (random) memory address. Since it does not point to a valid memory location, dereferencing it leads to undefined behavior, including program crashes.
Example of a wild pointer:
int* ptr; // Wild pointer (uninitialized)
std::cout << *ptr; // Undefined behavior! Might crash the program
2. How does a wild pointer differ from a dangling pointer?
Aspect | Wild Pointer | Dangling Pointer |
---|---|---|
Definition | Uninitialized pointer holding garbage value | Pointer pointing to memory that has been freed or is out of scope |
Cause | Declared but not assigned a valid memory address | Memory deallocation, object going out of scope, or returning a local address |
Effect | Can point to any random memory location | Can cause undefined behavior when accessed after memory is freed |
Prevention | Always initialize pointers | Set pointers to nullptr after freeing memory |
3. How can you prevent wild pointers?
To avoid wild pointers, follow these best practices:
✔ Initialize pointers before use
int* ptr = nullptr; // Safe initialization
✔ Allocate memory before dereferencing
int* ptr = new int(10); // Allocated memory
std::cout << *ptr; // Safe
delete ptr;
ptr = nullptr; // Avoids becoming a dangling pointer
✔ Use smart pointers in C++ (C++11 and later)
#include <memory>
std::unique_ptr<int> ptr = std::make_unique<int>(10); // No need to manually delete
4. How do you detect wild pointers in a program?
Detecting wild pointers can be challenging, but here are some techniques:
✔ Use Valgrind (Linux/Mac) or AddressSanitizer (GCC/Clang)
- Valgrind helps detect uninitialized memory access.
valgrind --leak-check=full ./program
- AddressSanitizer (compile with
-fsanitize=address
) can detect memory issues.
✔ Enable compiler warnings
- Use
-Wall -Wextra -Werror
in GCC/Clang to catch uninitialized variables.
✔ Use debug tools like GDB
- Run the program in GDB (
gdb ./program
) and check pointer values before dereferencing.
✔ Use assertions to check for nullptr
#include <cassert>
int* ptr = nullptr;
assert(ptr != nullptr); // This will terminate the program if ptr is NULL
By following these techniques, you can minimize the risk of wild pointers in your program. 🚀
Memory Management and Pointers
1. What is a memory leak in the context of pointers?
A memory leak occurs when dynamically allocated memory is not freed before the pointer to it is lost. This leads to wasted memory, which can degrade system performance and eventually cause the program to crash if memory runs out.
Example of a memory leak:
void memoryLeak() {
int* ptr = new int(10); // Memory allocated
// No delete statement, so memory is never freed (leak)
}
Each time memoryLeak()
is called, more memory is allocated but never freed.
2. How do you prevent memory leaks when using dynamic memory allocation?
✔ Always free allocated memory
int* ptr = new int(10);
delete ptr; // Prevents memory leak
ptr = nullptr; // Avoids dangling pointer
✔ Use Smart Pointers (C++11 and later)
Smart pointers automatically manage memory, preventing leaks.
#include <memory>
std::unique_ptr<int> ptr = std::make_unique<int>(10); // No need to delete
✔ Track allocations and deallocations carefully
Use tools like Valgrind, AddressSanitizer, or GDB to detect leaks.
✔ Follow the Rule of Thumb:
Every new
should have a delete
, and every malloc()
should have a free()
.
3. What is the purpose of malloc()
and free()
in C?
malloc(size_t size)
: Allocatessize
bytes of memory from the heap and returns a pointer to it. The memory is not initialized.free(void* ptr)
: Frees the dynamically allocated memory, making it available for reuse.
Example:
#include <stdlib.h>
int* ptr = (int*)malloc(sizeof(int) * 5); // Allocates memory for 5 integers
free(ptr); // Frees the allocated memory
4. What is the difference between malloc()
and new
in C++?
Feature | malloc() (C) | new (C++) |
---|---|---|
Memory Allocation | Allocates raw memory | Allocates memory and calls constructor |
Initialization | No initialization | Initializes objects if applicable |
Return Type | void* (requires casting) | Returns specific type (no casting needed) |
Usage | int* p = (int*)malloc(sizeof(int)); | int* p = new int; |
Freeing Memory | free(ptr); | delete ptr; |
✔ Use new
in C++ instead of malloc()
for object-oriented programming, as it automatically calls constructors.
5. What happens if you call free()
on a NULL pointer?
- Calling
free(NULL)
is safe and has no effect in C/C++. - The C standard guarantees that
free(NULL);
does nothing.
Example:
int* ptr = NULL;
free(ptr); // Safe, no effect
6. What happens if you call delete
twice on the same pointer?
- Calling
delete
twice on the same pointer causes undefined behavior, which may result in a crash or memory corruption.
Example of double delete (Undefined Behavior!):
int* ptr = new int(10);
delete ptr; // First delete (valid)
delete ptr; // Second delete (undefined behavior!)
✔ Solution: Set the pointer to nullptr
after deleting it.
int* ptr = new int(10);
delete ptr;
ptr = nullptr; // Prevents double delete
🚀 By following best practices, you can avoid memory leaks and undefined behavior in your programs!
Pointer Arithmetic
1. What operations can be performed on pointers?
Pointers support several operations:
✔ Assignment: Assign one pointer to another of the same type.
int a = 10;
int* p1 = &a;
int* p2 = p1; // Assigning one pointer to another
✔ Dereferencing (*
): Access the value stored at the pointer’s address.
std::cout << *p1; // Prints value of 'a' (10)
✔ Pointer Arithmetic:
- Increment (
ptr++
), decrement (ptr--
) - Addition (
ptr + n
), subtraction (ptr - n
) - Subtracting two pointers (
ptr1 - ptr2
)
✔ Comparison (==, !=, >, <
): Compare pointer addresses.
if (p1 == p2) { std::cout << "Same address"; }
2. What happens when you increment a pointer?
When you increment a pointer (ptr++
), it moves to the next memory location based on its data type size.
Example:
int arr[3] = {10, 20, 30};
int* ptr = arr; // Points to arr[0]
ptr++; // Moves to arr[1], not just 1 byte but sizeof(int) bytes
std::cout << *ptr; // Prints 20
📌 For an int*
, ptr++
increases the address by sizeof(int)
(usually 4 bytes).
3. How do pointer arithmetic operations depend on the data type?
Pointer arithmetic is based on the size of the data type:
Data Type | Size (sizeof(type) ) | ptr++ moves by |
---|---|---|
char* | 1 byte | 1 byte |
int* | 4 bytes (typical) | 4 bytes |
double* | 8 bytes | 8 bytes |
Example:
char c = 'A';
char* p1 = &c;
p1++; // Moves by 1 byte
double d = 3.14;
double* p2 = &d;
p2++; // Moves by 8 bytes (on most systems)
4. What is pointer subtraction?
Pointer subtraction (ptr1 - ptr2
) finds the distance (number of elements) between two pointers pointing to the same array.
Example:
int arr[] = {10, 20, 30, 40, 50};
int* p1 = &arr[1]; // Points to 20
int* p2 = &arr[4]; // Points to 50
std::cout << (p2 - p1); // Output: 3 (elements apart)
📌 Formula: (p2 - p1) = (Address2 - Address1) / sizeof(type)
5. Why can’t you add two pointers?
Adding two pointers (ptr1 + ptr2
) has no logical meaning because:
- A pointer stores a memory address, and adding two addresses doesn’t make sense.
- Pointer arithmetic is defined in terms of element sizes, not memory locations.
❌ Invalid:
int* p1, *p2;
int* p3 = p1 + p2; // Error: Addition of pointers is not allowed
✔ Allowed Operations:
- Pointer + Integer (
ptr + n
moves the pointern
elements ahead) - Pointer – Pointer (finds distance between elements)
🚀 By understanding these operations, you can use pointers efficiently in C/C++!
Function Pointers
1. What is a function pointer?
A function pointer is a pointer that stores the address of a function, allowing you to call the function indirectly.
✔ Functions in C/C++ are stored in memory, and their addresses can be assigned to pointers.
✔ Function pointers are useful for callback functions, dynamic function selection, and polymorphism in C.
2. How do you declare and use a function pointer?
Declaration:
returnType (*pointerName)(parameterTypes);
Example: Using a Function Pointer
#include <iostream>
// Function to be pointed to
void hello() {
std::cout << "Hello, World!\n";
}
int main() {
void (*funcPtr)(); // Function pointer declaration
funcPtr = hello; // Assign function address
funcPtr(); // Call function through pointer
return 0;
}
📌 No need for &
before function name (hello
) because function names decay into pointers.
3. What is a use case for function pointers?
Function pointers are commonly used in:
✔ Callback functions (e.g., signal handlers, event handling)
✔ Dynamic function selection (e.g., strategy patterns)
✔ Jump tables (efficient switch-case alternatives)
✔ Sorting with custom comparison functions (qsort()
in C)
Example: Function Pointer in qsort()
#include <stdio.h>
#include <stdlib.h>
// Comparison function for sorting in ascending order
int compare(const void* a, const void* b) {
return (*(int*)a - *(int*)b);
}
int main() {
int arr[] = {4, 2, 9, 1, 5};
int size = sizeof(arr) / sizeof(arr[0]);
qsort(arr, size, sizeof(int), compare); // Function pointer as argument
for (int i = 0; i < size; i++)
printf("%d ", arr[i]); // Output: 1 2 4 5 9
return 0;
}
📌 compare
is passed as a function pointer to qsort()
for sorting.
A callback function is a function passed as an argument to another function. This allows for dynamic function execution.
Example: Function Pointer as a Callback
#include <iostream>
// Callback function
void printMessage(const std::string& msg) {
std::cout << msg << std::endl;
}
// Function that takes a function pointer as a parameter
void executeCallback(void (*callback)(const std::string&)) {
callback("Callback executed!");
}
int main() {
executeCallback(printMessage);
return 0;
}
📌 The executeCallback()
function calls the function passed to it dynamically.
5. Can a function return a pointer to another function?
Yes! A function can return a pointer to another function, often used in function factories.
Example: Returning a Function Pointer
#include <iostream>
// Functions
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
// Function returning a pointer to another function
int (*getOperation(char op))(int, int) {
return (op == '+') ? add : subtract;
}
int main() {
auto func = getOperation('+'); // Get function pointer
std::cout << func(5, 3); // Output: 8
return 0;
}
📌 getOperation()
returns a pointer to either add
or subtract
, allowing dynamic function selection.
🚀 Function pointers are powerful tools for dynamic behavior in C/C++!
Pointers and Arrays
1. What is the relationship between arrays and pointers in C?
- In C, an array name acts as a pointer to its first element.
- The expression
arr
is equivalent to&arr[0]
. - The name of an array cannot be modified (it’s a constant pointer), but a pointer variable can be used to traverse an array.
Example:
int arr[] = {10, 20, 30};
int* ptr = arr; // Equivalent to int* ptr = &arr[0];
printf("%d", *ptr); // Output: 10
2. How do you pass an array to a function using pointers?
Arrays are always passed as pointers to functions to avoid copying large amounts of data.
Example: Passing an Array Using Pointers
#include <stdio.h>
void printArray(int* arr, int size) {
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
}
int main() {
int numbers[] = {1, 2, 3, 4, 5};
printArray(numbers, 5); // Passing array as a pointer
return 0;
}
📌 The function receives int* arr
, not int arr[]
, since both are equivalent.
3. What happens if you increment an array name?
- You cannot increment an array name (
arr++
) because it is a constant pointer (arr
is fixed at&arr[0]
). - However, you can increment a pointer variable that points to an array.
Example:
int arr[] = {10, 20, 30};
int* ptr = arr; // Pointer variable
ptr++; // Valid: Moves to the next element
arr++; // ❌ Invalid: Compiler error (array name is constant)
4. How do you dynamically allocate memory for an array?
- Use
malloc()
orcalloc()
in C. - Use
new[]
in C++. - Always free memory using
free()
in C ordelete[]
in C++.
Example in C (malloc)
#include <stdio.h>
#include <stdlib.h>
int main() {
int* arr = (int*)malloc(5 * sizeof(int)); // Allocate memory for 5 integers
if (!arr) { return 1; } // Check for allocation failure
for (int i = 0; i < 5; i++) {
arr[i] = i * 10;
printf("%d ", arr[i]);
}
free(arr); // Free allocated memory
return 0;
}
Example in C++ (new)
#include <iostream>
int main() {
int* arr = new int[5]; // Allocate memory for 5 integers
for (int i = 0; i < 5; i++) {
arr[i] = i * 10;
std::cout << arr[i] << " ";
}
delete[] arr; // Free allocated memory
return 0;
}
📌 Always use free()
(C) or delete[]
(C++) to prevent memory leaks.
5. How can you use pointers to iterate over an array?
A pointer can traverse an array just like an index.
Example: Using Pointer Arithmetic
#include <stdio.h>
int main() {
int arr[] = {10, 20, 30, 40, 50};
int* ptr = arr; // Points to arr[0]
for (int i = 0; i < 5; i++) {
printf("%d ", *(ptr + i)); // Access array using pointer arithmetic
}
return 0;
}
📌 ptr + i
moves the pointer by i
elements (not bytes).
🚀 Understanding pointers with arrays makes memory management and performance optimization easier in C/C++!
Pointers and Structures
1. How do you declare a pointer to a structure?
A pointer to a structure is declared using the struct
keyword followed by an asterisk (*
).
Example:
#include <stdio.h>
struct Student {
int id;
char name[20];
};
int main() {
struct Student s1 = {101, "Alice"};
struct Student* ptr = &s1; // Pointer to structure
printf("ID: %d, Name: %s\n", ptr->id, ptr->name);
return 0;
}
📌 ptr
is a pointer to struct Student
and holds the address of s1
.
2. What is the ->
operator used for in pointers to structures?
- The arrow operator (
->
) is used to access structure members through a pointer. - It is a shorthand for
(*pointer).member
.
Example:
ptr->id // Equivalent to (*ptr).id
ptr->name // Equivalent to (*ptr).name
✅ Using ->
avoids excessive parentheses and improves readability.
3. How can you allocate memory for a structure dynamically?
- Use
malloc()
in C. - Use
new
in C++.
Example in C (Using malloc()
)
#include <stdio.h>
#include <stdlib.h>
struct Student {
int id;
char name[20];
};
int main() {
struct Student* ptr = (struct Student*)malloc(sizeof(struct Student));
if (!ptr) { return 1; } // Check if memory allocation was successful
ptr->id = 102;
snprintf(ptr->name, sizeof(ptr->name), "Bob");
printf("ID: %d, Name: %s\n", ptr->id, ptr->name);
free(ptr); // Free allocated memory
return 0;
}
Example in C++ (Using new
)
#include <iostream>
struct Student {
int id;
std::string name;
};
int main() {
Student* ptr = new Student;
ptr->id = 103;
ptr->name = "Charlie";
std::cout << "ID: " << ptr->id << ", Name: " << ptr->name << std::endl;
delete ptr; // Free allocated memory
return 0;
}
📌 Always use free()
in C and delete
in C++ to prevent memory leaks.
4. Can a structure contain a pointer to itself?
Yes, a structure can contain a pointer to itself, which is useful for linked lists, trees, and other dynamic data structures.
Example: Self-referential Structure (Linked List Node)
#include <stdio.h>
struct Node {
int data;
struct Node* next; // Pointer to the next node (same structure type)
};
int main() {
struct Node node1, node2;
node1.data = 10;
node2.data = 20;
node1.next = &node2; // Linking nodes
printf("Node 1 Data: %d, Node 2 Data: %d\n", node1.data, node1.next->data);
return 0;
}
📌 This is the foundation of linked lists!
5. What is the difference between .
and ->
in structure access?
Operator | Used with | Example | Meaning |
---|---|---|---|
. (dot) | Structure variable | s1.id | Access member of a structure variable |
-> (arrow) | Pointer to structure | ptr->id | Access member through a structure pointer |
Example Demonstrating Both:
#include <stdio.h>
struct Student {
int id;
char name[20];
};
int main() {
struct Student s1 = {104, "David"};
struct Student* ptr = &s1;
printf("Using . operator: ID = %d, Name = %s\n", s1.id, s1.name);
printf("Using -> operator: ID = %d, Name = %s\n", ptr->id, ptr->name);
return 0;
}
📌 Use .
for normal variables and ->
for pointers!
Smart Pointers (C++ Specific)
1. What are smart pointers in C++?
Smart pointers are RAII-based (Resource Acquisition Is Initialization) wrappers around raw pointers that automatically manage memory in C++. They reside in the <memory>
header and help prevent memory leaks and dangling pointers.
✅ Types of Smart Pointers in C++:
std::unique_ptr
→ Exclusive ownership (cannot be shared).std::shared_ptr
→ Shared ownership (reference counting).std::weak_ptr
→ Weak reference (no ownership, avoids circular references).
📌 Smart pointers automatically deallocate memory when they go out of scope!
2. What is std::unique_ptr
and how does it work?
std::unique_ptr
allows only one owner of the resource.- It deletes the resource automatically when it goes out of scope.
- Cannot be copied, but can be moved to transfer ownership.
Example: Using std::unique_ptr
#include <iostream>
#include <memory> // Include <memory> for smart pointers
class Example {
public:
Example() { std::cout << "Constructor Called\n"; }
~Example() { std::cout << "Destructor Called\n"; }
};
int main() {
std::unique_ptr<Example> ptr = std::make_unique<Example>(); // Creates a unique_ptr
// std::unique_ptr<Example> ptr2 = ptr; ❌ (Copying not allowed)
std::unique_ptr<Example> ptr2 = std::move(ptr); // ✅ Transfer ownership
return 0; // Destructor is called when ptr2 goes out of scope
}
📌 Best choice when you want sole ownership of a resource.
3. How does std::shared_ptr
differ from std::unique_ptr
?
✅ std::shared_ptr
allows multiple pointers to share ownership of the same object.
✅ Uses reference counting: The resource is deleted when the last shared_ptr
goes out of scope.
Example: Using std::shared_ptr
#include <iostream>
#include <memory>
class Example {
public:
Example() { std::cout << "Constructor Called\n"; }
~Example() { std::cout << "Destructor Called\n"; }
};
int main() {
std::shared_ptr<Example> ptr1 = std::make_shared<Example>(); // Shared ownership
std::shared_ptr<Example> ptr2 = ptr1; // ptr2 shares ownership
std::cout << "Reference Count: " << ptr1.use_count() << std::endl;
return 0; // Destructor is called when the last reference goes out of scope
}
📌 Best choice when multiple parts of the program need shared access to a resource.
4. What is a weak pointer (std::weak_ptr
)?
✅ std::weak_ptr
is a non-owning reference to a std::shared_ptr
.
✅ Used to prevent circular references (memory leaks) in shared pointers.
Why Use std::weak_ptr
?
- If two
std::shared_ptr
s reference each other, their reference count never reaches zero, causing a memory leak (circular reference). std::weak_ptr
helps break this cyclic dependency.
Example: Preventing Circular References
#include <iostream>
#include <memory>
class B;
class A {
public:
std::shared_ptr<B> b_ptr;
~A() { std::cout << "A Destroyed\n"; }
};
class B {
public:
std::weak_ptr<A> a_ptr; // Use weak_ptr to prevent circular reference
~B() { std::cout << "B Destroyed\n"; }
};
int main() {
std::shared_ptr<A> a = std::make_shared<A>();
std::shared_ptr<B> b = std::make_shared<B>();
a->b_ptr = b;
b->a_ptr = a; // Using weak_ptr prevents a memory leak
return 0; // Objects are correctly deleted
}
📌 Best choice when objects should not keep each other alive indefinitely.
5. How do smart pointers help prevent memory leaks?
✅ Automatic Resource Management → Smart pointers ensure allocated memory is freed automatically.
✅ Exception Safety → If an exception occurs, smart pointers automatically clean up resources.
✅ No Need for Manual delete
→ Reduces the risk of forgetting to free memory.
✅ Prevents Dangling Pointers → Smart pointers go out of scope gracefully, preventing use-after-free errors.
✅ Avoids Circular References → std::weak_ptr
prevents memory leaks due to cyclic dependencies in shared pointers.
Example: Preventing Memory Leaks
#include <iostream>
#include <memory>
class Example {
public:
Example() { std::cout << "Resource Acquired\n"; }
~Example() { std::cout << "Resource Released\n"; }
};
void create() {
std::shared_ptr<Example> ptr = std::make_shared<Example>();
} // Object is automatically deleted when function exits
int main() {
create();
std::cout << "End of main\n";
return 0;
}
✅ No need for delete
, memory is freed when ptr
goes out of scope!
1. NULL Pointer
A NULL pointer is a pointer that is explicitly assigned NULL
or nullptr
(in C++11 and later). It does not point to any valid memory location.
Example:
int* ptr = NULL; // C-style null pointer
int* ptr2 = nullptr; // Modern C++ null pointer
2. Void Pointer
A void pointer (generic pointer) can hold the address of any data type but requires explicit type casting before dereferencing.
Example:
void* ptr;
int x = 10;
ptr = &x; // Storing address of an integer
3. Dangling Pointer
A dangling pointer occurs when a pointer points to memory that has been freed or deleted.
Example:
int* ptr = new int(5);
delete ptr; // ptr is now dangling
4. Wild Pointer
A wild pointer is an uninitialized pointer that holds a garbage value, leading to unpredictable behavior.
Example:
int* ptr; // Uninitialized, wild pointer
5. Generic Pointer
A generic pointer (same as void pointer) can store the address of any variable and can be typecast accordingly.
Example:
void* ptr;
int x = 10;
ptr = &x;
int* intPtr = (int*)ptr;
6. Near Pointer (Legacy – 16-bit systems)
A near pointer is a 16-bit pointer that accesses memory within the current segment.
Example: (Only valid in 16-bit compilers)
int near *ptr; // Supported in old MS-DOS compilers
7. Far Pointer (Legacy – 16-bit systems)
A far pointer is a 32-bit pointer with a segment and offset, used for accessing memory beyond the current segment.
Example: (Only valid in 16-bit compilers)
int far *ptr;
8. Huge Pointer (Legacy – 16-bit systems)
A huge pointer is similar to a far pointer but ensures a unique physical address.
Example: (Only valid in 16-bit compilers)
int huge *ptr;
9. Function Pointer
A function pointer stores the address of a function and can be used to call the function dynamically.
Example:
#include <iostream>
void display(int x) { std::cout << "Value: " << x << std::endl; }
int main() {
void (*funcPtr)(int) = &display;
funcPtr(10);
}
10. Array Pointer
A pointer to an array points to the first element of an array.
Example:
int arr[5] = {1, 2, 3, 4, 5};
int* ptr = arr;
11. Pointer to Pointer
A pointer to pointer stores the address of another pointer.
Example:
int x = 10;
int* ptr = &x;
int** ptr2 = &ptr;
12. Smart Pointer (C++11+)
A smart pointer manages memory automatically, preventing memory leaks.
Example:
#include <memory>
std::unique_ptr<int> ptr = std::make_unique<int>(42);
13. Const Pointer
A constant pointer cannot change the address it is pointing to.
Example:
int x = 10;
int* const ptr = &x; // Address is constant
14. Pointer to Const
A pointer to a constant points to a constant value and prevents modification.
Example:
const int x = 10;
const int* ptr = &x; // Cannot modify *ptr
15. Const Pointer to Const
A constant pointer to a constant means both the address and the value cannot be modified.
Example:
const int x = 10;
const int* const ptr = &x; // Neither value nor address can be changed
16. This Pointer (C++ Specific)
A this pointer is available in non-static member functions and points to the object that invoked the function.
Example:
class MyClass {
public:
void display() { std::cout << this; }
};
17. nullptr Pointer (C++11+)
nullptr
is a modern way to represent null pointers in C++.
Example:
int* ptr = nullptr;