Static vs. Dynamic Arrays in C: A Practical Guide

Introduction

Sequential lists are funadmental data structures used to store collections of elements in a linear fashion. In the C programming language, these are commonly implemented using arrays. There are two primary approaches: static arrays, which have a fixed size determined at compile time, and dynamic arrays, which can grow or shrink as needed during program execution. This guide explores the implementation and trade-offs of both.

Static Sequential Lists

Definition and Characteristics

A static sequential list is an array whose size is fixed when it is created. This means the number of elements it can hold cannot be changed after initialization. This approach is efficient for scenarios where the data size is known and constant.

  • Fixed Capacity: The size is determined at compile time and cannot be altered.
  • Random Access: Elements can be accessed in constant time O(1) using their index.
  • Sequential Storage: Elements are stored contiguously in memory.
  • Simple Implementation: No complex memory management is required.

Implementation Example

The following code demonstrates a simple static list implementation. The list can hold a maximum of 10 integers.

#include <stdio.h>

#define MAX_ELEMENTS 10

// Structure for a fixed-size array
typedef struct {
    int elements[MAX_ELEMENTS]; // Array to store data
    int count;                 // Current number of elements
} FixedArray;

// Initializes the fixed array
void createFixedArray(FixedArray *array) {
    array->count = 0; // Start with zero elements
}

// Adds a value to the fixed array if space is available
int addValue(FixedArray *array, int value) {
    if (array->count < MAX_ELEMENTS) {
        array->elements[array->count] = value; // Place the value
        array->count++; // Increment element count
        return 1; // Success
    }
    return 0; // Array is full
}

// Cleans up the array (resets count)
void destroyFixedArray(FixedArray *array) {
    array->count = 0;
}

int main() {
    FixedArray myArray;
    createFixedArray(&myArray);

    // Attempt to add values
    if (addValue(&myArray, 5) && addValue(&myArray, 15) && addValue(&myArray, 25)) {
        // Print the elements
        for (int i = 0; i < myArray.count; i++) {
            printf("%d ", myArray.elements[i]);
        }
    } else {
        fprintf(stderr, "Failed to add element.
");
    }

    destroyFixedArray(&myArray);
    return 0;
}
</stdio.h>

Output: 5 15 25

Dynamic Sequential Lists

Definition and Characteristics

A dynamic sequential list, or resizable array, can change its size during runtime. When the array becomes full, it is typically resized to a larger capacity (e.g., doubled), and existing elements are copied to the new memory location. This provides flexibility for applications with unpredictable data sizes.

  • Dynamic Resizing: Capacity can be increased or decreased as needed.
  • Random Access: Still provides O(1) access to elements by index.
  • Sequential Storage: Elements remain contiguous in memory.
  • Complex Memory Management: Requires handling memory allocation and deallocation.

Implementation Example

This example shows a dynamic array that starts with a small capacity and automatically resizes when it runs out of space.

#include <stdio.h>
#include <stdlib.h>

#define INITIAL_CAPACITY 5

// Structure for a resizable array
typedef struct {
    int *buffer;    // Pointer to the data array
    int count;      // Current number of elements
    int maxSize;    // Current maximum capacity
} ResizableArray;

// Initializes the resizable array with an initial capacity
void initResizableArray(ResizableArray *array) {
    array->buffer = (int *)malloc(INITIAL_CAPACITY * sizeof(int));
    if (array->buffer == NULL) {
        fprintf(stderr, "Memory allocation failed.
");
        exit(1);
    }
    array->count = 0;
    array->maxSize = INITIAL_CAPACITY;
}

// Appends a value to the resizable array, resizing if necessary
int appendValue(ResizableArray *array, int value) {
    // Check if we need to resize
    if (array->count == array->maxSize) {
        int newSize = array->maxSize * 2; // Double the capacity
        int *newBuffer = (int *)realloc(array->buffer, newSize * sizeof(int));

        if (newBuffer == NULL) {
            return 0; // Memory reallocation failed
        }

        array->buffer = newBuffer; // Update the buffer pointer
        array->maxSize = newSize;  // Update the maximum size
    }

    array->buffer[array->count] = value; // Add the new value
    array->count++; // Increment the count
    return 1; // Success
}

// Frees the memory allocated for the array
void cleanupResizableArray(ResizableArray *array) {
    free(array->buffer);
    array->buffer = NULL;
    array->count = 0;
    array->maxSize = 0;
}

int main() {
    ResizableArray myArray;
    initResizableArray(&myArray);

    // Add values, which may trigger resizing
    if (appendValue(&myArray, 100) && appendValue(&myArray, 200) && appendValue(&myArray, 300)) {
        // Print the elements
        for (int i = 0; i < myArray.count; i++) {
            printf("%d ", myArray.buffer[i]);
        }
    } else {
        fprintf(stderr, "Failed to append element.
");
    }

    cleanupResizableArray(&myArray);
    return 0;
}
</stdlib.h></stdio.h>

Output: 100 200 300

Comparison

Feature Static Array Dynamic Array
Memory Management Simpler; size is fixed at compile time. Complex; requires runtime allocation and reallocation.
Capacity Fixed; cannot be changed. Resizable; can grow or shrink.
Access Efficiency High (O(1) random access). High (O(1) random access).
Suitability Ideal for fixed-size data sets. Suitable for data sets with unknown or changing sizes.
Space Utilization High; no wasted space if sized correctly. May be lower due to over-allocation during resizing.
Coding Complexity Low; straightforward implementation. Higher; requires handling resizing logic and potential errors.

Tags: C Data Structures Arrays static array Dynamic Array

Posted on Mon, 21 Sep 2026 16:01:30 +0000 by Jabop