C & C++ Beginner Guide
Choose your language to start learning. Switch between C and C++ anytime using the buttons below.
Part 1: C Language
What is C & Why It Matters
C is a compiled, procedural language and the foundation of modern programming. It gives low-level control over memory while staying portable across platforms. Operating systems, embedded systems, and databases are written in C.
#include <stdio.h>
int main() {
printf("Hello from C!");
return 0;
}
Setting Up: Compiler, IDE & Hello World
To write C you need a compiler like GCC. You write a .c source file, then compile it to an executable. The smallest runnable program is a main() function with a return statement. This 'Hello World' is the classic first step.
#include <stdio.h>
int main() {
printf("Hello, World!\n");
return 0;
}
Variables & Data Types
C is statically typed — every variable must declare its type. The basic types are int (whole numbers), float (single-precision decimal), double (double-precision decimal), and char (single character). Variables store values in memory.
#include <stdio.h>
int main() {
int age = 25;
float price = 19.99;
char grade = 'A';
double big = 123456.789;
printf("Age: %d\n", age);
printf("Price: %.2f\n", price);
printf("Grade: %c\n", grade);
printf("Big: %.3f\n", big);
return 0;
}
Constants (#define & const)
Constants are values that cannot change. #define creates a preprocessor macro that replaces text before compilation. The const keyword creates a typed, read-only variable. Both prevent accidental modification.
#include <stdio.h>
#define PI 3.14159
int main() {
const int MAX_SCORE = 100;
printf("PI: %.5f\n", PI);
printf("Max score: %d\n", MAX_SCORE);
return 0;
}
Operators & Expressions
C operators perform calculations and comparisons. Arithmetic operators (+, -, *, /, %) do math. Relational operators (==, !=, >, <) compare and return true or false. Logical operators (&&, ||, !) combine conditions.
#include <stdio.h>
int main() {
int a = 10, b = 3;
printf("%d\n", a + b);
printf("%d\n", a / b);
printf("%d\n", a %% b);
printf("%d\n", a > b);
printf("%d\n", a == 10 && b == 3);
return 0;
}
Input & Output (printf/scanf)
printf displays output, and scanf reads input. scanf uses format specifiers and the address-of operator (&) to store input into variables. Together they make interactive programs.
#include <stdio.h>
int main() {
int age;
char name[50];
printf("Enter your name: ");
scanf("%s", name);
printf("Enter your age: ");
scanf("%d", &age);
printf("Hello %s, you are %d years old.\n", name, age);
return 0;
}
Conditionals (if/else/switch)
if and else make decisions based on conditions. switch compares one value against multiple cases. Both control which code block executes. Braces group multiple statements in a block.
#include <stdio.h>
int main() {
int score = 85;
if (score >= 90) {
printf("A\n");
} else if (score >= 70) {
printf("B\n");
} else {
printf("C\n");
}
return 0;
}
Loops (for/while/do-while)
Loops repeat code. for is used when the iteration count is known. while repeats while a condition holds. do-while always runs at least once because the condition is checked after the body.
#include <stdio.h>
int main() {
for (int i = 1; i <= 5; i++) {
printf("%d\n", i);
}
return 0;
}
Arrays
An array stores multiple values of the same type in contiguous memory. Arrays have a fixed size declared at creation, and elements are accessed by zero-based index. The size is the count of elements.
#include <stdio.h>
int main() {
int nums[5] = {10, 20, 30, 40, 50};
printf("First: %d\n", nums[0]);
printf("Last: %d\n", nums[4]);
int sum = 0;
for (int i = 0; i < 5; i++) {
sum += nums[i];
}
printf("Sum: %d\n", sum);
return 0;
}
Strings (char arrays)
C has no built-in string type — strings are char arrays ending with a null terminator (\0). The string.h library provides functions like strlen, strcpy, and strcmp to work with strings.
#include <stdio.h>
#include <string.h>
int main() {
char name[20] = "Ali";
printf("Name: %s\n", name);
printf("Length: %lu\n", strlen(name));
strcat(name, " Khan");
printf("Full: %s\n", name);
return 0;
}
Pointers Basics
A pointer stores a memory address. The & operator gets an address, and * dereferences a pointer to access the value at that address. Pointers give C its low-level power and enable pass-by-reference.
#include <stdio.h>
int main() {
int num = 42;
int *ptr = #
printf("Value: %d\n", num);
printf("Address: %p\n", (void*)ptr);
printf("Dereferenced: %d\n", *ptr);
*ptr = 99;
printf("After change: %d\n", num);
return 0;
}
Functions
Functions are reusable blocks of code. A function has a return type, a name, and optional parameters. void means it returns nothing. Functions break programs into manageable pieces.
#include <stdio.h>
void greet(char name[]) {
printf("Hello, %s\n", name);
}
int main() {
greet("Ali");
greet("Sara");
return 0;
}
Function Parameters & Return
Parameters pass data into a function. The return statement sends a value back to the caller. The return type must match the returned value's type. void means no return value.
#include <stdio.h>
int add(int a, int b) {
return a + b;
}
int main() {
int result = add(5, 3);
printf("Result: %d\n", result);
return 0;
}
Scope & Lifetime
Scope determines where a variable is visible. Variables declared inside a function are local to it. Global variables are visible everywhere. Static local variables keep their value between calls.
#include <stdio.h>
int global = 10;
void demo() {
int local = 20;
static int persistent = 0;
persistent++;
printf("Global: %d, Local: %d, Persistent: %d\n", global, local, persistent);
}
int main() {
demo();
demo();
return 0;
}
Structs
A struct groups related variables of different types into one unit. struct defines the blueprint, and you access members using the dot operator. Structs are the foundation of data modeling in C.
#include <stdio.h>
struct Student {
char name[50];
int age;
float grade;
};
int main() {
struct Student s1 = {"Ali", 25, 85.5};
printf("Name: %s\n", s1.name);
printf("Age: %d\n", s1.age);
printf("Grade: %.1f\n", s1.grade);
return 0;
}
Typedef
typedef creates an alias for an existing type. It makes code more readable and portable. A common use is creating short names for struct types.
#include <stdio.h>
typedef struct {
int x;
int y;
} Point;
int main() {
Point p = {3, 4};
printf("Point: (%d, %d)\n", p.x, p.y);
return 0;
}
Enums
An enum defines a set of named integer constants. By default the first is 0, and each subsequent increments by 1. Enums make code more readable than raw numbers.
#include <stdio.h>
enum Day {
MONDAY, TUESDAY, WEDNESDAY
};
int main() {
enum Day today = WEDNESDAY;
printf("Day value: %d\n", today);
return 0;
}
Preprocessor Directives
The preprocessor runs before compilation. #include imports files, #define creates macros, and #ifdef conditionally compiles code. Preprocessor directives begin with # and do not end with semicolons.
#include <stdio.h>
#define MAX 10
int main() {
#ifdef MAX
printf("MAX is defined: %d\n", MAX);
#else
printf("MAX is not defined\n");
#endif
return 0;
}
Dynamic Memory (malloc/free)
malloc allocates memory at runtime from the heap, returning a pointer. free releases that memory. Dynamic memory lets you work with data sizes known only at runtime. Always pair malloc with free to avoid leaks.
#include <stdio.h>
#include <stdlib.h>
int main() {
int n = 3;
int *arr = (int*)malloc(n * sizeof(int));
arr[0] = 10;
arr[1] = 20;
arr[2] = 30;
for (int i = 0; i < n; i++) {
printf("%d\n", arr[i]);
}
free(arr);
return 0;
}
C Beginner Recap + Mini Projects
You now know variables, constants, operators, input/output, conditionals, loops, arrays, strings, pointers, functions, scope, structs, typedef, enums, the preprocessor, and dynamic memory. Apply them in three mini projects: (1) Even/Odd Checker, (2) Simple Calculator, (3) Factorial Calculator.
#include <stdio.h>
int main() {
int n;
printf("Enter a number: ");
scanf("%d", &n);
if (n % 2 == 0) {
printf("%d is even\n", n);
} else {
printf("%d is odd\n", n);
}
return 0;
}
C Beginner Projects
About this project
Build a simple calculator that takes two numbers and an operator, then prints the result using switch.
What you'll practice
#include <stdio.h>
int main() {
double a, b;
char op;
printf("Enter first number: ");
scanf("%lf", &a);
printf("Enter second number: ");
scanf("%lf", &b);
printf("Enter operator (+, -, *, /): ");
scanf(" %c", &op);
switch (op) {
case '+': printf("%.2f + %.2f = %.2f\n", a, b, a + b); break;
case '-': printf("%.2f - %.2f = %.2f\n", a, b, a - b); break;
case '*': printf("%.2f * %.2f = %.2f\n", a, b, a * b); break;
case '/':
if (b != 0) printf("%.2f / %.2f = %.2f\n", a, b, a / b);
else printf("Error: Cannot divide by zero.\n");
break;
default: printf("Invalid operator.\n");
}
return 0;
}
About this project
Compute factorial and the first N Fibonacci numbers using loops and functions.
What you'll practice
#include <stdio.h>
int factorial(int n) {
int result = 1;
for (int i = 1; i <= n; i++) result *= i;
return result;
}
void fibonacci(int n) {
int a = 0, b = 1, next;
for (int i = 0; i < n; i++) {
printf("%d ", a);
next = a + b;
a = b;
b = next;
}
printf("\n");
}
int main() {
printf("Factorial of 5: %d\n", factorial(5));
printf("First 7 Fibonacci numbers: ");
fibonacci(7);
return 0;
}
About this project
Find the minimum, maximum, and average of an array of numbers.
What you'll practice
#include <stdio.h>
int main() {
int nums[] = {12, 5, 18, 3, 9};
int size = 5;
int min = nums[0], max = nums[0], sum = 0;
for (int i = 0; i < size; i++) {
sum += nums[i];
if (nums[i] < min) min = nums[i];
if (nums[i] > max) max = nums[i];
}
double avg = (double)sum / size;
printf("Min: %d\nMax: %d\nAverage: %.2f\n", min, max, avg);
return 0;
}
C Capstone Project
About this project
Store and display multiple student records using structs and arrays.
What you'll practice
#include <stdio.h>
struct Student {
char name[50];
int age;
float grade;
};
int main() {
struct Student students[3];
for (int i = 0; i < 3; i++) {
printf("Student %d name: ", i + 1);
scanf("%s", students[i].name);
printf("Age: ");
scanf("%d", &students[i].age);
printf("Grade: ");
scanf("%f", &students[i].grade);
}
printf("\n--- Records ---\n");
for (int i = 0; i < 3; i++) {
printf("%s | Age: %d | Grade: %.1f\n",
students[i].name, students[i].age, students[i].grade);
}
return 0;
}
Part 2: C++ Language
What is C++ & Why It Matters
C++ extends C with classes, objects, and modern features while keeping low-level control. It supports multiple programming styles: procedural, object-oriented, and generic. Games, browsers, and performance-critical software use C++.
#include <iostream>
int main() {
std::cout << "Hello from C++!";
return 0;
}
Namespace & std::
A namespace groups related names and avoids collisions. The standard library lives in the std namespace. You can write std::cout each time, or add 'using namespace std;' to bring all standard names into scope.
#include <iostream>
int main() {
using namespace std;
cout << "No std:: prefix needed" << endl;
return 0;
}
Input & Output (cin/cout)
C++ uses cin for input and cout for output. The extraction operator >> reads data from cin, and the insertion operator << writes to cout. Together they handle console interaction cleanly.
#include <iostream>
#include <string>
int main() {
std::string name;
int age;
std::cout << "Enter your name: ";
std::cin >> name;
std::cout << "Enter your age: ";
std::cin >> age;
std::cout << "Hello " << name << ", you are " << age << " years old." << std::endl;
return 0;
}
The string Class
C++ has a built-in std::string class that manages text automatically. Unlike C char arrays, strings grow and shrink dynamically and support methods like length(), append(), and comparison with ==.
#include <iostream>
#include <string>
int main() {
std::string greeting = "Hello";
greeting += " World";
std::cout << "Text: " << greeting << std::endl;
std::cout << "Length: " << greeting.length() << std::endl;
std::cout << "Substring: " << greeting.substr(0, 5) << std::endl;
return 0;
}
References
A reference is an alias for an existing variable. It is declared with & and must be initialized. References provide pass-by-reference to functions, letting them modify the original variable without pointers.
#include <iostream>
void addFive(int &num) {
num += 5;
}
int main() {
int value = 10;
addFive(value);
std::cout << "Value: " << value << std::endl;
return 0;
}
Vectors (Dynamic Arrays)
std::vector is a resizable array that manages its own memory. Unlike C arrays, vectors can grow with push_back and know their size with size(). They are the default choice for dynamic lists.
#include <iostream>
#include <vector>
int main() {
std::vector<int> nums = {1, 2, 3};
nums.push_back(4);
std::cout << "Size: " << nums.size() << std::endl;
std::cout << "First: " << nums[0] << std::endl;
std::cout << "Last: " << nums[nums.size() - 1] << std::endl;
return 0;
}
Range-Based for Loop
The range-based for loop iterates over containers without an index. It is cleaner and safer than traditional for loops when you need to visit every element of an array, vector, or string.
#include <iostream>
#include <vector>
int main() {
std::vector<int> nums = {10, 20, 30};
for (int n : nums) {
std::cout << n << std::endl;
}
return 0;
}
Functions & Overloading
C++ functions are reusable blocks of code. Function overloading lets you define multiple functions with the same name but different parameters. The compiler picks the right one based on arguments.
#include <iostream>
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
int main() {
std::cout << add(5, 3) << std::endl;
std::cout << add(5.5, 3.2) << std::endl;
return 0;
}
Default Arguments
Default arguments provide fallback values when a parameter is omitted. They are written in the function declaration with =. Default values make functions flexible without requiring overloads.
#include <iostream>
int power(int base, int exponent = 2) {
int result = 1;
for (int i = 0; i < exponent; i++) {
result *= base;
}
return result;
}
int main() {
std::cout << power(5) << std::endl;
std::cout << power(5, 3) << std::endl;
return 0;
}
Classes & Objects
A class bundles data (attributes) and behavior (methods) into one type. An object is an instance of a class. Classes are the core of object-oriented programming in C++.
#include <iostream>
#include <string>
class Car {
public:
std::string brand;
int year;
void info() {
std::cout << brand << " " << year << std::endl;
}
};
int main() {
Car myCar;
myCar.brand = "Toyota";
myCar.year = 2020;
myCar.info();
return 0;
}
Constructors
A constructor initializes an object when it is created. It has the same name as the class and no return type. Constructors can accept parameters to set initial attribute values.
#include <iostream>
#include <string>
class Person {
public:
std::string name;
int age;
Person(std::string n, int a) {
name = n;
age = a;
}
};
int main() {
Person p("Ali", 25);
std::cout << p.name << " " << p.age << std::endl;
return 0;
}
Access Specifiers (public/private)
Access specifiers control visibility. public members are accessible from anywhere. private members are only accessible inside the class. This is encapsulation — hiding internal data behind a controlled interface.
#include <iostream>
class BankAccount {
private:
double balance = 0;
public:
void deposit(double amount) {
balance += amount;
}
double getBalance() {
return balance;
}
};
int main() {
BankAccount acc;
acc.deposit(100);
std::cout << acc.getBalance() << std::endl;
return 0;
}
Getters & Setters
Getters read private attributes, and setters modify them with validation. This gives controlled access to data, ensuring invalid values are rejected before they corrupt state.
#include <iostream>
#include <string>
class Student {
private:
std::string name;
public:
std::string getName() {
return name;
}
void setName(std::string n) {
if (!n.empty()) {
name = n;
}
}
};
int main() {
Student s;
s.setName("Ali");
std::cout << s.getName() << std::endl;
return 0;
}
Inheritance
Inheritance lets a class acquire members from another class. The derived class extends the base class, reusing code and adding its own behavior. This models 'is-a' relationships.
#include <iostream>
#include <string>
class Animal {
public:
std::string name;
void eat() {
std::cout << name << " is eating" << std::endl;
}
};
class Dog : public Animal {
public:
void bark() {
std::cout << name << " barks" << std::endl;
}
};
int main() {
Dog d;
d.name = "Rex";
d.eat();
d.bark();
return 0;
}
Function Overriding
Overriding lets a derived class redefine a base class method. The base method must be virtual, and the derived method has the same signature but different behavior. The override keyword catches mistakes.
#include <iostream>
class Animal {
public:
virtual void sound() {
std::cout << "Some sound" << std::endl;
}
};
class Dog : public Animal {
public:
void sound() override {
std::cout << "Woof!" << std::endl;
}
};
int main() {
Animal* a = new Dog();
a->sound();
return 0;
}
Polymorphism
Polymorphism lets one interface work with different types. A base-class reference or pointer can point to any derived object, and virtual method calls dispatch to the correct implementation at runtime.
#include <iostream>
class Shape {
public:
virtual void draw() {
std::cout << "Drawing shape" << std::endl;
}
};
class Circle : public Shape {
public:
void draw() override {
std::cout << "Drawing circle" << std::endl;
}
};
class Square : public Shape {
public:
void draw() override {
std::cout << "Drawing square" << std::endl;
}
};
int main() {
Shape* s1 = new Circle();
Shape* s2 = new Square();
s1->draw();
s2->draw();
return 0;
}
Destructors
A destructor runs when an object is destroyed. It has the class name prefixed with ~ and no parameters. Destructors free resources like dynamic memory, closing the object's lifecycle.
#include <iostream>
class Resource {
public:
Resource() {
std::cout << "Resource acquired" << std::endl;
}
~Resource() {
std::cout << "Resource released" << std::endl;
}
};
int main() {
{
Resource r;
}
std::cout << "End of main" << std::endl;
return 0;
}
Exception Handling (try/catch)
C++ handles errors with try/catch. Code in try is monitored, and throw raises an exception. catch handles specific types. This separates normal flow from error handling and prevents crashes.
#include <iostream>
#include <stdexcept>
int main() {
try {
throw std::runtime_error("Something went wrong");
} catch (const std::exception& e) {
std::cout << "Caught: " << e.what() << std::endl;
}
std::cout << "Program continues" << std::endl;
return 0;
}
C++ Beginner Recap + Mini Projects
You now know namespaces, input/output, the string class, references, vectors, range-for, overloading, default arguments, classes, constructors, access specifiers, getters/setters, inheritance, overriding, polymorphism, destructors, and exceptions. Apply them in three mini projects: (1) Simple Calculator, (2) Average Finder with vector, (3) Class-based Bank Account.
#include <iostream>
#include <vector>
int main() {
std::vector<int> scores;
int n;
std::cout << "How many scores? ";
std::cin >> n;
int sum = 0;
for (int i = 0; i < n; i++) {
int score;
std::cout << "Score " << (i + 1) << ": ";
std::cin >> score;
scores.push_back(score);
sum += score;
}
double avg = (double)sum / n;
std::cout << "Average: " << avg << std::endl;
return 0;
}
C++ Beginner Projects
About this project
Build a menu-driven to-do list that can add, view, and remove tasks using std::vector.
What you'll practice
#include <iostream>
#include <vector>
#include <string>
int main() {
std::vector<std::string> tasks;
int choice;
do {
std::cout << "\n1. Add task\n2. View tasks\n3. Exit\nChoose: ";
std::cin >> choice;
std::cin.ignore();
switch (choice) {
case 1: {
std::string task;
std::cout << "Task: ";
std::getline(std::cin, task);
tasks.push_back(task);
break;
}
case 2:
for (size_t i = 0; i < tasks.size(); i++) {
std::cout << i + 1 << ". " << tasks[i] << std::endl;
}
break;
}
} while (choice != 3);
return 0;
}
About this project
Build a BankAccount class with deposit, withdraw, and getBalance using encapsulation.
What you'll practice
#include <iostream>
class BankAccount {
private:
double balance = 0;
public:
void deposit(double amount) {
if (amount > 0) balance += amount;
}
void withdraw(double amount) {
if (amount > 0 && amount <= balance) balance -= amount;
}
double getBalance() {
return balance;
}
};
int main() {
BankAccount acc;
acc.deposit(100);
acc.withdraw(40);
acc.withdraw(100); // rejected (insufficient)
std::cout << "Balance: " << acc.getBalance() << std::endl;
return 0;
}
About this project
Count how many times each word appears in a string using std::map.
What you'll practice
#include <iostream>
#include <map>
#include <sstream>
#include <string>
int main() {
std::string text = "the cat and the dog";
std::istringstream stream(text);
std::string word;
std::map<std::string, int> counts;
while (stream >> word) {
counts[word]++;
}
for (const auto& entry : counts) {
std::cout << entry.first << ": " << entry.second << std::endl;
}
return 0;
}
C++ Capstone Project
About this project
Build a library system using an abstract base class, inheritance, and polymorphism.
What you'll practice
#include <iostream>
#include <vector>
#include <string>
class Item {
public:
std::string title;
Item(std::string t) : title(t) {}
virtual void info() = 0;
};
class Book : public Item {
public:
std::string author;
Book(std::string t, std::string a) : Item(t), author(a) {}
void info() override {
std::cout << "Book: " << title << " by " << author << std::endl;
}
};
class Magazine : public Item {
public:
int issue;
Magazine(std::string t, int i) : Item(t), issue(i) {}
void info() override {
std::cout << "Magazine: " << title << " Issue " << issue << std::endl;
}
};
int main() {
std::vector<Item*> catalog;
catalog.push_back(new Book("Effective C++", "Scott Meyers"));
catalog.push_back(new Magazine("Tech Monthly", 42));
for (Item* item : catalog) {
item->info();
}
return 0;
}