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 ptr
    ptr = 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 modified
    int* 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; // right
    ptr++;      // right                                ptr++;    // wrong
Smart Pointers - when we forget to deallocate memory => may get memory leak that can crash program. Java & C# have Garbage Collection Mechanisms to smartly deallocate unused memory to be used again => no need to worry about any memory leaks
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 allocationsame 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 stack
        return arr; }
    int main()
    { int *brr = create();  // stores the returned pointer
        brr[3] = 5;            // now you can access arr of create in main using pointer
        delete[] 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
Differences - (NOTE - mai bs malloc likh rha but baaki bhi similar hai)
  • 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

Popular posts from this blog

Templates (for CP)

DSA Trees + Heap

Modular Basics + Number Theory + Permutations