array of variable size in c - c

I have this code below which creates an array of variable size that compiles and runs fine on my mac.
#include <stdio.h>
#include <stdlib.h>
int main(){
int w = 100;
int ar[w];
ar[2] = 42;
printf("%d\n",ar[2]);
}
I thought variable sized arrays were not permitted in C. what is happening here exactly? How is memory being managed? Does the memory get dynamically allocated at run time? Thanks

What's happening here is that variable-length arrays are a relatively new feature, only first appearing in the C standard in 1999. C standards are not adopted as quickly in the C world as JavaScript and Python; I can remember the excitement in 2007 or so when my workflow was finally able to include VLAs.
To add insult to injury, while C++ is a mostly-superset of C, VLAs are not supported, meaning that the common use-case of folks compiling C code with C++ compilers will not work.
There was enough pushback from the compiler vendors that the standard eventually (C11) made VLAs optional, mandating the feature-test macro __STDC_NO_VLA__ instead.
(see ISO stadndard 9899:2011 Programming Languages - C, section 6.7.6.2 4)

Related

What does it mean by C requires "all variables to be initialized at the beginning of the scope"

I'm learning about the difference between C++ and C and one of them is unlike C++, C does not allow a variable to be defined anywhere except at the beginning of the scope (from Thinking in C++)
The author gave an example where it would work in C++ but not in C, saying that retval has to be defined before the cout
//: C06:DefineInitialize.cpp
// Defining variables anywhere
#include "../require.h"
#include <iostream>
#include <string>
using namespace std;
class G {
int i;
public:
G(int ii);
};
G::G(int ii) { i = ii; }
int main() {
cout << "initialization value? ";
int retval = 0;
cin >> retval;
require(retval != 0);
int y = retval + 3;
G g(y);
} ///:~
However when I run this code, which is similar to test, it still works?
#include <stdlib.h>
#include <stdio.h>
int main() {
printf("Hello\n");
int i;
i = 0;
exit(0);
}
C does not allow a variable to be defined anywhere except at the beginning of the scope
This hasn't been true for 20 years, but 20 years ago is when Thinking In C++ was last revised.
When someone says "I'm programming in C" the question is then "which version of C?" There is a standard, but it has had several major revisions, and many non-standard extensions.
Prior to 1999, C required you to declare variables only at the start of the scope. In 1999 the standard changed to allow variable declarations anywhere you like.
C compilers can be configured to comply to various standards and extensions. Many C compilers will default to C99 or C11, often with extensions. The very common clang compiler currently defaults to C11 with GNU extensions. You can select which standard with -std. For example, if you want to see your code in C89: clang -std=c99.
Compiling your code using the C89 standard Thinking In C++ would have been written to, and because -Wall doesn't mean "all warnings" enough flags to get the compiler to issue warnings, gives us the warning we expect.
$ cc -Wall -Wextra -pedantic -std=c89 test.c
test.c:6:9: warning: ISO C90 forbids mixing declarations and code [-Wdeclaration-after-statement]
int i;
^
1 warning generated.
With -std=c99 there's no problem.
$ cc -Wall -Wextra -pedantic -std=c99 test.c
When learning C, I'd strongly advise to avoid extensions, write to the standard, and turn on lots of warnings. -std=c11 is a good choice for the moment.
A problem with a lot of material on C and C++ is the C standards have changed over the last 40+ years, and a lot of material is out of date.
Here's a brief history of the fault lines.
1978 introduces K&R C. Named for Brian Kernighan and Dennis Ritchie who authored The C Programming Language aka "K&R". A this point there was no standard for C.
You'll still see this legacy in K&R style function declarations where the type is separate
int foo(s, f, b)
char* s;
float f;
struct Baz * b;
{
return 5;
}
1989 brings the first C standard which goes by many names: ANSI C / ISO C / C89. Many features are added. Function prototypes as we know them today are introduced. Today, just about every C compiler will comply to C89.
And yes, variables must be defined at the beginning of the scope. This legacy carries on even in material produced today resulting in awkward blocks of declarations far away from where they're used.
1999 brings a major revision of the standard, C99. This adds inline functions, more types, variable-length arrays, one-line comments //, and the ability to declare variables anywhere you like.
The process of C compilers adopting C99 has been very slow and is still ongoing. But you can definitely rely on declaring variables where you like.
2011 brings C11 and 2018 brings C17 / C18. It's not relevant to go into their changes to the standard here, just be aware of them.
Finally, there are non-standard extensions. The major ones are POSIX, GCC, and Microsoft extensions. Many compilers implement POSIX extensions. Some compilers, such as clang, have adopted GCC extensions. While Microsoft extensions are typically only available for Microsoft compilers and often conflict with the standard. Be aware that a lot of material will use extensions without telling you resulting in code that only works on specific compilers.
C++ underwent a similar process of standardization, revision, and extension which is still ongoing. C++'s major versions are C++98, C++03, C++11, C++14, and C++17 and also have Gnu and Microsoft extensions.
Thinking In C++ was first published in 1995, so it would be written to C89 and non-standard C++. Its 2nd edition was published in 2000, just after C99. That's unlikely to have been enough time for the author to be comfortable with C99 conventions, and their readers would likely still be using C compilers which used C89 or even K&R standards.
Adoption of C and C++ standards by compilers can be very, very slow. You will still find a lot of material on C is written to C89.

Why does array allocation with a variable work?

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.

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.

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.

Does anyone know the reason why the variables have to be defined at the top of function

I have a question, does anyone know why the variables have to be defined initialized at the beginning of a function? Why can't you initialize or define variables in the middle of a function in C as in C++?
This is a tradition which comes from early C compilers, when compiler needs all local variable definitions before the actual code of function starts (to generate right stack pointer calculation). This was the only way of declaring local variables in early C language, both pre-standard (K&R) and first C standard, C90, published at 1989-1990 ( ANSI X3.159-1989, ISO/IEC 9899:1990 ).
C99 - the 1999 year ISO standard (ISO/IEC 9899:1999) of C allows declaraions in the middle of function.
C++ allows this because it is newer language than C. C++ standards are ISO/IEC 14882:1998 and ISO/IEC 14882:2003, so they are from 1998 and 2003 years.
You can initialize variable (give it a value: a=4;) at the definition point or any time later.
That is a left-over from early C. C99 allows variables to be defined anywhere in the function, including in loop structures.
for (int i = 0; i < 10; ++i) { int j; }
The throwback is from when compilers needed to know the size of the stack for the function before they instantiated the function's code. As compilers became better the requirement just became annoying.
You can do this in C so long as you use a C99 compiler. The restriction was lifted in C99.
Presumably the restriction was originally there because compilers were less capable, or perhaps simply because nobody thought of allowing such a convenience for the programmer.
When answering a question like this it is sometimes worth turning it around. Why would the original designers of C have done it the other way? They didn't have C++ to guide them!
In C++ and C99, you can define variables in the middle of a function. What you cannot do is refer to a variable that has not yet been defined.
From the point of view of object-oriented programming, it wouldn't make much sense otherwise: By defining a variable you bring an object to life (by calling its constructor). Before that, there is no object, so there's nothing to interact with until you pass the point of object construction.
Try writing a compiler with the primitive power of the old times and you'd realize flexibility is something you'd rather kill to get the software to work.
Putting variables first, then other statements simply made their parser/compiler code simpler.

Resources