c arrays: setting size dynamically? - c

I am new to C programming. I am trying to set the size of the array using a variable but I am getting an error: Storage size of 'array' isn't constant !!
01 int bound = bound*4;
02 static GLubyte vertsArray[bound];
I have noticed that when I replace bounds (within the brackets on line 02) with the number say '20', the program would run with no problems. But I am trying to set the size of the array dynamically ...
Any ideas why I am getting this error ?
thanks much,

You are getting this error because, as the compiler told you, your array size is not constant. In C89/90 version of C language array size has to be a constant. You can't "set the size of the array dynamically". If you need a run-time sized array, you have to either allocate it manually with malloc or use some non-standard compiler-specific approach (like alloca function).
In C99 version of C language support for so called Variable-Length Arrays (VLA) was added. A C99 compiler would accept run-time sized array declaration for an automatic array. Yet even in C99 you can't declare a static array of run-time size, as you are trying to.

To create an array of a non-constant size (i.e. known at compile time), you need to dynamically allocate space for it using malloc() (and correspondingly deallocate it using free() when it is no longer required).
As others have noted, the ability to declare dynamic arrays is available in C99 compliant compilers.

What you want is possible in C99; however, with earlier versions of C, you are stuck calling functions to dynamically allocate memory, e.g. alloca(3) or malloc(3).

