C Programming
Pointer Arithmetic; Dynamic Memory Allocation; Structures in C
C-CAT
Pointer Arithmetic
Valid Pointer Operations
int arr[] = {10, 20, 30, 40, 50};
int *p = arr; // p points to arr[0]
// Pointer + integer: moves pointer n elements forward
p++; // p now points to
arr[1]
printf("%d\n", *p); // 20
p += 2; // p now points to arr[3]
printf("%d\n", *p); // 40
// Pointer - pointer: gives number of elements between
int *p1 = &arr[0];
int *p2 =
&arr[4];
ptrdiff_t diff = p2 - p1;
printf("Distance: %td\n", diff); // 4
// Pointer comparison
int *pa = arr;
int *pb = arr + 3;
if (pb > pa) printf("pb is ahead of pa\n");
Pointer with sizeof
int x = 10;
int *p = &x;
printf("sizeof(int) = %zu\n", sizeof(int)); // 4
printf("sizeof(p) = %zu\n", sizeof(p)); // 8 (64-bit pointer)
printf("sizeof(*p) = %zu\n", sizeof(*p)); // 4 (sizeof int)
Dynamic Memory Allocation
Why Dynamic Memory?
- Array size must be known at compile time (static allocation)
- Dynamic allocation allows size to be determined at runtime
- Memory allocated from the heap (large pool)
malloc — Memory Allocation
#include <stdlib.h>
// malloc(size_in_bytes) → returns void*; uninitialized memory
int *arr = (int *) malloc(5 *
sizeof(int));
if (arr == NULL) {
printf("Memory allocation failed!\n");
exit(1);
}
// Use the array
for (int i = 0; i < 5; i++) {
arr[i] = i * 10;
}
for (int i = 0; i < 5;
i++) {
printf("%d ", arr[i]); // 0 10 20 30 40
}
// ALWAYS free when done!
free(arr);
arr = NULL; // good practice: set to NULL after free
calloc — Contiguous Allocation
// calloc(count, size_each) → returns void*; ZERO-initialized memory
int *arr = (int *) calloc(5, sizeof(int));
// All elements are initialized to 0
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]); // 0 0 0 0 0
}
free(arr);
realloc — Resize Allocation
int *arr = (int *) malloc(5 * sizeof(int));
// ... use arr with 5 elements ...
// Need more space: resize to 10 elements
arr = (int *) realloc(arr, 10 * sizeof(int));
if (arr == NULL) {
printf("Realloc failed!\n");
exit(1);
}
// arr can now hold 10 elements
free(arr);
Dynamic 2D Array
// Allocate n x m 2D array dynamically
int rows = 3, cols = 4;
int **matrix = (int**) malloc(rows * sizeof(int*));
for (int i = 0; i < rows; i++) {
matrix[i] = (int*) malloc(cols * sizeof(int));
}
// Use it like a normal 2D array
matrix[0][0] = 1;
matrix[1][2] = 42;
// Free: first free each row, then the array of pointers
for (int i = 0; i < rows; i++) {
free(matrix[i]);
}
free(matrix);
Memory Leaks
A memory leak occurs when dynamically allocated memory is never freed.
void bad_function() {
int *p = malloc(100);
// ... forgot to free(p) ...
return; // memory is LEAKED! 100 bytes lost
}
void good_function() {
int *p = malloc(100);
// ... use p ...
free(p); // Always free before returning
}
Structures in C
What is a Structure?
A structure groups different data types into a single unit.
#include <stdio.h>
#include <string.h>
// Define structure
struct student {
int rollno;
char name[50];
float gpa;
char grade;
};
// typedef makes usage cleaner
typedef struct student student_t;
// OR defined together:
typedef struct {
int rollno;
char name[50];
float gpa;
char grade;
} student_t;
int main() {
// Declare and initialize
student_t s1 = {101, "Alice", 3.8, 'A'};
// Access members using dot operator
printf("Roll: %d\n", s1.rollno);
printf("Name: %s\n", s1.name);
printf("GPA: %.1f\n", s1.gpa);
// Modify
s1.gpa = 3.9;
strcpy(s1.name, "Alice Johnson");
// Another way to initialize
student_t s2;
s2.rollno = 102;
strcpy(s2.name, "Bob");
s2.gpa = 3.5;
s2.grade = 'B';
return 0;
}
Array of Structures
#define MAX 100
student_t students[MAX];
int count = 0;
void add_student(int rollno, const char *name, float gpa) {
students[count].rollno =
rollno;
strcpy(students[count].name, name);
students[count].gpa = gpa;
count++;
}
void print_all() {
for (int i = 0; i < count; i++) {
printf("Roll: %d, Name: %s, GPA: %.1f\n",
students[i].rollno, students[i].name, students[i].gpa);
}
}
Pointer to Structure
student_t s = {101, "Alice", 3.8, 'A'};
student_t *ptr = &s;
// Two ways to access members via pointer:
printf("%s\n", (*ptr).name); // Using * and .
printf("%s\n", ptr->name); // Using arrow operator -> (more common)
ptr->gpa = 4.0; // modify via pointer
Structures as Function Arguments
// Pass by value (copy): changes don't affect original
void print_student(student_t s) {
printf("Name: %s, GPA: %.1f\n", s.name, s.gpa);
}
// Pass by pointer (reference): changes affect original
void update_gpa(student_t *s, float
new_gpa) {
s->gpa = new_gpa;
}
// Return structure from function
student_t create_student(int roll, const char *name, float gpa) {
student_t s;
s.rollno = roll;
strcpy(s.name, name);
s.gpa = gpa;
return s;
}
Nested Structures
typedef struct {
int day, month, year;
} date_t;
typedef struct {
int id;
char name[50];
date_t dob; // nested structure
float salary;
} employee_t;
employee_t emp = {1001, "John", {15, 3, 1990}, 55000.0};
printf("DOB: %d/%d/%d\n", emp.dob.day, emp.dob.month, emp.dob.year);
// 15/3/1990
Continue learning
Related notes
Definition of AI; Need of AI
Artificial Intelligence
Introduction to Data Engineering; Big Data — The 5 V's; Types of Data
Big Data and Data Engineering
Introduction to C Programming; C Program Structure; Data Types and Variables
C Programming
What Is a Computer?; Machine Cycle: Fetch–Decode–Execute; CPU Organization
Computer Architecture
Put this topic into timed practice
Open mock tests when you want full-exam pacing, or keep drilling in practice mode.