Expanding the size of an array in C?

Started by
15 comments, last by LessBread 17 years, 6 months ago
blah
Advertisement
Arrays are continuous in memory, so can't be resized. Arrays however have O(1) access time, so this is the advantage of that.

Vectors are resizable, but are slower than arrays.

If you have to resize your array, the only way to do it is create a new array of the new size, then copy over all the data from the old array. By the sounds of it, your resize array function is a one off cost that rarely needs to be done, so this would be acceptable, but know that it is usually a computationaly expensive action.
Check out realloc().

#include <stdlib.h>;#include <stdio.h>int main(){   /* Get a pointer to some memory of an adequate size for 16x16 copies      of a struct MapFormat. Note that no cast is needed as malloc returns      void*. */    if(!struct MapFormat *Map = malloc(16 * 16 * sizeof(struct MapFormat)))    {        printf("Insufficient memory for allocation. Terminating.");        exit(1); // Return 1 as an error value    }        // Do whatever with Map    if(!Map = realloc(Map, 128 * 128 * sizeof(struct MapFormat)))    {        printf("Insufficient memory for reallocation. Terminating.");        exit(1);    }    free(Map);}


EDIT: Tidied code up: checking for NULL, freeing Map.
[TheUnbeliever]
You can't resize an array in C, their size is set at compile time.

You can have a dynamically-sized array-like memory region, but you have to use memory allocation. Master it and move on. Don't let the technology master you. You will be all the happier for it.

Stephen M. Webb
Professional Free Software Developer

It is true, you absolutely cannot resize a "vanilla" array. However, you could use a linked list or a vector, both of which can be resized and neither of which is all that difficult to use.
There was a saying we had in college: Those who walk into the engineering building are never quite the same when they walk out.
You cannot resize an array that is statically declared like your code sample.

You CAN resize a heap-allocated block of memory. However, you cannot use two-dimensional syntax, so you have to calculate the address yourself.

Contrary to what Gullanian said, there is no speed difference between statically declared arrays, and arrays-in-vectors.

Something like this:

struct Array {  MapFormat * element;  size_t width;  size_t height;};void init_array(Array * a, size_t width, size_t height) {  a->element = (MapFormat *)calloc(sizeof(MapFormat), width*height);  a->width = width;  a->height = height;}MapFormat * get_element(Array const * a, size_t x, size_t y) {  if (x >= a->width) return NULL;  if (y >= a->height) return NULL;  return a->element + x + y * a->width;}void resize_array(Array * a, size_t nuWidth, size_t nuHeight) {  MapFormat * nuElem = (MapFormat *)calloc(sizeof(MapFormat), width*height);  for (size_t y = 0; y < min(a->height, nuHeight); ++y) {    for (size_t x = 0; x < min(a->width, nuWidth); ++x) {      nuElem[x + y * nuWidth] = a->element[x + y * a->width];    }  }  free(a->element);  a->element = nuElem;  a->width = nuWidth;  w->height = nuHeight;}

enum Bool { True, False, FileNotFound };

.

It looks like you want to load a map during runtime. Why not include a file header that declares the size of the map, and then allocate however much you need?
We''re sorry, but you don''t have the clearance to read this post. Please exit your browser at this time. (Code 23)
Quote:Original post by medevilenemy
It is true, you absolutely cannot resize a "vanilla" array. However, you could use a linked list or a vector, both of which can be resized and neither of which is all that difficult to use.


Well... strictly speaking you cannot resize a stack allocated array:

int foo[5];

You can always resize a heap allocated array (forgive any poor ansi c syntax, been in C++ too long):

int *foo = (int*)malloc( sizeof(int) * 5 );
foo = (int*)realloc( foo, sizeof(int) * 10 );

One mighty source of confusion is that you cannot have classic multi-dimensional arrays on the heap. But you can easily "fake" them:

int *foo = (int*)malloc( sizeof(int) * width * height );

//to simulate foo[x][y]
foo[ y * height + x ];

Just ALWAYS remember to free any memory you malloc.

-me
Quote:Original post by hplus0603
You cannot resize an array that is statically declared like your code sample.

You CAN resize a heap-allocated block of memory. However, you cannot use two-dimensional syntax, so you have to calculate the address yourself.

[emphesis added]


While multi-dimensional allocations are not supported directly, it is possible, though not straight forward, to simulate them.

To allocate a HxW array of ints -- outined briefly:
int** array = malloc(sizeof(int *) * H);int* rows = malloc(sizeof(int) * W * H);for(i = 0; i < H; i++)  array = rows + (i * W);


I don't have a compiler to test this in front of me, however this should be the gist of how it works. To the compiler, a statically-defined multi-dimensional array acts just an array of arrays anyhow, so allocating one manually provides the same results, though it does take a few extra steps and a little more memory.

That said, taking into account that you admit to your shortcomings with memory allocation, its much easier to allocate a single contigious block of memory and to calculate the given row-column position yourself; you can even write a generic function to do so. In this way, you will have 1 allocation, 1 de-allocation, and only 1 chance for a dangling pointer (this simulated multi-dimensional array above is 2, 2, and H+1 respectively.) Calculating the address yourself is also likely faster as it requires one less look-up, yielding one less chance for a cache-miss and keeping your memory accesses localized (good for your cache.) This is the approach I recommend.

The "Easy Way Out", if you know the maximum size of the array and the memory requirements aren't too high, is to simply statically allocate an array large enough for the biggest possible map, but only fill what you need. Stylistically this is bad, but it will work from a practical standpoint. A 256x256 array of integers, for example, is only 256KB (a quarter of a megabyte), and memory is not a limiting factor today like it used to be in the past.

Back in my DOS programming days I had to write a paging system for my RPG engine because I wanted a 4-layer map that could be up to 256x256 tiles. Each layer was a full 64k (using 8bit indices) for a total of 256k for a single map. This was back in the 16bit days, and your application (after DOS, drivers and other services loaded) had about 384-512 K to play in... A Traditional, static approach would have left me 128-256 K for all my code, graphics, scripts, sounds and other data. Clearly this was too limiting so the paging system was born. Today there's little reason to worry too much about a measly 256K - unless you're on the GBA, DS, or some other older, limited platform.

throw table_exception("(? ???)? ? ???");

This topic is closed to new replies.

Advertisement