Understanding C++ Arrays

Arrays are a fundamental part of C++ programming. They allow you to store multiple values in a single variable, which can be accessed by indexing. Arrays can be categorized into static arrays, local arrays, dynamic arrays, and standard library arrays like `std::array` and `std::vector`. This article will explore these different types of arrays in C++ and provide practical examples.

Arrays are a fundamental part of C++ programming. They allow you to store multiple values in a single variable, which can be accessed by indexing. Arrays can be categorized into static arrays, local arrays, dynamic arrays, and standard library arrays like std::array and std::vector. This article will explore these different types of arrays in C++ and provide practical examples.

Static Arrays

Static arrays are those declared directly in a namespace (outside any function) and are always initialized. If no explicit initializer is specified, all the elements are default-initialized, which means they are filled with zeroes for fundamental types like integers.

Example:

int foo[5]; // Elements are initialized to zero.

Local Arrays

Local arrays are those declared within a function. Unlike static arrays, they are left uninitialized unless explicitly initialized.

Example:

int foo[5]; // Uninitialized elements.

Explicit Initialization:

You can explicitly initialize elements in an array when it is declared:

int foo[5] = { 16, 2, 77, 40, 12071 }; // All elements are initialized with the specified values.
  • The number of values between braces {} must not exceed the number of elements in the array.
  • If fewer values are provided, the remaining elements are set to their default values.

Example with Partial Initialization:

int bar[5] = { 10, 20, 30 }; // Remaining elements are set to zero.

Empty Brace Initialization:

The initializer can even have no values, just the braces:

int baz[5] = { }; // All elements are initialized to zero.

Automatic Array Size Determination:

When initializing an array, C++ allows you to leave the square brackets empty [], and the compiler will automatically determine the size of the array based on the number of initialization values.

int foo[] = { 16, 2, 77, 40, 12071 }; // Array size is automatically determined as 5.
  • The above declaration will create an array foo with 5 int elements.

Universal Initialization:

C++ also supports universal initialization for arrays. Both of the following statements are equivalent:

int foo[] = { 10, 20, 30 };
int foo[] { 10, 20, 30 };

Dynamic Arrays

Dynamic arrays in C++ are arrays that can be allocated at runtime, allowing their size to be determined dynamically.

Initializing Dynamic Arrays:

char *c = new char[length];
std::fill(c, c + length, INITIAL_VALUE);

Alternatively, you can use the std::vector container:

std::vector<char> c(length, INITIAL_VALUE);

Important Notes:

  • std::fill fills a range defined by iterators.
  • std::fill_n fills a specified number of elements starting from a specified iterator.

Beware of Out-of-Bounds Access

In C++, it is syntactically correct to exceed the valid range of indices for an array. However, this can create problems because accessing out-of-range elements does not cause compilation errors but can result in runtime errors or undefined behavior.

Arrays as Function Parameters

To accept an array as a parameter for a function, the parameter can be declared as the array type with empty brackets, omitting the actual size of the array.

Example:

void procedure(int arg[])

Multidimensional Arrays:

In a function declaration, it is also possible to include multidimensional arrays. For instance, a tridimensional array parameter can be declared as follows:

void procedure(int myarray[][3][4])

Notice that the first brackets [] are left empty, while the following ones specify sizes for their respective dimensions. This is necessary for the compiler to determine the depth of each additional dimension.

std::array

std::array is a container that provides the performance and accessibility of a C-style array along with the benefits of a standard container, such as knowing its size, supporting assignment, random access iterators, etc.

Example:

template<typename T, std::size_t N>
struct array {
    T data[N];
};

With modern C++ features, it's even simpler to use:

std::array arr = { 1, 2, 3 };

std::vector vs std::array

  • std::vector is a template class that encapsulates a dynamic array stored on the heap, growing and shrinking automatically as elements are added or removed.
  • std::array encapsulates a statically-sized array stored inside the object itself, with the size known at compile time.

Raw Arrays vs. std::array

  • Using std::vector or std::array provides more features and safety compared to raw arrays.
  • Always prefer these safer alternatives unless you have a specific reason for using raw arrays.

When to Use What:

  • Use std::vector if you need a container with a dynamic size that can grow or shrink during runtime.
  • Use a raw array if you have a fixed size known at compile time and need maximum efficiency.

Summary

Arrays are a crucial part of C++ programming. While raw arrays offer performance advantages, std::array and std::vector provide safety and flexibility, making them the preferred choice in most situations. Understanding when and how to use these different types of arrays will help you write more efficient and maintainable C++ code.

References

On this page