Reference counted dynamic byte array What?

I have a reference counted dynamic byte array written in C. I'm currently using this implementation in a FIFO fashion. Particularly reading data from files into the arrays, then parsing the data in the array byte by byte. 

I'm looking for feedback on anything! Even the decision to use a dynamic byte array versus using a linked list or any other data structure. 

Edit: I'm trying to follow the Linux Kernel coding style, so I'm looking for feedback on how well I follow that convention. 

Files

Header

#ifndef DATA_BYTE_ARRAY
#define DATA_BYTE_ARRAY

#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
#include &lt;stdint.h&gt;
#include &lt;assert.h&gt;
#include &lt;string.h&gt;

#include "../memory.h"

/**
 * Dynamic array that grows when it's full (given that 
 * the util functions in this module are used). 
 *
 * For each grow it uses the current length doubled. See
 * byte_array_push for more info.
 */

struct byte_array {
        uint8_t refs;
        uint32_t length;
        uint32_t capability;
        uint8_t *bytes;
};

/**
 * Creates a byte array with the given length. 
 * 
 * Values of the returned struct:
 * - 1 reference 
 * - All bytes will be set to 0
 * - Current position will be set to 0
 * - Capability will reflect how many bytes are allocated. Which is 
 *   the same as given capability. 
 */

struct byte_array *byte_array_create(uint32_t capability);

/**
 * Adds the given input at the current position of the array.
 *
 * Note that if the pointer to the byte array is NULL an assertion will crash 
 * the program. 
 *
 * If the byte array is full more memory will be allocated. The amount
 * of new memory that will be allocated is the current amount doubled.
 */

void byte_array_push(struct byte_array *a, uint8_t input);

void byte_array_incref(struct byte_array *a);

void byte_array_decref(struct byte_array *a);

#endif


Source

#include "byte_array.h"

#define NEW_CAPABILITY a-&gt;capability * 2

static void zero_init_bytes(struct byte_array *a, 
                            uint32_t offset, 
                            uint32_t nmemb)
{
        uint8_t *bytes = a-&gt;bytes;
        bytes += offset;
        memset(bytes, 0, nmemb);
}

struct byte_array *byte_array_create(uint32_t capability)
{
        struct byte_array *result = assert_malloc(sizeof(*result));
        result-&gt;refs = 1;
        result-&gt;length = 0;
        result-&gt;capability = capability;
        result-&gt;bytes = assert_calloc(capability, sizeof(uint8_t));

        return result;
}

void byte_array_push(struct byte_array *a, uint8_t input)
{
        assert(a != NULL);

        if (a-&gt;length == a-&gt;capability) {
                void *tmp = assert_realloc(a-&gt;bytes, NEW_CAPABILITY);

                a-&gt;bytes = tmp;

                zero_init_bytes(
                        a, 
                        a-&gt;capability, 
                        NEW_CAPABILITY - a-&gt;capability
                );

                a-&gt;capability = NEW_CAPABILITY;
        }

        a-&gt;bytes[a-&gt;length++] = input;
}

void byte_array_incref(struct byte_array *a)
{
        assert(a != NULL);

        a-&gt;refs++;
}

void byte_array_decref(struct byte_array *a)
{
        assert(a != NULL);

        if (--a-&gt;refs != 0) return;

        free(a-&gt;bytes);
        free(a);
}
This looks mostly good to me. Your code looks like fairly clean C. I have some comments:


I think capacity is a better name than capability.
I would avoid calling your header memory.h, since memory is a header in C++. Maybe checked_alloc.h instead? Also, include it as "memory.h" and let your build system figure out its path.
How is your error handling in the assert_...alloc functions? Do they just terminate the program?
Two of your public interface functions are without documentation. Are they not supposed to be part of the public interface? If not, put them in the implementation file (only) and make them static. If they are, document them as well.
Note that the assert() macro is only evaluated if your library is compiled without NDEBUG. This means that the code using it will be unchecked for production builds. It might be fine, but maybe you want checking in production as well; I'm just pointing it out.
As far as I can see, you adhere to the Linux coding style.
Consider typedef uint8_t byte or something like that to emphasize what the role of the uint8_ts are. Remember that you have no guarantee that CHAR_BIT is 8. (Maybe you want to use char instead, which is guaranteed to always be one byte.)
I would change if (a-&gt;length == a-&gt;capability) to if (a-&gt;length &gt;= a-&gt;capability). The latter is a bit clearer, and if you at one point allow adding larger objects the code will still work.
Your macro looks nasty.

I'd do:

#define CAPACITY_GROWTH_FACTOR 2

/* ... */

a-&gt;capability *= CAPACITY_GROWTH_FACTOR;


Or even better, change the #define into a const size_t.
The nmemb variable isn't very readable. Change it to num_members or something like that.
Consider sorting your #includes alphabetically.
While I don't see anything wrong with your reference counting, you should thoroughly test it to verify that it works.
Regarding reference counting and your interface, ask yourself these questions:


What happens when you copy your array? What do you want to happen? How should a copy be made?
How should copies behave when you modify an array that has multiple references to it?
Will this be used in a multi-threaded environment?


The answers affect how the interface should be designed. Personally, it seems to me that the reference counting is on a very low level (the caller has to take care of it himself), meaning it would be easy to make mistakes. Make your interface easy to use correctly, and hard to use incorrectly. Reference counting might not even be necessary here, depending on what the array is meant to be used for.