A pointer is a variable that stores the memory address of another variable. Think of it like a house address that tells you where to find something.
int x = 42; // regular variable storing value 42 int *ptr = &x; // pointer storing address of x // Two key operators: // & (address-of): gets the address of a variable // * (dereference): accesses the value at an address
int a = 10, b = 20; int *p1 = &a; int *p2 = &b; // Trace these operations: *p1 = 30; // a becomes 30 p1 = p2; // p1 now points to b *p1 = 40; // b becomes 40 a = *p2; // a becomes 40
| Operation | a | b | p1 points to | p2 points to |
|---|---|---|---|---|
| Initial | 10 | 20 | a | b |
| *p1 = 30 | 30 | 20 | a | b |
| p1 = p2 | 30 | 20 | b | b |
| *p1 = 40 | 30 | 40 | b | b |
| a = *p2 | 40 | 40 | b | b |
char str[] = "Hello"; // array of characters char *ptr = "World"; // pointer to string literal // Key differences: // str[] is modifiable, stored in stack // *ptr points to read-only memory str[0] = 'J'; // OK: now "Jello" // ptr[0] = 'B'; // ERROR: can't modify literal // String traversal with pointers: char *p = str; while (*p != '\0') { printf("%c ", *p); p++; // move to next character }
int matrix[3][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} }; int (*ptr)[4] = matrix; // pointer to array of 4 ints // Accessing elements: // matrix[i][j] == *(*(matrix + i) + j) // ptr[i][j] == *(*(ptr + i) + j) printf("%d\n", ptr[1][2]); // prints 7 printf("%d\n", *(*(ptr+1)+2)); // also prints 7
// Pointers can be cast to/from integers, but it's dangerous! int x = 100; int *ptr = &x; unsigned int addr = (unsigned int)ptr; // store address as number // Key differences: // 1. Pointers have type information // 2. Pointer arithmetic uses sizeof(type) // 3. Pointers can be dereferenced // 4. Size varies (32-bit vs 64-bit systems) int arr[] = {10, 20, 30}; int *p = arr; p++; // moves by sizeof(int) bytes, not 1 // now p points to arr[1]
// String literals are READ-ONLY! char *str1 = "Hello"; // points to read-only memory char str2[] = "Hello"; // creates modifiable copy // str1[0] = 'J'; // CRASH! Segmentation fault str2[0] = 'J'; // OK! str2 is now "Jello" // Limitations: // 1. Can't modify string literals // 2. Multiple identical literals may share memory // 3. Size is fixed at compile time
// Method 1: 2D char array (fixed size for each string) char names1[5][20] = { "Alice", "Bob", "Charlie", "David", "Eve" }; // Method 2: Array of char pointers (variable sizes) char *names2[5] = { "Alice", "Bob", "Charlie", "David", "Eve" }; // Accessing strings: printf("%s\n", names1[2]); // prints "Charlie" printf("%c\n", names2[1][0]); // prints 'B' // Modifying: strcpy(names1[0], "Alan"); // OK for 2D array names2[0] = "Alan"; // OK: change pointer // names2[0][0] = 'X'; // ERROR: literal is read-only
// Preprocessor macros (compile-time substitution) #define MAX_SIZE 100 #define PI 3.14159 #define SQUARE(x) ((x) * (x)) // macro with parameter // const keyword (runtime constant) const int max_items = 50; const double pi = 3.14159; // Key differences: // #define: no type checking, just text replacement // const: type-safe, occupies memory, can't be modified int array[MAX_SIZE]; // OK with #define // int array2[max_items]; // ERROR in C (OK in C++)
// typedef: create alias for existing type typedef unsigned long ulong; typedef int bool; typedef char String[100]; // array type ulong bigNumber = 1000000; String name; // same as char name[100] // enum: create named integer constants enum Days { MONDAY, // 0 TUESDAY, // 1 WEDNESDAY, // 2 THURSDAY, // 3 FRIDAY = 10, // 10 (custom value) SATURDAY, // 11 SUNDAY // 12 }; enum Days today = MONDAY; // typedef with enum for cleaner syntax typedef enum { FALSE, TRUE } Boolean; Boolean isReady = FALSE;
// Define a structure type struct Person { char name[50]; int age; float height; char email[100]; }; // Create structure variables struct Person person1; struct Person person2 = {"Alice", 25, 5.6, "alice@email.com"}; // Access members with dot operator person1.age = 30; strcpy(person1.name, "Bob"); // typedef for cleaner syntax typedef struct { double x; double y; } Point; Point p1 = {3.5, 7.2}; // Structures with pointers struct Person *ptr = &person1; ptr->age = 31; // arrow operator for pointer access (*ptr).age = 31; // equivalent using dereference // Nested structures typedef struct { Point center; double radius; } Circle; Circle c = {{0.0, 0.0}, 5.0};
This demonstrates all concepts: flow control, arrays, pointers, structs, and I/O
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_CONTACTS 100 #define NAME_LENGTH 50 #define PHONE_LENGTH 20 // Structure definition typedef struct { char name[NAME_LENGTH]; char phone[PHONE_LENGTH]; int id; } Contact; // Global array and counter Contact contacts[MAX_CONTACTS]; int contactCount = 0; // Function prototypes void displayMenu(); void insertContact(); void searchContact(); void deleteContact(); void displayAll(); int main() { int choice; while (1) { displayMenu(); printf("Enter choice: "); scanf("%d", &choice); getchar(); // consume newline switch (choice) { case 1: insertContact(); break; case 2: searchContact(); break; case 3: deleteContact(); break; case 4: displayAll(); break; case 5: printf("Exiting...\n"); return 0; default: printf("Invalid choice!\n"); } } } void displayMenu() { printf("\n=== Contact Manager ===\n"); printf("1. Insert Contact\n"); printf("2. Search Contact\n"); printf("3. Delete Contact\n"); printf("4. Display All\n"); printf("5. Exit\n"); } void insertContact() { if (contactCount >= MAX_CONTACTS) { printf("Contact list full!\n"); return; } Contact *newContact = &contacts[contactCount]; printf("Enter name: "); fgets(newContact->name, NAME_LENGTH, stdin); newContact->name[strcspn(newContact->name, "\n")] = '\0'; printf("Enter phone: "); fgets(newContact->phone, PHONE_LENGTH, stdin); newContact->phone[strcspn(newContact->phone, "\n")] = '\0'; newContact->id = contactCount + 1; contactCount++; printf("Contact added successfully! ID: %d\n", newContact->id); } void searchContact() { char searchName[NAME_LENGTH]; printf("Enter name to search: "); fgets(searchName, NAME_LENGTH, stdin); searchName[strcspn(searchName, "\n")] = '\0'; int found = 0; for (int i = 0; i < contactCount; i++) { if (strstr(contacts[i].name, searchName) != NULL) { printf("Found: ID=%d, Name=%s, Phone=%s\n", contacts[i].id, contacts[i].name, contacts[i].phone); found = 1; } } if (!found) { printf("No contacts found.\n"); } } void deleteContact() { int id; printf("Enter ID to delete: "); scanf("%d", &id); getchar(); int index = -1; for (int i = 0; i < contactCount; i++) { if (contacts[i].id == id) { index = i; break; } } if (index == -1) { printf("Contact not found.\n"); return; } // Shift elements left to fill gap for (int i = index; i < contactCount - 1; i++) { contacts[i] = contacts[i + 1]; } contactCount--; printf("Contact deleted successfully.\n"); } void displayAll() { if (contactCount == 0) { printf("No contacts to display.\n"); return; } printf("\n=== All Contacts ===\n"); for (int i = 0; i < contactCount; i++) { printf("ID: %d | Name: %s | Phone: %s\n", contacts[i].id, contacts[i].name, contacts[i].phone); } }
What will be the output of this code?
int x = 5, y = 10; int *p = &x; int *q = &y; *p = *q; q = p; *q = 15; printf("%d %d", x, y);
Which of these will cause a runtime error?
A) char str[] = "Hello"; str[0] = 'J'; B) char *str = "Hello"; str = "World"; C) char *str = "Hello"; str[0] = 'J'; D) char str[10] = "Hello"; strcpy(str, "World");
Fill in the blank to correctly access the x coordinate:
typedef struct { float x, y; } Point; typedef struct { Point center; float radius; } Circle; Circle c = {{3.0, 4.0}, 5.0}; Circle *ptr = &c; // Access center's x coordinate through ptr: float xCoord = _________;
What's the key difference between these declarations?
char names1[3][10]; char *names2[3];
Given an int array, what does ptr+3 mean?
int arr[] = {10, 20, 30, 40, 50}; int *ptr = arr;