C++: The 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:
-
C++ streams can buffer independently
-
No more expensive synchronization checks
-
Significantly faster for large amounts of I/O
-
Trade Off: You can no longer safely mix
prinf
/scanf
withcin
/cout
B.
cin.tie(NULL)
- By default,
cin
is tied tocout
cout
automatically flushes before everycin
operaion.- This ensures ouput appears before prompting for input in interactive programs
- Untying removes this automatic flushing:
- No forced
count.flush()
before eachcin
- Faster when you don’t need immediate output visibility
- No forced
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
to2Ă—10^9
long long
range: approximately-9Ă—10^18
to9Ă—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
// 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
// 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
// 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];
}
Binary Search
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;
}
DFS - Depth First Search
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);
}
}
}
BFS - Breadth First Search
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.