How to create an array when the size is a variable not a constant?
int *a = new int[variable_int];
Remember to delete[] the allocated space when you are done with it!
Create an array when the size is a variable not a constant
There is no proper way to do this, as a program with any variable length array is ill-formed.
An alternative, so to speak, to a variable length array is a std::vector
:
std::vector<char> Sbuf;
Sbuf.push_back(someChar);
Of course, I should mention that if you are using char
specifically, std::string
might work well for you. Here are some examples of how to use std::string
, if you're interested.
The other alternative to a variable length array is the new
operator/keyword, although std::vector
is usually better if you can make use of it:
char* Sbuf = new char[siz];
delete [] Sbuf;
However, this solution does risk memory leaks. Thus, std::vector
is preferred.
Declaring the array size with a non-constant variable
This is a GCC extension to the standard:
You can use the -pedantic
option to cause GCC to issue a warning, or -std=c++98
to make in an error, when you use one of these extensions (in case portability is a concern).
Why can't I create an array with size determined by a global variable?
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.
Why is the size of array as a constant variable not allowed in C but allowed in C++?
In C const
doesn't mean "constant" (i.e., evaluable at compile time). It merely means read-only.
For example, within a function, this:
const int r = rand();
const time_t now = time(NULL);
is perfectly valid.
The name of an object defined as const int
is not a constant expression. That means that (in C prior to C99, and in all versions of C++) it can't be used to define the length of an array.
Although C99 (and, optionally, C11) support variable-length arrays (VLAs), they can't be initialized. In principle, the compiler doesn't know the size of a VLA when it's defined, so it can't check whether an initializer is valid. In your particular case, the compiler quite probably is able to figure it out, but the language rules are designed to cover the more general case.
C++ is nearly the same, but C++ has a special rule that C lacks: if an object is defined as const
, and its initialization is a constant expression, then the name of the object it itself a constant expression (at least for integral types).
There's no really good reason that C hasn't adopted this feature. In C, if you want a name constant of an integer type, the usual approach is to use a macro:
#define LEN 5
...
int arr[LEN] = {1, 2, 3, 4, 5};
Note that if you change the value of LEN
, you'll have to re-write the initializer.
Another approach is to use an anonymous enum
:
enum { LEN = 5 };
...
int arr[LEN] = {1, 2, 3, 4, 5};
The name of an enumeration constant is actually a constant expression. In C, for historical reasons, it's always of type int
; in C++ it's of the enumeration type. Unfortunately, this trick only works for constants of type int
, so it's restricted to values in the range from INT_MIN
to INT_MAX
.
Variable cannot be used as a constant c++ array
You can not use variables for compile time array size simply because compiler has no way of knowing what the value returned by your getMax
function will be ...
You need to use dynamic arrays in cases like this...
void countingSort(int *arr, int size)
{
int max = getMax(arr, size);
int *hilfsArr=new int[max + 1]; // allocate
... here put the rest of your code for this function
delete[] hilfsArr; // free before exiting function
}
How do I declare an array without initializing a constant?
There are three standard conformant ways to declare an array with a size unknown at compile time. Presented from most recommended to least.
std::vector
The community's favorite container and for good reason. Not only can it be declared with a run-time size, but the size can be changed at any time. This facilitates use when size cannot be predetermined, eg when repeatedly polling for user input. Examples:
// Known size
size_t n;
std::cin >> n;
std::vector<int> vec(n);
// Unknown size
std::vector<int> vec;
int input;
while (std::cin >> input) { // Note: not always the best way to read input
vec.push_back(in);
}
There's not much downside to using std::vector
. The known size case requires exactly one dynamic allocation. The unknown size requires more in the general case, but you wouldn't be able to do any better anyway. So performance is more or less optimal.
Semantically, it might not be ideal for sizes that are constant throughout the execution. It might not be apparent to the reader that this container is not intended to change. It is not known to the compiler either so it will allow you to do something wrong like push_back
into a vector
that is logically of constant size.
std::unique_ptr (or std::shared_ptr)
The safest solution if enforcing static size is important to you.
size_t n;
std::cin >> n;
auto arr = std::make_unique<int[]>(n);
arr
's size cannot change, though it can be made to release the current array and point to another one of different size. Therefore, if logically the size of your container is constant, this conveys intent in a clearer way. Unfortunately, it is also much weaker than std::vector
even in the constant-size case. It is not size-aware, so you have to explicitly store the size. For the same reason it does not offer iterators and can't be used in range for loops. It is up to you (and the project in question) if you want to sacrifice these features to enforce static size.
new[] - delete[]
Technically a solution, but unless you are forced to use an old C++ standard or you are writing a low-level library that manages memory internally they are strictly worse than the std::unique_ptr
or std::shared_ptr
solution. They offer no more features, but are significantly less safe because you have to explicitly free the memory when you're done with it. Otherwise, you will leak it and this might cause significant problems. To make matters worse, using delete[]
properly can be non-trivial for programs with complicated flows of execution and exception handling. Please don't use this when the above solutions are available to you!
size_t n;
std::cin >> n;
int* arr = new int[n];
...
// Control flow must reach exactly one corresponding delete[] !!!
delete[] arr;
Bonus: Compiler extension
Some compilers might actually be ok with the following code
size_t n;
std::cin >> n;
int arr[n];
Relying on this has severe drawbacks. Your code cannot be compiled on all C++ conformant compilers. It probably doesn't even compile on all versions of the given compiler. Also, I doubt that the produced executable checks the value of n
and allocates on the heap when needed meaning you can blow up your stack. This solution only makes sense when you know the upper bound of n
is small and when performance is so important to you that you're willing to rely on compiler-specific behavior to get it. These are truly exceptional cases.
Can't create array with constant size (expected constant expression”)
I know the size of arrays needs to be known at compile time, but surely that's the case here.
That's actually not the case. In C, const
qualifying doesn't result in a "constant expression". So newsize
isn't a constant expression (unlike C++).
Your code is valid in C99 and in C11, if variable length array (VLA) is supported by your implementation (VLAs are optional in C11). However, it seems Visual studio doesn't seem to support VLAs and expects a "constant expression" for array size as in C89.
So you may have to use dynamic memory allocation (malloc & friends), or simply specify the 100
as size, or use a macro for defining size and so on.
In C, why can't a const variable be used as an array size initializer?
In C, a const
-qualified variable is not a constant expression1. A constant expression is something that can be evaluated at compile time - a numeric literal like 10
or 3.14159
, a string literal like "Hello"
, a sizeof
expression, or some expression made up of the same like 10 + sizeof "Hello"
.
For array declarations at file scope (outside the body of any function) or as members of struct
or union
types, the array dimension must be a constant expression.
For auto
arrays (arrays declared within the body of a function that are not static
), you can use a variable or expression whose value isn't known until runtime, but only in C99 or later.
- C++ is different in this regard - in that language, a
const
-qualified variable does count as a constant expression.
Related Topics
Best C++ Code Formatter/Beautifier
How to Retrieve All Keys (Or Values) from a Std::Map and Put Them into a Vector
Move Assignment Operator and 'If (This != &Rhs)'
How to Initialize Const Member Variable in a Class
How to Explicitly Instantiate a Template Function
How to Read a File Line by Line or a Whole Text File At Once
How Does Array[100] = {0} Set the Entire Array to 0
Should the Trailing Return Type Syntax Style Become the Default For New C++11 Programs
How to Specialize Std::Hash≪Key≫::Operator() For User-Defined Type in Unordered Containers
C++ Static Member Method Call on Class Instance
Type of Integer Literals Not Int by Default
Capturing Stdout from a System() Command Optimally
How to Convert a Lambda to an Std::Function Using Templates
Why Is Conversion from String Constant to 'Char*' Valid in C But Invalid in C++
Implementing Comparison Operators Via 'Tuple' and 'Tie', a Good Idea