# How to Initialize and Finalize a mulle_buffer in C

> Learn to initialize and finalize a mulle_buffer in C. Discover create heap allocations and init stack storage for efficient memory management in your mulle-buffer projects.

- Repository: [mulle-c/mulle-buffer](https://github.com/mulle-c/mulle-buffer)
- Tags: how-to-guide
- Published: 2026-03-07

---

**Initialize a `mulle_buffer` using `mulle_buffer_create()` for heap allocation or `mulle_buffer_init_with_static_bytes()` for stack-based storage, then finalize with `mulle_buffer_destroy()` for heap objects or `mulle_buffer_done()` for stack instances.**

The **mulle_buffer** is the core type of the *mulle-c/mulle-buffer* library, providing a growable memory region with an associated allocator. Properly managing the lifecycle of this structure—initialization to finalization—is essential for preventing memory leaks and ensuring safe buffer operations in C applications.

## Initializing a mulle_buffer

The library offers multiple initialization strategies depending on whether you need heap-allocated dynamic storage, fixed-size stack buffers, or read-only views of constant data. All initializers are defined in [`src/mulle-buffer.h`](https://github.com/mulle-c/mulle-buffer/blob/main/src/mulle-buffer.h) and guarantee that the internal `_allocator` field is properly set (unless explicitly marked inflexible or readonly).

### Heap-Allocated Buffers

For dynamic memory management, use the convenient constructor that allocates and initializes in a single call. In `src/mulle-buffer.c#L44-L50`, `mulle_buffer_create()` combines object allocation with default capacity setup (96 bytes on 64-bit systems).

```c
#include "mulle-buffer.h"

/* Creates buffer with mulle_default_allocator when NULL is passed */
struct mulle_buffer *buf = mulle_buffer_create( NULL );

/* Use the buffer... */
mulle_buffer_add_string( buf, "Dynamic content" );

/* Clean up both object and storage */
mulle_buffer_destroy( buf );

```

Alternatively, separate the allocation and initialization steps using `mulle_buffer_alloc()` (inline at `src/mulle-buffer.h#L46-L53`) followed by `mulle_buffer_init()` (`src/mulle-buffer.h#L79-L88`), which allows specifying a custom initial capacity.

### Stack-Based Buffers

When you want to avoid heap allocations entirely or minimize them, initialize a `mulle_buffer` with pre-allocated stack storage. The `mulle_buffer_init_with_static_bytes()` function accepts a pointer to your storage array and its size.

```c
char storage[128];
struct mulle_buffer buf;  /* Object lives on stack */

mulle_buffer_init_with_static_bytes( &buf, 
                                     storage, 
                                     sizeof( storage ), 
                                     NULL );

mulle_buffer_add_string( &buf, "Stack-based data" );
puts( mulle_buffer_get_string( &buf ) );

/* Release only any potential heap growth, keep stack object */
mulle_buffer_done( &buf );

```

This pattern ensures zero malloc overhead unless the buffer grows beyond the static capacity.

### Read-Only Constant Buffers

For immutable data views, use `mulle_buffer_init_with_const_bytes()` (`src/mulle-buffer.h#L96-L124`). This creates a buffer referencing existing constant data without copy overhead, but marks it as read-only.

```c
const char data[] = "Immutable string";
struct mulle_buffer buf;

mulle_buffer_init_with_const_bytes( &buf, data, sizeof( data ) - 1 );

/* Reading is safe */
puts( mulle_buffer_get_string( &buf ) );

/* Writing would trigger assert in debug builds */
/* mulle_buffer_add_string( &buf, "x" );  // Fails assertion */

mulle_buffer_done( &buf );  /* No allocation performed */

```

### Advanced Initialization Options

The header [`src/mulle-buffer.h`](https://github.com/mulle-c/mulle-buffer/blob/main/src/mulle-buffer.h) provides additional specialized initializers for specific use cases:

- **`mulle_buffer_init_with_allocated_bytes`** – Takes ownership of pre-malloced memory
- **`mulle_buffer_init_inflexible_with_static_bytes`** – Creates a non-resizable buffer that fails gracefully if capacity is exceeded rather than reallocating

## Finalizing a mulle_buffer

Proper finalization releases internal storage and returns resources to the allocator. The library provides distinct cleanup functions depending on how the buffer object was allocated.

### Complete Destruction with mulle_buffer_destroy

Use `mulle_buffer_destroy()` (`src/mulle-buffer.h#L349-L357`) when the buffer object itself was heap-allocated via `mulle_buffer_create()` or `mulle_buffer_alloc()`. This function checks for NULL, obtains the stored allocator, frees the internal storage via `_mulle__buffer_destroy`, and then frees the buffer object itself.

```c
struct mulle_buffer *buf = mulle_buffer_create( NULL );
/* ... use buffer ... */
mulle_buffer_destroy( buf );  /* Frees everything */

```

### Partial Cleanup with mulle_buffer_done

For stack-allocated buffer objects or when you need to preserve the `struct mulle_buffer` container, use `mulle_buffer_done()` (`src/mulle-buffer.h#L68-L74`). This releases only the heap-allocated storage while leaving the object intact.

```c
struct mulle_buffer buf;
char storage[256];
mulle_buffer_init_with_static_bytes( &buf, storage, sizeof(storage), NULL );

/* ... operations ... */

mulle_buffer_done( &buf );  /* Object remains valid but empty */

```

### Reset for Reuse

The `mulle_buffer_reset()` function performs an implicit destroy-and-reinit cycle on the same object. This clears all contents while maintaining the existing allocator association and is useful for buffer pooling or iterative processing loops.

## Summary

- **`mulle_buffer_create()`** allocates and initializes a heap-based buffer with default capacity, using `mulle_default_allocator` when NULL is specified.
- **Stack initialization** via `mulle_buffer_init_with_static_bytes()` eliminates malloc overhead for fixed-size workloads.
- **Read-only buffers** initialized with `mulle_buffer_init_with_const_bytes()` provide zero-copy views of constant data.
- **`mulle_buffer_destroy()`** frees both heap-allocated objects and their internal storage.
- **`mulle_buffer_done()`** releases only internal storage, suitable for stack-allocated buffer objects.
- All finalization functions safely handle NULL pointers without crashing.

## Frequently Asked Questions

### What happens if I pass NULL to mulle_buffer_destroy?

The function safely ignores NULL pointers and returns immediately. As implemented in `src/mulle-buffer.h#L349-L357`, the API performs a NULL check before dereferencing, preventing segmentation faults during error handling paths or conditional cleanup logic.

### Can I use mulle_buffer without any heap allocations?

Yes. By using `mulle_buffer_init_with_static_bytes()` with a stack-allocated char array, you create a functional buffer that only allocates heap memory if writes exceed the static capacity. If you keep writes within the initial size, the buffer operates entirely on the stack with zero malloc calls.

### How do I handle allocation failures in mulle_buffer_create?

The function propagates allocation failures from the underlying `mulle_allocator` without aborting. If allocation fails, `mulle_buffer_create()` returns NULL. Production code should verify the returned pointer before use, as the high-level API does not implement internal error recovery or automatic retry logic.

### What is the difference between mulle_buffer_done and mulle_buffer_reset?

**`mulle_buffer_done()`** finalizes the buffer by freeing internal storage and clearing pointers, leaving the object in a clean but unusable state until explicitly reinitialized. **`mulle_buffer_reset()`** immediately reinitializes the same buffer object after destruction, preserving the allocator association and returning it to an empty, usable state suitable for immediate reuse without requiring a separate init call.