Jump to content
  • Advertisement
Sign in to follow this  
Kada2k6

Expanding the size of an array in C?

This topic is 4361 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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;
}

Share this post


Link to post
Share on other sites
Hidden
Thank you for your quick answers! I guess the solution I was looking for was similiar to the one TheUnbeliever provided, so thanks a lot for that. I will try it out right away. Thanks to all your others as well for explaining!

Share this post


Link to post
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?

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!