Concepts / Initializing an array with an initializer list

Initializing an array with an initializer list

The element count of an array is not optional, so a declaration must state its size.

  • Programming

Why a Variable Count Feels Natural

Many learners arrive at arrays with a comfortable mental model. A variable holds a value, and that value can be supplied at runtime, computed from other values, or passed in as a parameter. It seems reasonable to assume the same flexibility applies to the number of slots in an array. If a program needs room for n items, why shouldn't the array simply be declared with n?

This belief is the misconception this article corrects. In C++, the element count of an array is part of its declaration, and it cannot be an arbitrary runtime value. The rule is strict, and the compiler enforces it before the program ever runs. Before reading the rule, try a prediction.

What do you think happens?

Inside a function that receives an int parameter n, is the declaration int a[n]; accepted by the compiler, or rejected?

  • Accepted, because n is an int

  • Rejected, because the size is not known until the program is compiled

Reveal answer
Answer:

Rejected. The size n is a function parameter, so it is not a constant expression, and the compiler does not accept it as the element count.

A parameter's value is only known once the function is called, which is after compilation. The element count of an array must be fixed at compile time, so the declaration is refused. The rest of this article explains why and what to write instead.

The Size Is Part of the Declaration

The element count of an array is not optional, so a declaration must state its size. The size is written inside the brackets, as in int a[5]. The initializer list that follows the equals sign supplies values, but it does not supply the size. The list fills the slots that the size has already defined. It cannot define the size on its own. Providing values is not the same as providing a size.

Definition

A constant expression is a value that is fixed when the program is compiled, so the compiler knows the element count before the program runs. When an array's size is written, that size must be a constant expression.

A literal number such as 5 is a constant expression, because its value is fixed in the source code itself. A variable parameter such as n does not meet this requirement, because its value is only known once the function is called. This is the whole rule. Only the form of the size expression decides whether the declaration is accepted.

Key point

The compiler checks the element count when it reads the declaration. A size written as a function parameter is rejected, because the element count would not be known until runtime.

Accepted or Rejected at Compile Time

Consider two declarations that differ only in how the size is written. The first uses a parameter n, and the compiler rejects it. The second uses a literal 5, which is a constant expression, and the compiler accepts it. The diagram below traces the decision the compiler makes for any size expression.

int a[n];Constant expression?AcceptedRejectedsize writtenyes, e.g. 5no, e.g. parameter n
Given a declaration like int a[n], the compiler asks whether the size expression is a constant expression. If its value is fixed at compile time the declaration is accepted; if not, it is rejected.
cpp
Output
Compile error: the size of the array is not a constant expression
Notes on the code
  • The size is the variable n, whose value is known only when fill is called
  • The compiler refuses the declaration before the program runs
cpp
Notes on the code
  • The size 5 is a literal, fixed when the program is compiled
  • The initializer list {1, 2} fills the first two slots of the five defined by the size
Worked example

Deciding whether a declaration is accepted

A function is written as void f(int n) { int a[n] = {1, 2, 3}; }. Is the declaration accepted?

  1. 1
    Find the size expression

    The size written inside the brackets is n, not a number.

  2. 2
    Ask whether the size is fixed at compile time

    n is a function parameter. Its value is only known once f is called, so it is not a constant expression.

  3. 3
    Apply the rule

    The element count must be a constant expression, so the declaration is rejected. The initializer list {1, 2, 3} does not change this, because the list cannot supply the size.

  4. 4
    Correct the declaration

    If the count is truly fixed, write a literal such as 3, giving int a[3] = {1, 2, 3};. If the count must vary, a vector is the appropriate tool, as discussed later.

Result

Rejected. The size n is not a constant expression, so the element count is not fixed at compile time.

Tracing Which Slots Receive Values

Once the size is fixed, the initializer list fills positions from the start of the array. Take int a[5] = {1, 2};. The size defines five slots, indexed 0 through 4. The list supplies two values, so they go to the first two positions. The remaining positions are not left without values: in C++ they are value-initialized, which for an int means they are set to zero.

