Search code examples
cdynamic-arrays

C dynamically growing array


I have a program that reads a "raw" list of in-game entities, and I intend to make an array holding an index number (int) of an indeterminate number of entities, for processing various things. I would like to avoid using too much memory or CPU for keeping such indexes...

A quick and dirty solution I use so far is to declare, in the main processing function (local focus) the array with a size of the maximum game entities, and another integer to keep track of how many have been added to the list. This isn't satisfactory, as every list holds 3000+ arrays, which isn't that much, but feels like a waste, since I'll possible use the solution for 6-7 lists for varying functions.

I haven't found any C (not C++ or C#) specific solutions to achieve this. I can use pointers, but I am a bit afraid of using them (unless it's the only possible way).

The arrays do not leave the local function scope (they are to be passed to a function, then discarded), in case that changes things.

If pointers are the only solution, how can I keep track of them to avoid leaks?


Solution

  • I can use pointers, but I am a bit afraid of using them.

    If you need a dynamic array, you can't escape pointers. Why are you afraid though? They won't bite (as long as you're careful, that is). There's no built-in dynamic array in C, you'll just have to write one yourself. In C++, you can use the built-in std::vector class. C# and just about every other high-level language also have some similar class that manages dynamic arrays for you.

    If you do plan to write your own, here's something to get you started: most dynamic array implementations work by starting off with an array of some (small) default size, then whenever you run out of space when adding a new element, double the size of the array. As you can see in the example below, it's not very difficult at all: (I've omitted safety checks for brevity)

    typedef struct {
      int *array;
      size_t used;
      size_t size;
    } Array;
    
    void initArray(Array *a, size_t initialSize) {
      a->array = malloc(initialSize * sizeof(int));
      a->used = 0;
      a->size = initialSize;
    }
    
    void insertArray(Array *a, int element) {
      // a->used is the number of used entries, because a->array[a->used++] updates a->used only *after* the array has been accessed.
      // Therefore a->used can go up to a->size 
      if (a->used == a->size) {
        a->size *= 2;
        a->array = realloc(a->array, a->size * sizeof(int));
      }
      a->array[a->used++] = element;
    }
    
    void freeArray(Array *a) {
      free(a->array);
      a->array = NULL;
      a->used = a->size = 0;
    }
    

    Using it is just as simple:

    Array a;
    int i;
    
    initArray(&a, 5);  // initially 5 elements
    for (i = 0; i < 100; i++)
      insertArray(&a, i);  // automatically resizes as necessary
    printf("%d\n", a.array[9]);  // print 10th element
    printf("%d\n", a.used);  // print number of elements
    freeArray(&a);