When I try to run this, it gives me an error saying that the value in variable a
isn't constant. That doesn't make sense to me because I explicitly made the variable a
constant. Does the size of an array have to more constant than that? Meaning, only #define a 5
, or initializing it as int arr[5]
or using malloc
? What is wrong with what I did?
int main{
const int a = 5;
int i;
int arr [a];
for (i = 0; i < 5; i++) {
arr[i] = i * 2;
}
printf("%d", arr[1]);
return 0;
}
In C, const
should be read as read-only. It doesn't define a compile time.
const int a = 5;
Here a
, is not a constant expression as required by the C standard:
6.7.9 Initialization
4 All the expressions in an initializer for an object that has static or thread storage duration shall be constant
expressions or string literals.
So the error indicates you are using a C89/C90 compiler. You can read the input from user for a
and declare a variable length array, which is a C99-feature, which has automatic storage duration.
Using #define
is another way. But it's simply a textual replacement and defines an array with automatic storage duration. It's same as defining int arr[5];
yourself.
if you want to allocate memory on dynamic storage (commonly known as "heap"), you have to use malloc()
family functions, which will have lifetime thoughout the program execution until you call free()
on it.
(Note that this behaviour of const
is only in C. C++ differs in this and will work as you expected).
If I compile the code in C89, it fails with:
#include <stdio.h>
int main(){
const int a = 5;
int i;
int arr [a];
for (i = 0; i < 5; i++) {
arr[i] = i * 2;
}
printf("%d", arr[1]);
return 0;
}
$ gcc -Wall -Wextra -std=c89 -pedantic-errors test.c
test.c: In function âmainâ:
test.c:7:4: error: ISO C90 forbids variable length array âarrâ [-Wvla]
int arr [a];
^
because C89 doesn't support VLAs (Although gcc supports it as an extension even in C89/C90). So if you are using a compiler that doesn't support C99 then you can't use VLAs.
For example, visual studio doesn't fully support all C99 and C11 features. Although, Visual studio 2015 support most C99 features, VLAs are not one of them.
But the same code compiles in C99 and C11 without any problem:
$ gcc -Wall -Wextra -std=c99 -pedantic-errors t.c
$ gcc -Wall -Wextra -std=c11 -pedantic-errors t.c
It's because variable length arrays (VLAs) were added in C99. Note that VLAs have been made optional in C11 standard. So an implementation may not support VLAs in C11.
You need to test against __STDC_NO_VLA__
to check if VLAs are not supported by your implementation.
From 6.10.8.3 Conditional feature macros
__STDC_NO_VLA__
The integer constant 1, intended to indicate that the implementation does not support variable length arrays or variably
modified types.
I personally do not use VLAs as the allocation failure can't be portably found if the array size is reasonably large. E.g.
size_t size = 8*1024;
int arr[size];
In the above fragment, if arr
allocation failed, you won't know it until runtime. What's a "small enough" size for which the memory allocation is platform dependent. So on one machine, 1MB allocation may succeed and another it may fail and worse part is that there's no way to catch this failure.
Thus the use of VLAs is limited and can only be used with small arrays that you know will always succeed on a given platform. But in that I would simply hard-code the array size and take care of the boundary conditions.
Maybe use an enum to define the value of a
.
enum { a = 5 };
int arr [a];
Perhaps this is not the intention of an enum but the members of enums are the closest thing to a constant in C. Unlike the common practice of defining everything using #define
, the visibility of a
is limited by scope and here it is the same as arr
.
A const
-qualified variable is not the same thing as a constant expression; a constant expression has its value known at compile time, whereas a const
-qualified variable (normally) doesn't (even though it looks like it should).
Note that in C99 and later, it's possible to declare variable-length arrays, where the array size isn't known until run time. You have to use a C99 or later compiler, and given that the feature was made optional in the 2011 standard, you have to check a feature macro to see if VLAs are available:
static const int a = 10; // a is not a constant expression
#if defined( __STDC__ ) && defined ( __STDC_VERSION__ ) && __STDC_VERSION__ >= 199901L && !defined( __STDC_NO_VLA__ )
/**
* VLAs are available in this environment
*/
#define USE_VLA 1
#endif
#ifdef USE_VLA
int arr[a];
#else
/**
* VLAs are not available, either because it's a pre-1999 implementation,
* or it's a post-2011 implementation that does not support optional
* VLAs. We'll have to use dynamic memory allocation here, meaning we'll
* also need an explicit free call when we're done with arr
*/
int *arr = malloc( sizeof *arr * a );
#endif
...
do_something_interesting_with( a );
...
#ifndef USE_VLA
free( a );
#endif
At least up until very recently, Microsoft's C compiler did not support VLAs. They have been adding some C99 features, though, such as mixed declarations and code, so maybe the latest version supports VLAs. I don't know.