1

I am new to C language (coming from java) and wondering what is a better approach in my situation. I am programming a game and in the function where i generate the moves, i want to return some pointer to an array of structs (a Move is represented by a struct).

Because i don't know in advance what will be the array size, i thought about starting with an empty array an than resize it every time i want to add a move (by realloc(size+1)). but i wonder if it is more optimal to just set an initial size and if i need to,just double the size. what is the better approach performance wize?

Thank you!

6
  • 3
    Clearly the double size one. Commented Aug 23, 2013 at 6:09
  • 1
    Doubling is more efficient, thats what vector does i think Commented Aug 23, 2013 at 6:09
  • even if will be some waisted space? Commented Aug 23, 2013 at 6:09
  • @user2030118 it is your player moves, there should not be so many.. Commented Aug 23, 2013 at 6:10
  • Do you keep on adding moves to the array or is it on a per-turn basis? Commented Aug 23, 2013 at 6:19

6 Answers 6

2

Calling realloc many times would be inefficient. So adding one memory size is a bad idea. Double the size and when you are done and get the exact size you wanted for storing the data you can realloc down to that size. That should take care of wasted memory. But realloc down only at the end when you think you don't need to to increase anymore.

Depending on the particular situation and your implementation if you think doubling is bit too much when the total memory allocated becomes big you can add checks to incrementally add memory. Something like

if (memory_allocated < 100)
   //realloc to double size
else
  //realloc 10 more

The numbers above are arbitrary and you can choose better ones. But use this if doubling the memory is a huge concern. Otherwise doubling and reallocing down to exact is a good enough solution.

Sign up to request clarification or add additional context in comments.

5 Comments

I'd go one step further: don't use realloc() to shrink the array! That memory will be needed later anyway.
@H2CO3 That would be dependent on the implementation. I don't know what is stored and if that is temporary only. Suppose he shrinks the data added then the doubled memory in an earlier iteration can become a memory hog. Shrinking down when you are done can take care of memory hogging. But that obviously depends on the particular implementation.
Hum, as malloc and realloc use pagination, does it really matter ?
@H2CO3 Could you answer what DCMaxxx said? I don't know about that.
@DCMaxxx It does, since the algorithms used by the allocator functions are still complex and slow. So one would benefit from calling realloc() lesser times.
2

Apart from doubling the array size using realloc to improve the allocation performance, I'd ask if you really need O(1) access time to each of the Move items. If not you could also use a list instead, like:

typedef struct Move Move;
struct Move {
    /* your stuff here */
    Move *next;
};

With this in mind, you could add a new Move item to the lists head or tail each time you create a new one. But here you'd end up with O(n) access time for random access to the Move items.

3 Comments

But even then, you could create a "cache array" to store the address of each element. But then you must be sure that this cache is updated every time the linked list changes. Besides, it would be feasible to combine the 2 concepts: make a linked list of arrays. This could be especially helpful if data are added in chunks: now I add 10 entries, then I add 40, then it might be helpful to add a structure which consists of a next pointer, a count value, maybe a size value (if the size of the memory block matters) and a number of elements.
yes,i also thought about this solution(linked list). i also consider it
Linked list is significantly slower than resizable arrays most of the time because of poor locality of reference. Use linked list only when you need to frequently insert in the middle or front.
1

You could double. But if you are concerned about the time and wasted space, you need to know the distribution of the number of moves. That is, what percent of the time are there 1 moves, 2 moves, etc. Then a method might be clearer. Such as double when number of moves is <= 100, but add 20 for greater than 100.

Initially, write code into your game that tracks these stats and adjust your method accordingly.

Comments

1

suppose you have an array of n elements,and now it is full. everytime you call realloc(), every elements will be moved to a new space.

realloc(size+1):

the sum of moves is 1+2+...+n = O(n^2)

(even if it begins as k+k+1...+n, it turns out to be O(n^2), where k is the original space you malloc)

realloc(size*2) even if the original space is just one:

the sum of moves is n*(1/2+1/4+...+1/(2^logn)),(2^logn = n) and the sum's upper bound is 2n, that's to say, O(n).

it's clear that, when the number of total element is quite few, they are almost same.But if the n is large, the double one is more efficient.

by the way, the one which double the size when array is full,is a popular implement of many dynamic array.

Comments

0

Increasing by constant amount will lead to each insertion to cost O(n), therefore inserting n elements will have time complexity of O(n²).

The amortized cost of inserting a single element when you increase the allocation by a constant factor is O(1), which means O(n) for insertion of n elements. You don't need to double every time, allocating just 25 % or 20 % or just 15 percent more at most will overallocate that 15 %, and you will still get the O(1) amortized cost per insertion. With 15 % say, the O(1) will have a higher constant factor, but on average will now overallocate much less than with 100 % increment every time the buffer is full.

Comments

-1

No contest. Choose an arbitrary size and double it each time you need to allocate more memory. The function calls to realloc() for every single struct you need to add would cause your program to be slow.

realloc() is also expensive. Every time you call it, you're going to use a new block of memory on the heap. realloc() does free the originally allocated block when the new memory is successfully allocated; however, this leads to heap fragmentation and you run the risk of running out of contiguous memory to allocate even though there's plenty of free memory.

Finally, every time you call realloc(), you run the risk of the memory allocation failing. Why not minimize the risk by calling it as few times as possible?

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.