CACS151 C Programming

C ProgrammingUnit 712 min read

Arrays, DMA & Memory Management in C: Syntax, Operations & Real-World Use

Unit 7 of C Programming covers arrays (1D/2D), dynamic memory allocation (malloc/calloc/realloc), memory management functions, and their applications in problem-solving, with visual traces of operations and comparisons to static allocation.

TAKEAWAYS:

  • Arrays store homogeneous data in contiguous memory locations, accessed via indices (0 to n-1).
  • Dynamic memory allocation (malloc, calloc, realloc) allocates memory at runtime, unlike static arrays with fixed size.
  • DMA avoids stack overflow and enables flexible data structures (linked lists, trees) but requires manual free() to prevent memory leaks.
  • Common operations include traversal, searching (linear/binary), sorting, and matrix arithmetic.
  • Real-world uses include handling variable-sized inputs (e.g., user orders in Daraz), efficient data storage (e.g., NTC’s network traffic logs), and resource optimization (e.g., Pathao’s ride allocation).
  • Exam questions often test array initialization, DMA functions, and problem-solving with arrays (e.g., finding min/max, sum, or second-largest element).

1. Arrays in C: Definition and Basics

Arrays are contiguous memory locations that store elements of the same data type. They are declared with a fixed size and accessed using indices starting from 0.

Key Features:

  • Fixed size: Size must be known at compile-time (for static arrays).
  • Homogeneous elements: All elements must be of the same type.
  • Contiguous memory: Elements are stored in adjacent memory locations.

Syntax:

data_type array_name[size];

Example:

int marks[5]; // Array to store 5 integers

Initialization:

int arr1[3] = {1, 2, 3}; // Explicit initialization
int arr2[] = {4, 5, 6};  // Size inferred (3)
int arr3[5] = {0};       // All elements initialized to 0

Accessing Elements:

printf("%d", arr1[0]); // Output: 1 (first element)

Traversal Example:

#include <stdio.h>
int main() {
    int arr[] = {10, 20, 30, 40, 50};
    int n = sizeof(arr)/sizeof(arr[0]); // Calculate size
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    return 0;
}

Output:

10 20 30 40 50

Visual: Array in Memory


```figure
{"type":"array","values":[10,20,30,40,50],"caption":"1D array in contiguous memory blocks (addresses 1000-1016)"}

[10][20][30][40][50] Address: 1000 1004 1008 1012 1016


2. One-Dimensional (1D) Arrays

Used for storing linear data (e.g., list of numbers, student marks).

Example: Sum of Array Elements

#include <stdio.h>
int main() {
    int arr[] = {5, 10, 15, 20};
    int sum = 0;
    for (int i = 0; i < 4; i++) {
        sum += arr[i];
    }
    printf("Sum: %d", sum); // Output: 50
    return 0;
}

Exam Worked Example: Generate Pattern

Question: Write a program to generate the following output:

1 12 123 1234 12345

Solution:

#include <stdio.h>
int main() {
    for (int i = 1; i <= 5; i++) {
        for (int j = 1; j <= i; j++) {
            printf("%d", j);
        }
        printf(" ");
    }
    return 0;
}

Output:

1 12 123 1234 12345

3. Two-Dimensional (2D) Arrays (Matrices)

Used for tabular data (e.g., matrices, grids).

Syntax:

data_type array_name[rows][columns];

Example:

int matrix[2][3] = {{1, 2, 3}, {4, 5, 6}};

Traversal:

for (int i = 0; i < 2; i++) {
    for (int j = 0; j < 3; j++) {
        printf("%d ", matrix[i][j]);
    }
    printf("\n");
}

Output:

1 2 3
4 5 6

Visual: 2D Array in Memory


```figure
{"type":"array","values":[[1,2,3],[4,5,6],[7,8,9]],"caption":"2D array (3x3 matrix) stored in row-major order (addresses 1000-1018)"}

Row 0: [1][2][3] Row 1: [4][5][6] Address: 1000 1004 1008 1012 1016 1020


