Is there a standard C library for dynamic arrays?

1.5k Views Asked by At

One of the greatest things about Python is the flexibility of dynamic arrays (lists).

It's so useful I find it hard to believe there isn't a library for this already included in C. This question indicates that there is no standard library for this. Apparently, glibc includes functionality for queues, but as I'm on a windows machine this is not helpful. As the question is 10 years old, I'm wondering if there's been an update.

Is implementing the functionality yourself still the only way to get something like a Python list or is there a standard C library that allows you to use dynamic arrays?

3

There are 3 best solutions below

2
0___________ On BEST ANSWER

C language has something which is called flexible array members:

typedef struct 
{
    size_t size;
    size_t used; 
    int data[];
}int_arr;


int_arr *addsize(int_arr *arr, size_t inc)
{
    size_t newsize = 0;
    size_t newused = 0;

    if(arr)
    {
        newsize = arr -> size + inc;
        newused = arr -> used;
    }
    arr = realloc(arr, sizeof(*arr) + newsize * sizeof(arr -> data[0]));
    if(arr)
    {
        arr -> size = newsize;
        arr -> used = newused;
    }
    return arr;
}
2
Harith On

There is currently no standard library for dynamic arrays, but it's not hard to implement the functionality with realloc() and family.

Here's something you can start with:

struct dynamic_array {
    void *array;          
    size_t occupied_size;
    size_t allocated_size; 
};

See: Dynamic arrays in C.

9
Luis Colorado On

Here is the implementation I normally use on my code:

#define DYNARRAY_GROW(_cell_type, _array, _need, _to_add) do {    \
               if (_array##_len + (_need) >= (_to_add)) {         \
                    _array##_cap += (_to_add);                    \
                    _cell_type *_aux = realloc(_array,            \
                              _array##_cap * sizeof _array[0]);   \
                    if (!_aux) {                                  \
                        /* error checking code ... */             \
                        ERR("Error growing array " #_array "\n"); \
                    } else {                                      \
                        _array = _aux;                            \
                    }                                             \
               }                                                  \
           } while (0)

later, I define an array by using the following variables:

    MyCellType *A     = NULL;  /* pointer to cell type */
    size_t      A_len = 0,     /* no elements, empty array */
                A_cap = 0;
#define ARRAY_A_GROW_INCREMENT        (20) /* NUMBER OF ELEMENTS \
                                            * TO GROW IN CASE OF NEED */
    ...
    /* ASSUME I NEED TO GROW THE ARRAY FOR 3 ELEMENTS */
    DYNARRAY_GROW(MyType, A, 3, ARRAY_A_GROW_INCREMENT);
    A[A_len++] = first_element;
    A[A_len++] = second_element;
    A[A_len++] = third_element;
    /* if A has need to grow, the number of new cells given to the array
     * is not 3, but the value of ARRAY_A_GROW_INCREMENT (in this case 20)
     * so you save calls to realloc() */

There's a drawback, although (but this also applies to any kind of array you can have in this manner):

  • in the reallocation, it is possible that a new memory segment is completely allocated, and all the array contents to be moved to another place in memory. This makes that any other pointer reference that points into the array to be invalid from the reallocation time onwards... and it has been source of some errors I have learned the bad way. Always think that the elements can move, so be careful with pointers that happen to point to elements inside the array (this includes the pointers that are themselves inside the array)
  • If you test your code with a C++ compiler (let's say you use GTest or similar) then you need to cast the realloc() call return value, as the void * is not assignment compatible with any other type in that language, as C is. So, in that case, substitute the call to realloc to show as:
_cell_type *_aux = (_cell_type *) realloc(...