I recently tried this experiment in which instead of going for dynamic memory allocation for memory requirements of unknown size, I did a static allocation. When an array a[i] was declared by me, I kept i (size of the array) variable and dependent on the input that the user gives.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
void function(int );
int main(void)
{
int i;
printf("Enter:");
scanf("%d",&i);
function(i);
printf("i = %d\n",i);
getch();
return 0;
}
void function(int i)
{
char a[i];
char b[4];
strncpy(a,"hello",i);
strcpy(b,"world");
int j = 0;
char *c = a;
for( j = 0; j< 20; j++ )
printf("%c",*c++);
}
My questions are:
Is such an operation legal?
If no, why does the compiler not issue any warning or error?
Where will this memory be allocated: Stack or heap?
Why does ANSI C/GCC allow this?
Is such an operation legal?
It's called a variable length array.
VLAs are legal in ANSI C99 and as an extension to some pre-C99 compilers. GCC supports it both as strict C99 and as an extension to non-C99 code. It's also legal in C++0x.
If no, why does the compiler not issue any warning or error?
With gcc:
$ gcc -std=c89 src/vla.c -Wall -ansi -pedantic
src/vla.c: In function ‘function’:, not dynamic array.
src/vla.c:17: warning: ISO C90 forbids variable length array ‘a’
src/vla.c:21: warning: ISO C90 forbids mixed declarations and code
The presence of 'conio.h' from MSDOS indicates you're probably using a Microsoft Visual C++ compiler, so don't worry about it. MS has worked to make their compiler more conformant to the C++0x standard, but makes no claims about how standard its C compiler mode is. You're asking why Spanish dialect words aren't in the French dictionary.
Where will this memory be allocated: Stack or heap?
It is an automatic object, so most C implementations will put in on the stack for efficiency reasons.
Why does ANSI C/GCC allow this
It is useful for creating temporary arrays of variable size at runtime whose lifetime doesn't extend beyond the function call.
This is valid C99.
Look here for a more detailed explanation in another StackOverflow question.
This is legal, but not all compilers support it. At least Visual Studio <= 2003 afaik do not support it.
I would assume it is not Ansi C++, try gcc -ansi -pedantic.
Variable length arrays are illegal in ANSI C (C89). Try upping your compiler's warning level and I'm sure you'll get a warning/error.
The code is valid, but there is one thing to keep in mind when using variable length arrays.
void function(int i)
{
int a[i];
.
.
}
There is no error checking here. This code can fail if i is too big.
Dynamic memory allocation on stack:
There is a library call _malloca which allocates memory dynamically on program stack (very much like malloc does on Heap)
Reference: _malloca
Related
Before C99, does the C standard allow defining or casting to pointers to arrays of length determined at runtime?
I understand that the standard doesn't allow variable length arrays before C99, but whether pointers to arrays of runtime-determined size are allowed is not obvious to me, since the compiler knows how much memory to allocate for a pointer at compile time, unlike the array.
gcc 10.1.0 allows it, even with -std=c90, but I am curious about whether the standard allows it rather than whether specific compilers do. This question is very similar, but the answer doesn't talk about the standard.
Here is a code example:
#include <stdio.h>
int f() {
int a;
scanf("%d", &a)
return a;
}
int main() {
int dim1 = f();
int dim2 = 2*dim1;
int (*p)[dim1][dim2]; // is this allowed pre-C99?
return 0;
}
This is a constraint violation. A conforming C89 compiler must issue a diagnostic for this program.
3.5.4.2 Array declarators
Constraints
The expression that specifies the size of an array shall be an integral constant expression that has a value greater than zero.
With gcc use -std=c90 -pedantic to get (mostly) conforming mode.
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.
#include "stdio.h"
int main()
{
int n;
printf("Enter n:\n");
scanf("%d",&n);
int arr[n][n];
arr[3][3] = 4;
printf("%d",arr[3][3]);
getchar();
return 0;
}
Wasn't using int arr[n], where n is a variable, illegal in C? I am trying to understand what's happening here. Apparently the code works on my clang LLVM compiler and on IDEOne and on Codeblocks. I guess the compiler is just making things easy for me, by doing automatic memory allocation. But another astounding fact is that when I try to set n to 1, 2 or 3 it still works.
Variable length arrays are allowed by C standard since C99. Note that they are still not allowed by C++
standard.
Also important point to note is for versions before c99 and for most C++ compilers variable length arrays are supported by implementations in the form of extensions.
I am trying to create an array according to the size that the user inputs but it does not seem to be working for c programming. The following are my codes:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int x, y;
scanf("%d", &x);
scanf("%d", &y);
double arr[x][y];
}
The compiler keeps returning an error of" Error: Expression must have a constant value. at the line double ... could anyone help point out the error?
You have two choices:
Either use a decent C compiler that supports C99 (or later) and variable-length arrays (I'd go with this approach, personally);
or if that is not possible, or the resulting array would be too large to fit in a block-scope variable (causing, for example, a stack overflow), you can use malloc(); however, you won't be able to create a true two-dimensional array using that approach, only a pointer-to-pointer, which may or may not be what you are looking for.
The code can work in C99 mode or when the compiler supports VLA(variable length arrays) as an extension (e.g, GCC supports VLA as GNU extesnion).
In C89, you have to use pointers with dynamic memory to simulate.
Older C standards don't provide support for arrays that do not have compile-time sizes:
int array[42];
char text[] = "Hello World";
int numbers = { 1, 2, 3, 4 };
(in the case of the latter two examples, the size is derived from the data)
You either need a newer compiler, to specify the -std=c99 if you are using GCC, or you need to allocate memory for the array yourself.
You're using a C89 (Visual Studio? Though that would give you an error on the declaration of arr next) or a C++ compiler. VLA's (Variable Length Arrays) are a C99 feature.
You need to allocate the memory in run-time . The compiler doesn't allow the declaration of arrays becuase it does not know the size of the array before hand . You need to use malloc() to allocate memory
Why does the following code compile with the Dev-C++ compiler and
not with Visual Studio?
Any idea? Here is the code:
#include<stdio.h>
main(){
int n,i;
scanf("%d",&n);
int arr[n];
for(i= 0 ; i <n ; i++)
{
//Do something with the array
}
fflush(stdin);
getchar();
}
Here are the errors:
Errors http://img688.imageshack.us/img688/6618/26863513.jpg
This:
int arr[n];
is invalid because n is not a constant expression. You need to allocate variable sized arrays on the heap using malloc (and then free them when you are done with free).
If you are trying to compile this with a .cpp extension, main must have a return type of int. If you are trying to compile this with a .c extension, then you need to use c-style local variable declaration and declare all of your local variables at the top of the function.
Visual C++ doesn't do stack allocations with that syntax (though I wish it did). You can do stack allocations explicitly with:
int *arr = (int *)_alloca(n*sizeof(*arr));
and no need to free it since it's automatically freed when the scope ends.
This isn’t valid C++ – the Visual C++ compiler does not contain an up-to-date C compiler (rather a C subset of C++) and in particular it doesn’t implement C99 or anything newer. Your code uses features that the Visual C++ compiler doesn’t know (int arr[n]).
To simplify the answers you have gotten:
Your code is C99 and Visual C++ only supports C89. Do yourself a favour and get a better compiler for Windows. The Intel compiler has much better support for C99 than the Microsoft compiler (which has none).
Your program is not a Standard compliant program.
Any standard compliant compiler is required to issue a diagnostic when attempting to compile it.
If Dev-C++ compiled it without a warning, the compiler was invoked in a non compliance mode.
Other than the required diagnostic, a compliant compiler can attempt to compile anyway or just plainly abort compilation.
main()
In C89 this is valid and requires no diagnostic, In C99 this is invalid and requires a diagnostic (valid C99 definitions are int main(void) or int main(int argc, char **argv) or equivalent) ... so if you are using a compliant compiler it is a C89 compiler.
scanf("%d",&n);
int arr[n];
Oops, this is invalid in C89. In C89 you cannot have code intermixed with declarations. A C89 compiler must issue a diagnostic when it sees the declaration of the array.
So ... you are using your compiler in a non-conforming way. There's no way to tell why it compiles or fails to compile.