Barun Debnath đź•ąď¸Ź
7 min read

Enough C++ To Build Anything: Part 1

Table of Contents

C++: The Godfather Of Programming languages

C++ Godfather of Programming Languages

AI Generated Meme with prompt “C++: Godfather of Programming Languages”

I always had/have a love-hate relationship with C++. I try to use it for DSA and sometimes to build something, but anyhow I move on with other attractive languages - Python, Golang, etc.

My recent craze with learning DBs and performance engineering made me realized the importance of C++. Specially the optimizations and low level stuffs that C++ provides.

Hence I finally decided to learn C++ properly. This is Part 1 of the series and this part will cover all the basics of C++.


Basic Setup and Syntax

Template for Competitive Programming (if you are doing)

#include <bits/stdc++.h>  // Includes all standard libraries
using namespace std;

int main() {
    ios_base::sync_with_stdio(false);  // Faster I/O
    cin.tie(NULL);
    
    // Your code here
    
    return 0;
}
  • Why IO is faster with just two lines, you may ask??

    • removes synchronization overhead

    A. ios_base:sync_with_stdio(false)

    • By default, C++ streams (cin, cout) are synchronized with C streams (stdin, stdout) to allow safe mixing of C and C++ I/O.
    • This synchronization makes C++ streams unbuffered, every operation immediately flushes to the C stream buffer.
    • When you disable it:
      1. C++ streams can buffer independently

      2. No more expensive synchronization checks

      3. Significantly faster for large amounts of I/O

    Trade Off: You can no longer safely mix prinf/scanf with cin/cout

    B. cin.tie(NULL)

    • By default, cin is tied to cout
    • cout automatically flushes before every cin operaion.
    • This ensures ouput appears before prompting for input in interactive programs
    • Untying removes this automatic flushing:
      • No forced count.flush() before each cin
      • Faster when you don’t need immediate output visibility

Individual Headers

#include <iostream>   // cin, cout
#include <vector>     // vector
#include <algorithm>  // sort, binary_search, etc.
#include <string>     // string
#include <queue>      // queue, priority_queue
#include <stack>      // stack
#include <map>        // map, unordered_map
#include <set>        // set, unordered_set
#include <iomanip>    // setprecision, fixed

Variables and Data Types

Primitive Types

// Integers
int num = 42;           // 4 bytes, -2^31 to 2^31-1
long long big = 1e18;   // 8 bytes, use for large numbers
unsigned int positive = 100;

// Floating point
double price = 99.99;   // 8 bytes, preferred over float
float small = 3.14f;    // 4 bytes

// Character and Boolean
char grade = 'A';
bool isValid = true;

// String
string name = "Alice";
  • Use long long for large numbers in competitive programming
  • int range: approximately -2Ă—10^9 to 2Ă—10^9
  • long long range: approximately -9Ă—10^18 to 9Ă—10^18

Input and Output

Basic I/O

int n;
cin >> n;           // Read integer
cout << n << endl;  // Print with newline

string name;
cin >> name;        // Reads until whitespace
getline(cin, name); // Reads entire line including spaces

// Multiple inputs
int a, b, c;
cin >> a >> b >> c;

Formatted Output

cout << "Answer: " << result << "\n";
cout << fixed << setprecision(2) << 3.14159;  // Output: 3.14

// Fast I/O for competitive programming
ios_base::sync_with_stdio(false);
cin.tie(NULL);

Control Flow

Conditionals

if (x > 0) {
    cout << "Positive";
} else if (x < 0) {
    cout << "Negative";
} else {
    cout << "Zero";
}

// Ternary operator
string result = (x > 0) ? "Positive" : "Non-positive";

Loops

// For loop
for (int i = 0; i < n; i++) {
    cout << i << " ";
}

// Range-based for loop (C++11)
vector<int> arr = {1, 2, 3, 4, 5};
for (int x : arr) {
    cout << x << " ";
}

// While loop
int i = 0;
while (i < n) {
    cout << i << " ";
    i++;
}

Functions

Basic Functions

// Function declaration
int add(int a, int b) {
    return a + b;
}

// Function with reference parameters (modifies original)
void swap(int& a, int& b) {
    int temp = a;
    a = b;
    b = temp;
}

// Function overloading
int max(int a, int b) { return (a > b) ? a : b; }
double max(double a, double b) { return (a > b) ? a : b; }

Lambda Functions (from C++11)

auto add = [](int a, int b) { return a + b; };
cout << add(3, 4); // Output: 7

// Useful with STL algorithms
sort(arr.begin(), arr.end(), [](int a, int b) { return a > b; }); // Descending sort

Arrays & Vectors

Static Arrays

