pointers-memory · intermediate · ~15 min

Flexible Array Member Allocation

Allocate, manage, and free contiguous C99 flexible array members safely.

Challenge

C99 flexible array members (type member[]) placed as the last element of a struct allow allocating a struct and its variable-length payload in a single contiguous dynamic memory block.

Your Task

Given the dynamic buffer struct:

typedef struct {
    uint32_t capacity;
    uint32_t length;
    uint8_t data[]; // flexible array member
} DynBuffer;

Implement:

DynBuffer *dyn_buffer_create(size_t capacity);
int dyn_buffer_append(DynBuffer *buf, const uint8_t *bytes, size_t len);
void dyn_buffer_free(DynBuffer *buf);

Rules

  1. In dyn_buffer_create:
    • If capacity > 1024 * 1024 (1MB) or capacity check overflows sizeof(DynBuffer) + capacity, return NULL.
    • Allocate sizeof(DynBuffer) + capacity bytes.
    • Set capacity = (uint32_t)capacity, length = 0.
    • Return pointer to the allocated DynBuffer.
  2. In dyn_buffer_append:
    • If buf == NULL, bytes == NULL, or len == 0, return -1.
    • If buf->length + len > buf->capacity, return -1 (buffer capacity exceeded).
    • Copy bytes into buf->data + buf->length.
    • Increase buf->length += len and return 0.
  3. In dyn_buffer_free:
    • If buf != NULL, free buf.

Example

DynBuffer *b = dyn_buffer_create(10);
uint8_t msg[] = "ABC";
dyn_buffer_append(b, msg, 3); // returns 0, length == 3
dyn_buffer_free(b);

Input format

capacity: initial byte capacity; buf: DynBuffer pointer; bytes: byte array to append.

Output format

Returns pointer to DynBuffer or integer status 0/-1.

Constraints

Single allocation for header + flexible array member. Zero memory leaks.

Starter code

#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>

typedef struct {
    uint32_t capacity;
    uint32_t length;
    uint8_t data[];
} DynBuffer;

DynBuffer *dyn_buffer_create(size_t capacity) {
    (void)capacity;
    return NULL;
}
int dyn_buffer_append(DynBuffer *buf, const uint8_t *bytes, size_t len) {
    (void)buf; (void)bytes; (void)len;
    return -1;
}
void dyn_buffer_free(DynBuffer *buf) {
    (void)buf;
}

Common mistakes

Allocating sizeof(DynBuffer*) instead of sizeof(DynBuffer) + capacity; forgetting data offset.

Edge cases to handle

Appending more than capacity returns -1 without buffer modification; capacity == 0 creates empty buffer.

Background lessons

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.