a[0]1a[1]2a[2]0a[3]0a[4]0
Which index positions receive the listed values when the declaration gives fewer values than the declared size. The first two positions take the listed values, and the remaining three are filled with zero.

Read the diagram from left to right. The values in the list are matched to positions in order, so the list never decides where the array begins or how long it is. The declared size decides both. If the list had supplied more values than the size allows, the declaration would not describe the array the programmer intended, so the size and the list must agree.

Reading a Declaration Piece by Piece

A declaration with an initializer list has four visible parts. The type names what each element is. The name identifies the array. The bracketed size gives the element count, and it must be a constant expression. The initializer list after the equals sign supplies the initial values. The diagram below labels each part of int a[3] = {1, 2, 3};.

intelement typeaarray name[3]element count, a constantexpression= {1, 2, 3}initial values
Each token in the declaration and what it contributes. The bracketed size sets the element count, the type sets what each element is, and the initializer list supplies the initial values.

The bracketed part is the one this article focuses on. When you read a declaration, look there first. If the bracket holds a literal number, or another expression whose value is fixed at compile time, the element count is settled. If the bracket holds a function parameter or another value that is only known while the program runs, the declaration is not valid for a fixed-size array.

Mistakes With Array Sizes

  • Common mistake

    Assuming the initializer list determines the size

    What it looks like
    int a[] is not the topic here, but consider int a[n] = {1, 2, 3}; with n as a parameter
    Why it fails

    The list supplies values, not a size. The size must already be stated and must be a constant expression.

    Do this instead

    Write the size as a constant, such as int a[3] = {1, 2, 3};, or switch to vector if the count varies.

  • Common mistake

    Using a function parameter as the array size

    What it looks like
    void fill(int n) { int a[n]; }
    Why it fails

    n is only known when the function is called, so it is not a constant expression and the compiler rejects the declaration.

    Do this instead

    Use a literal size for an array, or use vector when the element count must come from a variable.

  • Common mistake

    Believing a fixed size means the program can never handle a changing count

    Why it fails

    The rule does not forbid counts that change. It means array is the wrong tool for that job.

    Do this instead

    When the element count needs to be a variable, use vector instead of array.

  • Common mistake

    Forgetting that a list shorter than the size leaves the remaining slots without listed values

Choosing Between Array and Vector

The source gives the decision rule directly: when the element count needs to be a variable, use vector instead of array. The table below compares the two choices across the situations a learner is likely to meet. A fixed-size array fits problems where the count is known as a constant. A vector fits problems where the count can only be known while the program runs.

SituationUse an arrayUse a vector
The element count is a literal fixed in the codeFits well, such as int a[3] = {1, 2, 3};Works, but an array is the direct match
The element count comes from a function parameterRejected, because the size is not a constant expressionFits, such as std::vector<int> v(n);
The count can only be known at runtimeNot suitable, since the size must be fixed at compile timeAppropriate, because it can be sized at runtime

Choosing a container for a fixed or variable element count

cpp
Notes on the code
  • The vector is sized from n at runtime, which the array form could not do
  • The rule that the size of an array must be a constant does not apply to a vector

Checking Your Reasoning

MEDIUM

For each declaration, decide whether it is accepted or rejected, and give the reason in terms of the size. (a) int b[4] = {9, 8}; (b) void g(int m) { int c[m]; } (c) void h() { const int k = 6; int d[k]; }. Hint: ask whether each size is fixed when the program is compiled.

Hints
  • Look at what sits inside the brackets, not at the initializer list
  • A literal number is fixed at compile time. A function parameter is not
  • Part (c) is harder: consider whether the value of k is fixed when the program is compiled

Key Takeaways

  • The element count of an array is not optional, so a declaration must state its size.
  • The size must be a constant expression, a value fixed when the program is compiled. A function parameter such as n is rejected.
  • An initializer list supplies values for the slots the size defines. It cannot define the size, and any slots it does not reach are filled with zero.
  • When the element count needs to be a variable, use vector instead of array.

Related concepts

More concepts starting with I