C Programs for Learning Basics, Data Structures, and
Pointers
DS2040, Satyajit Das
January 9, 2025
1 Introduction
This document contains 15 C programs designed to help you understand fundamental C
programming concepts, basic data structures, and pointers. Each program is accompanied
by:
• A short description
• The source code
• Instructions for compilation and execution
• Key concepts
2 Programs
2.1 1. Hello World
Purpose: The classic introductory program—verifies your environment is set up and
shows basic C syntax.
Listing 1: hello.c
1 #include <stdio.h>
2
3 int main(void) {
4 printf("Hello, World!\n");
5 return 0;
6 }
Instructions:
• Compile: gcc hello.c -o hello
• Run: ./hello
Key Concepts:
• Basic structure of a C program (#include, main(), return 0;)
• Printing output to the console.
1
2.2 2. Simple Input and Output
Purpose: Demonstrates reading integers from the user and printing results.
Listing 2: simple_io.c
1 #include <stdio.h>
2
3 int main(void) {
4 int number;
5 printf("Enter an integer: ");
6 scanf("%d", &number);
7 printf("You entered: %d\n", number);
8 return 0;
9 }
Instructions:
• Compile: gcc simple_io.c -o simple_io
• Run: ./simple_io
Key Concepts:
• Using scanf() and printf().
• Relationship between format specifiers (e.g., %d) and variable types.
2.3 3. If-Else and Loops
Purpose: Illustrates conditional logic and basic loops in C.
Listing 3: control_flow.c
1 #include <stdio.h>
2
3 int main(void) {
4 int i, sum = 0;
5
6 for (i = 1; i <= 5; i++) {
7 if (i % 2 == 0) {
8 printf("%d is even\n", i);
9 } else {
10 printf("%d is odd\n", i);
11 }
12 sum += i;
13 }
14
15 printf("Sum of numbers 1 to 5 is %d\n", sum);
16 return 0;
17 }
Instructions:
• Compile: gcc control_flow.c -o control_flow
• Run: ./control_flow
2
Key Concepts:
• for loop, if statement, % operator for checking even/odd.
• Accumulating a sum in a loop.
2.4 4. Arrays and Summation
Purpose: Shows how to handle arrays, sum their elements, and print results.
Listing 4: array_sum.c
1 #include <stdio.h>
2
3 #define SIZE 5
4
5 int main(void) {
6 int arr[SIZE] = {1, 2, 3, 4, 5};
7 int sum = 0;
8
9 for (int i = 0; i < SIZE; i++) {
10 sum += arr[i];
11 }
12
13 printf("Sum of array elements = %d\n", sum);
14 return 0;
15 }
Instructions:
• Compile: gcc array_sum.c -o array_sum
• Run: ./array_sum
Key Concepts:
• Declaring and initializing arrays.
• Iterating through arrays with a loop.
• Accumulating values.
2.5 5. Pointer Basics
Purpose: Demonstrates how to use pointers to print variable addresses and values.
Listing 5: pointer_basics.c
1 #include <stdio.h>
2
3 int main(void) {
4 int x = 10;
5 int *ptr = &x; // pointer to x
6
7 printf("Value of x: %d\n", x);
3
8 printf("Address of x: %p\n", (void*)&x);
9 printf("Value of ptr: %p\n", (void*)ptr);
10 printf("Value pointed by ptr: %d\n", *ptr);
11
12 return 0;
13 }
Instructions:
• Compile: gcc pointer_basics.c -o pointer_basics
• Run: ./pointer_basics
Key Concepts:
• Declaring pointers (int *ptr).
• Dereferencing (*ptr).
• Difference between address and value.
2.6 6. Pointer Arithmetic
Purpose: Explores how incrementing pointers relates to the size of their data type.
Listing 6: pointer_arithmetic.c
1 #include <stdio.h>
2
3 int main(void) {
4 int arr[3] = {10, 20, 30};
5 int *p = arr; // points to arr[0]
6
7 printf("p points to arr[0]: value = %d\n", *p);
8 p++; // Move to arr[1]
9 printf("p now points to arr[1]: value = %d\n", *p);
10 p++; // Move to arr[2]
11 printf("p now points to arr[2]: value = %d\n", *p);
12
13 return 0;
14 }
Instructions:
• Compile: gcc pointer_arithmetic.c -o pointer_arithmetic
• Run: ./pointer_arithmetic
Key Concepts:
• Relationship between pointer increments and array indexing.
• Each increment of an int * moves sizeof(int) bytes in memory.
4
2.7 7. Swapping Values with Pointers
Purpose: Demonstrates using pointers in function calls to swap two variables.
Listing 7: swap.c
1 #include <stdio.h>
2
3 void swap(int *a, int *b) {
4 int temp = *a;
5 *a = *b;
6 *b = temp;
7 }
8
9 int main(void) {
10 int x = 5, y = 10;
11 printf("Before swap: x = %d, y = %d\n", x, y);
12 swap(&x, &y);
13 printf("After swap: x = %d, y = %d\n", x, y);
14 return 0;
15 }
Instructions:
• Compile: gcc swap.c -o swap
• Run: ./swap
Key Concepts:
• Passing addresses to a function.
• Dereferencing to modify original variables.
2.8 8. Dynamic Memory Allocation
Purpose: Explores malloc() and free() to dynamically manage memory for arrays.
Listing 8: dynamic_allocation.c
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main(void) {
5 int n;
6 printf("Enter the number of elements: ");
7 scanf("%d", &n);
8
9 int *arr = (int *)malloc(n * sizeof(int));
10 if (arr == NULL) {
11 printf("Memory allocation failed!\n");
12 return 1;
13 }
14
15 // Store values
5
16 for (int i = 0; i < n; i++) {
17 arr[i] = i + 1;
18 }
19
20 // Print values
21 printf("Allocated array elements:\n");
22 for (int i = 0; i < n; i++) {
23 printf("%d ", arr[i]);
24 }
25 printf("\n");
26
27 free(arr); // Release the allocated memory
28 return 0;
29 }
Instructions:
• Compile: gcc dynamic_allocation.c -o dynamic_allocation
• Run: ./dynamic_allocation
Key Concepts:
• malloc() for dynamic memory allocation.
• Checking for NULL to avoid segmentation faults.
• free() to release allocated memory.
2.9 9. Structure Basics
Purpose: Shows how to define and use a struct in C.
Listing 9: structure_basics.c
1 #include <stdio.h>
2 #include <string.h>
3
4 struct Student {
5 char name[50];
6 int age;
7 };
8
9 int main(void) {
10 struct Student s1;
11
12 strcpy(s1.name, "Alice");
13 s1.age = 20;
14
15 printf("Student Name: %s, Age: %d\n", s1.name, s1.age);
16
17 return 0;
18 }
Instructions:
6
• Compile: gcc structure_basics.c -o structure_basics
• Run: ./structure_basics
Key Concepts:
• Declaring a structure.
• Accessing structure members using the dot (.) operator.
• Using library functions (strcpy) to manipulate strings within structures.
2.10 10. Singly Linked List (Insertion & Print)
Purpose: Provides a foundational data structure using pointers—linked lists.
Listing 10: linked_list.c
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 struct Node {
5 int data;
6 struct Node *next;
7 };
8
9 void insertAtHead(struct Node **head, int value) {
10 struct Node *newNode = (struct Node*)malloc(sizeof(struct Node));
11 newNode->data = value;
12 newNode->next = *head;
13 *head = newNode;
14 }
15
16 void printList(struct Node *head) {
17 struct Node *current = head;
18 while (current != NULL) {
19 printf("%d -> ", current->data);
20 current = current->next;
21 }
22 printf("NULL\n");
23 }
24
25 int main(void) {
26 struct Node *head = NULL;
27
28 insertAtHead(&head, 30);
29 insertAtHead(&head, 20);
30 insertAtHead(&head, 10);
31
32 printList(head);
33 return 0;
34 }
Instructions:
7
• Compile: gcc linked_list.c -o linked_list
• Run: ./linked_list
Key Concepts:
• Dynamic allocation for nodes.
• Maintaining a head pointer to a linked list.
• Inserting new nodes at the head of the list.
2.11 11. Stack (Array Implementation)
Purpose: Implements a simple stack using an array.
Listing 11: stack_array.c
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 #define MAX_SIZE 5
5
6 typedef struct {
7 int top;
8 int arr[MAX_SIZE];
9 } Stack;
10
11 void initStack(Stack *s) {
12 s->top = -1;
13 }
14
15 int isFull(Stack *s) {
16 return s->top == MAX_SIZE - 1;
17 }
18
19 int isEmpty(Stack *s) {
20 return s->top == -1;
21 }
22
23 void push(Stack *s, int value) {
24 if (isFull(s)) {
25 printf("Stack overflow!\n");
26 return;
27 }
28 s->arr[++(s->top)] = value;
29 }
30
31 int pop(Stack *s) {
32 if (isEmpty(s)) {
33 printf("Stack underflow!\n");
34 return -1;
35 }
8
36 return s->arr[(s->top)--];
37 }
38
39 int main(void) {
40 Stack myStack;
41 initStack(&myStack);
42
43 push(&myStack, 10);
44 push(&myStack, 20);
45 push(&myStack, 30);
46
47 printf("Popped: %d\n", pop(&myStack));
48 printf("Popped: %d\n", pop(&myStack));
49
50 return 0;
51 }
Instructions:
• Compile: gcc stack_array.c -o stack_array
• Run: ./stack_array
Key Concepts:
• LIFO (Last-In, First-Out) principle.
• Array-based stack with top index.
• Overflow and underflow checks.
2.12 12. Queue (Array Implementation)
Purpose: Implements a simple queue using an array.
Listing 12: queue_array.c
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 #define MAX_SIZE 5
5
6 typedef struct {
7 int front, rear;
8 int arr[MAX_SIZE];
9 } Queue;
10
11 void initQueue(Queue *q) {
12 q->front = -1;
13 q->rear = -1;
14 }
15
16 int isEmpty(Queue *q) {
17 return q->front == -1;
9
18 }
19
20 int isFull(Queue *q) {
21 return (q->rear + 1) % MAX_SIZE == q->front;
22 }
23
24 void enqueue(Queue *q, int value) {
25 if (isFull(q)) {
26 printf("Queue is full!\n");
27 return;
28 }
29 if (q->front == -1)
30 q->front = 0;
31 q->rear = (q->rear + 1) % MAX_SIZE;
32 q->arr[q->rear] = value;
33 }
34
35 int dequeue(Queue *q) {
36 if (isEmpty(q)) {
37 printf("Queue is empty!\n");
38 return -1;
39 }
40 int result = q->arr[q->front];
41 if (q->front == q->rear) {
42 // Only one element
43 q->front = -1;
44 q->rear = -1;
45 } else {
46 q->front = (q->front + 1) % MAX_SIZE;
47 }
48 return result;
49 }
50
51 int main(void) {
52 Queue myQueue;
53 initQueue(&myQueue);
54
55 enqueue(&myQueue, 1);
56 enqueue(&myQueue, 2);
57 enqueue(&myQueue, 3);
58
59 printf("Dequeued: %d\n", dequeue(&myQueue));
60 printf("Dequeued: %d\n", dequeue(&myQueue));
61
62 return 0;
63 }
Instructions:
• Compile: gcc queue_array.c -o queue_array
• Run: ./queue_array
10
Key Concepts:
• FIFO (First-In, First-Out) principle.
• Circular indexing using (rear + 1) % MAX_SIZE.
• Checking for empty and full conditions.
2.13 13. Bubble Sort
Purpose: Illustrates a simple sorting algorithm operating on an array in-place.
Listing 13: bubble_sort.c
1 #include <stdio.h>
2
3 void bubbleSort(int arr[], int n) {
4 for (int i = 0; i < n - 1; i++) {
5 for (int j = 0; j < n - i - 1; j++) {
6 if (arr[j] > arr[j + 1]) {
7 // Swap
8 int temp = arr[j];
9 arr[j] = arr[j + 1];
10 arr[j + 1] = temp;
11 }
12 }
13 }
14 }
15
16 int main(void) {
17 int arr[] = {64, 34, 25, 12, 22, 11, 90};
18 int n = sizeof(arr) / sizeof(arr[0]);
19
20 printf("Original array:\n");
21 for(int i = 0; i < n; i++) {
22 printf("%d ", arr[i]);
23 }
24 printf("\n");
25
26 bubbleSort(arr, n);
27
28 printf("Sorted array:\n");
29 for(int i = 0; i < n; i++) {
30 printf("%d ", arr[i]);
31 }
32 printf("\n");
33
34 return 0;
35 }
Instructions:
• Compile: gcc bubble_sort.c -o bubble_sort
11
• Run: ./bubble_sort
Key Concepts:
• Nested loops and swapping adjacent elements.
• Time complexity: O(n2 ) average/worst case.
2.14 14. Binary Search (Iterative)
Purpose: Demonstrates searching a sorted array in O(log n) time.
Listing 14: binary_search.c
1 #include <stdio.h>
2
3 int binarySearch(int arr[], int size, int target) {
4 int low = 0;
5 int high = size - 1;
6
7 while (low <= high) {
8 int mid = (low + high) / 2;
9
10 if (arr[mid] == target) {
11 return mid;
12 } else if (arr[mid] < target) {
13 low = mid + 1;
14 } else {
15 high = mid - 1;
16 }
17 }
18 return -1;
19 }
20
21 int main(void) {
22 int arr[] = {2, 4, 6, 8, 10, 12};
23 int size = sizeof(arr) / sizeof(arr[0]);
24 int target = 8;
25
26 int result = binarySearch(arr, size, target);
27 if (result != -1) {
28 printf("Element %d found at index %d.\n", target, result);
29 } else {
30 printf("Element %d not found.\n", target);
31 }
32
33 return 0;
34 }
Instructions:
• Compile: gcc binary_search.c -o binary_search
• Run: ./binary_search
12
Key Concepts:
• Requires sorted array for correctness.
• Iterative approach to finding a target in O(log n).
2.15 15. File I/O (Read and Write)
Purpose: Demonstrates reading from and writing to a file in C.
Listing 15: file_io.c
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main(void) {
5 FILE *fp = fopen("output.txt", "w");
6 if (fp == NULL) {
7 printf("Error opening file for writing.\n");
8 return 1;
9 }
10 fprintf(fp, "Hello, file!\n");
11 fclose(fp);
12
13 fp = fopen("output.txt", "r");
14 if (fp == NULL) {
15 printf("Error opening file for reading.\n");
16 return 1;
17 }
18
19 char buffer[100];
20 while (fgets(buffer, sizeof(buffer), fp) != NULL) {
21 printf("%s", buffer);
22 }
23 fclose(fp);
24
25 return 0;
26 }
Instructions:
1. Compile: gcc file_io.c -o file_io
2. Run: ./file_io
3. This will write "Hello, file!" to output.txt and then read it back.
Key Concepts:
• Using FILE * to handle file streams.
• fopen, fprintf, fgets, fclose.
• Error checking when opening/reading/writing files.
13
3 Tips for Running and Understanding the Programs
• Compilation: Use gcc filename.c -o outputname on Linux or macOS. On
Windows, the command is similar, though you may end up with an .exe file.
• Execution: On UNIX-like systems, run ./outputname. On Windows, run outputname.exe
or outputname.
• Experimentation: Modify values, change array sizes, or add additional printf
statements to see how behavior changes. Insert debugging printouts to trace loops
or pointer operations.
• Common Pitfalls:
– Not checking the return of malloc() for NULL.
– Off-by-one errors in loops and array indexing.
– Forgetting to free dynamically allocated memory, leading to leaks.
– Mixing scanf and fgets without clearing input buffers.
• Further Exploration:
– Explore advanced data structures (trees, graphs, hash tables).
– Implement additional sorting algorithms (insertion sort, merge sort, quicksort).
– Add error handling and input validation.
– Use debuggers like gdb to step through code line by line.
14