开发者

Is it bad practice to declare an array mid-function

开发者 https://www.devze.com 2023-01-02 10:18 出处:网络
in an effort to only ask what I\'m really looking for here... I\'m really only concerned if it\'s considered bad practice or not to declare an array like below where the size could vary. If it is... I

in an effort to only ask what I'm really looking for here... I'm really only concerned if it's considered bad practice or not to declare an array like below where the size could vary. If it is... I would generally malloc() instead.

void MyFunction()
{

    int size;

    //do a bunch of stuff
    size = 10; //but could have been something else
开发者_运维问答    int array[size];

    //do more stuff...

}


Generally yes, this is bad practice, although new standards allow you to use this syntax. In my opinion you must allocate (on the heap) the memory you want to use and release it once you're done with it. Since there is no portable way of checking if the stack is enough to hold that array you should use some methods that can really be checked - like malloc/calloc & free. In the embedded world stack size can be an issue.

If you are worried about fragmentation you can create your own memory allocator, but this is a totally different story.


That depends. The first clearly isn't what I'd call "proper", and the second is only under rather limited circumstances.

In the first, you shouldn't cast the return from malloc in C -- doing so can cover up the bug of accidentally omitting inclusion of the correct header (<stdlib.h>).

In the second, you're restricting the code to C99 or a gcc extension. As long as you're aware of that, and it works for your purposes, it's all right, but hardly what I'd call an ideal of portability.

As far as what you're really asking: with the minor bug mentioned above fixed, the first is portable, but may be slower than you'd like. If the second is portable enough for your purposes, it'll normally be faster.


For your question, I think each has its advantages and disadvantages.

Dynamic Allocation:
Slow, but you can detect when there is no memory to be given to your programmer by checking the pointer.

Stack Allocation:
Only in C99 and it is blazingly fast but in case of stackoverflow you are out of luck.

In summary, when you need a small array, reserve it on the stack. Otherwise, use dynamic memory wisely.


The argument against VLAs runs that because of the absolute badness of overflowing the stack, by the time you've done enough thinking/checking to make them safe, you've done enough thinking/checking to use a fixed-size array:

1) In order to safely use VLAs, you must know that there is enough stack available.

2) In the vast majority of cases, the way that you know there's enough stack is that you know an upper bound on the size required, and you know (or at least are willing to guess or require) a lower bound on the stack available, and the one is smaller than the other. So just use a fixed-size array.

3) In the vast majority of the few cases that aren't that simple, you're using multiple VLAs (perhaps one in each call to a recursive function), and you know an upper bound on their total size, which is less than a lower bound on available stack. So you could use a fixed-size array and divide it into pieces as required.

4) If you ever encounter one of the remaining cases, in a situation where the performance of malloc is unacceptable, do let me know...

It may be more convenient, from the POV of the source code, to use VLAs. For instance you can use sizeof (in the defining scope) instead of maintaining the size in a variable, and that business with dividing an array into chunks might require passing an extra parameter around. So there's some small gain in convenience, sometimes.

It's also easier to miss that you're using a humongous amount of stack, yielding undefined behavior, if instead of a rather scary-looking int buf[1920*1024] or int buf[MAX_IMG_SIZE] you have an int buf[img->size]. That works fine right up to the first time you actually handle a big image. That's broadly an issue of proper testing, but if you miss some possible difficult inputs, then it won't be the first or last test suite to do so. I find that a fixed-size array reminds me either to put in fixed-size checks of the input, or to replace it with a dynamic allocation and stop worrying whether it fits on the stack or not. There is no valid option to put it on the stack and not worry whether it fits...


two points from a UNIX/C perspective -

malloc is only slow when you force it to call brk(). Meaning for reasonable arrays it is the same as allocating stack space for a variable. By the way when you use method #2 (via alloca and in the code libc I have seen) also invokes brk() for huge objects. So it is a wash. Note: with #2 & #1 you still have to invoke directly or indirectly a memset-type call to zero the bytes in the array. This is just a side note to the real issue (IMO):

The real issue is memory leaks. alloca cleans up after itself when the function retruns so #2 is less likely to cause a problem. With malloc/calloc you have to call free() or start a leak.

0

精彩评论

暂无评论...
验证码 换一张
取 消