use either of these
GLubyte* vertsArray = (GLubyte*) malloc(sizeof(GLubyte) * bound);
GLubyte* vertsArray = new GLubyte[bound];
remember to free the memory when you don't need the object anymore
delete [] vertsArray;
free((void*)vertsArray;
Despite what they say in the comments I still say that you should prefer new instead of malloc if you are not 100% forced to use C. See this link for more information

Related

Dynamically allocating array with the [] operator instead of using malloc?

I am sure this has been asked a million times but I couldn't find an answer that explained it. I have been told to never do this but I haven't really understood why. Why doesn't something like this count as dynamically allocating memory and why is it that bad?
int a;
scanf("%d",&a);
int arr[a];
This is not dynamic allocation but a variable length array.
The lifetime of such an array is its enclosing scope, just like an array with a fixed size, so you don't need to worry about deallocation. These arrays typically reside on the stack, so the size of the stack does put limitations on how big a VLA (or any array) can be.
If you find that a VLA is too big for the stack, you can always fall back to using malloc.
Dynamically allocating array with the [] operator instead of using malloc?
The [] here is used to define an array. [] here, is not an operator.
int arr[a];
I have been told to never do this but i havent really understood why.
This mantra applies to many things in C (and life), do not use until you understand how to use it.
Why doesnt something like this count as dynamically allocating memory
It is dynamically allocating memory allocation, but usually uses a different memory pool and has a different lifetime than via malloc().
... and why is it that bad?
int arr[a]; is a variable length array (VLA) and has the following issues:
Not always available. VLAs supported in C99 and often, but not always, in later versions. Research __STDC_NO_VLA__.
With int a, code is undefined behavior (UB) when a <= 0.
When a is too large, there is no standard mechanism to detect insufficient memory.
VLA better used in controlled smaller size cases.
First of all, let me tell you that this is called variable length array, and it's an optional feature. Better not to rely on this feature (or compiler support).
On the other hand, allocator functions (malloc(), free() and family) are standard compliant and any conforming compiler / library will support these functions.
That said, the differences are mentioned in other answers, primary differences are with scope and portability.
Why doesnt something like this count as dynamically allocating memory
That the size of the object is determined at runtime is not sufficient for dynamic allocation. Dynamic allocation requires direct or indirect use of one of the functions that specifically performs dynamic memory allocation, with malloc, calloc, and realloc being the main examples. Your example ...
int arr[a];
... does not do this, so the object is not dynamically allocated. You arr is a more-or-less ordinary local variable with variable-length array type.
Semantically, dynamically allocated objects have "allocated" storage duration, which means that they exist and retain their last-stored value until explicitly deallocated. Your arr instead has "automatic" storage duration, which means that it ceases to exist when execution of its innermost containing block terminates.
and why is it that bad?
Opinions vary. VLAs were a required feature in C99, but support was made optional in C11. If you use VLAs in your code, then, you limit its portability. C++ does not support them (or at least did not -- I understand that they are now coming to C++, too, and maybe they have already arrived), which may be an issue for some.
However, the main risk cited is that the usual and natural implementation of VLAs is to allocate them on the stack, and stack size is typically a lot more limited than heap space. In a naive example such as yours, it is easy to create a stack overflow, and this may depend on user input, thus making it both difficult to test and a potential security risk.
I do use VLAs in my code from time to time, but usually in ways that are not subject to the stack-busting risk described above. I generally look skeptically on admonitions to "never do that", but indeed I would never write the exact code you present for a production application.
This is an example of a variable length array. Its lifetime is the same as any other auto variable (including fixed-length arrays), so memory for it will be released once you exit its enclosing scope.
Unlike fixed-length arrays, VLAs cannot be declared at file scope (outside of any function) or with the static keyword, nor can they be declared with an initializer. Because of how they are typically managed, they cannot be arbitrarily large. Despite the name, they cannot be resized once they are defined - the "variable" in variable length only means that their size can be different each time they are defined.
VLAs are useful but limited. They're great when you need some temporary working storage that's local to a function and doesn't need to be too big (not much bigger than a megabyte or so).
They were only introduced in C99 and made optional in C11, so support for them may be a little spotty.

is defining size of arrays as a variable enter by user legal?

I thought size of arrays should be constant.I code in VS 2019 and even when I do something like this:
const int size = 5;
int number[size];
I will receive this error expression must have a constant value ,only alternative for using an integer directly for array size ,is using macro define ,otherwise I will receive error.
But in some IDEs like dev ,it is even possible to took size of array as input from user.I also saw people code's here with user defined array size.
So here is my problem :
is it right ,to do this? are there risks and problem for user defined array size?
Variable-length arrays (VLAs) are legal from C99 onwards, although some compilers like GCC will allow them as an extension in older versions too. From C11 onwards, compilers are no longer required to support VLAs and will define __STDC_NO_VLA__ as 1 if they don't support it.
VLAs are inherently risky: either you know the maximum size of your data beforehand, in which case you can allocate a fixed-length array, or you don't, in which case you run the risk of overflowing the stack.
It's worth noting that in C++, variable-length arrays were never part of the standard.
At least in C, const has more the meaning "read-only" than constant.
In C you can use an enumertaion member. The members are treated as constants.
enum { size = 5 };
int number[size];
This works.

Creating a variable-sized array without malloc

I'm writing a program in C which I want to read an array length, and create an array of that size. However, C does not support variable-lengthed arrays, so I was wondering how I could do this. I do not want to change my compiler settings.
I was thinking about somehow using preprocessor directive to my advantage, but I have not been able to do so. Pretty much, I have an integer variable containing my desired size, and I would like to declare the array with 0's. Also, I do not want to use malloc/other dynamic array methods.
This might seem basic, but I have been struggling to do this for some time. If it matters, I am receiving the array size through I/O.
There are several possible solutions, none of which satisfy all of your requirements.
A call to malloc is the obvious solution; that's what it's for. You've said you don't want to use malloc, but you haven't explained why.
C does support variable-length arrays -- more or less. VLAs did not exist in C90, were introduced in C99, and were made optional in C11. So if you want portable code, you can't assume that they're supported. If they are, you can do something like this:
int size;
// get value of size from input
int vla[size];
There are some restrictions. If there isn't enough memory (stack size can be more restrictive than heap size), the behavior is undefined. On the other hand, the same is true for ordinary fixed-size arrays, and VLAs can let you allocate a smaller amount of memory rather than assuming a fixed upper bound. VLAs exist only at block scope, so the object will cease to exist when control leaves the enclosing block (typically when the function returns).
You could define an array (probably at file scope, outside any function definition) that you know is big enough for your data. You'll have to specify some upper bound. For example, you can define int arr[10000]; and then reject any input bigger than 10,000. You could then use an initial subset of that array for your data.
You say you want to create a "variably-sized array", but you "do not want to use malloc/other dynamic array methods". It sounds like you want to create a dynamic array, but you don't want to create a dynamic array. It's like saying you want to drive a screw, but you don't want to use a screwdriver.
May I ask: why are you allergic to malloc()?
The reason I ask is that many attempts to define a safe profile for C propose that malloc is the source of all evil. In that case:
int *arr;
arr = mmap(0, sizeof *arr * N, PROT_READ|PROT_WRITE, MAP_PRIVATE, -1, 0);
What you can do is read the array length, and then generate the source code of a program:
fprintf(outfile, "int main(void) { static int arr[%d]; ...}\n", size);
Then execute the compiler on the generated program (e.g. using the system function), and run the resulting executable.
Any language which supports variable length arrays uses dynamic memory allocation mechanism underneath to implement the functionality. 'C' does not have a syntactic sugar which supports true variable length arrays, but it provides all the mechanics needed to mimic one.
malloc, realloc, free, and others can easily be used to handle dynamic allocations and deallocations for arrays of any size and types of elements. You can allocate data in memory and use a pointer to return the reference to caller functions or pass to other functions. ('C' VLAs on the other hand are of limited use and cannot be returned to the caller if allocated on stack).
So, your best option (unless you are in embedded software development) is to start using 'c' dynamic memory allocation.
However, C does not support variable-lengthed arrays,
Wrong. This is perfectly valid C code:
#include <stdio.h>
int main(void)
{
int size;
scanf("%d", &size);
int arr[size];
}
It's called VLA (variable length array) and has been a part of C since 1999. However, it's optional from C11, but big compilers like clang and gcc will never remove them. At least not in the foreseeable future.

Why use malloc() when I can just define a variable-length array?

I was reading about creating array dynamically in C. So the proper way as described there was:
int n;
scanf("%d", &n);
int *arr = (int*)malloc(n*sizeof(int));
But then I thought if I could just do something like this-
int n, i, sum=0;
scanf("%d", &n);
int arr[n];
And I compiled and ran it without any error. So, my question is why should I use malloc()? Does this have something to do with the old and new C versions?
There are at least five benefits to using malloc over variable length arrays.
Most notably, objects created with malloc persist after execution of the current block ends. This means that such objects can be returned (by pointer) to callers of functions. This use is frequent in real-world applications. Arrays created as variable-length arrays cease to exist when execution of their block ends.
Arrays created with malloc can be resized with realloc. Variable-length arrays cannot be resized.
As of the 2011 C standard, variable-length arrays are optional for C implementations to support. A general-purpose C implementation of any quality will support them, but the fact they are optional means code that is intended to be portable must either not use variable-length arrays or must guard against the lack of support by testing the preprocessor macro __STDC_NO_VLA__ and providing alternate code.
Commonly, variable-length arrays are much more limited in size than arrays allocated with malloc. Variable-length arrays are generally implemented using stack space, and stacks are typically limited to some not-large number of mebibytes (although that can generally be increased when building an executable). For objects created with malloc, gibibytes of memory may be available in modern systems.
If creation of an array does fail with malloc, NULL will be returned, and the programmer can easily write code to detect that and deal with it. If creation of a variable-length array fails, the common behavior is for the operating system to terminate the program with some memory error. (Various C implementations may provide means to intercept this error, but it is considerably more of a nuisance than testing the malloc return value for NULL, and it is not portable.)
And I compiled and run it without any error. So, my question is why should I use malloc() really? Does this have something to do with the old and new C versions?
Stack-allocated arrays are not equivalent to buffers in the free-store (the heap, the memory area that malloc and calloc use).
Assuming the array exists on the stack (which is implied as an automatic-variable) then your array cannot exceed the maximum stack size for your platform. On Linux with pthreads the default is 2 megabytes. The limit is similar on Windows.
Because of scope and object lifetime: pointers to elements in an array that exist on the stack cannot live longer than the array they point into, which means you cannot return pointers to those arrays and elements after the scope they're declared in expires.
VLA arrays are optional in C11. In C++ they're not part of the spec at all (i.e. they're vendor extensions) so your code won't be portable.

Variable Length Array

I would like to know how a variable length array is managed (what extra variables or data structures are kept on the stack in order to have variable length arrays).
Thanks a lot.
It's just a dynamically sized array (implementation-dependent, but most commonly on the stack). It's pretty much like alloca in the old days, with the exception that sizeof will return the actual size of the array, which implies that the size of the array must also be stored somewhere (implementation-dependent as well, but probably on the stack too).
The size of variable length arrays is determined on run-time, instead of compilation time.
The way it's managed depends on the compiler.
GCC, for instance, allocates memory on the stack.But there is no special structure. It's just a normal array, whose size is known at run-time.
alternatively you could use some containers, e.g. ArrayList in java or vector in c/c++

Resources