Related
I need to declare an array of structures with size symbolnum, but because symbolnum is variable C will produce an error when i write the following code:
extern int symbolnum;
struct SymbTab stab[symbolnum];
I already tried:
extern int symbolnum;
const int size = symbolnum;
struct SymTab stab[size];
Is there a way to achieve this without using dynamic memory allocation functions like malloc() or initializing the size of array using a very big number?
The size of global arrays must be fixed at compile time. VLAs are only allowed inside of functions.
If the value of symbolnum isn't known until runtime, you'll need to declare stab as a pointer type and allocate memory for it dynamically.
Alternately, if the array doesn't take up more than a few 10s of KB, you can define the VLA in the main function and set a global pointer to it.
C11 and later permit variable-length arrays as an optional feature. C99 permitted them as a mandatory feature. However, in no case are VLAs permitted at file scope, which appears to be what you are trying to achieve.
And file-scope VLAs wouldn't make sense in light of C semantics anyway. Objects declared at file scope have static storage duration, meaning that they come into existence at or before the beginning of program execution, and live until program termination. That means the array length is needed before the variable can take anything other than its initial value (which is zero or an integer constant expression), so one might as well just use that initial value directly.
Additionally, some C implementations (notably MSVC) never implemented VLAs even when C99 was the current standard, and have no intention to do so now that the feature is optional in the current standard.
So,
Is there a way to achieve this without using dynamic memory allocation
functions like malloc() or initializing the size of array using a very
big number?
It depends a bit on your exact needs (and on your C implementation), but likely not. One possibility would be to use a local VLA in main(), or in some other function whose execution encompasses the whole need for the array. If your C implementation supports it them you could declare a VLA there, and pass around a pointer to that. But note well that if the upper bound on the number of elements you need is really "a very large number" then this is unlikely to be suitable. VLAs are typically allocated on the stack, which puts a relatively tight bound on how large they can be.
"Is there a way to achieve this without using dynamic memory allocation functions like malloc() or initializing the size of array
using a very big number?"
If you can use variable length array (VLA), then yes it can be done. The following illustrates one way...
With a struct definition in global space, (eg, top of .c file, or in .h file) local array instances of that struct can be created using a VLA, keeping in mind the stipulations mentioned in the link for using VLA. The VLA struct array can then be passed as a function parameter, to either be used in the called function, or to be updated and returned, just as any other function parameter is used. Here is a simple example:
//define either at top of .c file in file global space
//or in a header file that is included in any .c. Then
//the typedef num_s can be used to create instances where needed
//
typedef struct SymbTab{
int iVal;
double dVal;
} SymbTab_s;
void populate_struct(size_t symbolnum, SymbTab_s *stab);
int main(void)
{
size_t symbolnum = 0;//(using size_t). note, as you describe, this
//comes after flex analysis normally, but for
//this demo user input is used for simple
// example of dynamically sizing array.
printf("Enter symbolnum of struct array:\n");
scanf("%zu", &symbolnum);
SymbTab_s stab[symbolnum]; //dynamically sized array of SymbTab_s
memset(stab, 0, sizeof(SymbTab_s) * symbolnum); //initialize new array
populate_struct(symbolnum, stab); //pass as function argument and update values
//demo updated values
for(int i=0; i < symbolnum; i++)
{
printf("%d, %lf\n", stab[i].iVal, stab[i].dVal);
}
return 0;
}
//simple function to demo form of parameters
//note size parameter is passed first
void populate_struct(size_t symbolnum, SymbTab_s *stab)
{
for(int i=0; i < symbolnum; i++)
{
stab[i].iVal = i;
stab[i].dVal = 1.0*i;
}
}
This question already has answers here:
Do I really need malloc?
(2 answers)
Closed 2 years ago.
As far as I know, the C compiler (I am using GCC 6) will scan the code in order to:
Finding syntax issues;
Allocating memory to the program (Static allocation concept);
So why does this code work?
int main(){
int integers_amount; // each int has 4 bytes
printf("How many intergers do you wanna store? \n");
scanf("%d", &integers_amount);
int array[integers_amount];
printf("Size of array: %d\n", sizeof(array)); // Should be 4 times integer_amount
for(int i = 0; i < integers_amount; i++){
int integer;
printf("Type the integer: \n");
scanf("%d", &integer);
array[i] = integer;
}
for(int j = 0; j < integers_amount; j++){
printf("Integer typed: %d \n", array[j]);
}
return 0;
}
My point is:
How does the C compiler infer the size of the array during compilation time?
I mean, it was declared but its value has not been informed just yet (Compilation time). I really believed that the compiler allocated the needed amount of memory (in bytes) at compilation time - That is the concept of static allocation matter of fact.
From what I could see, the allocation for the variable 'array' is done during runtime, only after the user has informed the 'size' of the array. Is that correct?
I thought that dynamic allocation was used to use the needed memory only (let's say that I declare an integer array of size 10 because I don't know how many values the user will need to hold there, but I ended up only using 7, so I have a waste of 12 bytes).
If during runtime I have those bytes informed I can allocate only the memory needed. However, it doesn't seem to be the case because from the code we can see that the array is only allocated during runtime.
Can I have some help understanding that?
Thanks in advance.
How does the C compiler infer the size of the array during compilation time?
It's what's called a variable length array or for short a VLA, the size is determined at runtime but it's a one off, you cannot resize anymore. Some compilers even warn you about the usage of such arrays, as they are stored in the stack, which has a very limited size, it can potencially cause a stackoverflow.
From what I could see, the allocation for the variable 'array' is done during runtime, only after the user has informed the 'size' of the array. Is that correct?
Yes, that is correct. That's why these can be dangerous, the compiler won't know what is the size of the array at compile time, so if it's too large there is nothing it can do to avoid problems. For that reason C++ forbids VLA's.
let's say that I declare an integer array of size 10 because I don't know how many values the user will need to hold there, but I ended up only using 7, so I have a waste of 12 bytes
Contrary to fixed size arrays, a variable length array size can be determined at runtime, but when its size is defined you can no longer change it, for that you have dynamic memory allocation (discussed ahead) if you are really set on having the exact size needed, and not one byte more.
Anyway, if you are expecting an outside value to set the size of the array, odds are that it is the size you need, if not, well there is nothing you can do, aside from the mentioned dynamic memory allocation, in any case it's better to have a little more wasted space than too little space.
Can I have some help understanding that?
There are three concepts I find relevant to the discussion:
Fixed size arrays, i.e. int array[10]:
Their size defined at compile time, they cannot be resized and are useful if you already know the size they should have.
Variable length arrays, i.e. int array[size], size being a non constant variable:
Their size is defined at runtime, but can only be set once, they are useful if the size of the array is dependant on external values, e.g. a user input or some value retrived from a file.
Dynamically allocated arrays: i.e. int *array = malloc(sizeof *arr * size), size may or may not be a constant:
These are used when your array will need to be resized, or if it's too large to store in the stack, which has limited size. You can change its size at any point in your code using realloc, which may simply resize the array or, as #Peter reminded, may simply allocate a new array and copy the contents of the old one over.
Variables defined inside functions, like array in your snippet (main is a function like any other!), have "automatic" storage duration; typically, this translates to them being on the "stack", a universal concept for a first in/last out storage which gets built and unbuilt as functions are entered and exited.
The "stack" simply is an address which keeps track of the current edge of unused storage available for local variables of a function. The compiler emits code for moving it "forward" when a function is entered in order to accommodate the memory needs of local variables and to move it "backward" when the program flow leaves the function (the double quotes are there because the stack may as well grow towards smaller addresses).
Typically these stack adjustments upon entering into and returning from functions are computed at compile time; after all, the local variables are all visible in the program code. But principally, nothing keeps a program from changing the stack pointer "on the fly". Very early on, Unixes made use of this and provided a function which dynamically allocates space on the stack, called alloca(). The FreeBSD man page says: "The alloca() function appeared in Version 32V AT&T UNIX"ยด(which was released in 1979).
alloca behaves very much like alloc except that the storage is lost when the current function returns, and that it underlies the usual stack size restrictions.
So the first part of the answer is that your array does not have static storage duration. The memory where local variables will reside is not known at compile time (for example, a function with local variables in it may or may not be called at all, depending on run-time user input!). If it were, your astonishment would be entirely justified.
The second part of the answer is that array is a variable length array, a fairly new feature of the C programming language which was only added in 1999. It declares an object on the stack whose size is not known until run time (leading to the anti-paradigmatic consequence that sizeof(array) is not a compile time constant!).
One could argue that variable length arrays are only syntactic sugar around an alloca call; but alloca is, although widely available, not part of any standard.
I understand what variable length arrays are and how they are implemented. This question is about why they exist.
We know that VLAs are only allowed within function blocks (or prototypes) and that they basically cannot be anywhere but on the stack (assuming the normal implementation): C11, 6.7.6.2-2:
If an identifier is declared as having a variably modified type, it shall be an ordinary
identifier (as defined in 6.2.3), have no linkage, and have either block scope or function
prototype scope. If an identifier is declared to be an object with static or thread storage
duration, it shall not have a variable length array type.
Let's take a small example:
void f(int n)
{
int array[n];
/* etc */
}
there are two cases that need to be taken care of:
n <= 0: f has to guard against this, otherwise the behavior is undefined: C11, 6.7.6.2-5 (emphasis mine):
If the size is an expression that is not an integer constant expression: if it occurs in a
declaration at function prototype scope, it is treated as if it were replaced by *; otherwise,
each time it is evaluated it shall have a value greater than zero. The size of each instance
of a variable length array type does not change during its lifetime. Where a size
expression is part of the operand of a sizeof operator and changing the value of the
size expression would not affect the result of the operator, it is unspecified whether or not
the size expression is evaluated.
n > stack_space_left / element_size: There is no standard way of finding how much stack space is left (since there is no such thing as stack so long as the standard is concerned). So this test is impossible. Only sensible solution is to have a predefined maximum possible size for n, say N, to make sure stack overflow doesn't occur.
In other words, the programmer must make sure 0 < n <= N for some N of choice. However, the program should work for n == N anyway, so one might as well declare the array with constant size N rather than variable length n.
I am aware that VLAs were introduced to replace alloca (as also mentioned in this answer), but in effect they are the same thing (allocate variable size memory on stack).
So the question is why did alloca and consequently VLA exist and why weren't they deprecated? The only safe way to use VLAs seem to me to be with a bounded size in which case taking a normal array with the maximum size is always a viable solution.
For reasons that are not entirely clear to me, almost every time the topic of C99 VLA pops up in a discussion, people start talking predominantly about the possibility of declaring run-time-sized arrays as local objects (i.e. creating them "on the stack"). This is rather surprising and misleading, since this facet of VLA functionality - support for local array declarations - happens to be a rather auxiliary, secondary capability provided by VLA. It does not really play any significant role in what VLA can do. Most of the time, the matter of local VLA declarations and their accompanying potential pitfalls is forced into the foreground by VLA critics, who use it as a "straw man" intended to derail the discussion and bog it down among barely relevant details.
The essence of VLA support in C is, first and foremost, a revolutionary qualitative extension of the language's concept of type. It involves the introduction of such fundamentally new kind of types as variably modified types. Virtually every important implementation detail associated with VLA is actually attached to its type, not to the VLA object per se. It is the very introduction of variably modified types into the language that makes up the bulk of the proverbial VLA cake, while the ability to declare objects of such types in local memory is nothing more than a insignificant and fairly inconsequential icing on that cake.
Consider this: every time one declares something like this in one's code
/* Block scope */
int n = 10;
...
typedef int A[n];
...
n = 5; /* <- Does not affect `A` */
size-related characteristics of the variably modified type A (e.g. the value of n) are finalized at the exact moment when the control passes over the above typedef-declaration. Any changes in the value of n made further down the line (below this declaration of A) don't affect the size of A. Stop for a second and think about what it means. It means that the implementation is supposed to associate with A a hidden internal variable, which will store the size of the array type. This hidden internal variable is initialized from n at run time when the control passes over the declaration of A.
This gives the above typedef-declaration a rather interesting and unusual property, something we haven't seen before: this typedef-declaration generates executable code (!). Moreover, it doesn't just generate executable code, it generates critically important executable code. If we somehow forget to initialize the internal variable associated with such typedef-declaration, we'll end up with a "broken"/uninitialized typedef alias. The importance of that internal code is the reason why the language imposes some unusual restrictions on such variably modified declarations: the language prohibits passing control into their scope from outside of their scope
/* Block scope */
int n = 10;
goto skip; /* Error: invalid goto */
typedef int A[n];
skip:;
Note once again that the above code does not define any VLA arrays. It simply declares a seemingly innocent alias for a variably modified type. Yet, it is illegal to jump over such typedef-declaration. (We are already familiar with such jump-related restrictions in C++, albeit in other contexts).
A code-generating typedef, a typedef that requires run-time initialization is a significant departure from what typedef is in the "classic" language. (It also happens to pose a significant hurdle of the way of adoption of VLA in C++.)
When one declares an actual VLA object, in addition to allocating the actual array memory the compiler also creates one or more hidden internal variables, which hold the size(s) of the array in question. One has to understand that these hidden variables are associated not with the array itself, but rather with its variably modified type.
One important and remarkable consequence of this approach is as follows: the additional information about array size, associated with a VLA, is not built directly into the object representation of the VLA. It is actually stored besides the array, as "sidecar" data. This means that object representation of a (possibly multidimensional) VLA is fully compatible with object representation of an ordinary classic compile-time-sized array of the same dimensionality and the same sizes. For example
void foo(unsigned n, unsigned m, unsigned k, int a[n][m][k]) {}
void bar(int a[5][5][5]) {}
int main(void)
{
unsigned n = 5;
int vla_a[n][n][n];
bar(a);
int classic_a[5][6][7];
foo(5, 6, 7, classic_a);
}
Both function calls in the above code are perfectly valid and their behavior is fully defined by the language, despite the fact that we pass a VLA where a "classic" array is expected, and vice versa. Granted, the compiler cannot control the type compatibility in such calls (since at least one of the involved types is run-time-sized). However, if desired, the compiler (or the user) has everything necessary to perform the run-time check in debug version of code.
(Note: As usual, parameters of array type are always implicitly adjusted into parameters of pointer type. This applies to VLA parameter declarations exactly as it applies to "classic" array parameter declarations. This means that in the above example parameter a actually has type int (*)[m][k]. This type is unaffected by the value of n. I intentionally added a few extra dimensions to the array to maintain its dependence on run-time values.)
Compatibility between VLA and "classic" arrays as function parameters is also supported by the fact that the compiler does not have to accompany a variably modified parameter with any additional hidden information about its size. Instead, the language syntax forces the user to pass this extra information in the open. In the above example the user was forced to first include parameters n, m and k into function parameter list. Without declaring n, m and k first, the user would not have been able to declare a (see also the above note about n). These parameters, explicitly passed into the function by the user, will bring over the information about the actual sizes of a.
For another example, by taking advantage of VLA support we can write the following code
#include <stdio.h>
#include <stdlib.h>
void init(unsigned n, unsigned m, int a[n][m])
{
for (unsigned i = 0; i < n; ++i)
for (unsigned j = 0; j < m; ++j)
a[i][j] = rand() % 100;
}
void display(unsigned n, unsigned m, int a[n][m])
{
for (unsigned i = 0; i < n; ++i)
for (unsigned j = 0; j < m; ++j)
printf("%2d%s", a[i][j], j + 1 < m ? " " : "\n");
printf("\n");
}
int main(void)
{
int a1[5][5] = { 42 };
display(5, 5, a1);
init(5, 5, a1);
display(5, 5, a1);
unsigned n = rand() % 10 + 5, m = rand() % 10 + 5;
int (*a2)[n][m] = malloc(sizeof *a2);
init(n, m, *a2);
display(n, m, *a2);
free(a2);
}
This code is intended to draw your attention to the following fact: this code makes heavy use of valuable properties of variably modified types. It is impossible to implement elegantly without VLA. This is the primary reason why these properties are desperately needed in C to replace the ugly hacks that were used in their place previously. Yet at the same time, not even a single VLA is created in local memory in the above program, meaning that this popular vector of VLA criticism is not applicable to this code at all.
Basically, the two last examples above is a concise illustration of what the point of VLA support is.
Looking at the comments and the answers, it seems to me that VLAs are useful when you know that normally your input is not too big (similar to knowing your recursion is probably not too deep), but you don't actually have an upper bound, and you would generally ignore the possible stack overflow (similar to ignoring them with recursion) hoping they don't happen.
It may actually be not an issue altogether either, for example if you have unlimited stack size.
That said, here's another use for them I have found which doesn't actually allocate memory on stack, but makes working with dynamic multi-dimensional arrays easier. I'll demonstrate by a simple example:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
size_t n, m;
scanf("%zu %zu", &n, &m);
int (*array)[n][m] = malloc(sizeof *array);
for (size_t i = 0; i < n; ++i)
for (size_t j = 0; j < m; ++j)
(*array)[i][j] = i + j;
free(array);
return 0;
}
Despite of all the points you mentioned about VLA, the best part of VLA is that the compiler automatically handles the storage management and the complexities of index calculations of arrays whose bounds are not compile-time constants.
If you want local dynamic memory allocation then the only option is VLA.
I think this could be the reason that VLA is adopted in C99 (optional on C11).
One thing I want to clear that is there are some remarkable differences between alloca and VLA. This post points out the differences:
The memory alloca() returns is valid as long as the current function persists. The lifetime of the memory occupied by a VLA is valid as long as the VLA's identifier remains in scope.
You can alloca() memory in a loop for example and use the memory outside the loop, a VLA would be gone because the identifier goes out of scope when the loop terminates.
Your argument seems to be that since one has to bound check the size of the VLA, why not just allocate the maximum size and be done with the runtime allocation.
That argument overlooks the fact that memory is a limited resource in the system, shared between many processes. Memory wastefully allocated in one process is not available to any other (or perhaps it is, but at the expense of swapping to disk).
By the same argument we would not need to malloc an array at run time when we could statically allocate the maximum size that could be needed. In the end heap exhaustion is only slightly preferable to stack overflow.
Stack allocation (a so VLA allocation) is VERY fast, just requires a quick modification to the stack pointer (typically a single CPU instuction). No need for expensive heap allocation/deallocation.
But, why not just use a constant size array instead?
Let suppose you are writing a high performance code, and you need a variable size buffer, let say between 8 and 512 elements. You can just declare a 512 elements array, but if most of the times you only require 8 elements then overallocating can affect the performance due to affecting the cache locality in the stack memory. Now imagine this function has to be called millions of times.
Another example, imagine your function (with a local VLA) is recursive, you know beforehand that in any moment the total size of all recursively allocated VLAs is limited (i.e. the arrays have variable size, but the sum of all sizes is bounded). In this case, if you use the maximun possible size as fixed local array size you may allocate much more memory than otherwise required, making your code slower (due to cache misses) and even causing stack overflows.
VLAs do not have to allocate any memory or only stack memory. They are very handy in many aspects of programming.
Some examples
Used as function parameters.
int foo(size_t cols, int (*array)[cols])
{
//access as normal 2D array
prinf("%d", array[5][6]);
/* ... */
}
Allocate 2D(or more) array dynamically
inr foo(size_t rows, size_t cols)
{
int (*array)[cols] = malloc(rows * sizeof(*array));
/* ... */
//access as normal 2D array
prinf("%d", array[5][6]);
/* ... */
When shall i use malloc instead of normal array definition in C?
I can't understand the difference between:
int a[3]={1,2,3}
int array[sizeof(a)/sizeof(int)]
and:
array=(int *)malloc(sizeof(int)*sizeof(a));
In general, use malloc() when:
the array is too large to be placed on the stack
the lifetime of the array must outlive the scope where it is created
Otherwise, use a stack allocated array.
int a[3]={1,2,3}
int array[sizeof(a)/sizeof(int)]
If used as local variables, both a and array would be allocated on the stack. Stack allocation has its pros and cons:
pro: it is very fast - it only takes one register subtraction operation to create stack space and one register addition operation to reclaim it back
con: stack size is usually limited (and also fixed at link time on Windows)
In both cases the number of elements in each arrays is a compile-time constant: 3 is obviously a constant while sizeof(a)/sizeof(int) can be computed at compile time since both the size of a and the size of int are known at the time when array is declared.
When the number of elements is known only at run-time or when the size of the array is too large to safely fit into the stack space, then heap allocation is used:
array=(int *)malloc(sizeof(int)*sizeof(a));
As already pointed out, this should be malloc(sizeof(a)) since the size of a is already the number of bytes it takes and not the number of elements and thus additional multiplication by sizeof(int) is not necessary.
Heap allocaiton and deallocation is relatively expensive operation (compared to stack allocation) and this should be carefully weighted against the benefits it provides, e.g. in code that gets called multitude of times in tight loops.
Modern C compilers support the C99 version of the C standard that introduces the so-called variable-length arrays (or VLAs) which resemble similar features available in other languages. VLA's size is specified at run-time, like in this case:
void func(int n)
{
int array[n];
...
}
array is still allocated on the stack as if memory for the array has been allocated by a call to alloca(3).
You definately have to use malloc() if you don't want your array to have a fixed size. Depending on what you are trying to do, you might not know in advance how much memory you are going to need for a given task or you might need to dynamically resize your array at runtime, for example you might enlarge it if there is more data coming in. The latter can be done using realloc() without data loss.
Instead of initializing an array as in your original post you should just initialize a pointer to integer like.
int* array; // this variable will just contain the addresse of an integer sized block in memory
int length = 5; // how long do you want your array to be;
array = malloc(sizeof(int) * length); // this allocates the memory needed for your array and sets the pointer created above to first block of that region;
int newLength = 10;
array = realloc(array, sizeof(int) * newLength); // increase the size of the array while leaving its contents intact;
Your code is very strange.
The answer to the question in the title is probably something like "use automatically allocated arrays when you need quite small amounts of data that is short-lived, heap allocations using malloc() for anything else". But it's hard to pin down an exact answer, it depends a lot on the situation.
Not sure why you are showing first an array, then another array that tries to compute its length from the first one, and finally a malloc() call which tries do to the same.
Normally you have an idea of the number of desired elements, rather than an existing array whose size you want to mimic.
The second line is better as:
int array[sizeof a / sizeof *a];
No need to repeat a dependency on the type of a, the above will define array as an array of int with the same number of elements as the array a. Note that this only works if a is indeed an array.
Also, the third line should probably be:
array = malloc(sizeof a);
No need to get too clever (especially since you got it wrong) about the sizeof argument, and no need to cast malloc()'s return value.
Why does the array a not get initialized by global variable size?
#include<stdio.h>
int size = 5;
int main()
{
int a[size] = {1, 2, 3, 4, 5};
printf("%d", a[0]);
return 0;
}
The compilation error is shown as
variable-sized object may not be initialized
According to me, the array should get initialized by size.
And what would be the answer if I insist on using global variable (if it is possible)?
In C99, 6.7.8/3:
The type of the entity to be
initialized shall be an array of
unknown size or an object type that is
not a variable length array type.
6.6/2:
A constant expression can be evaluated
during translation rather than runtime
6.6/6:
An integer constant expression
shall have integer type and shall only
have operands that are integer
constants, enumeration constants,
character constants, sizeof
expressions whose results are integer
constants, and floating constants that
are the immediate operands of casts.
6.7.5.2/4:
If the size is an integer constant
expression and the element type has a
known constant size, the array type is
not a variable length array type;
otherwise, the array type is a
variable length array type.
a has variable length array type, because size is not an integer constant expression. Thus, it cannot have an initializer list.
In C90, there are no VLAs, so the code is illegal for that reason.
In C++ there are also no VLAs, but you could make size a const int. That's because in C++ you can use const int variables in ICEs. In C you can't.
Presumably you didn't intend a to have variable length, so what you need is:
#define size 5
If you actually did intend a to have variable length, I suppose you could do something like this:
int a[size];
int initlen = size;
if (initlen > 5) initlen = 5;
memcpy(a, (int[]){1,2,3,4,5}, initlen*sizeof(int));
Or maybe:
int a[size];
for (int i = 0; i < size && i < 5; ++i) {
a[i] = i+1;
}
It's difficult to say, though, what "should" happen here in the case where size != 5. It doesn't really make sense to specify a fixed-size initial value for a variable-length array.
You don't need to tell the compiler what size the array is if you're giving an initializer. The compiler will figure out the size based on how many elements you're initializing it with.
int a[] = {1,2,3,4,5};
Then you can even let the compiler tell you the size by getting the total size of the array in bytes sizeof(a) and dividing it by the size of one element sizeof(a[0]):
int size = sizeof(a) / sizeof(a[0]);
The compiler cannot assume that the value of size is still 5 by the time main() gets control. If you want a true constant in an old-style C project, use:
#define size 5
size is a variable, and C does not allow you to declare (edit: C99 allows you to declare them, just not initialize them like you are doing) arrays with variable size like that. If you want to create an array whose size is a variable, use malloc or make the size a constant.
It looks like that your compiler is not C99 Compliant...speaking of which, which compiler are you using? If it's gcc you need to pass the switch '-std=c99'.... if you are using a pre-C99 compiler, that statement is illegal, if that's the case, do this:
int main() {
int a[5]={1,2,3,4,5};
printf("%d",a[0]);
return 0;
}
In pre-C99 standard compilers, use a constant instead of a variable.
Edit: You can find out more about the C99 standard here... and here....
The compiler needs to know the size of the array while declaring it.
Because the size of an array doesn't change after its declaration.
If you put the size of the array in a variable, you can imagine that the value of that variable will change when the program is executed.
In this case, the compiler will be forced to allocate extra memory to this array.
In this case, this is not possible because the array is a static data structure allocated on the stack.
I hope that this will help.
#include<stdio.h>
/* int size=5; */
#define size 5 /* use this instead*/
/*OR*/
int a[size]={1,2,3,4,5}; /* this*/
int main()
{
int a[size]={1,2,3,4,5};
printf("%d",a[0]);
return 0;
}
int size means that size is a variable and C does not allow variablesize arrays.
I am using VS2008 where using
const int size=5;
allows
int a[size]={1,2,3,4,5};
You cannot create arrays with globally variable size the same reason why you cannot create an array with size determined by a variable in general. The reason is because C++ enables manual memory management, which let's be honest is the reason why we learn this language, and when we allocate memory, we need to keep in mind the advantages and drawbacks of its two types and what we can do with it.
Stack memory literally implements the stack data structure. It has fixed size (a few megabytes as far as I know), and when you put any data on the stack, you push it to the top. Stack fits perfectly for scoped variables that are supposed to only live for a restricted amount of time, which means it will disappear as soon as they see }. Stacks use functions as a unit of grouping all variables, and whenever we call any function (including main), it pushes the total amount of memory this function uses, which is the sum of all variables it allocates. This total size is called stack frame, and it must be constant. Otherwise, if we allocate an array dynamically on the stack:
int size;
scanf("%d", %size);
int array[size];
We don't know how much space we need to reserve for the array and its stack frame responsively, which makes this a forbidden operations. You can, however, initialise it with a constant and constant expression:
constexprt int getSize(int n){
return n * 2; //This can be anything, I just multiplied to get arbitrary value.
}
const int size = 45;
int constantArray[size]; //Works
int constantExpressionArray[getSize(2)]; //Also works
The reason why constant works is because they are always assured to have the same and known size, and furthermore they don't take up space in memory but compilers just substitute all constant calls with their respective values. Constant expresions also are functions that are executed in the compile-time, which means all values must be known, and then it just substitudes the result (that must always be the same) into its call, which assure the compiler in both cases the size of the arrays are going to be the same (45 for the first one and 4 for the second one).
If you want to have an array with size that veries each time you execute it, you should either allocate it dynamically:
int* dynamicArray = new int[variableSize];
or use std::vector:
std::vector<int> dynamicArray(variableSize);
In the latter case it sets variableSize to be the capacity,which is the length of the array it needs to exceed to resize. If you use it responsibly, you will end up simply using the array underneath it and will only suffer from the performance penalties imposed by dynamically allocating memory and jumping between the functions.