Why does array allocation with a variable work? - c

This code:
int main() {
int size;
scanf("%d", &size);
int array[size];
}
works fine with GCC, but VC expects a constant expression for the size of the array so does not compile it (which makes more sense to me). Any idea why it works with GCC?

Yes, because gcc supports variable length arrays.
It was added as a part of C99 standard, however, in the later standards (C11 and C18), it's an optional feature.

Because variable-length arrays (VLAs) are neither valid in C90 nor C++11 MSVC does not support them:
From https://learn.microsoft.com/en-us/cpp/build/reference/za-ze-disable-language-extensions?view=vs-2019:(
The C compiler is an C89/C90 compiler that, by default, enables
Microsoft extensions to the C language.
VLAs may be best avoided in any event because a C11 compiler need not implement them and they are potentially unsafe. Typically an implementation will allocate VLAs on the stack. In your code, it only takes a user to enter an arbitrarily large value to break your code in someone-deterministic manner - any use of VLAs should have some constraint test to ensure the length is reasonable and in the capability of the system to support.

Related

setting the size of array

i am solving a problem. In my code i have two arrays
array[];
array2[];
i am inputing 2 numbers through scanf , and i want the size of arrays to be the count of number 1 and 2 e.g
int x;
int y;
scanf(" %d %d\n",&x,&y);
int indexX[x*y];
int indexY[x*y];
This does not work.
Being new to C im quite lost how to implement it , is the only way dynamicly allocate memory? If no , how can i achieve wanted result ? Or how could i dynamicly alocate the memory for it?
my code throws error
warning: ISO C++ forbids variable length array ‘indexX’ [-Wvla]
warning: ISO C++ forbids variable length array ‘indexY’ [-Wvla]
According to your error messages, you compile with a C++ compiler. Do not! C is not C++ and C++ is not C with classes. They are different languages. As the messages state, C++ does not provide VLAs (see below).
Use a standard-compliant C compiler, or at least a C99 compiler. Variable length arrays (VLAs) were added with the C99 release of the standard as a mandatory feature. C11 relaxed this by making it optional, but most (if not all) compilers which support C99 also implement it in C11 mode.
before defining the array, you should verify scanf really set these two variables by checking the result of scanf. Otherwise you use uninitialised variables, which is undefined behaviour and may (likely - will) result in strange behaviour - at best.
Additinally you can also initialise the variables before scanf to 1 (a VLA of size 0 is also undefined behaviour). This way you can check later and are still safe with the VLA definition.
Warning: Most, if not all modern implementations place VLAs on the stack. The size of the stack is normally limited to some 100 bytes (embedded systems) up to some MiB (standard OS like Windows, OS-X, Linux). There is no check if the VLA fits onto the stack, so you should not allocate too large arrays. If you are not sure, better use dynamically allocated memory (malloc& friends).

Assigning a dynamic array using declaration for static array in C?

So for example,
int aaa(unsigned int par1, unsigned int par2){
int array[par1*par2];
return 0;
}
I tried compiling the code that contains this, and it compiled well and had no run-time issue - the array was properly created.
But I know that this is basically declaring a dynamic array in static array declaration fashion. What may go wrong with this declaration? Will there be a compiler issue in a different compiler?
This is correct as per the 1999 C standard. The 2011 standard changed it to be an optional feature, which in practice means that all C11 compilers will support it except for MSVC.
Before 1999 some compilers offered this as a non-standard extension.
Here is a link to StackOverflow search for other questions on this topic.
But I know that this is basically declaring a dynamic array in static array declaration fashion.
This is called VLA (Variable-Length Array). This array is not static - it is placed in automatic memory (also known as "the stack").
What may go wrong with this declaration?
It may overflow the stack when the size of the array exceeds a certain limit specific to your system.
Will there be a compiler issue in a different compiler?
This is a C99 feature, so compiler that do not support C99 may fail to compile this code.
I believe this is a C99-only feature. It's called VLA (variable-length arrays).
The C++0x does't support VLA:
https://groups.google.com/forum/#!topic/comp.std.c++/K_4lgA1JYeg
But some compilers might not be strictly compliant with the standard.

Why does auto a=1; compile in C?

