Dynamic Memory Allocation + Pointers
Pointers - stores address of variable
int *a = &b --> a is pointer pointing to address of b --> use *a to access b
int &a = b --> a is alias to b --> both a and b have same address => use a to access b
arr[3] = { 5, 10, 20 }; *arr --> 5 but *(arr + 1) --> 10 for 2-D array -> *(*arr + 1) --> arr[0][1] and *(*(arr + 1)) --> arr[1][0]
- Dereferencing - Retrieve data contained at memory location where the pointer points
- void pointers give great flexibility as can point to any data type.
But to dereference => first transform it into some other data type
- Memory Leak - When user forgets to deallocate memory for future use
- m=malloc(5); m=NULL; → allocate 5-byte memory from heap and store address in pointer m → but now program has lost this address bcz no pointer points to it anymore → this memory can't be accessed or freed for lifetime of program
- Dangling Pointer - When delete ptr → only deletes memory of pointer but pointer still exists pointing to deleted memory location → results in unexpected behaviour
- if(ptr != NULL) ---> bcz if removed NULL pointer => Undefined behavior{ delete ptrptr = NULL } ---> Set to null after deletion to avoid dangling pointer
- Wild Pointer - Uninitialized pointers bcz they point to some random memory location and program may behave unexpectedly
- int* p; --> No initialization => points to unknown memory location *p = 12; ---> we are updating unknown memory location to 12 --> BAD practice ---------------------------------------------------------------------------------
- int a = 10;int* p = &a; --> not a wild pointer now bcz points to known value*p = 12; --> OK as value of a gets changed ---------------------------------------------------------------------------------
- int* p = (int*)malloc(sizeof(int));*p = 12; ---> ALSO acceptable
const int* ptr --> pointer to const int type => can modify ptr itself but the object pointed to by ptr cannot be modifiedint* const ptr --> const pointer to int type => cannot modify ptr but the object pointed to by ptr can be modified
const int a = 10; int a = 10;const int* ptr = &a; int* const ptr = &a;*ptr = 5; // wrong *ptr = 5; // rightptr++; // right ptr++; // wrong
In C++, use Smart Pointer --> whenever object is destroyed or goes out of scope => frees memory also => no need to use "delete" explicitly
Smart pointers are classes that wrap a pointer to use memory efficiently
- unique_ptr - when single ownership is needed => Only one unique pointer for one object => to assign different object --> first remove current object from the pointer
- shared_ptr - many pointers can point to one object => maintain Reference Counter to keep track of pointers ---> If reference count is 0 => frees memory
- Weak_ptr - similar to shared_ptr but will not maintain Reference Counter to avoid the circular dependency created by objects pointing to each other using shared_ptr
malloc or memory allocation - dynamically allocate memory of specified size and returns void pointer => can be cast into any pointer => initialized with default garbage value
calloc or contiguous allocation - same as malloc but initializes each block with 0
realloc or re-allocation - dynamically change memory size of previously allocated memory => maintains already present value and create new blocks with default garbage value
int*p = (int*) malloc (n * sizeof(int)); --> memory size = 4*n bytes (bcz 1 int = 4 byte)
int *p = (int*) calloc (n, sizeof(int));
int *p = realloc(p, n * sizeof(int));
if(p==NULL) -> "memory not allocated"
free(p) -> "frees memory"
Memory Layout of C Program
- When the program starts --> code gets copied to the main memory (RAM)
- Stack - holds continuous memory occupied by functions (limited scope assigned)
- Heap contains data as dynamic memory using pointers (universal scope assigned)
Benefit - int main-> int f1-> int f2-> int f3 (all in stack) => But if f1 assigned in heap
=> don't have to wait for both f2 and f3 to get executed --> f1 itself creates and deletes - Stack is very fast → 1 CPU instruction bcz only stack pointer moves
- Heap is slow bcz maintains record of all free blocks of memory (using free list)
- Memory automatically freed in stack once goes out of scope but in heap delete it explicitly
- Initialized and uninitialized data segment hold initialized and uninitialized global variable
- int *create(){ int *arr = new int[50]; // assigned using heap// int arr[50]; --> This cannot be accessed inside main bcz assigned in stackreturn arr; }int main(){ int *brr = create(); // stores the returned pointerbrr[3] = 5; // now you can access arr of create in main using pointerdelete[] brr;} // remember to free the allocated memory in heap
- NOTE - Name 'arr' is local inside create function but memory is allocated globally in heap --> can access it globally using pointer if it is appropriately shared
new keyword
- new → internally calls malloc to allocate memory + calls constructor
- int arr; => created a block of int and name it as arr
- int* ptr = new int => creates block of int and assigned its address to ptr
- int* ptr = new int and int* ptr = new int() => Both are correct
- Can allocate other data types or custom class --> node* head = new node
- Can also assign value ---> float* a = new float(45.67)
- Can also assign array ---> int* a = new int[7]
- delete keyword must be there bcz memory is assigned in heap → else memory leak
- for object => delete name and for array => delete[] name
- malloc & free => C library function that can also be used in C++
- new & delete => specific for C++ only
- Both malloc and new are used to allocate memory dynamically in heap But “new” also calls the constructor of class whereas “malloc” does not
- Both delete and free are used to deallocate the allocated memory from heap But “delete” also calls the Destructor of class whereas "free" does not
- free should not be used with "new" as it does not call destructor of that object => cannot clean-up the resources of objects
- delete should not be used with "malloc"
- shows undefined behavior means anything can happen => may work normally, may crash immediately, may give random errors
Due to this undefined behaviour => always use what is general convention
--> Never do experiments with heap ---> DANGER !!
Comments
Post a Comment