#### **Example: Matrix Addition**
```c
#include <stdio.h>
int main() {
    int A[2][2] = {{1, 2}, {3, 4}};
    int B[2][2] = {{5, 6}, {7, 8}};
    int C[2][2];

    for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 2; j++) {
            C[i][j] = A[i][j] + B[i][j];
        }
    }

    printf("Result:\n");
    for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 2; j++) {
            printf("%d ", C[i][j]);
        }
        printf("\n");
    }
    return 0;
}

Output:

6 8
10 12

4. Dynamic Memory Allocation (DMA)

Static arrays have fixed size, but DMA allows runtime allocation using functions like malloc, calloc, and realloc.

Why Use DMA?

  • Handle variable-sized data (e.g., user inputs, unknown array sizes).
  • Avoid stack overflow (static arrays are limited by stack size).
  • Enable flexible data structures (linked lists, trees).

Memory Management Functions:

Function Description Syntax
malloc() Allocates memory (uninitialized). ptr = (cast_type*)malloc(size)
calloc() Allocates and initializes memory to 0. ptr = (cast_type*)calloc(n, size)
realloc() Resizes previously allocated memory. ptr = realloc(ptr, new_size)
free() Deallocates memory to prevent leaks. free(ptr)

Example: Sum of N Numbers Using DMA

#include <stdio.h>
#include <stdlib.h>
int main() {
    int n, sum = 0;
    printf("Enter size: ");
    scanf("%d", &n);

    int *arr = (int*)malloc(n * sizeof(int));
    printf("Enter %d numbers:\n", n);
    for (int i = 0; i < n; i++) {
        scanf("%d", &arr[i]);
        sum += arr[i];
    }

    printf("Sum: %d\n", sum);
    free(arr); // Free memory
    return 0;
}

Input/Output:

Enter size: 3
Enter 3 numbers:
10 20 30
Sum: 60

Visual: DMA Process

flowchart TD
    A["Declare pointer: `int *arr;`"] --> B["Allocate memory: `arr = malloc(n*sizeof(int))`"]
    B --> C["Store values: `arr[i] = input;`"]
    C --> D["Use memory: `sum += arr[i];`"]
    D --> E["Free memory: `free(arr);`"]

Trace of malloc Execution:

Step Code Memory Allocation arr Value
1 int *arr; arr points to NULL NULL
2 arr = malloc(3*sizeof(int)) 12 bytes allocated Address of block
3 arr[0] = 10; [10][0][0] Points to block
4 free(arr); Memory deallocated NULL (good practice)

5. Limitations of Static Memory Allocation

Static Allocation Dynamic Allocation (DMA)
Fixed size at compile-time Size determined at runtime
Limited by stack size Limited by heap size
No manual memory management Requires free() to avoid leaks
Faster access (contiguous) Slightly slower (heap fragmentation)

Example: Memory Leak

int *ptr = malloc(10 * sizeof(int));
// Forgetting to free(ptr) causes a memory leak!

6. Applications of Arrays and DMA

In the Real World:

  1. eSewa/Khalti (Nepal):

    • Use: Arrays store transaction records (e.g., transactions[1000][3] where each row is [user_id, amount, timestamp]).
    • Why? Efficiently retrieve and process large datasets (e.g., monthly summaries).
  2. Daraz (Nepal):

    • Use: DMA allocates memory for order queues dynamically (e.g., order_queue = malloc(num_orders * sizeof(Order))).
    • Why? Handles variable customer loads without preallocating excessive memory.
  3. NTC (Nepal Telecommunications Corporation):

    • Use: 2D arrays track network traffic (e.g., traffic[24][60] for hourly/minute data).
    • Why? Enables real-time analysis and load balancing.
  4. Bank Loan Calculations (e.g., NMB, Global IME):

    • Use: Arrays store loan installments (e.g., installments[60] for a 5-year loan).
    • Worked Example:
      • Monthly Interest: ( \text{Interest} = \text{Principal} \times \text{Rate} / 12 )
      • Code:
        float installments[60];
        float principal = 1000000, rate = 0.08;
        for (int i = 0; i < 60; i++) {
            installments[i] = (principal * rate / 12) + (principal / 60);
        }
        
      • Output: First 3 installments:
        Month 1: 8666.67
        Month 2: 8666.67
        Month 3: 8666.67
        
  5. Pathao (Ride Allocation):

    • Use: DMA allocates ride requests dynamically (e.g., rides = malloc(num_requests * sizeof(Ride))).
    • Why? Scales with demand (e.g., peak hours in Kathmandu).

7. Common Array Operations

int linearSearch(int arr[], int n, int key) {
    for (int i = 0; i < n; i++) {
        if (arr[i] == key) return i;
    }
    return -1;
}

Trace:

Step i arr[i] key Action
1 0 10 20 Continue
2 1 20 20 Return 1

b) Binary Search (Requires Sorted Array)

int binarySearch(int arr[], int left, int right, int key) {
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (arr[mid] == key) return mid;
        if (arr[mid] < key) left = mid + 1;
        else right = mid - 1;
    }
    return -1;
}

Visual: Binary Search Steps

100201302403504lowhigh
Binary search on sorted array [10, 20, 30, 40, 50] (searching for 30)

c) Bubble Sort

void bubbleSort(int arr[], int n) {
    for (int i = 0; i < n-1; i++) {
        for (int j = 0; j < n-i-1; j++) {
            if (arr[j] > arr[j+1]) {
                int temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    }
}

Trace for [5, 3, 8, 4]:

Pass Array State Swaps
1 [3, 5, 4, 8] (5,3)
2 [3, 4, 5, 8] (5,4)
3 [3, 4, 5, 8] No swaps

8. Exam Tip: How to Score Full Marks

  1. Define Clearly:

    • For arrays: "Contiguous memory locations storing homogeneous data with indices starting from 0."
    • For DMA: "Allocation of memory at runtime using malloc, calloc, or realloc to handle variable-sized data."
  2. Program Structure:

    • Always include:
      • #include <stdio.h> and #include <stdlib.h> for DMA.
      • Variable declarations.
      • main() function.
      • Proper comments explaining logic.
  3. DMA Pitfalls:

    • Check for NULL after malloc/calloc:
      if (ptr == NULL) {
          printf("Memory allocation failed!");
          exit(1);
      }
      
    • Always free() memory to avoid leaks.
  4. Common Exam Questions:

    • Array Initialization: Show both explicit and implicit methods.
    • DMA Functions: Explain differences between malloc (uninitialized) and calloc (zero-initialized).
    • Problem-Solving: For questions like "find the second largest age", use:
      int first = INT_MIN, second = INT_MIN;
      for (int i = 0; i < n; i++) {
          if (arr[i] > first) {
              second = first;
              first = arr[i];
          } else if (arr[i] > second && arr[i] != first) {
              second = arr[i];
          }
      }
      
  5. Visuals in Exams:

    • Draw memory diagrams for DMA operations (e.g., before/after malloc).
    • Show array traversal with indices (e.g., arr[0] to arr[n-1]).
  6. Real-World Tie-Ins:

    • Relate problems to Nepali contexts (e.g., NTC traffic data, Daraz order queues).
    • Example answer for "Why use DMA?":

      "DMA is used in Daraz’s order processing system to dynamically allocate memory for customer orders. Since the number of orders varies hourly, static arrays would waste memory or overflow. DMA ensures efficient memory usage and scalability."


9. Practice Problems for TU/PU Exams

  1. Array Initialization: Write a program to initialize a 1D array with values 1, 2, 3, 4, 5 and print it in reverse order.

  2. DMA Application: Write a program to input N student marks and find the average using DMA.

  3. Matrix Operations: Write a program to multiply two matrices of order 2x3 and 3x2.

  4. Searching: Write a program to search for an element in an array using binary search (assume sorted array).

  5. Memory Management: Explain the difference between malloc and calloc with an example where you allocate memory for 5 integers and initialize them to 0.


Final Note: Arrays and DMA are fundamental for efficient programming. Master these concepts, and you’ll ace problems involving data storage, manipulation, and real-world simulations (e.g., banking, e-commerce). Always visualize memory and trace code step-by-step during exams!

Based on the TU BCA syllabus for C Programming (CACS151), unit 7.

Discussion

Loading…