The code:
int main(void)
{
auto a=1;
return 0;
}
gets compiled without errors by the MS Visual Studio 2012 compiler, when the file has the .c extension. I have always thought that when you use the .c extension, compilation should be according to the C syntax, and not C++. Moreover, as far as I know auto without a type is allowed only in C++ since C++11, where it means that the type is deduced from the initializer.
Does that mean that my compiler isn't sticking to C, or is the code actually correct in C-language?
auto is an old C keyword that means "local scope". auto a is the same as auto int a, and because local scope is the default for a variable declared inside a function, it's also the same as int a in this example.
This keyword is actually a leftover from C's predecessor B, where there were no base types: everything was int, pointer to int, array of int.(*) Declarations would be either auto or extrn [sic]. C inherited the "everything is int" as a default rule, so you could declare integers with
auto a;
extern b;
static c;
ISO C got rid of this, but many compilers still accept it for backward compatibility. If it seems unfamiliar, then you should realise that a related rule is at work in
unsigned d; // actually unsigned int
which is still common in modern code.
C++11 reused the keyword, which few if any C++ programmers were using with the original meaning, for its type inference. This is mostly safe because the "everything is int" rule from C had already been dropped in C++98; the only thing that breaks is auto T a, which no-one was using anyway. (Somewhere in his papers on the history of the language, Stroustrup comments on this, but I can't find the exact reference right now.)
(*) String handling in B was interesting: you'd use arrays of int and pack multiple characters in each member. B was actually BCPL with different syntax.
This is both an answer and an extended comment to No, this isn't legal C since 1999. No decent modern C compiler allows for this.
Yes, auto a=1; is illegal in C1999 (and also C2011). Just because this is now illegal does not mean that a modern C compiler should reject code that contains such constructs. I would argue exactly the opposite, that a decent modern C compiler must still allow for this.
Both clang and gcc do just that when compiling the sample code in the question against the 1999 or 2011 versions of the standard. Both compilers issue a diagnostic and then carry on as if the objectionable statement had been auto int a=1;.
In my opinion, this is what a decent compiler should do. By issuing a diagnostic, clang and gcc are full compliant with the standard. The standard does not say that a compiler must reject illegal code. The standard merely says that a conforming implementation must produce at least one diagnostic message if a translation unit contains a violation of any syntax rule or constraint (5.1.1.3).
Given code that contains illegal constructs, any decent compiler will try to make sense of the illegal code so that the compiler can find the next error in the code. A compiler that stops at the first error isn't a very good compiler. There is a way to make sense out of auto a=1, which is to apply the "implicit int" rule. This rule forces the compiler to interpret auto a=1 as if it were auto int a=1 when the compiler is used in C90 or K&R mode.
Most compilers typically do reject code (reject: refuse to generate an object file or an executable) that contains illegal syntax. This is a case where the compiler authors decided that failing to compile is not the best option. The best thing to do is to issue a diagnostic, fix the code, and carry on. There's just too much legacy code that is peppered with constructs such as register a=1;. The compiler should be able to compile that code in C99 or C11 mode (with a diagnostic, of course).
auto has a meaning in C and C++ prior to the 2011 Standard. It means that a variable has automatic lifetime, that is, lifetime determined by the scope. This is opposed to, e.g., static lifetime, where a variable lasts "forever", regardless of the scope. auto is the default lifetime, and is almost never spelled out explicitly. This is why it was safe to change the meaning in C++.
Now in C, prior to the 99 Standard, if you don't specify the type of a variable, it defaults to int.
So with auto a = 1; you are declaring (and defining) an int variable, with lifetime determined by the scope.
("lifetime" is more properly called "storage duration", but I think that is perhaps less clear).
In C, and historic dialects of C++, auto is a keyword meaning that a has automatic storage. Since it can only be applied to local variables, which are automatic by default, no-one uses it; which is why C++ has now repurposed the keyword.
Historically, C has allowed variable declarations with no type specifier; the type defaults to int. So this declaration is equivalent to
int a=1;
I think this is deprecated (and possibly forbidden) in modern C; but some popular compilers default to C90 (which, I think, does allow it), and, annoyingly, only enable warnings if you specifically ask for them. Compiling with GCC and either specifying C99 with -std=c99, or enabling the warning with -Wall or -Wimplicit-int, gives a warning:
warning: type defaults to ‘int’ in declaration of ‘a’
In C, auto means the same thing register does in C++11: it means that a variable has automatic storage duration.
And in C prior to C99 (and Microsoft's compiler does not support either C99 or C11, although it may support parts of it), the type can be omitted in many cases, where it will default to int.
It does not take the type from the initialiser at all. You just happened to pick an initialiser that's compatible.
Visual studio compilation type is available at right click on file -> Properties -> C/C++ -> Advanced -> Compile As. To make sure it is compiled as C force /TC option.Then in this case it is what larsmans said (old C auto keyword). It might be compiled as C++ without you knowing.
A storage class defines the scope (visibility) and life time of variables and/or functions within a C Program.
There are following storage classes which can be used in a C Program
auto
register
static
extern
auto is the default storage class for all local variables.
{
int Count;
auto int Month;
}
The example above defines two variables with the same storage class. auto can only be used within functions, i.e. local variables.
int is default type for auto in below code:
auto Month;
/* Equals to */
int Month;
Below code is legal too:
/* Default-int */
main()
{
reurn 0;
}

Dynamic array declaration in C

Following piece of code compiles in gcc. But it is not correct way of writing as it surpasses the use of malloc function. What is the problem in this code?
#include<stdio.h>
main()
{
int n;
scanf("%d",&n);
int a[n];
}
your code is legal ISO C99 code. It's not C89 ANSI compliant: if you are stuck with compatibility rules, because of old compilers or company policies, you need to use malloc().
More importantly, in C99, using your definition, the array is allocated on stack, that is usually a limited resource, while with malloc() it's allocated in the heap.
Your array is a variable length array (VLA). This is an advanced feature of C, introduced in the C99 version of the standard.
The problem with VLAs is that they can easily overflow the stack. Unless you have a specific reason to use a VLA, use dynamic memory with malloc and avoid the risk of stack overflow.
Your main declaration is wrong. It should be
int main(void)
"...it is not correct way of writing as it surpasses the use of malloc function..." - what is that supposed to mean? According to the rules of modern C language, the only problem with your code is the missing int in the declaration of main. I.e. it has nothing to do with any malloc.
It can be said that your code is self-contradictory in a sense that it uses a perfectly valid C99 feature - variable length array int a[n] - but at the same time relies on an obsolete feature of C89/90 - implied int in the declaration of main, which is no longer supported by C99.
You need to decide which version of C language you are trying to use - C89/90 or C99. Once you make that decision, we'll be able to discuss the correctness of your code.

Why is variable length array forbidden: "C90 forbids variable length array"?

I know that I'm not supposed to do this in C90, and it's a rather basic stuff.
char name[strlen(s)];
ArrayLength.c:11: warning: ISO C90 forbids variable length array ‘name’
Did they want me to specifically use malloc? I'm just curios here about the logic behind it.
It's forbidden because C90 doesn't support variable-length arrays (VLAs). It's really as simple as that.
Your options are:
Declare a fixed-length array that can cope with the maximum string length you want to work with.
Dynamically-allocate the array (using malloc).
Work with a compiler that offers VLAs a non-standard language extension, e.g. GCC. (I don't recommend this, because it means you'll end up writing non-portable code.)
Use C99 instead, where VLAs are supported. Note that VLAs are allocated on the stack, which can cause all sorts of issues if you run out of stack space (unlike with malloc, there's no concept of being able to check that the allocation was successful).
[Note: If you're allocating an array in order to make a copy of s, you'll need to use strlen(s)+1 as the size (remember the null terminator).]
It's not that "they" don't want you to do it, it's simply not part of the language (or rather, wasn't prior to 1999). The standard workaround is to use malloc or alloca. (alloca is essentially identical to variable length array allocation, but is not a standard function, so it may not be available on all systems of interest. Also, some people have strong objections to it's use, but they tend to object strong to variable-length arrays for the same reasons.)
This warning points to the usage of a GNU gcc extension is a serious portablity problem.
The code is illegal, because the value of strlen(s) is not known at compile time. GNU gcc provides an extension for automatic arrays that allocate based on run time values; but relying on these makes the code out of compliance with the standard.
If the value of strlen(s) isn't known until run-time then one can bring the code into compliance by either converting to performing the allocation/deallocation explicitly on conventions arrays, or by using STL containers.(e.g. std::vector).
It's a matter of the language having restrictions for the presumed convenience of the
compiler and its intended runtime environment.

Resources