int arr[100];               // uninitialized
int nums[5] = {1,2,3,4,5};
int matrix[10][10];         // 2D array

// size must be known at compile time
const int SIZE = 1000;
int large_arr[SIZE];

Vectors (Dynamic Arrays)

vector<int> v;          //Empty Vector
vector<int> v(10);      // 10 elements, all 0
vector<int> v(10, 5);   // 10 elements, all 5
vector<int> v = {1,2,3}; // initialize with values

//common operations
v.push_back(42);        // add element at end
v.pop_back();           // remove last element
cout << v.size();       // number of elements
cout << v[0];           // access element (no bounds checking)
cout << v.at(0);        // access element (with bounds checking)

// 2D
vector<vector<int>> matrix(n, vector<int>(m, 0)); //nXm matrix filled wih 0

Vector Iteration

// method 1: Index based
for (int i=0; i<v.size(); i++) {
  cout << v[i] << " ";
}

// method 2: Iterator
for (auto it = v.begin(); it != v.end(); it++) {
  cout << *it << " ";
}

// Method 3: Range based
for (int x: v) {
  cout << x << " ";
}

Strings

Basics

string s = "Hello";
s += " World";      // Concatenation
cout << s.length(); // or s.size()
cout << s[0];       // Access character
s.push_back('!');   // Add character at end
s.pop_back();       // remove last character

String functions

string s = "programming";

// substring
string sub = s.substr(3,4);  // "gram" (start at index 3, length 4)

// find
int pos = s.find("gram");    // Returns index, or string::npos if not found

// Character checks
if (isalpha(s[0])) { /* is letter */ }
if (isdigit(s[0])) { /* is digit */ }
if (islower(s[0])) { /*is lowercase*/ }

// convert case
//transform(start-of-string, end-of-string, output-destination, functin-to-apply);
transform(s.begin(), s.end(), s.begin(), ::tolower);
transform(s.begin(), s.end(), s.begin(), ::toupper);

String to number conversion

string s = "123";
int num = stoi(s);  // string to int
long long big = stoll(s); //string to long long
double d = stod(s); //string to double

// number to string
int num = 123;
string s = to_string(num);

Pointers and references

Pointers

int x = 10;
int* ptr = &x;  // ptr stores address of x
cout << *ptr;   // dereference: prints value at address (10)
cout << ptr;    // prints address
*ptr = 20;      // changes value of x to 20

References

int x = 10;
int& ref = x;   // ref is an alias for x
ref = 20;       // changes x to 20

// references in functions (no copying)
void increment(int& n) {
  n++;          // modifies original variable
}

STL Containers

Vector

vector<int> v = {3, 1, 4, 1, 5};
sort(v.begin(), v.end()); // sort ascending
reverse(v.begin(), v.end());; //reverse
cout << *max_element(v.begin(), v.end()); // find maximum

Map

map<string, int> m;
m["apple"] = 5;
m["banana"] = 3;

// check if key exists
if (m.find("apple") != m.end()) {
  cout << "Found apple";
}

//iterate
for (auto& pair: m) {
  cout << pair.first << ": " << pair.second << end;
}

// unordered map (faster average case)
unordered_map<string, int> um;

Set (unique elements)

set<int> s;
s.insert(5);
s.insert(3);
s.insert(5); // duplicate, won't be added
// s now contains {3,5}

// check memsership
if (s.count(5)) { // or s.find(5) != s.end()
  count << "5 is in set";
}

//unordered set (faster average case)
unordered_set<int> us;

Queue and Stack

queue<int> q;
q.push(1);
q.push(2);
cout << q.front(); // 1
q.pop(); //removes front element

stack<int> st;
st.push(1);
st.push(2);
cout << st.top(); // 2
st.pop(); // removes top element

// priority queue (max heap by default)
priority_queue<int> pq;
pq.push(3);
pq.push(1);
pq.push(4);
cout << pq.top(); // 4 (maximum element)

// min heap
priority_queue<int, vector<int>, greater<int>> min_pq;

STL Algorithms

Sorting


vector<int> v = {3, 1, 4, 1, 5};
sort(v.begin(), s.end());     // ascending
sort(v.begin(), s.end(), greater<int>()); //descending

// custom comparator

sort(v.begin(), v.end(), [](int a, int b) {
  return a > b; //descending
})

Useful Algorithms

vector<int> v = {1,2,3,4,5};

// min/max
cout << *min_element(v.begin(), v.end());
cout << *max_element(v.begin(), v.end());

// Sum
int sum = accumulate(v.begin(), v.end(), 0);

// Count
int count = count(v.begin(), v.end(), 3);

// Reverse
reverse(v.begin(), v.end());

