📚
C++ Fundamentals
Master the core concepts of C++ programming
Basic Syntax and Structure
Hello World and Basic Structure
#include <iostream> // Preprocessor directive
#include <string>
#include <vector>
using namespace std; // Using directive (optional)
// Function declaration
void greetUser(const string& name);
int main() {
// Output to console
cout << "Hello, World!" << endl;
// Variables and data types
int age = 25; // Integer
double height = 5.9; // Double precision floating point
char grade = 'A'; // Character
bool isStudent = true; // Boolean
string name = "Alice"; // String (C++ string class)
// Constants
const double PI = 3.14159; // Compile-time constant
const int MAX_SIZE = 100;
// Auto keyword (C++11) - type deduction
auto temperature = 98.6; // Deduced as double
auto count = 42; // Deduced as int
// Input from user
cout << "Enter your name: ";
string userName;
getline(cin, userName); // Read entire line including spaces
// Function call
greetUser(userName);
return 0; // Return success status
}
// Function definition
void greetUser(const string& name) {
cout << "Welcome to C++, " << name << "!" << endl;
}
// Compilation commands:
// g++ -o program program.cpp (basic compilation)
// g++ -std=c++17 -o program program.cpp (with C++17 standard)💡 C++ Key Concepts
- • Compiled Language: C++ code is compiled to machine code for fast execution
- • Header Files: Use
#includeto include libraries and declarations - • Namespaces: Organize code and avoid naming conflicts
- • Strong Typing: Variables must be declared with specific types
Data Types and Variables
Fundamental Data Types
#include <iostream>
#include <climits> // For type limits
#include <string>
int main() {
// Integer types
short shortNum = 32767; // 16-bit: -32,768 to 32,767
int regularNum = 2000000; // 32-bit: -2^31 to 2^31-1
long longNum = 9000000000L; // 64-bit on most systems
long long bigNum = 9000000000LL; // At least 64-bit
// Unsigned integers (only positive values)
unsigned int positiveNum = 4000000000U;
unsigned char byte = 255; // 0 to 255
// Floating point types
float decimal = 3.14f; // 32-bit floating point
double preciseDecimal = 3.14159; // 64-bit floating point
long double extendedDecimal = 3.141592653589793L; // Extended precision
// Character types
char letter = 'A'; // Single character
wchar_t wideChar = L'Ω'; // Wide character
char16_t utf16Char = u'€'; // UTF-16 character (C++11)
char32_t utf32Char = U'🚀'; // UTF-32 character (C++11)
// Boolean
bool isTrue = true; // true or false
// String types
string cppString = "Hello C++"; // C++ string class
const char* cString = "Hello C"; // C-style string (null-terminated)
// Type information
cout << "Size of int: " << sizeof(int) << " bytes" << endl;
cout << "Size of double: " << sizeof(double) << " bytes" << endl;
cout << "Max int value: " << INT_MAX << endl;
cout << "Min int value: " << INT_MIN << endl;
// Type casting
int intValue = 100;
double doubleValue = static_cast<double>(intValue); // Safe casting
int backToInt = static_cast<int>(3.14); // Explicit casting
// C-style casting (not recommended)
double oldStyleCast = (double)intValue;
// Const and constexpr
const int ARRAY_SIZE = 10; // Runtime constant
constexpr int COMPILE_TIME = 20; // Compile-time constant (C++11)
return 0;
}Arrays and Pointers
#include <iostream>
#include <array> // For std::array (C++11)
#include <vector> // For std::vector
int main() {
// C-style arrays
int numbers[5] = {1, 2, 3, 4, 5}; // Fixed size array
int matrix[3][3] = {{1,2,3}, {4,5,6}, {7,8,9}}; // 2D array
// Array access
cout << "First element: " << numbers[0] << endl;
cout << "Array size: " << sizeof(numbers)/sizeof(numbers[0]) << endl;
// C++11 std::array (safer alternative)
array<int, 5> modernArray = {10, 20, 30, 40, 50};
cout << "Modern array size: " << modernArray.size() << endl;
// Dynamic arrays with std::vector
vector<int> dynamicArray = {100, 200, 300};
dynamicArray.push_back(400); // Add element
dynamicArray.pop_back(); // Remove last element
cout << "Vector size: " << dynamicArray.size() << endl;
// Iterating through arrays
cout << "C-style array: ";
for (int i = 0; i < 5; i++) {
cout << numbers[i] << " ";
}
cout << endl;
// Range-based for loop (C++11)
cout << "Modern array: ";
for (const auto& value : modernArray) {
cout << value << " ";
}
cout << endl;
// Pointers
int value = 42;
int* ptr = &value; // Pointer to int
cout << "Value: " << value << endl;
cout << "Address: " << &value << endl;
cout << "Pointer: " << ptr << endl;
cout << "Dereferenced: " << *ptr << endl;
// Pointer arithmetic
int arr[] = {10, 20, 30, 40, 50};
int* arrPtr = arr; // Points to first element
cout << "First element: " << *arrPtr << endl;
cout << "Second element: " << *(arrPtr + 1) << endl;
cout << "Third element: " << arrPtr[2] << endl; // Array notation
// Null pointers
int* nullPtr = nullptr; // C++11 null pointer
if (nullPtr == nullptr) {
cout << "Pointer is null" << endl;
}
// References (aliases)
int original = 100;
int& ref = original; // Reference to original
ref = 200; // Changes original
cout << "Original after reference change: " << original << endl;
return 0;
}Control Flow
Conditionals and Loops
#include <iostream>
#include <vector>
#include <string>
int main() {
int score = 85;
// If-else statements
if (score >= 90) {
cout << "Grade: A" << endl;
} else if (score >= 80) {
cout << "Grade: B" << endl;
} else if (score >= 70) {
cout << "Grade: C" << endl;
} else {
cout << "Grade: F" << endl;
}
// Ternary operator
string result = (score >= 60) ? "Pass" : "Fail";
cout << "Result: " << result << endl;
// Switch statement
char grade = 'B';
switch (grade) {
case 'A':
cout << "Excellent!" << endl;
break;
case 'B':
cout << "Good job!" << endl;
break;
case 'C':
cout << "Average" << endl;
break;
default:
cout << "Need improvement" << endl;
break;
}
// For loops
cout << "Counting 1 to 5: ";
for (int i = 1; i <= 5; i++) {
cout << i << " ";
}
cout << endl;
// Range-based for loop (C++11)
vector<string> fruits = {"apple", "banana", "orange"};
cout << "Fruits: ";
for (const auto& fruit : fruits) {
cout << fruit << " ";
}
cout << endl;
// While loop
int count = 0;
cout << "While loop: ";
while (count < 3) {
cout << count << " ";
count++;
}
cout << endl;
// Do-while loop
int number = 0;
cout << "Do-while loop: ";
do {
cout << number << " ";
number++;
} while (number < 2);
cout << endl;
// Break and continue
cout << "Break and continue example: ";
for (int i = 0; i < 10; i++) {
if (i == 3) continue; // Skip iteration when i is 3
if (i == 7) break; // Exit loop when i is 7
cout << i << " ";
}
cout << endl;
// Nested loops
cout << "Multiplication table (3x3):" << endl;
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
cout << i * j << " ";
}
cout << endl;
}
return 0;
}Functions
Function Declaration and Definition
#include <iostream>
#include <vector>
#include <string>
using namespace std;
// Function declarations (prototypes)
void printMessage();
int add(int a, int b);
double calculateArea(double length, double width);
void printArray(const int arr[], int size);
void modifyValue(int& value); // Pass by reference
void printVector(const vector<int>& vec); // Pass by const reference
// Function overloading - same name, different parameters
int multiply(int a, int b);
double multiply(double a, double b);
int multiply(int a, int b, int c);
// Default parameters
void greet(const string& name, const string& greeting = "Hello");
// Template function (generic programming)
template<typename T>
T getMax(T a, T b) {
return (a > b) ? a : b;
}
int main() {
// Function calls
printMessage();
int result = add(5, 3);
cout << "5 + 3 = " << result << endl;
double area = calculateArea(5.0, 3.0);
cout << "Area: " << area << endl;
// Array parameter
int numbers[] = {1, 2, 3, 4, 5};
printArray(numbers, 5);
// Pass by reference
int value = 10;
cout << "Before modification: " << value << endl;
modifyValue(value);
cout << "After modification: " << value << endl;
// Vector parameter
vector<int> vec = {10, 20, 30, 40};
printVector(vec);
// Function overloading
cout << "Int multiply: " << multiply(4, 5) << endl;
cout << "Double multiply: " << multiply(4.5, 2.0) << endl;
cout << "Triple multiply: " << multiply(2, 3, 4) << endl;
// Default parameters
greet("Alice"); // Uses default greeting
greet("Bob", "Good morning"); // Custom greeting
// Template function
cout << "Max of 10, 20: " << getMax(10, 20) << endl;
cout << "Max of 3.14, 2.71: " << getMax(3.14, 2.71) << endl;
cout << "Max of 'a', 'z': " << getMax('a', 'z') << endl;
return 0;
}
// Function definitions
void printMessage() {
cout << "Hello from a function!" << endl;
}
int add(int a, int b) {
return a + b;
}
double calculateArea(double length, double width) {
return length * width;
}
void printArray(const int arr[], int size) {
cout << "Array elements: ";
for (int i = 0; i < size; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
void modifyValue(int& value) {
value *= 2; // Modify the original variable
}
void printVector(const vector<int>& vec) {
cout << "Vector elements: ";
for (const auto& element : vec) {
cout << element << " ";
}
cout << endl;
}
// Function overloading implementations
int multiply(int a, int b) {
return a * b;
}
double multiply(double a, double b) {
return a * b;
}
int multiply(int a, int b, int c) {
return a * b * c;
}
void greet(const string& name, const string& greeting) {
cout << greeting << ", " << name << "!" << endl;
}Memory Management
Dynamic Memory Allocation
#include <iostream>
#include <memory> // For smart pointers (C++11)
using namespace std;
int main() {
// Stack vs Heap
int stackVariable = 42; // Stored on stack (automatic cleanup)
// Dynamic allocation with new/delete (C-style, not recommended)
int* heapVariable = new int(42); // Stored on heap
cout << "Heap value: " << *heapVariable << endl;
delete heapVariable; // Manual cleanup required
heapVariable = nullptr; // Avoid dangling pointer
// Dynamic array allocation
int size = 5;
int* dynamicArray = new int[size]{1, 2, 3, 4, 5};
cout << "Dynamic array: ";
for (int i = 0; i < size; i++) {
cout << dynamicArray[i] << " ";
}
cout << endl;
delete[] dynamicArray; // Use delete[] for arrays
dynamicArray = nullptr;
// Smart Pointers (C++11) - Automatic memory management
// unique_ptr - Exclusive ownership
unique_ptr<int> uniquePtr = make_unique<int>(100);
cout << "Unique ptr value: " << *uniquePtr << endl;
// Automatically deleted when uniquePtr goes out of scope
// unique_ptr with arrays
unique_ptr<int[]> uniqueArray = make_unique<int[]>(5);
for (int i = 0; i < 5; i++) {
uniqueArray[i] = i * 10;
}
cout << "Unique array: ";
for (int i = 0; i < 5; i++) {
cout << uniqueArray[i] << " ";
}
cout << endl;
// shared_ptr - Shared ownership
shared_ptr<int> sharedPtr1 = make_shared<int>(200);
shared_ptr<int> sharedPtr2 = sharedPtr1; // Share ownership
cout << "Shared ptr value: " << *sharedPtr1 << endl;
cout << "Reference count: " << sharedPtr1.use_count() << endl;
// weak_ptr - Non-owning observer
weak_ptr<int> weakPtr = sharedPtr1;
if (auto locked = weakPtr.lock()) { // Check if still valid
cout << "Weak ptr value: " << *locked << endl;
}
// Memory leaks example (what NOT to do)
/*
void memoryLeak() {
int* ptr = new int(42);
// Forgot to call delete - MEMORY LEAK!
return; // ptr goes out of scope, memory not freed
}
*/
// RAII (Resource Acquisition Is Initialization) principle
// Resources are automatically managed by constructors/destructors
return 0;
}
// Custom class demonstrating RAII
class RAIIExample {
private:
int* data;
size_t size;
public:
// Constructor - acquire resource
RAIIExample(size_t s) : size(s) {
data = new int[size];
cout << "Resource acquired" << endl;
}
// Destructor - release resource
~RAIIExample() {
delete[] data;
cout << "Resource released" << endl;
}
// Copy constructor (Rule of 3/5)
RAIIExample(const RAIIExample& other) : size(other.size) {
data = new int[size];
for (size_t i = 0; i < size; i++) {
data[i] = other.data[i];
}
}
// Assignment operator
RAIIExample& operator=(const RAIIExample& other) {
if (this != &other) {
delete[] data; // Clean up existing resource
size = other.size;
data = new int[size];
for (size_t i = 0; i < size; i++) {
data[i] = other.data[i];
}
}
return *this;
}
// Move constructor (C++11)
RAIIExample(RAIIExample&& other) noexcept
: data(other.data), size(other.size) {
other.data = nullptr;
other.size = 0;
}
// Move assignment operator (C++11)
RAIIExample& operator=(RAIIExample&& other) noexcept {
if (this != &other) {
delete[] data;
data = other.data;
size = other.size;
other.data = nullptr;
other.size = 0;
}
return *this;
}
};⚠️ Memory Management Best Practices
- • Prefer smart pointers over raw pointers for dynamic allocation
- • Follow RAII principle - resources managed by constructors/destructors
- • Every new must have a delete (if not using smart pointers)
- • Use containers like vector instead of raw arrays when possible
- • Set pointers to nullptr after deletion to avoid dangling pointers