C Tutorial — Learn C Programming
Key takeaway: This free C tutorial teaches you systems programming from scratch — variables, pointers, arrays, functions, structs, and memory management — with practical code examples you can compile and run.
C is a general-purpose, procedural programming language created in 1972. It is used for operating systems, embedded systems, game engines, and performance-critical applications. This tutorial is for beginners, CS students, and developers who want to understand how computers work at a low level.
Last updated: September 2026
Dynamic Memory Allocation in C
Dynamic memory allocation allows you to allocate memory during runtime. This is essential for creating flexible programs that can handle varying amounts of data.
malloc() - Memory Allocation
#include <stdio.h>
#include <stdlib.h>
int main() {
int n;
printf("Enter number of elements: ");
scanf("%d", &n);
// Allocate memory for n integers
int *arr = (int*)malloc(n * sizeof(int));
if (arr == NULL) {
printf("Memory allocation failed!\n");
return 1;
}
// Input elements
printf("Enter %d elements: ", n);
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
// Display elements
printf("You entered: ");
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
// Free allocated memory
free(arr);
return 0;
}calloc() - Initialized Allocation
#include <stdio.h>
#include <stdlib.h>
int main() {
int n = 5;
// Using malloc (uninitialized)
int *arr1 = (int*)malloc(n * sizeof(int));
printf("malloc array (uninitialized): ");
for (int i = 0; i < n; i++) {
printf("%d ", arr1[i]); // Garbage values
}
printf("\n");
// Using calloc (initialized to zero)
int *arr2 = (int*)calloc(n, sizeof(int));
printf("calloc array (zero-initialized): ");
for (int i = 0; i < n; i++) {
printf("%d ", arr2[i]); // All zeros
}
printf("\n");
// Initialize malloc array manually
for (int i = 0; i < n; i++) {
arr1[i] = i + 1;
}
printf("Initialized malloc array: ");
for (int i = 0; i < n; i++) {
printf("%d ", arr1[i]);
}
printf("\n");
free(arr1);
free(arr2);
return 0;
}realloc() - Resize Memory
#include <stdio.h>
#include <stdlib.h>
int main() {
int *arr;
int size = 3;
int newSize = 6;
// Initial allocation
arr = (int*)malloc(size * sizeof(int));
// Initialize with values
for (int i = 0; i < size; i++) {
arr[i] = i + 1;
}
printf("Original array: ");
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
// Resize array
arr = (int*)realloc(arr, newSize * sizeof(int));
if (arr == NULL) {
printf("Reallocation failed!\n");
return 1;
}
// Initialize new elements
for (int i = size; i < newSize; i++) {
arr[i] = i + 1;
}
printf("Resized array: ");
for (int i = 0; i < newSize; i++) {
printf("%d ", arr[i]);
}
printf("\n");
free(arr);
return 0;
}Dynamic 2D Array
#include <stdio.h>
#include <stdlib.h>
int main() {
int rows = 3, cols = 4;
// Allocate memory for array of pointers
int **matrix = (int**)malloc(rows * sizeof(int*));
// Allocate memory for each row
for (int i = 0; i < rows; i++) {
matrix[i] = (int*)malloc(cols * sizeof(int));
}
// Initialize matrix
int value = 1;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
matrix[i][j] = value++;
}
}
// Display matrix
printf("Dynamic 2D Array:\n");
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
printf("%3d ", matrix[i][j]);
}
printf("\n");
}
// Free memory
for (int i = 0; i < rows; i++) {
free(matrix[i]);
}
free(matrix);
return 0;
}Memory Management Rules:
- Always check if allocation was successful (pointer != NULL)
- Always free dynamically allocated memory with free()
- Don't use freed memory (dangling pointers)
- Don't free the same memory twice
- Set pointers to NULL after freeing