Macros perform text substitution during pre-processing. They avoid function call overhead but are prone to side effects.
// Define a macro to find the maximum value. // Note the parentheses around the arguments and the whole expression to avoid operator precedence issues. #define MAX(x, y) ((x) > (y) ? (x) : (y)) // --- SIDE EFFECT EXAMPLE --- int a = 5; int z = MAX(a++, 10); // The preprocessor expands this to: int z = ((a++) > (10) ? (a++) : (10)); // If a++ > 10 is true, 'a' would be incremented twice! This is unexpected behavior.
Data is represented by state: a collection of variables and their values. Key concepts:
#include <stdio.h> int num; printf("Enter a number: "); // scanf needs the ADDRESS (&) of a variable to store the input. scanf("%d", &num); // %d is the format specifier for an integer. printf("You entered: %d\n", num);
#include <iostream> int num; std::cout << "Enter a number: "; std::cin >> num; std::cout << "You entered: " << num << std::endl;
A variable that stores the memory address of another variable.
& (Address-of Operator): Gets the memory address of a variable.* (Dereference Operator): Gets the value at the address a pointer is holding.int score = 100; int* scorePtr = &score; // Pointer holds the address of score. // To change score's value via the pointer, you must dereference it. *scorePtr = 150; printf("New score: %d\n", score); // Prints "New score: 150"
A composite data type that groups variables. Access members with the dot operator (.).
struct Player { char name[50]; int health; }; void main() { struct Player p1; strcpy(p1.name, "Zelda"); p1.health = 100; }
Compilers add invisible bytes within structs to align members to memory addresses that are multiples of the word size (e.g., 4 bytes). This improves CPU access speed.
A dynamic data structure where nodes are linked using pointers.
struct Node { int data; struct Node* next; // Self-referential pointer. }; // To traverse without losing the list, use a temporary pointer. void printList(struct Node* head) { struct Node* temp = head; while (temp != NULL) { printf("%d -> ", temp->data); temp = temp->next; // Advance the temporary pointer. } }
A function that calls itself. Every recursive solution must have:
int factorial(int n) { // Base Case: The simplest problem we can solve. if (n <= 1) { return 1; } // Recursive Step: Solve a smaller version of the same problem. else { return n * factorial(n - 1); } }
A node-based structure where for any node, all keys in the left subtree are smaller, and all keys in the right subtree are larger.
malloc/new). Flexible, large, but requires manual management (free/delete).free/delete heap memory.A class is a blueprint for objects.
~ClassName) called when an object is destroyed. Used for cleanup, especially freeing heap memory.class Character { public: // Constructor: allocates memory on the heap for the name. Character(const char* newName) { name = new char[strlen(newName) + 1]; strcpy(name, newName); } // Destructor: frees the heap memory to prevent a leak. ~Character() { delete[] name; } private: char* name; };