// Unique (removes consecutive duplicates, vector should be sorted first)
// 1. sort vector
// 2. unique() only removes consecutive duplicates. Moves unique elements to front, returns iterator pointing to the new end, elements after this iterator are in undefined state
// 3. erase the undefined elements
sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end());

Classes and Objects

class Rectangle {
  private:
    int length;
    int width;
  public:
    // constructor
    Rectangle(int l, int w): length(l), width(w) {}

    // methods
    int area() {
      return length * width;
    }

    void setDimensions(int l, int w) {
      length = l;
      width = w;
    }
};

// usage
Rectangle rect(5,3);
cout << rect.area(); //15

Pair

pair<int, int> p = {3,4};
cout << p.first << " " << p.second;
// useful for coordinates, key-value pairs
vector<pair<int,int>> points = {
  {1,2},
  {3,4},
  {5,6}
};

// sort by first element, then by second
sort(points.begin(), point.end());

Common DSA Patterns

Two Pointers

D2 Diagram

// check if array is palindrome
bool isPalindrome(vector<int>& arr) {
  int left = 0;
  int right = arr.size() - 1;
  while (left < right) {
    if (arr[left] != arr[right]) return false;
    left++;
    right--;
  }  

  return true;
}

Sliding Window

D2 Diagram

// maximum sum of k consecutive elements
int maxSum(vector<int>& arr, int k) {
  int n = arr.size();
  int windowSum = 0;

  // calculate sum of first window
  for(int i=0; i<k; i++) {
    windowSum += arr[i];
  }

  int maxSum = windowSum;

  // Slide the window
  for(int i=k; i<n; i++) {
    windowSum = windowSum - arr[i-k] + arr[i];
    maxSum = max(maxSum, windowSum);
  }

  return maxSum;
}

Prefix Sum

D2 Diagram

// Build prefix sum array
vector<int> buildPrefixSum(vector<int>& arr) {
  int n = arr.size();
  vector<int> prefix(n);
  prefix[0] = arr[0];

  for(int i=1; i<n; i++) {
    prefix[i] = prefix[i-1] + arr[i];
  }

  return prefix;
}

// Range sum query: sum from index l to r
int rangeSum(vector<int>& prefix, int l, int r) {
  if (l == 0) return prefix[r];
  return prefix[r] - prefix[l-1];
}

D2 Diagram

int binarySearch(vector<int>& arr, int target) {
  int left = 0, right = arr.size() - 1;

  while (left <= right) {
    int mid = left + (right - left) / 2; //prevents overflow

    if (arr[mid] == target) {
      return mid;
    } else if (arr[mid] < target) {
      left = mid + 1;
    } else {
      right = mid - 1;
    }
  }

  return -1;
}

D2 Diagram

void dfs(vector<vector<int>>& graph, int node, vector<bool>& visited) {
  visited[node] = true;

  //process current node
  cout << node << " ";

  for(int neighbor : graph[node]) {
    if (!visited[neighbor]) {
      dfs(graph, neighbor, visited);
    }
  }
}

D2 Diagram

void bfs(vector<vector<int>>& graph, int start) {
  int n = graph.size();
  vector<bool> visited(n, false);
  queue<int> q;

  q.push(start);
  visited[start] = true;

  while (!q.empty()) {
    int node = q.front();
    q.pop();

    // process current node
    cout << node << " ";

    // add all visited neighbors to queue
    for(int neighbor: graph[node]) {
      if(!visited[neighbor]) {
        visited[neighbor] = true;
        q.push(neighbor);
      }
    }
  }
}

Common operations quick reference

Time Complexity

  • Vector access - O(1)
  • Vector push_back - O(1) amortized
  • Vector insert/erase: O(n)
  • Map operations: O(log n)
  • Unordered_map operations: O(1) average, O(n) worst
  • Set operations: O(log n)
  • Sort: O(nlogn)
  • Binary search: O(log n)

Space Complexity

  • Vector: O(n)
  • Map/Set: O(n)
  • Recursion depth: O(depth)

Debugging

  • Follow the methods here to debug efficiently
// Print vector
void printVector(vector<int>& v) {
    for (int x : v) cout << x << " ";
    cout << endl;
}

// Debug macro
#define debug(x) cout << #x << " = " << x << endl;

int main() {
    int n = 5;
    debug(n);  // Prints: n = 5
}

Are we done??

Yes or No!! This is just a Part 1 of me trying to explore C++ in depth. Yeah, yeah I know it was too much DSA focused, but hear me out - C++ is a language for performance crazy fanatic people, maybe, just maybe learning DSA can help you in the long run.

Wrapping the blog with this. In Part 2, we will see more templates, more tips and tricks and will write C++ till you accept that it’s really is godfather of all languages.